How can I limit QuickCheck options, for example. use only non-negative ints?

I am new to Haskell. This is very nice so far, but I am running copies for my QuickCheck properties, and I would like to fix it.

Here is an example:

prop_Myfunc :: [Int] -> (Int,Int) -> Bool prop_Myfunc ints (i,j) = ints !! i == ints !! j 

This will not work because QuickCheck generates negative numbers, so I get

 *** Failed! (after 2 tests and 2 shrinks): Exception: Prelude.(!!): negative index 

I tried to use Google to resolve this issue, and I found, for example. NonNegative and ==>, but I don’t understand how they work.

How can I limit the above example so that I and j are never negative? And also, so that none of them are too high? That is: 0 <= i,j < length ints

+6
source share
3 answers

Test.QuickCheck.Modifiers wrappers (from Test.QuickCheck.Modifiers , if they are not implicitly replicated) can be used as follows:

 prop_Myfunc :: [Int] -> (NonNegative Int, NonNegative Int) -> Bool prop_Myfunc ints (NonNegative i, NonNegative j) = ints !! i == ints !! j 

You can treat SomeWrapper a as a with a modified distribution. For example, NonNegative a provides a >= 0 . After the shell has been generated, the value can be obtained using pattern matching or explicit access ( getNonNegative in this case).

As for limiting the top edge of your indexes, I think this is not possible with wrappers (in the Haskkell system, type parameterization with a value is impossible, the length of the list in this case). However, with the ==> operator ==> you can add an arbitrary logical constraint for your test:

 prop_Myfunc ints (NonNegative i, NonNegative j) = i < l && j < l ==> ints !! i == ints !! j where l = length ints 

It works differently: when the condition is not true, it just discards the current test case. But be careful: if there are too many thrown cases (the condition is too restrictive), the test becomes much less useful. Lossless behavior is often achieved using shrink ing test data, but that's a whole other topic.

+5
source

First, see this SO answer for an example of how to write a custom Gen ... function and how to use the forAll combinator.

And here's how to write a generator for a non-empty list and two real non-negative indexes in the list:

 import Test.QuickCheck genArgs :: Gen ( [Int], Int, Int ) genArgs = do x <- arbitrary xs <- arbitrary let n = length xs i <- choose (0,n) j <- choose (0,n) return ( (x:xs), i, j) -- return a non-empty list test = quickCheck $ forAll genArgs $ \(xs,i,j) -> prop_myfunc xs (i,j) 
+10
source

I was in a similar situation since you and I finally found how to use ==> here: http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html , in the "Conditional Property".

In your example, you need to replace Bool with Property and insert the requirements for your variables before the property test, as shown below:

 prop_Myfunc :: [Int] -> (Int,Int) -> Property prop_Myfunc ints (i,j) = (i >= 0 && j >= 0) ==> ints !! i == ints !! j 

(I did not test this specific example, but it worked for me in a similar case.)

Note the type ==> : (==>) :: Testable prop => Bool -> prop -> Property .

0
source

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


All Articles