1

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.

Community
  • 1
  • 1
Gspia
  • 809
  • 6
  • 15
  • My understanding of smallcheck is that it (tries to) exhaustively search the entire domain in some 'fair' manner. Any value which can be produced by `auxShB` should also eventually be in the `series` for `Shape`. If you want to observe examples with specific properties, you have to write a different `Series` which only generates things with that property. I believe that there are duplicates because `auxTriplet` is not an injection (and therefore, neither is `auxShB`). Consider writing your `Shape` type to be correct by construction. – user2407038 Sep 21 '16 at 17:03

0 Answers0