Why does QuickCheck give up?
Asked Answered
M

1

12

I am using QuickCheck to test the following program:

{-# LANGUAGE TemplateHaskell #-}

import Test.QuickCheck
import Test.QuickCheck.All

elementAt :: (Integral b) => [a] -> b -> a
elementAt [x] _ = x
elementAt (x:xs) 1 = x
elementAt (x:xs) b = elementAt xs (b - 1)

prop_elementAt xs b = length xs > 0 && b >= 0 && b < length xs ==> elementAt xs (b + 1) == xs !! b

main = $(quickCheckAll)

Although the response varies, I constantly receive the message

*** Gave up! Passed only x tests.

Is this something I should be concerned about? Or does the nature of the test input dictate how long QuickCheck will run for?

Max answered 29/8, 2013 at 5:17 Comment(0)
D
18

The way ==> works is first quickcheck will generate random values for xs and b, then check if the predicate length xs > 0 && b >= 0 && b < length xs is satisfied only then it will check for the satisfiability of the property.

As there is a limit for how many test cases it will generate it might happen that lots of the time the above predicate is not satisfied. So quickcheck gives up before generating enough valid testcases (satisfying the predicate).

You should instead declare Arbitrary instance to a newtype to generate only testcases satisfying those predicates.

{-# LANGUAGE TemplateHaskell #-}

import Test.QuickCheck
import Test.QuickCheck.All

elementAt :: (Integral b) => [a] -> b -> a
elementAt [x] _ = x
elementAt (x:xs) 1 = x
elementAt (x:xs) b = elementAt xs (b - 1)

prop_elementAt (Foo xs b) = elementAt xs (b + 1) == xs !! b

data Foo a b = Foo [a] b deriving (Show)

instance (Integral b, Arbitrary a, Arbitrary b) => Arbitrary (Foo a b) where
  arbitrary = do
    as <- listOf1 arbitrary           -- length xs > 0
    b <- choose (0,length as - 1)     -- b >= 0 and b < length xs
    return (Foo as $ fromIntegral b)

main = $(quickCheckAll)
Delft answered 29/8, 2013 at 5:27 Comment(2)
Had the same problem with the same 99 Haskell Problems question and it seems to work fine. But running verboseCheck prop_elementAt for me returns endless lists consisting only of the element (), meaning an implementation of elementAt (x:xs) _ = x still passes. Any idea on how to generate a list with actual elements in it?Elvera
Thats because it infers the wrong type of prop_elemAt. Give it explicit type (example prop_elementAt :: Foo [Int] Int -> Bool).Delft

© 2022 - 2024 — McMap. All rights reserved.