Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell quickcheck - how to generate only printable strings

Tags:

I have a set of simple demo programs which encode/decode strings, and want to generate some quickCheck tests for them, but to limit the tests to printable strings only. Using a guard is too slow and fails because of too many generated and rejected test cases, so I want to create a safe generator for this domain.

The references to this that I have seen say to either (1) define one's own Arbitrary instance for Char and use that to generate only printable characters for strings, or (2) to have to wrapper the functions themselves in a newtype and write an Arbitrary instance for that.

But trying to do (1) it fails because there is now a definition for this in Test.QuickCheck, and so how would one do this - create a safeChar generator for a new type and then again have to produce an adapter to the tested functions? (The RWH book section on this notes that it is out of date in recommending this DIY Char definition.)

Trying to do (2) seems like I can either just add a guard to the test proposition which is localized and simple (but fails), or writing a new wrapper and associated generator, which seems messier.

Clearly this is simple(!) and all the tools are provided, but could someone advise if this is a correct analysis, and give an example of how to best do this?

like image 350
guthrie Avatar asked Jan 05 '14 14:01

guthrie


2 Answers

The starting point is definitely a genSafeChar generator, which can have type Gen Char. For example:

genSafeChar :: Gen Char genSafeChar = elements ['a'..'z'] 

Then you can build that up into a genSafeString generator, e.g. with listOf:

genSafeString :: Gen String genSafeString = listOf genSafeChar 

At this point you have a couple of reasonable choices. Either make a newtype wrapper for String:

newtype SafeString = SafeString { unwrapSafeString :: String }     deriving Show  instance Arbitrary SafeString where     arbitrary = SafeString <$> genSafeString 

(in this case you might just inline the definition of genSafeString)

and you can then use it something like this:

testWibble (SafeString str) = str == str 

Or, you can use forAll at each point you need a safe string:

testWibble = forAll genSafeString $ \str -> str == str 
like image 194
GS - Apologise to Monica Avatar answered Sep 30 '22 19:09

GS - Apologise to Monica


Currently QuickCheck has a PrintableString type, which also has an instance of arbitrary, which means that you can readily generate arbitrary strings with:

arbitraryPrintableString :: Gen String arbitraryPrintableString = getPrintableString <$> arbitrary 
like image 33
Damian Nadales Avatar answered Sep 30 '22 19:09

Damian Nadales