Test a function with a list of bounded value with quickCheck - haskell

I need to test some function with quickCheck do validate these function.
I need to send value in the range 1 to 40 to the function but I'm very beginner with quickCheck and it's modificator.
I tried :
myTestFunction (x,y,z) (Positive div) = ....
with
quickCheck myTestFunction
div remain positive but can take very high value (and I don't want)
What is the correct way to give div random value in the range a to b ?
Is it also possible to impose a list of value (non random) to quickCheck ?

You need to combine two parts. The first is generation—you need to write a QuickCheck random generator that outputs numbers in your desired range. Happily, we can do this with a built-in function:
choose :: Random a => (a, a) -> Gen a
Next, we need to specify a property that uses this custom generator. This is where the property combinators really come in handy. Again, the function we want is the first one in the documentation section:
forAll :: (Show a, Testable prop) => Gen a -> (a -> prop) -> Property
This lets us pass our custom generator in for a function parameter.
Putting all this together, the test case will look something like this:
prop_myTest (x, y, z) = forAll (choose (1, 40)) $ \ ndiv -> ...
The "prop_" naming scheme is conventionally used for QuickCheck tests. This will help people quickly understand what's going on in your code and is used by some test frameworks, so it's a good habit to get into now.

Related

QuickCheck Generator not terminating

This QuickCheck generator
notEqual :: Gen (Int, Int)
notEqual = do
(a, b) <- arbitrary
if a /= b
then return (a, b)
else notEqual
Doesn't seem to terminate when passed to forAll. I'm guessing the recursion is going into an infinite loop somehow, but why?
If you are in doubt of termination/finding results you can always try to circumvent this:
notEqual' :: Gen (Int, Int)
notEqual' = do
start <- arbitrary
delta <- oneof [pos, neg]
pure (start, start + delta)
where
pos = getPositive <$> arbitrary
neg = getNegative <$> arbitrary
Of course internally both Postitive and Negative use suchThat so as Ashesh mentioned
notEqual :: Gen (Int, Int)
notEqual = genPair `suchThat` uncurry (/=)
where genPair = arbitrary
might be easier
The suchThat combinator that #Ashesh and #Carsten pointed out is definitely what I am looking for, to succinctly and idiomatically generate a non-equal pair.
An explanation for the infinite recursion (Thanks to #oisdk):
All QuckCheck runners (quickCheck, forAll etc.) pass a size parameter to test genarators. This has no defined semantics, but early tests use a small parameter, starting at 0*, and gradually growing. Generators use this to generate samples of different 'sizes,' whatever that may mean for a specific datatype.
arbitrary for integral types (called recursively by arbitrary for (Int, Int)), uses this for the magnitude of the generated value - generate an integral between 0 and size.
This means, unfortunately, that the first test attempted by quickCheck, (or in my case forAll,) uses the size 0, which can only generate (0, 0). This always fails the test of /=, causing the action to recurse infinitely, looking for more.
* I'm assuming this, as the behaviour of the size parameter doesn't seem to be documented anywhere.

Creating a conditioned Arbitrary instance ( * Ambiguous type variable `a' arising from a use of `quickCheck')

I have this test I want to make:
prop_inverse_stringsToInts st = isDigitList st ==> st == map show (stringsToInts st)
Which is testing a function that converts a list of Strings to a list of Integers, but of course the strings need to be digits so I created a pre-condition that checks that using the isDigitList function I made, but the condition is too specific and quickCheck gives up : "*** Gave up! Passed only 43 tests; 1000 discarded tests."
So I wanted to create an Arbitrary instance for my case, but the thing is I am inexperienced with working with Arbitrary, so I don't really know how to do this and every time I shuffle code I get a new error. All I want is an Arbitrary that only returns the Foo [String] if it passes the isDigitList (which receives a [String] and returns a Bool). So far I have something like this :
Foo a = Foo [String] deriving (Show,Eq)
instance (Arbitrary a) => Arbitrary (Foo a ) where
arbitrary = do
st <- (arbitrary :: Gen [String])
if isDigitList st
then do return (Foo st)
else do return (Foo []) -- This is probably a bad idea
I altered my property to :
prop_inverse_stringsToInts :: Foo a -> Bool
prop_inverse_stringsToInts (Foo st) = st == map show (stringsToInts st)
But now I am getting the error "* Ambiguous type variable a0' arising from a use of `quickCheck'" even though I am running quickCheck like this : > quickCheck (prop_inverse_stringsToInts :: Foo a -> Bool)
Can someone help please? Thank you in advance!
It seems you know the basics, but I'll repeat them here just to be sure. There are two ways to get QuickCheck to generate the inputs you want:
Have it generate some inputs and then filter out ones you don't want, or
Have it generate only the inputs you want.
You started with option 1, but as you saw, that didn't work out great. Compared to all possible lists of String, there really aren't that many that are digit lists. The better option is to generate only the inputs you want.
To succeed at option 2, you need to make a generator, which would be a value of type Gen [String] that generates lists of Strings that fit your criteria. The generator you propose still uses the method of filtering, so you may want to try a different approach. Consider instead, something like:
genDigitStrings :: Gen [String]
genDigitStrings = do
intList <- arbitrary :: Gen [Integer]
return $ fmap show intList
This generator produces arbitrary lists of Strings that are always shown integers, meaning that they will always be digit lists. You can then go ahead and insert this into an Arbitrary instance for some newtype if you want.
For your own sanity, you can even check your work with a test like this:
propReallyActuallyDigitStrings = forAll genDigitStrings isDigitList
If that passes, you have some confidence that your generator really only produces digit lists, and if it fails, then you should adjust your generator.

How do I test that something is valid for all elements in a map?

I have the following things in my application:
newtype User = User Text
newtype Counts = Counts (Map User Int)
subjectUnderTest :: Counts -> Text
An example of correct output would be
> subjectUnderTest $ fromList [(User "foo", 4), (User "bar", 4), (User "qux", 2)]
"4: foo, bar\n2: qux"
I would like to write property-based tests that verify things like "all users are represented in the output", "all counts are represented in the output" and "all users are on the same line as their corresponding count". In common for these properties is that the wording of them starts with "all ..."
How do I write a property that verifies that something is valid for each element in the Map?
I'm assuming that this question is only a simplified representation of something more complex, so here's a couple of things strategies to consider:
Split up the functionality
It looks like subjectUnderTest does two unrelated things:
It groups the values in the map by value, instead of by key.
It formats, or pretty-prints, the inverted map.
If you can split up the functionality into those two steps, they're easier to test in in isolation.
The first step, you can make parametrically polymorphic. Instead of testing a function with the type Counts -> Text, consider testing a function with the type Eq b => Map a b -> [(b, [a])]. Property-based testing is easier with parametric polymorphism, because you get certain properties for free. For example, you can be sure that the values in the output can only come from the input, because there's no way to conjure a and b values out of thin air.
You're still going to have to write tests for the properties you ask about. Write a function with a type like Eq b => Map a b -> Testable. If you want to test that all the values are there, pull them out of the map and make list of them. Sort the list and nub it. It's now a [b] value. That's your expected output.
Now call your function. It returns something like [(b, [a])]. Map it using fst, sort and nub it. That list should be equal to your expected output.
For the next step (pretty-printing), see the next section.
Roundtrips
When you want to property-base pretty-printing, the easiest approach is usually to bite the bullet and also write a parser. The printer and the parser should be the dual of each other, so if you have a function MyType -> String, your should have a parser with the type String -> Maybe MyType.
You can now write a general property like MyType -> Testable. It takes as input a value of MyType (let's call it expected). You now produce a value (let's call it actual) as actual = parse $ print expected. You can now verify that Just expected === actual.
If the particular String format is important, I'd follow it up with a few actual examples, using good old parametrised tests.
Just because you're doing property-based testing doesn't mean that a 'normal' unit test can't be useful as well.
Example
Here's a simple example of what I meant above. Assume that
invertMap :: (Ord b, Eq b) => Map a b -> [(b, [a])]
you can define one of the properties as:
allValuesAreNowKeys :: (Show a, Ord a) => Map k a -> Property
allValuesAreNowKeys m =
let expected = nub $ sort $ Map.elems m
actual = invertMap m
in expected === nub (sort $ fmap fst actual)
Since this property is still parametrically polymorphic, you'll have to add it to your test suite with a particular type, e.g.:
tests = [
testGroup "Sorting Group 1" [
testProperty "all values are now keys" (allValuesAreNowKeys :: Map String Int -> Property)]]
There are prettier ways to define lists of properties; that one is just the template used by the quickcheck-test-framework Stack template...

"For all" statements in Haskell

I'm building comfort going through some Haskell toy problems and I've written the following speck of code
multipOf :: [a] -> (Int, a)
multipOf x = (length x, head x)
gmcompress x = (map multipOf).group $ x
which successfully preforms the following operation
gmcompress [1,1,1,1,2,2,2,3] = [(4,1),(3,2),(1,3)]
Now I want this function to instead of telling me that an element of the set had multiplicity 1, to just leave it alone. So to give the result [(4,1),(3,2),3] instead. It be great if there were a way to say (either during or after turning the list into one of pairs) for all elements of multiplicity 1, leave as just an element; else, pair. My initial, naive, thought was to do the following.
multipOf :: [a] -> (Int, a)
multipOf x = if length x = 1 then head x else (length x, head x)
gmcompress x = (map multipOf).group $ x
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?
Your diagnosis is right; the then and else must have the same type. There's no "getting past this issue," strictly speaking. Whatever solution you adopt has to use same type in both branches of the conditional. One way would be to design a custom data type that encodes the possibilities that you want, and use that instead. Something like this would work:
-- | A 'Run' of #a# is either 'One' #a# or 'Many' of them (with the number
-- as an argument to the 'Many' constructor).
data Run a = One a | Many Int a
But to tell you the truth, I don't think this would really gain you anything. I'd stick to the (Int, a) encoding rather than going to this Run type.

Haskell QuickCheck Unique Random Number Generation

Does anyone know exactly how to define a generator in Haskell using QuickCheck such that chosen elements are picked only ONCE?
I've gotten as far as realizing that I might need a "Gen (Maybe Positive)" generator, but of course that will generate number with repetition. I want it so that the numbers chosen are picked without repetition. In the instance when a number is returned I want Just returned and in the instance where the randoms are all exhausted I want Gen Nothing returned.
Thanks,
Mark
You can't. Look at the definition of Gen. There's no way for it to carry any state about what has been picked so far. Given the same random generator and size limit it must always generate the same result. You can however write a Eq a => Gen [a] that generates a list of values with no repetitions. A simple (but somewhat naive) one would be something like this.
uniques :: Eq a => Gen a -> Gen [a]
uniques gen = fmap nub $ listOf gen
QuickCheck is generally for randomized testing, not exhaustive testing. There are a few great libraries that do handle exhaustive testing -- look at smallcheck and lazysmallcheck.
You can use permutations (in module Data.List) for this.
Here is the function signature for permutations:
permutations :: [a] -> [[a]]
As you can see, it returns a list of lists. Here is a little example (using GHCi 7.0.4):
> permutations [1..3]
[[1,2,3],[2,1,3],[3,2,1],[2,3,1],[3,1,2],[1,3,2]]
So you could do something like:
prop_unique_elements = forAll (elements (permutations [1..3])) $ \x -> foo == bar
I haven't tested that so it will need some massaging, but I hope it conveys the point clearly. Good luck.

Resources