packages feed

cleveland-0.1.1: morley-test/Test/Interpreter/CallSelf.hs

-- SPDX-FileCopyrightText: 2021 Oxhead Alpha
-- SPDX-License-Identifier: LicenseRef-MIT-OA

-- | Tests for the contract that calls self several times.

{-# OPTIONS_GHC -Wno-deprecations #-}

module Test.Interpreter.CallSelf
  ( test_self_caller
  ) where

import Hedgehog (forAll, property, withTests)
import Hedgehog.Gen qualified as Gen
import Test.HUnit (Assertion, (@?=))
import Test.Tasty (TestTree)
import Test.Tasty.HUnit (testCase)
import Test.Tasty.Hedgehog (testProperty)
import Unsafe qualified (fromIntegral)

import Morley.Michelson.Interpret (ContractEnv(..), InterpreterState(..), RemainingSteps(..))
import Morley.Michelson.Typed as T
import Morley.Michelson.Untyped qualified as U
import Test.Cleveland
import Test.Cleveland.Michelson (ContractPropValidator, contractProp)
import Test.Cleveland.Michelson.Dummy
import Test.Cleveland.Michelson.Import (embedContract)

import Test.Util.Contracts

gasForOneExecution :: Num a => a
gasForOneExecution = 19

gasForLastExecution :: Num a => a
gasForLastExecution = 20

type Parameter = 'TInt
type Storage = 'TNat

test_self_caller :: [TestTree]
test_self_caller =
  [ testCase ("With parameter 1 single execution consumes " <>
      show @_ @Int gasForLastExecution <> " gas") $
    contractProp selfCaller (unitValidator gasForLastExecution) unitContractEnv
    (1 :: Integer) (0 :: Natural)

  , testCase ("With parameter 2 single execution consumes " <>
      show @_ @Int gasForOneExecution <> " gas") $
    contractProp selfCaller (unitValidator gasForOneExecution) unitContractEnv
    (2 :: Integer) (0 :: Natural)

  , testProperty propertyDescription $
    withTests 10 $ property $ do
      callCount <- forAll $ Gen.enum minCalls maxCalls
      testScenarioProps $ clevelandTransferScenario (T.convertContract selfCaller) callCount
  ]
  where
    -- Environment for unit test
    unitContractEnv = dummyContractEnv
    -- Validator for unit test
    unitValidator ::
      RemainingSteps -> ContractPropValidator Storage Assertion
    unitValidator gasDiff (_, (isRemainingSteps -> remSteps, _)) =
      remSteps @?= ceMaxSteps unitContractEnv - gasDiff

    propertyDescription =
      "calls itself n times, sets storage to n OR fails due to gas limit"

    minCalls = 1
    maxCalls = 10

    selfCaller = $$(embedContract @Parameter @Storage (inContractsDir "call_self_several_times.tz"))

    clevelandTransferScenario :: Monad m => U.Contract -> Integer -> Scenario m
    clevelandTransferScenario uSelfContract parameter = scenario do
      address <- originateUntypedSimple "self-caller" (U.ValueInt 0) uSelfContract
      transfer TransferData
        { tdTo = address
        , tdAmount = 1
        , tdEntrypoint = DefEpName
        , tdParameter = parameter
        }
      let expectedStorage :: Natural = Unsafe.fromIntegral @Integer @Natural parameter
      getStorage @Natural address @@== expectedStorage