Skip to content

Commit f082707

Browse files
authored
Merge pull request #92 from iconnect/adinapoli/investigate-migration-hangs
Add resize to arbitraryOfType and arbitraryOfDecl
2 parents 59ecd88 + e840934 commit f082707

2 files changed

Lines changed: 24 additions & 14 deletions

File tree

src/Data/API/Tools/QuickCheck.hs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,19 @@ distinguishedElements (x:xs) = ((True, x) : map ((,) False) xs)
194194
-- | Generate an 'Arbitrary' instance for a union:
195195
--
196196
-- > instance Arbitrary Foo where
197-
-- > arbitrary = oneOf [ fmap Bar arbitrary, fmap Baz arbitrary ]
197+
-- > arbitrary = sized $ \ x -> oneOf [ fmap Bar (resize (x `div` 2) arbitrary)
198+
-- > , fmap Baz (resize (x `div` 2) arbitrary) ]
198199

199200
gen_su_ab :: Tool (APINode, SpecUnion)
200201
gen_su_ab = mkTool $ \ ts (an, su) -> mkArbitraryInstance ts (nodeRepT an) (bdy an su) (shrinkUnion an su)
201202
where
202203
bdy an su | null (suFields su) = nodeConE an
203-
| otherwise = [e| oneof $(listE alts) |]
204-
where
205-
alts = [ [e| fmap $(nodeAltConE an k) arbitrary |]
206-
| (k, _) <- suFields su ]
204+
| otherwise = do
205+
x <- newName "x"
206+
let alts = [ [e| fmap $(nodeAltConE an k) (QC.resize ($(varE x) `div` 2) arbitrary) |]
207+
| (k, _) <- suFields su ]
208+
appE (varE 'QC.sized) $ lamE [varP x] $
209+
varE 'oneof `appE` listE alts
207210

208211
-- For a union, we shrink the individual wrappers.
209212
shrinkUnion :: APINode -> SpecUnion -> ExpQ

src/Data/API/Value.hs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -367,12 +367,16 @@ arbitrary api = do tn <- QC.elements (Map.keys api)
367367
return (TyName tn, v)
368368

369369
-- | Given a schema and a type, generate an arbitrary value of that
370-
-- type.
370+
-- type. Uses 'QC.sized' and 'QC.resize' to ensure recursive schemas
371+
-- terminate by halving the size parameter at each structural
372+
-- recursion point.
371373
arbitraryOfType :: NormAPI -> APIType -> QC.Gen Value
372-
arbitraryOfType api ty0 = case ty0 of
373-
TyName tn -> arbitraryOfDecl api (lookupTyName api tn)
374-
TyList ty -> List <$> QC.listOf (arbitraryOfType api ty)
375-
TyMaybe ty -> Maybe <$> QC.oneof [pure Nothing, Just <$> arbitraryOfType api ty]
374+
arbitraryOfType api ty0 = QC.sized $ \ size -> case ty0 of
375+
TyName tn -> QC.resize (size `div` 2) $ arbitraryOfDecl api (lookupTyName api tn)
376+
TyList ty -> List <$> QC.resize (size `div` 2) (QC.listOf (arbitraryOfType api ty))
377+
TyMaybe ty -> Maybe <$> if size <= 0
378+
then pure Nothing
379+
else QC.oneof [pure Nothing, Just <$> QC.resize (size `div` 2) (arbitraryOfType api ty)]
376380
TyJSON -> JSON <$> arbitraryJSONValue
377381
TyBasic bt -> arbitraryOfBasicType bt
378382

@@ -388,12 +392,15 @@ arbitraryOfBasicType bt = case bt of
388392
<$> QC.arbitrary
389393

390394
arbitraryOfDecl :: NormAPI -> NormTypeDecl -> QC.Gen Value
391-
arbitraryOfDecl api d = case d of
392-
NRecordType nrt -> Record <$> traverse (\ (fn, ty) -> Field fn <$> arbitraryOfType api ty) (Map.toList nrt)
395+
arbitraryOfDecl api d = QC.sized $ \size ->
396+
case d of
397+
NRecordType nrt ->
398+
let fields = Map.toList nrt
399+
in Record <$> traverse (\ (fn, ty) -> Field fn <$> QC.resize (size `div` 2) (arbitraryOfType api ty)) fields
393400
NUnionType nut -> do (fn, ty) <- QC.elements (Map.toList nut)
394-
Union fn <$> arbitraryOfType api ty
401+
Union fn <$> QC.resize (size `div` 2) (arbitraryOfType api ty)
395402
NEnumType net -> Enum <$> QC.elements (Set.toList net)
396-
NTypeSynonym ty -> arbitraryOfType api ty
403+
NTypeSynonym ty -> QC.resize (size `div` 2) (arbitraryOfType api ty)
397404
NNewtype bt -> arbitraryOfBasicType bt
398405

399406
-- | A reasonably varied generator for JSON 'JS.Value's.

0 commit comments

Comments
 (0)