packages feed

morley-0.1.0.0: test/Test/Ext.hs

module Test.Ext
  ( typeCheckHandlerSpec
  , interpretHandlerSpec
  ) where

import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldSatisfy)

import Michelson.Interpret (InterpreterState(..))
import Michelson.TypeCheck (HST(..), SomeHST(..), runTypeCheckT)
import Michelson.Typed (CVal(..), Instr, Val(..), extractNotes, fromUType, withSomeSingT)
import qualified Michelson.Typed as T
import Michelson.Untyped (CT(..), T(..), Type(..), ann, noAnn)
import Morley.Ext (interpretMorley, typeCheckHandler)
import Morley.Test (specWithTypedContract)
import Morley.Test.Dummy (dummyContractEnv)
import Morley.Types
  (MorleyLogs(..), StackTypePattern(..), TyVar(..), UExtInstr, UExtInstrAbstract(..))

interpretHandlerSpec :: Spec
interpretHandlerSpec = describe "interpretHandler PRINT/TEST_ASSERT tests" $
  specWithTypedContract "contracts/testassert_square.tz" $ \c -> do
    it "TEST_ASSERT assertion passed" $ do
      runTest True c 100 100
      runTest True c 1 1
    it "TEST_ASSERT assertion failed" $ do
      runTest False c 0 100
      runTest False c -1 -2
  where
    runTest corr contract x y = do
      let x' = VC $ CvInt x :: Val Instr ('T.Tc 'T.CInt)
      let y' = VC $ CvInt y :: Val Instr ('T.Tc 'T.CInt)
      let area' = VC $ CvInt $ x * y :: Val Instr ('T.Tc 'T.CInt)
      let check (a, InterpreterState s _) =
            if corr then isRight a && s == MorleyLogs ["Area is " <> show area']
            else isLeft a && s == MorleyLogs ["Sides are " <> show x' <> " x " <> show y']
      interpretMorley contract (VPair (x', y')) VUnit dummyContractEnv `shouldSatisfy` check

typeCheckHandlerSpec :: Spec
typeCheckHandlerSpec = describe "typeCheckHandler STACKTYPE tests" $ do
  it "Correct test on [] pattern" $ runNopTest test1 True
  it "Correct test on [a, b] pattern" $ runNopTest test2 True
  it "Correct test on [a, b, ...] pattern" $ runNopTest test3 True
  it "Correct test on [a, b, ...] pattern and stack [a, b]" $ runNopTest test4 True

  it "Failed test on [] pattern and stack [a]" $ runNopTest test5 False
  it "Failed test on [a, b] pattern and stack [a, b, c]" $ runNopTest test6 False
  it "Failed test on [a, b] pattern and stack [a]" $ runNopTest test7 False
  it "Failed test on [a, b, ...] pattern and stack [a]" $ runNopTest test8 False
  it "Failed test on [a, b] pattern and stack [a, c]" $ runNopTest test9 False
  where
    p2 = StkCons (TyCon t1) (StkCons (TyCon t2) StkEmpty)
    p3 = StkCons (TyCon t1) (StkCons (TyCon t2) StkRest)

    test1 = (STACKTYPE StkEmpty, convertToHST [])
    test2 = (STACKTYPE p2, convertToHST [t1, t2])
    test3 = (STACKTYPE p3, convertToHST [t1, t2, t3])
    test4 = (STACKTYPE p3, convertToHST [t1, t2])

    test5 = (STACKTYPE StkEmpty, convertToHST [t1])
    test6 = (STACKTYPE p2, convertToHST [t1, t2, t3])
    test7 = (STACKTYPE p2, convertToHST [t1])
    test8 = (STACKTYPE p3, convertToHST [t1])
    test9 = (STACKTYPE p2, convertToHST [t1, t3])

    t1 = Type (TOption (ann "f") (Type TKey (ann "key"))) (ann "opt")
    t2 = Type (TPair (ann "f") (ann "s") (Type TUnit "x") (Type TSignature "s")) noAnn
    t3 = Type (Tc CInt) (ann "tint")

    convertToHST :: [Type] -> SomeHST
    convertToHST [] = SomeHST SNil
    convertToHST (t : ts) = withSomeSingT (fromUType t) $ \sing ->
      let nt = either (const $ error "unexpected trouble with extracting annotations") id (extractNotes t sing) in
      case convertToHST ts of
        SomeHST is -> SomeHST ((sing, nt, noAnn) ::& is)

    nh (ni, si) = runTypeCheckT typeCheckHandler (Type TKey noAnn) $ typeCheckHandler ni [] si

    runNopTest :: (UExtInstr, SomeHST) -> Bool -> Expectation
    runNopTest tcase correct = case (nh tcase, correct) of
      (Right _, False) -> expectationFailure $ "Test expected to fail but it passed"
      (Left e, True)   -> expectationFailure $ "Test expected to pass but it failed with error: " <> show e
      _                -> pass