Here's another way to define the Arbitrary instance:
newtype CAndS = CAndS String
instance Arbitrary CAndS where
arbitrary = CAndS <$> listOf (elements "CS")
Besides testing a function against a reference solution, you could test that the sum of 'C'
s and 'S'
es is the same as the length of the string:
prop_CountersAddUp :: CAndS -> Bool
prop_CountersAddUp (CAndS css) = length css == cs + ss
where (cs, ss) = countCAndS css
If the string is supposed to accept input that has characters other than 'C'
s and 'S'
es (but not count them), you should perhaps create a generator that generates all kinds of characters, but with a higher probability of 'C'
and 'S'
:
newtype CAndS = CAndS String
instance Arbitrary CAndS where
arbitrary = CAndS <$> listOf (frequency [ (1, return 'C')
, (1, return 'S')
, (2, arbitrary) ])
Or you might generate a string that is annotated with the right answer:
newtype CAndS = CAndS (String, Int, Int)
instance Arbitrary CAndS where
arbitrary = CAndS <$> sized (\n -> do
cs <- choose (0, n)
let ss = n - cs
css <- shuffle (replicate cs 'C' ++ replicate ss 'S')
return (css, cs, ss))
So you can test it:
prop_CountersEqual :: CAndS -> Bool
prop_CountersEqual (CAndS (css, cs, ss)) = cs == cs' && ss == ss'
where (cs', ss') = countCAndS css