Suppose that I am writing tests for Data.Set
. I would like to check that deleting elements from the set works, and so I might write something like this:
prop_deleteA it x = member x it ==> not (member x (delete x it))
assuming that it
has a suitable Arbitrary
instance. However, this relies on quickcheck generating values of x
that happen to exist within the set, which is not in general guaranteed. It would be much better if x
could be made to depend on it
so as to guarantee that x
is already a member of it
. How might I do this?
I had the thought that I could write
prop_deleteB it f = let x = f it
in not (member x (delete x it))
where f :: Set a -> a
is suitably defined by means of coarbitrary. However, coarbitrary would only allow us to define f :: Set a -> b
, which unfortunately isn't what we want. My best thought so far has been to define a new type
data SetAndElement a = SetAndElement (Set a) a
which allows us to write a suitable Arbitrary
instance
instance (Ord a, Arbitrary a) => Arbitrary (SetAndElement a) where
arbitrary = do it <- suchThat arbitrary (not . Set.null)
x <- elements (elems it)
return (SetAndElement it x)
allowing prop_delete
to be written as
prop_deleteC (SetAndElement it x) = not (member x (delete x it))
This works, but seems a little involved; are there any better options? (If not, I'll modify the question and put this as an answer.) The actual Data.Set
implementation (containers package) tests deletion by checking that (delete x) . (insert x) == id
if x
was not already a member of the given set.