Get the latest tech news
Falsify: Hypothesis-Inspired Shrinking for Haskell (2023)
Consider this falsify property test that tries to verify the (obviously false) property that all elements of all lists of up to 10 binary digits are the same (we will explain the details below; hopefully the intent is clear): prop_list :: Property () = do prop_list <- gen $ Gen.integral $ Range.between (0, 10) n <- gen $ replicateM n $ Gen.int $ Range.between (0, 1) xs $ P.pairwise P.eq .$ ("xs", xs) assert we might get a counter-example such as this: failed after 9 shrinks (xs !! 0) /= (xs !! 1) xs : [0,1] xs !! 0: 0 xs !! 1: 1 More interesting than the counter-example itself is how falsify arrived at that counter-example; if we look at the shrink history ( --falsify-verbose), we see that the list shrunk as follows: [1,1,0,1,0,1] ~> [1,1,0] -- shrink the list length ~> [0,1,0] -- shrink an element of the list ~> [0,1] -- shrink the list length again The test runner is able to go back and forth between shrinking the length and the list, and shrinking elements in the list. That is, we have integrated shrinking (like in hedgehog: we do not specify a separate generator and shrinker), which is internal: works across monadic bind.
In this blog post we will introduce falsify, a new library that provides property based testing in Haskell and has an approach to shrinking that is inspired by Hypothesis. This is a key component in making this work with infinite data structures; see upcoming paper for an in-depth discussion. It generated a function that maps anything to 0, a predicate that is True for 96 and False for everything else, and a list containing only the value 96; this is indeed a nice counter-example, as the output from the assert explains.
Or read this on Hacker News