Quickcheck: Custom Arbitrary Items

Suppose I write tests for Data.Set. I would like to verify that removing items from the set works, and so I can write something like this:

prop_deleteA it x = member x it ==> not (member x (delete x it))

assuming it ithas a suitable instance Arbitrary. However, this depends on the quickcheck values ​​generating the values xthat exist in the set, which is usually not guaranteed. It would be much better if xyou could depend on itto ensure that you are xalready a member it. How can i do this?

I had a thought that I could write

prop_deleteB it f = let x = f it
                   in not (member x (delete x it))

where f :: Set a -> asuitably determined using coarse. However, a coarbitrary would allow us to determine f :: Set a -> bthat, unfortunately, is not what we want. So far I have been thinking about defining a new type

data SetAndElement a = SetAndElement (Set a) a

allowing you to write a suitable instance Arbitrary

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)

allows you to prop_deleterecord as

prop_deleteC (SetAndElement it x) = not (member x (delete x it))

It works, but seems a bit involved; are there any better options? (If not, I will change the question and put this as the answer.) The actual implementation Data.Set(container package) checks the deletion, checking that (delete x) . (insert x) == idif it xhas not been a member of this set.

+4
source share
1 answer

, . , setOf1 ( Set ) setElements ( Set), forAll:

-- example implementations of both combinators
setOf1 :: (Arbitrary a, Ord a) => Gen a -> Gen (Set a)
setOf1 = fmap fromList . listOf1

setElements :: Set a -> Gen a
setElements = elements . toList

prop_delete =
  forAll (setOf1 arbitrary)   $ \theSet ->
  forAll (setElements theSet) $ \x ->
    not (member (x :: Int) (delete x theSet))

, SetAndElement, data , :

prop_null =  forAll (setOf1 (arbitrary :: Gen Integer)) $ not . null

, setOf1 setElements, forAll :

prop_delete :: (Arbitrary a, Ord a) => (NonEmptyList a) -> Property
prop_delete (NonEmpty xs) =
  let theSet = fromList xs
  in forAll (elements xs) $ \x ->
      not (member x (delete x theSet))

setElements NonEmptySet,

newtype NonEmptySet x = NonEmptySet {getNonEmptySet :: Set a}

instance (Ord a, Arbitray a) => Arbitrary (NonEmptySet a) where
  arbitrary = fmap NonEmptySet . setOf1 $ arbitrary

prop_delete :: (Arbitrary a, Ord a) => (NonEmptySet a) -> Property
prop_delete (NonEmptySet theSet) =
  forAll (setElements theSet) $ \x ->
    not (member x (delete x theSet))

, NonEmptySet , , setElements , .

+4

Source: https://habr.com/ru/post/1629719/


All Articles