packages feed

h-gpgme-0.6.3.1: test/InternalTest.hs

{-# LANGUAGE OverloadedStrings #-}
module InternalTest (tests) where

import Bindings.Gpgme
import Foreign
import Foreign.C.String (newCString)
import Test.Tasty (TestTree)
import Test.Tasty.HUnit (testCase)
import Test.HUnit

import Crypto.Gpgme
import Crypto.Gpgme.Internal

tests :: [TestTree]
tests =
    [ testCase "collectSignaturesWithoutVerify" collectSignaturesWithoutVerify
    , testCase "collectFprsWalksList" collectFprsWalksList
    , testCase "verifyGarbageDoesNotCrash" verifyGarbageDoesNotCrash
    ]

-- gpgme_op_verify_result returns NULL when no successful verify ran on the
-- context, which used to segfault (stackoverflow.com/questions/48908274)
collectSignaturesWithoutVerify :: Assertion
collectSignaturesWithoutVerify = do
    _ <- c'gpgme_check_version nullPtr
    ctxPtr <- malloc
    checkError "gpgme_new" =<< c'gpgme_new ctxPtr
    ctx <- peek ctxPtr
    sigs <- collectSignatures' ctx
    c'gpgme_release ctx
    free ctxPtr
    assertEqual "expected no signatures" [] sigs

-- collectFprs used to diverge on any non-empty list because peeking a
-- whole C'_gpgme_invalid_key recurses via its mistyped next field
collectFprsWalksList :: Assertion
collectFprsWalksList = do
    second <- newInvalidKey "BBBB" 2 nullPtr
    first <- newInvalidKey "AAAA" 1 second
    assertEqual "expected both invalid keys" [("AAAA", 1), ("BBBB", 2)] (collectFprs first)
  where
    newInvalidKey fpr reason next = do
        ptr <- mallocBytes (sizeOf (undefined :: C'_gpgme_invalid_key))
        poke (castPtr (p'_gpgme_invalid_key'next ptr)) next
        poke (p'_gpgme_invalid_key'fpr ptr) =<< newCString fpr
        poke (p'_gpgme_invalid_key'reason ptr) reason
        return ptr

verifyGarbageDoesNotCrash :: Assertion
verifyGarbageDoesNotCrash = do
    res <- verify' "test/bob" "this is not a signature"
    case res of
        Left _ -> return ()
        Right r -> assertFailure ("expected verification error, got: " ++ show r)