capnp-0.13.0.0: tests/Module/Capnp/Canonicalize.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ViewPatterns #-}
module Module.Capnp.Canonicalize
( canonicalizeTests
) where
import Test.Hspec
import Test.QuickCheck (property)
import Test.QuickCheck.IO (propertyIO)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Vector as V
import Control.Monad (unless)
import Capnp.Canonicalize
import Capnp.New (Parsed, Raw(..), createPure, encode, msgToLBS)
import qualified Capnp.Message as M
import qualified Capnp.New.Basics as B
import qualified Capnp.Untyped as U
import Instances ()
import Util (capnpCanonicalize)
canonicalizeTests :: Spec
canonicalizeTests =
describe "canonicalization tests" $ do
it "agrees with reference implementation" $
property $ \case
B.Struct (V.toList -> []) (V.toList -> []) ->
-- skip this; it fails due to a bug in the reference implementation:
--
-- https://github.com/capnproto/capnproto/issues/1084
--
-- TODO: when that issue is fixed, stop skipping this case.
propertyIO $ pure ()
struct ->
propertyIO $ implsAgreeOn struct
implsAgreeOn :: Parsed B.AnyStruct -> IO ()
implsAgreeOn struct = do
let Just ourMsg = ourImplCanonicalize struct
refMsg <- refImplCanonicalize struct
unless (ourMsg == refMsg) $
error $ concat
[ "Our implementation disagrees with the reference implementation on " ++ show struct
, ".\n\nWe produce:\n\n"
, show $ LBS.unpack $ msgToLBS ourMsg
, "\n\n"
, "But the reference implementation generates:\n\n"
, show $ LBS.unpack $ msgToLBS refMsg
]
ourImplCanonicalize :: Parsed B.AnyStruct -> Maybe (M.Message 'M.Const)
ourImplCanonicalize struct = createPure maxBound $ do
msg <- M.newMessage Nothing
Raw rawStruct <- encode msg struct
(msg, _) <- canonicalize rawStruct
pure msg
refImplCanonicalize :: Parsed B.AnyStruct -> IO (M.Message 'M.Const)
refImplCanonicalize struct = do
msg <- createPure maxBound $ do
msg <- M.newMessage Nothing
Raw rawStruct <- encode msg struct
U.setRoot rawStruct
pure msg
lbs <- capnpCanonicalize (msgToLBS msg)
let segment = M.fromByteString $ LBS.toStrict lbs
pure $ M.singleSegment segment