module Test.QuickCheck.Arbitrary.ADT (
ConstructorArbitraryPair(..)
, ADTArbitrarySingleton(..)
, ADTArbitrary(..)
, ToADTArbitrary(..)
, GToADTArbitrarySingleton(..)
, GToADTArbitrary(..)
, GArbitrary(..)
, genericArbitrary
) where
import Data.Typeable
import GHC.Generics
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Gen
data ConstructorArbitraryPair a =
ConstructorArbitraryPair
{ capConstructor :: String
, capArbitrary :: a
} deriving (Eq,Generic,Read,Show,Typeable)
instance Functor ConstructorArbitraryPair where
fmap f (ConstructorArbitraryPair c a) = ConstructorArbitraryPair c (f a)
instance (Arbitrary a) => Arbitrary (ConstructorArbitraryPair a) where
arbitrary = ConstructorArbitraryPair <$> arbitrary <*> arbitrary
data ADTArbitrarySingleton a =
ADTArbitrarySingleton
{ adtasModuleName :: String
, adtasTypeName :: String
, adtasCAP :: ConstructorArbitraryPair a
} deriving (Eq,Generic,Read,Show,Typeable)
instance Functor ADTArbitrarySingleton where
fmap f (ADTArbitrarySingleton m t c) = ADTArbitrarySingleton m t (f <$> c)
instance (Arbitrary a) => Arbitrary (ADTArbitrarySingleton a) where
arbitrary = ADTArbitrarySingleton <$> arbitrary <*> arbitrary <*> arbitrary
data ADTArbitrary a =
ADTArbitrary
{ adtModuleName :: String
, adtTypeName :: String
, adtCAPs :: [ConstructorArbitraryPair a]
} deriving (Eq,Generic,Read,Show,Typeable)
instance Functor ADTArbitrary where
fmap f (ADTArbitrary m t cs) = ADTArbitrary m t (fmap f <$> cs)
instance (Arbitrary a) => Arbitrary (ADTArbitrary a) where
arbitrary = ADTArbitrary <$> arbitrary <*> arbitrary <*> arbitrary
class ToADTArbitrary a where
toADTArbitrarySingleton :: Proxy a -> Gen (ADTArbitrarySingleton a)
default toADTArbitrarySingleton ::
( Generic a
, GToADTArbitrarySingleton (Rep a)
)
=> Proxy a
-> Gen (ADTArbitrarySingleton a)
toADTArbitrarySingleton _ = fmap to <$> gToADTArbitrarySingleton (Proxy :: Proxy (Rep a))
toADTArbitrary :: Proxy a -> Gen (ADTArbitrary a)
default toADTArbitrary ::
( Generic a
, GToADTArbitrary (Rep a)
)
=> Proxy a
-> Gen (ADTArbitrary a)
toADTArbitrary _ = fmap to <$> gToADTArbitrary (Proxy :: Proxy (Rep a))
class GToADTArbitrarySingleton rep where
gToADTArbitrarySingleton :: Proxy rep -> Gen (ADTArbitrarySingleton (rep a))
instance GToADTArbitrarySingleton U1 where
gToADTArbitrarySingleton _ = pure $ ADTArbitrarySingleton "" "" $ ConstructorArbitraryPair "" U1
instance (GToADTArbitrarySingleton l, GToADTArbitrarySingleton r) => GToADTArbitrarySingleton (l :+: r) where
gToADTArbitrarySingleton _ = do
b <- arbitrary
if b then fmap L1 <$> gToADTArbitrarySingleton (Proxy :: Proxy l)
else fmap R1 <$> gToADTArbitrarySingleton (Proxy :: Proxy r)
instance (GToADTArbitrarySingleton l, GToADTArbitrarySingleton r) => GToADTArbitrarySingleton (l :*: r) where
gToADTArbitrarySingleton _ = do
x <- getArb <$> gToADTArbitrarySingleton (Proxy :: Proxy l)
y <- getArb <$> gToADTArbitrarySingleton (Proxy :: Proxy r)
return $ ADTArbitrarySingleton "" "" $ ConstructorArbitraryPair "" (x :*: y)
where
getArb = capArbitrary . adtasCAP
instance Arbitrary a => GToADTArbitrarySingleton (K1 i a) where
gToADTArbitrarySingleton _ =
ADTArbitrarySingleton
<$> pure ""
<*> pure ""
<*> (ConstructorArbitraryPair
<$> pure ""
<*> K1 <$> arbitrary)
instance (Constructor c, GToADTArbitrarySingleton rep) => GToADTArbitrarySingleton (M1 C c rep) where
gToADTArbitrarySingleton _ =
ADTArbitrarySingleton
<$> pure ""
<*> pure ""
<*> (ConstructorArbitraryPair con <$> ac)
where
kRep = gToADTArbitrarySingleton (Proxy :: Proxy rep)
ac = M1 . capArbitrary . adtasCAP <$> kRep
con = conName (undefined :: M1 C c rep ())
instance (Datatype t, Typeable t, GToADTArbitrarySingleton rep) => GToADTArbitrarySingleton (M1 D t rep) where
gToADTArbitrarySingleton _ =
ADTArbitrarySingleton
<$> pure m
<*> pure t
<*> (ConstructorArbitraryPair
<$> (capConstructor . adtasCAP <$> kRep)
<*> ac)
where
kRep = gToADTArbitrarySingleton (Proxy :: Proxy rep)
ac = M1 . capArbitrary . adtasCAP <$> kRep
m = moduleName (undefined :: M1 D t rep ())
t = datatypeName (undefined :: M1 D t rep ())
instance GToADTArbitrarySingleton rep => GToADTArbitrarySingleton (M1 S t rep) where
gToADTArbitrarySingleton _ =
ADTArbitrarySingleton
<$> pure ""
<*> pure ""
<*> (ConstructorArbitraryPair
<$> pure ""
<*> ac)
where
kRep = gToADTArbitrarySingleton (Proxy :: Proxy rep)
ac = M1 . capArbitrary . adtasCAP <$> kRep
class GToADTArbitrary rep where
gToADTArbitrary :: Proxy rep -> Gen (ADTArbitrary (rep a))
instance GToADTArbitrary U1 where
gToADTArbitrary _ = pure $ ADTArbitrary "" "" [ConstructorArbitraryPair "" U1]
instance (GToADTArbitrary l, GToADTArbitrary r) => GToADTArbitrary (l :+: r) where
gToADTArbitrary _ = do
a <- fmap L1 <$> gToADTArbitrary (Proxy :: Proxy l)
b <- fmap R1 <$> gToADTArbitrary (Proxy :: Proxy r)
return $ ADTArbitrary "" "" (adtCAPs a ++ adtCAPs b)
instance (GToADTArbitrarySingleton l, GToADTArbitrarySingleton r) => GToADTArbitrary (l :*: r) where
gToADTArbitrary _ = do
x <- getArb <$> gToADTArbitrarySingleton (Proxy :: Proxy l)
y <- getArb <$> gToADTArbitrarySingleton (Proxy :: Proxy r)
return $ ADTArbitrary "" "" [ConstructorArbitraryPair "" (x :*: y)]
where
getArb = capArbitrary . adtasCAP
instance Arbitrary a => GToADTArbitrary (K1 i a) where
gToADTArbitrary _ =
ADTArbitrary
<$> pure ""
<*> pure ""
<*> (:[]) <$> genCap
where
arb = arbitrary :: Gen a
genCap = ConstructorArbitraryPair <$> pure "" <*> (K1 <$> arb)
instance (Constructor c, GToADTArbitrary rep) => GToADTArbitrary (M1 C c rep) where
gToADTArbitrary _ = ADTArbitrary <$> pure "" <*> pure "" <*> (:[]) . ConstructorArbitraryPair con <$> ac
where
kRep = gToADTArbitrary (Proxy :: Proxy rep)
ac = M1 . capArbitrary . head . adtCAPs <$> kRep
con = conName (undefined :: M1 C c rep ())
instance (Datatype t, GToADTArbitrary rep) => GToADTArbitrary (M1 D t rep) where
gToADTArbitrary _ = ADTArbitrary <$> pure m <*> pure t <*> m1caps
where
kRep = gToADTArbitrary (Proxy :: Proxy rep)
caps = adtCAPs <$> kRep
m1caps = (fmap . fmap) M1 <$> caps
m = moduleName (undefined :: M1 D t rep ())
t = datatypeName (undefined :: M1 D t rep ())
instance GToADTArbitrary rep => GToADTArbitrary (M1 S t rep) where
gToADTArbitrary _ =
ADTArbitrary
<$> pure ""
<*> pure ""
<*> (:[]) <$> (ConstructorArbitraryPair "" <$> ac)
where
kRep = gToADTArbitrary (Proxy :: Proxy rep)
ac = M1 . capArbitrary . head . adtCAPs <$> kRep
class GArbitrary rep where
gArbitrary :: Gen (rep a)
instance GArbitrary U1 where
gArbitrary = pure U1
instance (GArbitrary l, GArbitrary r) => GArbitrary (l :+: r) where
gArbitrary = do
b <- arbitrary
if b then L1 <$> gArbitrary
else R1 <$> gArbitrary
instance (GArbitrary l, GArbitrary r) => GArbitrary (l :*: r) where
gArbitrary = (:*:) <$> gArbitrary <*> gArbitrary
instance Arbitrary a => GArbitrary (K1 i a) where
gArbitrary = K1 <$> arbitrary
instance GArbitrary rep => GArbitrary (M1 i t rep) where
gArbitrary = M1 <$> gArbitrary
genericArbitrary :: (Generic a, GArbitrary (Rep a)) => Gen a
genericArbitrary = to <$> gArbitrary