上下文
我有以下功能:
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
我想做点什么:
-- 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
也就是说,我想使用显式生成器在Blind a
的参数中为BS.ByteString
和prop_SignAndVerify
生成任意值。
但上面的代码不起作用,因为函数forAll
具有类型签名:
forAll :: (Show a, Testable prop) => Gen a -> (a -> prop) -> Property
此函数运行生成器并将生成的任意值加到(a -> prop)
,返回Property
。但Property
不能进一步部分应用;它隐藏了潜在的功能。
我认为上述工作需要的是:
forAll' :: (Show a, Testable prop) => Gen a -> (a -> prop) -> prop
问题
所以我的问题是,如何在genRSA
的参数上使用genRSAMessage
和prop_SignAndVerify
,还是有替代方法?
由于
答案 0 :(得分:6)
您想检查prop_SignAndVerify key message
所有多个key
和message
。因此,如果我们有一个固定的key
,我们的测试将如下所示:
main = do
quickCheck . verbose $
let key = someGeneratedKey
in forAll genRSAMessage $ \message ->
prop_SignAndVerify key message
如果我们有一个固定的message
,我们的测试将如下所示:
main = do
quickCheck . verbose $
forAll genRSAMessage $ \key ->
let message = someMessage
in prop_SignAndVerify key message
我们所要做的就是结合两种变体:
main = do
quickCheck . verbose $
forAll genRSA $ \key ->
forAll genRSAMessage $ \message ->
prop_SignAndVerify key message
由于eta转换,您可以摆脱message
,但在我看来,测试应该易于阅读。
答案 1 :(得分:2)
您可以利用Gen
的monadic性质来构建属性中更复杂的Gen
值:
main =
let g = do
key <- genRSA
message <- genRSAMessage
return $ prop_SignAndVerify (Blind key) message
in quickCheck . verbose $ forAll g id
此处,g
是Gen Bool
值。
或者,您可以利用Gen
的适用性,并使用g
撰写<*>
:
main =
let g =
return (\key message -> prop_SignAndVerify (Blind key) message)
<*> genRSA
<*> genRSAMessage
in quickCheck . verbose $ forAll g id
g
此处仍为Gen Bool
值。