I've got a protocol that I've typed like so:
data ProtocolPacket
= Packet1 Word8 Text Int8
| Packet2 Text
| Packet3 Int Text Text Text Text
| Packet4 Int Double Double Double Int16 Int16 Int16
...
deriving (Show,Eq)
In addition, I've implemented serialization/deserialization code for each packet. Naturally, I would like to test this protocol in Quickcheck and make sure that serializing and deserializing any packet for any combination of inputs will give me back exactly what I put in. So I go ahead and implement these packets for the Arbitrary
type class like so:
instance Arbitrary ProtocolPacket where
arbitrary = do
packetID <- choose (0x00,...) :: Gen Word8
case packetID of
0x00 -> do
a <- arbitrary
b <- arbitrary
c <- arbitrary
return $ Packet1 a b c
0x01 -> do
a <- arbitrary
return $ Packet2 a
0x02 -> do
a <- arbitrary
b <- arbitrary
c <- arbitrary
d <- arbitrary
e <- arbitrary
return $ Packet3 a b c d e
0x03 -> do
a <- arbitrary
b <- arbitrary
c <- arbitrary
d <- arbitrary
e <- arbitrary
f <- arbitrary
g <- arbitrary
return $ Packet4 a b c d e f g
...
Assume that I've gone ahead and defined Arbitrary
for all relevant data constructor arguments that don't have Arbitrary
defined out of the box, such code needs to be hand-written by me in order for the packet fields to be populated with meaningful data. But that's it.
But as you can see, I'm repeating myself a lot for something that is just grunt work. And this is a small sample of what I'm actually dealing with. Ideally, I would like to be able to just do this:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data ProtocolPacket
= Packet1 Word8 Text Int8
| Packet2 Text
| Packet3 Int Text Text Text Text
| Packet4 Int Double Double Double Int16 Int16 Int16
...
deriving (Show,Eq,Generic)
instance Arbitrary ProtocolPacket
like I can do with FromJSON
and ToJSON
, but this doesn't work. Is there there a method that does?
generic-random
. – DilatometerliftM2
operator and its siblings. Your case is the same as: ` case packetID of 0x00 -> liftM3 Packet1 a a a; 0x01 -> liftM Packet2 a; 0x02 -> liftM5 Packet3 a a a a a; 0x03 -> liftM7 Packet4 a a a a a a a; where a = arbitrary` – Serotherapyuncaught exception: ErrorCall (no representation.) Exception thrown while printing test case: 'No representation.'
from Quickcheck and I'm not sure what's generating it. Right now, all I can tell is that it doesn't like data constructors that haveByteString
as an argument. I have no idea why. I'm currently testing it on pretty simple examples. – SpoliationQuickCheck
, but it needs some care: github.com/nick8325/quickcheck/pull/40 – Flattop