-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Generic implementation for QuickCheck's Arbitrary -- -- Generic implementations of methods of the Arbitrary class from -- the QuickCheck library. The approach taken here can lead to diverging -- instances for mutually recursive types but is safe for simply -- recursive ones and guarantees flat distribution for constructors of -- sum-types. @package generic-arbitrary @version 1.0.0 -- | This module is a generic implementation of the arbitrary -- method. Example usage: -- --
-- data Foo = Foo
-- { _fooX :: X
-- , _fooY :: Y
-- } deriving (Generic)
--
-- instance Arbitrary Foo where
-- arbitrary = genericArbitrary
-- shrink = genericShrink
--
--
-- This instance can also be derived using DerivingVia language extension
--
--
-- data Foo = Foo
-- { _fooX :: X
-- , _fooY :: Y
-- } deriving (Generic)
-- deriving (Arbitrary) via GenericArbitrary Foo
--
--
-- The generated arbitrary method is equivalent to
--
-- -- Foo <$> arbitrary <*> arbitrary ---- -- . -- -- It can also handle a recursive types problem. Assuming a type -- --
-- data R = R R -- deriving Generic ---- -- there is no instance -- --
-- instance Arbitrary R where -- arbitrary = genericArbitrary -- shrink = genericShrink ---- -- If you try to compile this you will get a type level error -- --
-- • R refers to itself in all constructors ---- -- Which means that there is no finite term for R because it is -- recursive. But, if you correct the definition of R like this. -- --
-- data R = R R | F -- deriving Generic ---- -- Then it will compile. And the arbitrary generated will not -- hang forever, because it respects the size parameter. -- -- There is a limitation of recursion detection: -- --
-- data R1 = R1 R2 -- deriving (Eq, Ord, Show, Generic) -- deriving anyclass NFData -- deriving Arbitrary via (GenericArbitrary R1) -- -- data R2 = R2 R1 -- deriving (Eq, Ord, Show, Generic) -- deriving anyclass NFData -- deriving Arbitrary via (GenericArbitrary R2) ---- -- This code will compile and the arbitrary generated will -- always hang. Yes, there is a problem with mutually recursive types. -- -- Now lets see an example of datatype with parameters -- --
-- data A a = A a -- deriving (Eq, Ord, Show) -- deriving anyclass NFData -- deriving (Generic) -- -- instance (Arbitrary a) => Arbitrary (A a) where -- arbitrary = genericArbitrary -- shrink = genericShrink ---- -- It should work from first glance, but when compile it will throw an -- error: -- --
-- • Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary
-- (A a)
-- (GHC.Generics.D1
-- ('GHC.Generics.MetaData A ParametersTest "main" 'False)
-- (GHC.Generics.C1
-- ('GHC.Generics.MetaCons A 'GHC.Generics.PrefixI 'False)
-- (GHC.Generics.S1
-- ('GHC.Generics.MetaSel
-- 'Nothing
-- 'GHC.Generics.NoSourceUnpackedness
-- 'GHC.Generics.NoSourceStrictness
-- 'GHC.Generics.DecidedLazy)
-- (GHC.Generics.Rec0 a))))
-- (TypesDiffer (A a) a))
-- arising from a use of ‘genericArbitrary’
--
--
-- Here the TypesDiffer is a type familty dealing with recursive
-- types and helping us to eliminate inproper instances. To convince the
-- compiller, that the a parameter is not an A a we
-- must fix the instance with additional constraint
--
-- -- instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where -- arbitrary = genericArbitrary -- shrink = genericShrink ---- -- Now everything compiles and works as expected. module Test.QuickCheck.Arbitrary.Generic genericArbitrary :: forall a ga some. (Generic a, GArbitrary a ga some, ga ~ Rep a) => Gen a -- | Newtype for DerivingVia -- -- Usage: -- --
-- data Foo = Foo
-- { _fooX :: X
-- , _fooY :: Y
-- } deriving (Generic)
-- deriving (Arbitrary) via GenericArbitrary Foo
--
newtype GenericArbitrary a
GenericArbitrary :: a -> GenericArbitrary a
[unGenericArbitrary] :: GenericArbitrary a -> a
-- | Constraint helper for types with parameters
--
-- Usage:
--
-- -- data A a = A a -- deriving (Generic) -- instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where -- arbitrary = genericArbitrary -- shrink = genericShrink --type Arg self field = (TypesDiffer self field ~ 'True) -- | Generic arbitrary. -- -- Parameters are: * self: the ADT we generating instance for * a: some -- part of the `Rep self` * finite: Is a finite? Infinite type -- has no finite values (like Stream) class (Finite self a ~ finite) => GArbitrary self a (finite :: Bool) class (Finite self a ~ af, Finite self b ~ bf) => FiniteSum self (a :: * -> *) (b :: * -> *) af bf class FiniteSumElem self a type family Finite self (a :: * -> *) :: Bool type family AllFieldsFinal self (a :: * -> *) :: Bool type family TypesDiffer a b type family ArgumentsCount (a :: * -> *) :: Nat -- | Calculates count of constructors encoded by particular :+:. -- Internal use only. type family SumLen a :: Nat -- | Random generation and shrinking of values. -- -- QuickCheck provides Arbitrary instances for most types in -- base, except those which incur extra dependencies. For a -- wider range of Arbitrary instances see the -- quickcheck-instances package. class Arbitrary a -- | A generator for values of the given type. -- -- It is worth spending time thinking about what sort of test data you -- want - good generators are often the difference between finding bugs -- and not finding them. You can use sample, label and -- classify to check the quality of your test data. -- -- There is no generic arbitrary implementation included because -- we don't know how to make a high-quality one. If you want one, -- consider using the testing-feat or generic-random -- packages. -- -- The QuickCheck manual goes into detail on how to write good -- generators. Make sure to look at it, especially if your type is -- recursive! arbitrary :: Arbitrary a => Gen a -- | Produces a (possibly) empty list of all the possible immediate shrinks -- of the given value. -- -- The default implementation returns the empty list, so will not try to -- shrink the value. If your data type has no special invariants, you can -- enable shrinking by defining shrink = genericShrink, -- but by customising the behaviour of shrink you can often get -- simpler counterexamples. -- -- Most implementations of shrink should try at least three -- things: -- --
-- data Tree a = Nil | Branch a (Tree a) (Tree a) ---- -- We can then define shrink as follows: -- --
-- shrink Nil = [] -- shrink (Branch x l r) = -- -- shrink Branch to Nil -- [Nil] ++ -- -- shrink to subterms -- [l, r] ++ -- -- recursively shrink subterms -- [Branch x' l' r' | (x', l', r') <- shrink (x, l, r)] ---- -- There are a couple of subtleties here: -- --
-- shrink x = shrinkToNil x ++ genericShrink x -- where -- shrinkToNil Nil = [] -- shrinkToNil (Branch _ l r) = [Nil] ---- -- genericShrink is a combination of subterms, which -- shrinks a term to any of its subterms, and recursivelyShrink, -- which shrinks all subterms of a term. These may be useful if you need -- a bit more control over shrinking than genericShrink gives you. -- -- A final gotcha: we cannot define shrink as simply -- shrink x = Nil:genericShrink x as this shrinks -- Nil to Nil, and shrinking will go into an infinite -- loop. -- -- If all this leaves you bewildered, you might try shrink = -- genericShrink to begin with, after deriving -- Generic for your type. However, if your data type has any -- special invariants, you will need to check that genericShrink -- can't break those invariants. shrink :: Arbitrary a => a -> [a] -- | Shrink a term to any of its immediate subterms, and also recursively -- shrink all subterms. genericShrink :: (Generic a, RecursivelyShrink (Rep a), GSubterms (Rep a) a) => a -> [a] instance GHC.Classes.Eq a => GHC.Classes.Eq (Test.QuickCheck.Arbitrary.Generic.GenericArbitrary a) instance GHC.Show.Show a => GHC.Show.Show (Test.QuickCheck.Arbitrary.Generic.GenericArbitrary a) instance (Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self a, Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self b, Test.QuickCheck.Arbitrary.Generic.Finite self a GHC.Types.~ 'GHC.Types.True, Test.QuickCheck.Arbitrary.Generic.Finite self b GHC.Types.~ 'GHC.Types.True) => Test.QuickCheck.Arbitrary.Generic.FiniteSum self a b 'GHC.Types.True 'GHC.Types.True instance (Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self a, Test.QuickCheck.Arbitrary.Generic.Finite self a GHC.Types.~ 'GHC.Types.True, Test.QuickCheck.Arbitrary.Generic.Finite self b GHC.Types.~ 'GHC.Types.False) => Test.QuickCheck.Arbitrary.Generic.FiniteSum self a b 'GHC.Types.True 'GHC.Types.False instance (Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self b, Test.QuickCheck.Arbitrary.Generic.Finite self a GHC.Types.~ 'GHC.Types.False, Test.QuickCheck.Arbitrary.Generic.Finite self b GHC.Types.~ 'GHC.Types.True) => Test.QuickCheck.Arbitrary.Generic.FiniteSum self a b 'GHC.Types.False 'GHC.Types.True instance Test.QuickCheck.Arbitrary.Generic.FiniteSum self a b af bf => Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self (a GHC.Generics.:+: b) instance Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.C c f) 'GHC.Types.True => Test.QuickCheck.Arbitrary.Generic.FiniteSumElem self (GHC.Generics.M1 GHC.Generics.C c f) instance (Test.QuickCheck.Arbitrary.Generic.FiniteSum self a b af bf, Test.QuickCheck.Arbitrary.Generic.GArbitrary self (a GHC.Generics.:+: b) 'GHC.Types.True) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.D t (a GHC.Generics.:+: b)) 'GHC.Types.True instance (GHC.Generics.Generic a, Test.QuickCheck.Arbitrary.Generic.GArbitrary a (GHC.Generics.Rep a) some, Test.QuickCheck.Arbitrary.RecursivelyShrink (GHC.Generics.Rep a), Test.QuickCheck.Arbitrary.GSubterms (GHC.Generics.Rep a) a) => Test.QuickCheck.Arbitrary.Arbitrary (Test.QuickCheck.Arbitrary.Generic.GenericArbitrary a) instance Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.C c f) 'GHC.Types.True => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.D t (GHC.Generics.M1 GHC.Generics.C c f)) 'GHC.Types.True instance (Test.QuickCheck.Arbitrary.Generic.GArbitrary self f some, GHC.TypeNats.KnownNat (Test.QuickCheck.Arbitrary.Generic.ArgumentsCount f), Test.QuickCheck.Arbitrary.Generic.AllFieldsFinal self f GHC.Types.~ some) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.C c f) some instance Test.QuickCheck.Arbitrary.Generic.GArbitrary self GHC.Generics.U1 'GHC.Types.True instance Test.QuickCheck.Arbitrary.Generic.GArbitrary self f some => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.S t f) some instance (Test.QuickCheck.Arbitrary.Arbitrary t, Test.QuickCheck.Arbitrary.Generic.Finite self (GHC.Generics.K1 GHC.Generics.R t) GHC.Types.~ some) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.K1 GHC.Generics.R t) some instance (Test.QuickCheck.Arbitrary.Generic.GArbitrary self a af, Test.QuickCheck.Arbitrary.Generic.GArbitrary self b bf, (af Data.Type.Bool.&& bf) GHC.Types.~ some) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (a GHC.Generics.:*: b) some instance ((TypeError ...), Test.QuickCheck.Arbitrary.Generic.AllFieldsFinal self f GHC.Types.~ 'GHC.Types.False) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.D t (GHC.Generics.M1 GHC.Generics.C c f)) 'GHC.Types.False instance (Test.QuickCheck.Arbitrary.Generic.GArbitrary self a af, Test.QuickCheck.Arbitrary.Generic.GArbitrary self b bf, GHC.TypeNats.KnownNat (Test.QuickCheck.Arbitrary.Generic.SumLen a), GHC.TypeNats.KnownNat (Test.QuickCheck.Arbitrary.Generic.SumLen b), (af Data.Type.Bool.|| bf) GHC.Types.~ some) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (a GHC.Generics.:+: b) some instance ((TypeError ...), (Test.QuickCheck.Arbitrary.Generic.Finite self a Data.Type.Bool.|| Test.QuickCheck.Arbitrary.Generic.Finite self b) GHC.Types.~ 'GHC.Types.False) => Test.QuickCheck.Arbitrary.Generic.GArbitrary self (GHC.Generics.M1 GHC.Generics.D t (a GHC.Generics.:+: b)) 'GHC.Types.False