{-# 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 (cerialize, createPure, msgToLBS) import qualified Capnp.Message as M import qualified Capnp.Untyped as U import qualified Capnp.Untyped.Pure as PU import Instances () import Util (capnpCanonicalize) canonicalizeTests :: Spec canonicalizeTests = describe "canonicalization tests" $ do it "agrees with reference implementation" $ property $ \case PU.Struct (PU.Slice (V.toList -> [])) (PU.Slice (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 :: PU.Struct -> 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 :: PU.Struct -> Maybe M.ConstMsg ourImplCanonicalize struct = createPure maxBound $ do msg <- M.newMessage Nothing rawStruct <- cerialize msg struct (msg, _) <- canonicalize rawStruct pure msg refImplCanonicalize :: PU.Struct -> IO M.ConstMsg refImplCanonicalize struct = do msg <- createPure maxBound $ do msg <- M.newMessage Nothing rawStruct <- cerialize msg struct U.setRoot rawStruct pure msg lbs <- capnpCanonicalize (msgToLBS msg) segment <- M.fromByteString $ LBS.toStrict lbs pure $ M.singleSegment segment