morley-0.1.0.0: test/Test/Interpreter.hs
module Test.Interpreter
( spec
) where
import Fmt (pretty)
import Test.Hspec (Expectation, Spec, describe, expectationFailure, it, shouldBe, shouldSatisfy)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (Property, label, (.&&.), (===))
import Michelson.Interpret (ContractEnv(..), ContractReturn, MichelsonFailed(..), RemainingSteps)
import Michelson.Typed (CT(..), CVal(..), Instr(..), T(..), Val(..), fromVal, toVal, ( # ))
import Morley.Ext (interpretMorley)
import Morley.Test (ContractPropValidator, contractProp, specWithTypedContract)
import Morley.Test.Dummy (dummyContractEnv)
import Morley.Test.Util (failedProp)
import Morley.Types (MorleyLogs)
import Test.Interpreter.Auction (auctionSpec)
import Test.Interpreter.CallSelf (selfCallerSpec)
import Test.Interpreter.Compare (compareSpec)
import Test.Interpreter.Conditionals (conditionalsSpec)
import Test.Interpreter.StringCaller (stringCallerSpec)
spec :: Spec
spec = describe "Advanced type interpreter tests" $ do
let contractResShouldBe (res, _) expected =
case res of
Left err -> expectationFailure $ "Unexpected failure: " <> pretty err
Right (_ops, v) -> v `shouldBe` expected
specWithTypedContract "contracts/basic5.tz" $ \contract ->
it "Basic test" $
interpretMorley contract VUnit (toVal [1 :: Integer]) dummyContractEnv
`contractResShouldBe` (toVal [13 :: Integer, 100])
specWithTypedContract "contracts/increment.tz" $ \contract ->
it "Basic test" $
interpretMorley contract VUnit (toVal @Integer 23) dummyContractEnv
`contractResShouldBe` (toVal @Integer 24)
specWithTypedContract "contracts/fail.tz" $ \contract ->
it "Fail test" $
interpretMorley contract VUnit VUnit dummyContractEnv
`shouldSatisfy` (isLeft . fst)
specWithTypedContract "contracts/mutez_add_overflow.tz" $ \contract ->
it "Mutez add overflow test" $
interpretMorley contract VUnit VUnit dummyContractEnv
`shouldSatisfy` (isLeft . fst)
specWithTypedContract "contracts/mutez_sub_underflow.tz" $ \contract ->
it "Mutez sub underflow test" $
interpretMorley contract VUnit VUnit dummyContractEnv
`shouldSatisfy` (isLeft . fst)
specWithTypedContract "contracts/basic1.tz" $ \contract -> do
prop "Random check" $ \input ->
contractProp @_ @[Integer] contract (validateBasic1 input)
dummyContractEnv () input
auctionSpec
compareSpec
conditionalsSpec
stringCallerSpec
selfCallerSpec
specWithTypedContract "contracts/steps_to_quota_test1.tz" $ \contract -> do
it "Amount of steps should reduce" $ do
validateStepsToQuotaTest
(interpretMorley contract VUnit (VC (CvNat 0)) dummyContractEnv) 4
specWithTypedContract "contracts/steps_to_quota_test2.tz" $ \contract -> do
it "Amount of steps should reduce" $ do
validateStepsToQuotaTest
(interpretMorley contract VUnit (VC (CvNat 0)) dummyContractEnv) 8
specWithTypedContract "contracts/gas_exhaustion.tz" $ \contract -> do
it "Contract should fail due to gas exhaustion" $ do
let dummyStr = toVal @Text "x"
case fst $ interpretMorley contract dummyStr dummyStr dummyContractEnv of
Right _ -> expectationFailure "expecting contract to fail"
Left MichelsonGasExhaustion -> pass
Left _ -> expectationFailure "expecting another failure reason"
validateBasic1
:: [Integer] -> ContractPropValidator ('TList ('Tc 'CInt)) Property
validateBasic1 input (Right (ops, res), _) =
(fromVal res === [sum input + 12, 100])
.&&.
(label "returned no ops" $ null ops)
validateBasic1 _ (Left e, _) = failedProp $ show e
validateStepsToQuotaTest ::
ContractReturn MorleyLogs ('Tc 'CNat) -> RemainingSteps -> Expectation
validateStepsToQuotaTest res numOfSteps =
case fst res of
Right ([], VC (CvNat x)) ->
(fromInteger . toInteger) x `shouldBe` ceMaxSteps dummyContractEnv - numOfSteps
_ -> expectationFailure "unexpected contract result"
--------------------
-- Examples
--------------------
-- | @myInstr@ is an equivalent to Michelson code:
--
-- PUSH int 223;
-- SOME;
-- IF_NONE { DUP; } { SWAP; };
-- ADD;
-- PUSH nat 12
-- ADD;
_myInstr :: Typeable s => Instr ('Tc 'CInt : s) ('Tc 'CInt : s)
_myInstr =
PUSH (VC $ CvInt 223) #
SOME #
IF_NONE DUP SWAP #
ADD #
PUSH (VC $ CvNat 12) #
ADD
_myInstr2 :: Typeable a => Instr a ('TOption ('Tc 'CInt) : a)
_myInstr2 =
PUSH (VOption $ Just $ VC $ CvInt 223) #
Nop