问题
Context
I have the following function:
prop_SignAndVerify :: (PrivKey a b) => Blind a -> BS.ByteString -> Bool
prop_SignAndVerify bsk msg = case verify pk msg sig of
Left e -> error e
Right b -> b
where
sk = getBlind bsk
pk = toPublic sk
sig = case sign sk msg of
Left e -> error e
Right s -> s
I would like to do something like:
-- instance PrivKey RSA.PrivateKey RSA.PublicKey where...
genRSA :: Gen RSA.PrivateKey
genRSAMessage :: Gen BS.ByteString
main = do
quickCheck . verbose
$ forAll genRSA
$ forAll genRSAMessage prop_SignAndVerify
That is, I would like to use explicit generators to generate arbitrary values for Blind a
and BS.ByteString
in the parameters of prop_SignAndVerify
.
The code above, however, doesn't work, because the function forAll
has type signature:
forAll :: (Show a, Testable prop) => Gen a -> (a -> prop) -> Property
This function runs the generator and apples the generated arbitrary value to (a -> prop)
, returning a Property
. This Property
however cannot be further partially applied; it hides the underlying function.
I think what we need for the above to work would be something like:
forAll' :: (Show a, Testable prop) => Gen a -> (a -> prop) -> prop
Question
So my question is, how can I use genRSA
and genRSAMessage
over the parameters of prop_SignAndVerify
, or is there an alternative approach?
Thanks
回答1:
You could take advantage of the monadic nature of Gen
to compose a more complex Gen
value from your property:
main =
let g = do
key <- genRSA
message <- genRSAMessage
return $ prop_SignAndVerify (Blind key) message
in quickCheck . verbose $ forAll g id
Here, g
is a Gen Bool
value.
Alternatively, you can take advantage of the applicative nature of Gen
and compose g
using <*>
:
main =
let g =
return (\key message -> prop_SignAndVerify (Blind key) message)
<*> genRSA
<*> genRSAMessage
in quickCheck . verbose $ forAll g id
g
is still a Gen Bool
value here as well.
回答2:
You want to check prop_SignAndVerify key message
for all many key
s and message
s. So if we had a fixed key
, our tests would look like that:
main = do
quickCheck . verbose $
let key = someGeneratedKey
in forAll genRSAMessage $ \message ->
prop_SignAndVerify key message
If we had a fixed message
, our test would look like this:
main = do
quickCheck . verbose $
forAll genRSAMessage $ \key ->
let message = someMessage
in prop_SignAndVerify key message
All we have to do is to combine both variants:
main = do
quickCheck . verbose $
forAll genRSA $ \key ->
forAll genRSAMessage $ \message ->
prop_SignAndVerify key message
You can get rid of the message
due to eta conversion, but in my opinion tests should be easily readable.
来源:https://stackoverflow.com/questions/45519955/using-quickcheck-to-generate-multiple-arbitrary-parameters-for-a-given-function