recover-rtti-0.6.0: tests/Test/RecoverRTTI/QuickCheck/DepGen.hs
module Test.RecoverRTTI.QuickCheck.DepGen (
-- * Dependent generator
DepGen(..)
, depClassifier
, depGen
-- * Creation
, arbitraryDepGen
-- * Bundle a dependent generator with a lifting function
, GenK(..)
, GenKU(..)
, GenUK(..)
, GenKK(..)
, GenNP(..)
, genJust
, genLeft
, genRight
, genPair
, genNP
) where
import Data.Kind
import Data.SOP
import Data.SOP.Dict
import Test.QuickCheck
import Test.RecoverRTTI.QuickCheck.Sized (SizedGen)
import Test.RecoverRTTI.QuickCheck.Sized qualified as SG
{-------------------------------------------------------------------------------
Dependent generator
-------------------------------------------------------------------------------}
-- | Dependent generator
data DepGen c a where
DepGen :: (Show a, Eq a) => c a -> SizedGen a -> DepGen c a
depClassifier :: DepGen c a -> c a
depClassifier (DepGen c _) = c
depGen :: DepGen c a -> SizedGen a
depGen (DepGen _ gen) = gen
{-------------------------------------------------------------------------------
Construction
-------------------------------------------------------------------------------}
arbitraryDepGen :: (Arbitrary a, Show a, Eq a) => c a -> DepGen c a
arbitraryDepGen cc = DepGen cc $ SG.arbitrary
{-------------------------------------------------------------------------------
Bundle a dependent generator with a lifting function
These are designed to work with 'MaybeF' and co.
-------------------------------------------------------------------------------}
data GenK c (f :: Type -> Type) a = GenK {
justGen :: SizedGen a -> SizedGen (f a)
, justElem :: DepGen c a
}
data GenKU c (f :: Type -> Type -> Type) a = GenKU {
leftGen :: forall b. SizedGen a -> SizedGen (f a b)
, leftElem :: DepGen c a
}
data GenUK c (f :: Type -> Type -> Type) b = GenUK {
rightGen :: forall a. SizedGen b -> SizedGen (f a b)
, rightElem :: DepGen c b
}
data GenKK c (f :: Type -> Type -> Type) (ab :: (Type, Type)) where
GenKK :: forall c f a b. {
pairGen :: SizedGen a -> SizedGen b -> SizedGen (f a b)
, pairFst :: DepGen c a
, pairSnd :: DepGen c b
}
-> GenKK c f '(a, b)
data GenNP c f xs = GenNP {
npGen :: NP SizedGen xs -> SizedGen (f xs)
, npElem :: NP (DepGen c) xs
}
genJust ::
( forall x. Show x => Show (f x)
, forall x. Eq x => Eq (f x)
)
=> (c a -> c' (f a)) -> GenK c f a -> DepGen c' (f a)
genJust cf (GenK gen (DepGen cx gx)) =
DepGen (cf cx) (gen gx)
genLeft ::
( forall x y. (Show x, Show y) => Show (f x y)
, forall x y. (Eq x, Eq y) => Eq (f x y)
, Show b, Eq b
)
=> (c a -> c' (f a b)) -> GenKU c f a -> DepGen c' (f a b)
genLeft cf (GenKU gen (DepGen cx gx)) =
DepGen (cf cx) (gen gx)
genRight ::
( forall x y. (Show x, Show y) => Show (f x y)
, forall x y. (Eq x, Eq y) => Eq (f x y)
, Show a, Eq a
)
=> (c b -> c' (f a b)) -> GenUK c f b -> DepGen c' (f a b)
genRight cf (GenUK gen (DepGen cy gy)) =
DepGen (cf cy) (gen gy)
genPair ::
( forall x y. (Show x, Show y) => Show (f x y)
, forall x y. (Eq x, Eq y) => Eq (f x y)
)
=> ((c a, c b) -> c' (f a b)) -> GenKK c f '(a, b) -> DepGen c' (f a b)
genPair cf (GenKK gen (DepGen cx gx) (DepGen cy gy)) =
DepGen (cf (cx, cy)) $
gen (SG.withSize (`div` 2) gx)
(SG.withSize (`div` 2) gy)
genNP :: forall c c' f xs.
( SListI xs
, All Show xs => Show (f xs )
, All Eq xs => Eq (f xs)
)
=> (NP c xs -> c' (f xs)) -> GenNP c f xs -> DepGen c' (f xs)
genNP cf (GenNP gen elems) =
case (all_NP allShow, all_NP allEq) of
(Dict, Dict) ->
DepGen
(cf (hmap depClassifier elems))
(gen (hmap (SG.withSize divSize . depGen) elems))
where
divSize :: Int -> Int
divSize sz = (sz - 1) `div` lengthSList (Proxy @xs)
allShow :: NP (Dict Show) xs
allShow = hmap (\DepGen{} -> Dict) elems
allEq :: NP (Dict Eq) xs
allEq = hmap (\DepGen{} -> Dict) elems