I'm trying to create Arbitrary instances for some of my types to be used in QuickCheck property testing. I need randomly generated UUIDs, with the constraint that all-zero (nil) UUIDs are disallowed - that is, 00000000-0000-0000-0000-000000000000. Therefore, I set up the following generator:
nonzeroIdGen :: Gen UUID.UUID
nonzeroIdGen = arbitrary `suchThat` (not . UUID.null)
Which I use in an Arbitrary instance as follows:
instance Arbitrary E.EventId where
arbitrary = do
maybeEid <- E.mkEventId <$> nonzeroIdGen
return $ fromJust maybeEid
In general, this is unsafe code; but for testing, with supposedly guaranteed nonzero UUIDs, I thought the fromJust to be ok.
mkEventId is defined as
mkEventId :: UUID.UUID -> Maybe EventId
mkEventId uid = EventId <$> validateId uid
with EventId a new type-wrapper around UUID.UUID, and
validateId :: UUID.UUID -> Maybe UUID.UUID
validateId uuid = if UUID.null uuid then Nothing else Just uuid
To my surprise, I get failing tests because of all-zero UUIDs generated by the above code. A trace in mkEventId shows the following:
00000001-0000-0001-0000-000000000001
Just (EventId {getEventId = 00000001-0000-0001-0000-000000000001})
00000000-0000-0000-0000-000000000000
Nothing
Create valid Events. FAILED [1]
The first generated ID is fine, the second one is all-zero, despite my nonzeroIdGen generator from above. What am I missing?