packages feed

morley-1.4.0: test/Test/Morley/Expression.hs

-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

-- | Tests for 'Morley.Micheline.Expression'.

module Test.Morley.Expression
  ( test_Roundtrip_binary
  , test_Roundtrip_expression
  , test_Roundtrip_JSON
  , test_toExpression
  ) where

import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode)
import qualified Data.Sequence as Seq
import Hedgehog (Gen)
import Test.Tasty (TestTree)

import Michelson.Test.Gen
import qualified Michelson.Typed as T
import qualified Michelson.Untyped as U
import qualified Morley.Micheline as M
import Test.Util.Hedgehog (roundtripTree)
import Tezos.Core (Mutez)

import Test.Hspec.Expectations (shouldBe)
import Test.Tasty.HUnit (testCase)

testJSON
  :: forall a. (Eq a, Show a, ToJSON a, FromJSON a, Typeable a)
  => Gen a -> TestTree
testJSON genA = roundtripTree @a genA encode eitherDecode

testValue
  :: forall a. (Eq a, Show a, M.ToExpression a, M.FromExpression a, Typeable a)
  => Gen a -> TestTree
testValue genA = roundtripTree @a genA M.toExpression (maybeToRight () . M.fromExpression)

testValueJSON
  :: forall a. (Eq a, Show a, M.ToExpression a, M.FromExpression a, Typeable a)
  => Gen a -> TestTree
testValueJSON genA = roundtripTree @a genA
  (encode . M.toExpression)
  (maybeToRight "error" . M.fromExpression <=< eitherDecode)

testBinary :: Gen M.Expression -> TestTree
testBinary genA = roundtripTree genA M.encodeExpression M.eitherDecodeExpression

test_Roundtrip_JSON :: [TestTree]
test_Roundtrip_JSON =
  [ testJSON M.genExprAnnotation
  , testJSON M.genExpression
  , testJSON M.genMichelinePrimAp
  , testValueJSON @(T.Value $ T.ToT Integer) genValueInt
  , testValueJSON @(T.Value $ T.ToT Mutez) genValueMutez
  , testValueJSON @(T.Value $ T.ToT ()) genValueUnit
  ]

test_Roundtrip_binary :: [TestTree]
test_Roundtrip_binary =
  [ testBinary M.genExpression
  ]

test_Roundtrip_expression :: [TestTree]
test_Roundtrip_expression =
  [ testValue @(T.Value $ T.ToT Integer) genValueInt
  , testValue @(T.Value $ T.ToT Mutez) genValueMutez
  , testValue @(T.Value $ T.ToT ()) genValueUnit
  ]

test_toExpression :: [TestTree]
test_toExpression =
  [ testCase "Converting TInt to Expression" $
      M.toExpression T.TInt `shouldBe`
        M.ExpressionPrim (M.MichelinePrimAp (M.MichelinePrimitive "int") mempty mempty)

  , testCase "Converting (TOption TString) to Expression" $
      M.toExpression (T.TOption T.TString) `shouldBe`
        M.ExpressionPrim
          ( M.MichelinePrimAp
            { mpaPrim = M.MichelinePrimitive "option"
            , mpaArgs = Seq.fromList [M.ExpressionPrim
                ( M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "string"
                , mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList [] }
                )]
            , mpaAnnots = Seq.fromList []
            }
          )

  , testCase "Converting Instr (DIP SIZE) to Expression" $
      M.toExpression (T.DIP (T.SIZE @'T.TString)) `shouldBe`
        M.ExpressionSeq (Seq.fromList
          [ M.ExpressionPrim (M.MichelinePrimAp
              { mpaPrim = M.MichelinePrimitive "DIP"
              , mpaArgs = Seq.fromList [M.ExpressionSeq (Seq.fromList [M.ExpressionPrim (M.MichelinePrimAp
                  { mpaPrim = M.MichelinePrimitive "SIZE"
                  , mpaArgs = Seq.fromList []
                  , mpaAnnots = Seq.fromList []
                  })])]
              , mpaAnnots = Seq.fromList []
              })]
          )
  , testCase "Converting VInt to Expression" $
      M.toExpression @(T.Value $ T.ToT Integer) (T.VInt 12) `shouldBe` M.ExpressionInt 12

  , testCase "Converting NTPair to Expression" $
      M.toExpression (T.NTPair (U.ann "pair") (U.ann "a") (U.ann "b") (T.NTString U.noAnn) (T.NTInt $ U.ann "val")) `shouldBe`
        M.ExpressionPrim
          (M.MichelinePrimAp
              { mpaPrim = M.MichelinePrimitive "pair"
              , mpaArgs = Seq.fromList
                [ M.ExpressionPrim (M.MichelinePrimAp
                  { mpaPrim = M.MichelinePrimitive "string"
                  , mpaArgs = Seq.fromList []
                  , mpaAnnots = Seq.fromList [M.AnnotationField (U.ann "a") ]})
                , M.ExpressionPrim (M.MichelinePrimAp
                  { mpaPrim = M.MichelinePrimitive "int"
                  , mpaArgs = Seq.fromList []
                  , mpaAnnots = Seq.fromList [ M.AnnotationType (U.ann "val"), M.AnnotationField (U.ann "b")]})
                ]
              , mpaAnnots = Seq.fromList [ M.AnnotationType (U.ann "pair") ]
              }
          )
  , testCase "Converting sample contract to Expression" $
      M.toExpression sampleContract `shouldBe`
        M.ExpressionSeq (Seq.fromList
          [ M.ExpressionPrim (M.MichelinePrimAp
              { mpaPrim = M.MichelinePrimitive "parameter"
              , mpaArgs = Seq.fromList [M.ExpressionPrim (M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "unit", mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList [M.AnnotationField (U.ann "")]})]
              , mpaAnnots = Seq.fromList []
              })
          , M.ExpressionPrim (M.MichelinePrimAp
              { mpaPrim = M.MichelinePrimitive "storage"
              , mpaArgs = Seq.fromList [M.ExpressionPrim (M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "chain_id", mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList []})]
              , mpaAnnots = Seq.fromList []
              })
          , M.ExpressionPrim (M.MichelinePrimAp
              { mpaPrim = M.MichelinePrimitive "code"
              , mpaArgs = Seq.fromList [M.ExpressionSeq (Seq.fromList
                [ M.ExpressionPrim (M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "DROP", mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList []})
                , M.ExpressionPrim (M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "CHAIN_ID", mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList []})
                , M.ExpressionPrim (M.MichelinePrimAp
                    { mpaPrim = M.MichelinePrimitive "NIL"
                    , mpaArgs = Seq.fromList
                      [ M.ExpressionPrim (M.MichelinePrimAp
                        { mpaPrim = M.MichelinePrimitive "operation"
                        , mpaArgs = Seq.fromList []
                        , mpaAnnots = Seq.fromList []
                        })
                      ]
                    , mpaAnnots = Seq.fromList []
                    })
                , M.ExpressionPrim (M.MichelinePrimAp {mpaPrim = M.MichelinePrimitive "PAIR", mpaArgs = Seq.fromList [], mpaAnnots = Seq.fromList []})
                ])]
              , mpaAnnots = Seq.fromList []
              })
          ])
  ]
  where
    sampleContract :: T.Contract 'T.TUnit 'T.TChainId
    sampleContract =
      let code = T.DROP `T.Seq` T.CHAIN_ID `T.Seq` T.NIL `T.Seq` T.PAIR
      in T.Contract
            { cCode = code
            , cParamNotes = T.starParamNotes @'T.TUnit
            , cStoreNotes = T.starNotes
            }