2

I'm trying to understand how shrink works in Haskell's QuickCheck, so I've come up with a minimal example shown below, but when I run it, the falsified examples are not shrunk.

The result object shows that no shrinks where tried, and adding a "trace" to the shrink definition doesn't print anything.

So why are the counterexamples not shrunk? Why is 'shrink' never called?

import Debug.Trace
import Test.QuickCheck

simpleString = listOf1 $ choose ('a','d')

newtype SimpleString = SimpleString String deriving (Show)

splits l = [splitAt i l | i <- [0..length l]]
removeOne l = [x ++ drop 1 y | (x,y) <- splits l, y /= []]

instance Arbitrary SimpleString where
    arbitrary = fmap SimpleString simpleString
    shrink ss | trace ("shrink " ++ show ss) False = undefined
    shrink (SimpleString []) | trace "  shrink []" True = [SimpleString ""]
    shrink (SimpleString ss) | trace ("  shrink " ++ show ss) True = [SimpleString ss' | ss' <- removeOne ss ]

numberOf c l = length $ filter (== c) l

prop = forAll arbitrary $ \(SimpleString s) -> length s > 5 ==> numberOf 'a' s /= numberOf 'b' s

Every sample run with quickCheckResult prop yields something like the following:

*** Failed! Falsified (after 4 tests):  
SimpleString "aaccbb"
Failure {numTests = 4, numDiscarded = 190, numShrinks = 0, numShrinkTries = 0, numShrinkFinal = 0, usedSeed = SMGen 8220098710381543270 7510598040095200595, usedSize = 6, reason = "Falsified", theException = Nothing, output = "*** Failed! Falsified (after 4 tests):\nSimpleString \"aaccbb\"\n", failingTestCase = ["SimpleString \"aaccbb\""], failingLabels = [], failingClasses = fromList []}

Note that numShrinks = 0, numShrinkTries = 0 always. Why is this?

Thanks

PS: I'm running ghc 8.8.3 with QuickCheck 2.14.2 on macOS.

  • 4
    From a look at the documentation for [`forAll`](https://hackage.haskell.org/package/QuickCheck-2.14.2/docs/Test-QuickCheck.html#v:forAll), you probably want the one that comes right after it, `forAllShrink`, with docstring "Like `forAll`, but tries to shrink the argument for failing test cases.". – Daniel Wagner Aug 22 '21 at 01:01

0 Answers0