【问题标题】:Using QuickCheck to generate multiple arbitrary parameters for a given function使用 QuickCheck 为给定函数生成多个任意参数
【发布时间】:2017-08-07 15:07:58
【问题描述】:

上下文

我有以下功能:

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

也就是说,我想使用显式生成器来为prop_SignAndVerify的参数中的Blind aBS.ByteString生成任意值。

但是,上面的代码不起作用,因为函数 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

问题

所以我的问题是,我如何在prop_SignAndVerify 的参数上使用genRSAgenRSAMessage,或者是否有替代方法?

谢谢

【问题讨论】:

    标签: haskell typeclass quickcheck


    【解决方案1】:

    您想在prop_SignAndVerify key message 中查看所有 多个keys 和messages。因此,如果我们有一个固定的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,但我认为测试应该易于阅读。

    【讨论】:

    • 双重 eta 转换后:quickCheck . verbose $ forAll genRSA $ forAll genRSAMessage . prop_SignAndVerify 我觉得它很好读,但当然这是一个品味问题。
    【解决方案2】:

    您可以利用 Gen 的一元性质从您的属性中组成更复杂的 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 的应用性质并使用&lt;*&gt; 编写g

    main =
      let g =
            return (\key message -> prop_SignAndVerify (Blind key) message)
            <*> genRSA
            <*> genRSAMessage
      in quickCheck . verbose $ forAll g id
    

    g 仍然是 Gen Bool 值。

    【讨论】:

    • 我只是避免在应用版本中返回(注意 而不是第一个 ): (\key message -> prop_SignAndVerify (Blind key) message) genRSA genRSAMessage
    猜你喜欢
    • 2018-02-11
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 2018-10-28
    • 1970-01-01
    相关资源
    最近更新 更多