@@ -1,14 +1,8 @@
1−#if __GLASGOW_HASKELL__ >= 806
1+{-# LANGUAGE FlexibleContexts, UndecidableInstances, TypeOperators, DataKinds, TypeFamilies, ScopedTypeVariables#-}
2−{-# OPTIONS_GHC -Wno-star-is-type #-}
4−#if __GLASGOW_HASKELL__ >= 800
5−{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-}
10−This module is a generic implementation of the 'arbitrary' method. Example
5+Generic implementation of the 'arbitrary' method. Example usage:
14data Foo = Foo
8data Foo = Foo
@@ -33,184 +27,45 @@ data Foo = Foo
34The generated 'arbitrary' method is equivalent to
28The generated 'arbitrary' method is equivalent to
37−Foo '<$>' arbitrary '<*>' arbitrary
30+@Foo <$> arbitrary <*> arbitrary@.
40−It can also handle a recursive types problem. Assuming a type
50−instance Arbitrary R where
51− arbitrary = genericArbitrary
52− shrink = genericShrink
55−If you try to compile this you will get a type level error
57−> • R refers to itself in all constructors
59−Which means that there is no finite term for @R@ because it is recursive. But,
60−if you correct the definition of @R@ like this.
67−Then it will compile. And the @arbitrary@ generated will not hang forever, because
68−it respects the @size@ parameter.
70−There is a limitation of recursion detection:
74− deriving (Eq, Ord, Show, Generic)
75− deriving anyclass NFData
76− deriving Arbitrary via (GenericArbitrary R1)
79− deriving (Eq, Ord, Show, Generic)
80− deriving anyclass NFData
81− deriving Arbitrary via (GenericArbitrary R2)
84−This code will compile and the @arbitrary@ generated will always hang. Yes,
85−there is a problem with mutually recursive types.
87−Now lets see an example of datatype with parameters
91− deriving (Eq, Ord, Show)
92− deriving anyclass NFData
95−instance (Arbitrary a) => Arbitrary (A a) where
96− arbitrary = genericArbitrary
97− shrink = genericShrink
100−It should work from first glance, but when compile it will throw an error:
103− • Could not deduce (Test.QuickCheck.Arbitrary.Generic.GArbitrary
106− ('GHC.Generics.MetaData "A" "ParametersTest" "main" 'False)
108− ('GHC.Generics.MetaCons "A" 'GHC.Generics.PrefixI 'False)
110− ('GHC.Generics.MetaSel
112− 'GHC.Generics.NoSourceUnpackedness
113− 'GHC.Generics.NoSourceStrictness
114− 'GHC.Generics.DecidedLazy)
115− (GHC.Generics.Rec0 a))))
116− (TypesDiffer (A a) a))
117− arising from a use of ‘genericArbitrary’
120−Here the @TypesDiffer@ is a type familty dealing with recursive types and
121−helping us to eliminate inproper instances. To convince the compiller, that the
122−@a@ parameter is not an @A a@ we must fix the instance with additional constraint
125−instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where
126− arbitrary = genericArbitrary
127− shrink = genericShrink
130−Now everything compiles and works as expected.
134module Test.QuickCheck.Arbitrary.Generic
34module Test.QuickCheck.Arbitrary.Generic
137−#if MIN_VERSION_QuickCheck(2, 14, 0)
138− , GenericArbitrary(..)
35+ ( GenericArbitrary(..)
151 , Arbitrary(..)
36 , Arbitrary(..)
152 , genericShrink
39 , genericShrink
155import Control.Applicative
42import Control.Applicative
43+import Data.Coerce (coerce)
156import Data.Proxy
44import Data.Proxy
157import Data.Type.Bool
45import Data.Type.Bool
158import GHC.Generics as G
46import GHC.Generics as G
159import GHC.TypeLits
47import GHC.TypeLits
161import Test.QuickCheck as QC
48import Test.QuickCheck as QC
162−#if MIN_VERSION_QuickCheck(2, 14, 0)
163−import Data.Coerce (coerce)
164import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
49import Test.QuickCheck.Arbitrary (GSubterms, RecursivelyShrink)
168−-- | Newtype for @DerivingVia@
176−-- } deriving (Generic)
177−-- deriving (Arbitrary) via GenericArbitrary Foo
181newtype GenericArbitrary a = GenericArbitrary { unGenericArbitrary :: a }
51newtype GenericArbitrary a = GenericArbitrary { unGenericArbitrary :: a }
182 deriving (Show, Eq)
52 deriving (Show, Eq)
185 ( Generic a,
55 ( Generic a,
186− GArbitrary a (Rep a) some,
56+ GArbitrary a (Rep a) 'True,
187 RecursivelyShrink (Rep a),
57 RecursivelyShrink (Rep a),
188 GSubterms (Rep a) a
58 GSubterms (Rep a) a
189 ) => Arbitrary (GenericArbitrary a) where
59 ) => Arbitrary (GenericArbitrary a) where
190 arbitrary = coerce (genericArbitrary :: Gen a)
60 arbitrary = coerce (genericArbitrary :: Gen a)
191 shrink = coerce (genericShrink :: a -> [a])
61 shrink = coerce (genericShrink :: a -> [a])
194−-- | Constraint helper for types with parameters
200−-- deriving (Generic)
201−-- instance (Arg (A a) a, Arbitrary a) => Arbitrary (A a) where
202−-- arbitrary = genericArbitrary
203−-- shrink = genericShrink
208−type Arg self field = (TypesDiffer self field ~ 'True)
210type family TypesDiffer a b where
63type family TypesDiffer a b where
211 TypesDiffer a a = 'False
64 TypesDiffer a a = 'False
212 TypesDiffer a b = 'True
65 TypesDiffer a b = 'True
67+type Arg self field = (TypesDiffer self field ~ 'True)
214type family AllFieldsFinal self (a :: * -> *) :: Bool where
69type family AllFieldsFinal self (a :: * -> *) :: Bool where
215 AllFieldsFinal self U1 = 'True
70 AllFieldsFinal self U1 = 'True
216 AllFieldsFinal self (a :*: b) = AllFieldsFinal self a && AllFieldsFinal self b
71 AllFieldsFinal self (a :*: b) = AllFieldsFinal self a && AllFieldsFinal self b
@@ -246,8 +101,8 @@ class (Finite self a ~ finite) => GArbitrary self a (finite :: Bool) where
246 gArbitrary :: Proxy self -> QC.Gen (a x)
101 gArbitrary :: Proxy self -> QC.Gen (a x)
249− ( GArbitrary self (M1 C c f) 'True
104+ ( GArbitrary self (C1 c f) 'True
250− ) => GArbitrary self (M1 D t (M1 C c f)) 'True where
105+ ) => GArbitrary self (D1 t (C1 c f)) 'True where
251 gArbitrary _ = M1 <$> gArbitrary (Proxy :: Proxy self)
106 gArbitrary _ = M1 <$> gArbitrary (Proxy :: Proxy self)
253-- | The constructor meta information
108-- | The constructor meta information
@@ -255,7 +110,7 @@ instance
255 ( GArbitrary self f some
110 ( GArbitrary self f some
256 , KnownNat (ArgumentsCount f)
111 , KnownNat (ArgumentsCount f)
257 , AllFieldsFinal self f ~ some
112 , AllFieldsFinal self f ~ some
258− ) => GArbitrary self (M1 C c f) some where
113+ ) => GArbitrary self (C1 c f) some where
259 gArbitrary _ = M1 <$> scale predNat (gArbitrary (Proxy :: Proxy self))
114 gArbitrary _ = M1 <$> scale predNat (gArbitrary (Proxy :: Proxy self))
261 argumentsCount = fromIntegral $ natVal (Proxy :: Proxy (ArgumentsCount f))
116 argumentsCount = fromIntegral $ natVal (Proxy :: Proxy (ArgumentsCount f))
@@ -268,14 +123,14 @@ instance GArbitrary self U1 'True where
268 gArbitrary _ = pure U1
123 gArbitrary _ = pure U1
270-- | Constructor field meta information
125-- | Constructor field meta information
271−instance GArbitrary self f some => GArbitrary self (M1 S t f) some where
126+instance GArbitrary self f some => GArbitrary self (S1 t f) some where
272 gArbitrary _ = M1 <$> gArbitrary (Proxy :: Proxy self)
127 gArbitrary _ = M1 <$> gArbitrary (Proxy :: Proxy self)
274-- | Data of the constructor field
129-- | Data of the constructor field
276 ( Arbitrary t
131 ( Arbitrary t
277− , Finite self (K1 R t) ~ some
132+ , Finite self (Rec0 t) ~ some
278− ) => GArbitrary self (K1 R t) some where
133+ ) => GArbitrary self (Rec0 t) some where
279 gArbitrary _ = K1 <$> arbitrary
134 gArbitrary _ = K1 <$> arbitrary
281-- | Product
136-- | Product
@@ -291,7 +146,7 @@ instance
292 ( TypeError (ShowType self :<>: Text " refers to itself in all constructors")
147 ( TypeError (ShowType self :<>: Text " refers to itself in all constructors")
293 , AllFieldsFinal self f ~ 'False
148 , AllFieldsFinal self f ~ 'False
294− ) => GArbitrary self (M1 D t (M1 C c f)) 'False where
149+ ) => GArbitrary self (D1 t (C1 c f)) 'False where
295 gArbitrary _ = error "Unreachable"
150 gArbitrary _ = error "Unreachable"
@@ -299,7 +154,7 @@ instance
300 ( FiniteSum self a b af bf
155 ( FiniteSum self a b af bf
301 , GArbitrary self (a :+: b) 'True
156 , GArbitrary self (a :+: b) 'True
302− ) => GArbitrary self (M1 D t (a :+: b)) 'True where
157+ ) => GArbitrary self (D1 t (a :+: b)) 'True where
303 gArbitrary _ = sized $ \s -> M1 <$>
158 gArbitrary _ = sized $ \s -> M1 <$>
305 then gArbitrary (Proxy :: Proxy self)
160 then gArbitrary (Proxy :: Proxy self)
@@ -355,8 +210,8 @@ instance
355 finiteElem _ = finiteSum (Proxy :: Proxy self)
210 finiteElem _ = finiteSum (Proxy :: Proxy self)
358− ( GArbitrary self (M1 C c f) 'True
213+ ( GArbitrary self (C1 c f) 'True
359− ) => FiniteSumElem self (M1 C c f) where
214+ ) => FiniteSumElem self (C1 c f) where
360 finiteElem _ = [gArbitrary (Proxy :: Proxy self)]
215 finiteElem _ = [gArbitrary (Proxy :: Proxy self)]
@@ -364,7 +219,7 @@ instance
365 ( TypeError (ShowType self :<>: Text " refers to itself in all constructors")
220 ( TypeError (ShowType self :<>: Text " refers to itself in all constructors")
366 , (Finite self a || Finite self b) ~ 'False
221 , (Finite self a || Finite self b) ~ 'False
367− ) => GArbitrary self (M1 D t (a :+: b)) 'False where
222+ ) => GArbitrary self (D1 t (a :+: b)) 'False where
368 gArbitrary _ = error "Unreachable"
223 gArbitrary _ = error "Unreachable"