I have a custom result/error monad, nothing fancy:
import Control.Monad (liftM, ap)
data MyResult a = Error String | Success a
instance Functor MyResult where
fmap = liftM
instance Applicative MyResult where
pure = return
(<*>) = ap
instance Monad MyResult where
(Error s) >>= f = Error s
(Success a) >>= f = f a
return = Success
I want values in this monad to instantiate QuickCheck's Testable
class, so I can write properties that hold (i.e. pass tests) when a value is Success _
, and not hold (i.e. fail tests) when a value is Error _
.
For example, I would like to be able to write a test like this:
myProp :: Property
myProp = forAll (arbitrary :: Int)
(\x -> if x == 0 then Error "0 not allowed" else Success ())
and have the String
in the Error
be the test failure message if the test fails.
I assume I need to instantiate Testable
for MyResult
:
instance Testable t => Testable (MyResult t) where
property (Success _) = undefined -- what goes here?
property (Error s) = undefined -- what goes here?
However I can't figure out how I should implement the property
function in Testable
, despite reading the QuickCheck documentation and relevant source code.
Any help here is greatly appreciated.
You need to make a Property
from your result. The easiest way to do this is
property (Success _) = property True
property (Error _) = property False
You could also convert your Error
result to a Quickcheck Result
property (Error s) = property $ failed { reason = s }
See https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/src/Test-QuickCheck-Property.html for the definition of failed