The following data structure can be tested with the Tasty-SmallCheck related code that follows. There is a relation that has to hold with the constructor ShB: the second and the third positive integers should be at most as large as the first one.
data Shape = ShA Int Int Bool
| ShB Int Int Int Bool Bool
deriving (Show,Read,Eq)
The constructor ShA should have positive Int's but otherwise there is no relation between the parameters.
auxShA :: (Positive Int, Positive Int, Bool) -> Shape
auxShA (i,j,b) = ShA (fromIntegral i) (fromIntegral j) b
auxShB :: (Positive Int, Positive Int, Positive Int) -> Bool -> Bool -> Shape
auxShB (a1,a2,a3) = ShB i u d
where
(i,u,d) = auxTriplet (a1,a2,a3)
auxTriplet :: (Positive Int, Positive Int, Positive Int) -> (Int,Int,Int)
auxTriplet (a,b,c)
| a >= b && a >= c = (fromIntegral a, fromIntegral b, fromIntegral c)
| b >= a && b >= c = (fromIntegral b, fromIntegral a, fromIntegral c)
| otherwise = (fromIntegral c, fromIntegral a, fromIntegral b)
consB :: (Serial m a1, Serial m a2, Serial m a3, Serial m b, Serial m c) =>
((a1,a2,a3) -> b -> c -> e) -> Series m e
consB f = decDepth $
f <$> series
<~> series
<~> series
instance Monad m => Serial m Shape where
series = cons1 auxShA \/ consB auxShB
The generated cases are otherwise ok but there are duplicates that can be seen e.g. with
list 4 series :: [Shape]
The question is, how to generate the test cases with SmallCheck (tasty) when the following holds?
- there are properties that has to hold, e.g. the first parameter has to Positive
- what if the first parameter should be larger than 10::Int?
- And continuing, what if the second parameter should between the first - 5 and the first, and the third should be between the second - 5 and the second?
Or, how to generate test cases that dynamically can depend on the previous generated values?
First thought was to write constructors to Shape that check that inputs are valid (e.g. the bullet points above), but the problem of duplicate test case generation would remain with that approach.
The above code uses similar solution as in SmallCheck invariant -answer.