morley-0.1.0.4: 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(..), ToT, 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.EnvironmentSpec (environmentSpec)
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
environmentSpec
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"
specWithTypedContract "contracts/add1_list.tz" $ \contract -> do
let
validate ::
[Integer] -> ContractPropValidator (ToT [Integer]) Property
validate param (res, _) =
case res of
Left failed -> failedProp $
"add1_list unexpectedly failed: " <> pretty failed
Right (fromVal . snd -> finalStorage) ->
map succ param === finalStorage
prop "Random check" $ \param ->
contractProp contract (validate param) dummyContractEnv param param
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