packages feed

cleveland-0.1.0: morley-test/Test/Interpreter/StringCaller.hs

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

-- | Tests for the 'string_caller.tz' contract and its interaction with
-- the 'fail_or_store_and_transfer.tz' contract. Both of them have comments describing
-- their behavior.

module Test.Interpreter.StringCaller
  ( test_stringCaller
  ) where

import Hedgehog (forAll, property, withTests)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.Hedgehog (testProperty)

import Hedgehog.Gen.Michelson (genMText)
import Morley.Michelson.Text (MText)
import Morley.Tezos.Address (Address, ta)
import Test.Cleveland
import Test.Cleveland.Lorentz.Import (embedContract)

import Test.Util.Contracts

test_stringCaller :: TestTree
test_stringCaller =
  -- failOrStoreAndTransfer's pre-conditions:
  -- balance is >= 1300
  testGroup "calls failOrStoreAndTransfer, updates storage & balance, checks pre-conditions"
    [ testScenario "when parameter is a constant" $ myScenario constStr

    -- The test is trivial, so it's kinda useless to run it many times
    , testProperty "when parameter is an arbitrary value" $
      withTests 2 $ property do
        mtext <- forAll genMText
        testScenarioProps $ myScenario mtext
    ]
  where
    constStr = "caller"

myScenario :: Monad m => MText -> Scenario m
myScenario str = scenario do
  let
    initFailOrStoreBalance = 900
    initStringCallerBalance = 500

  failOrStoreAddress <- originate OriginateData
    { odName = "failOrStoreAndTransfer"
    , odBalance = initFailOrStoreBalance
    , odStorage = "hello"
    , odContract = failOrStoreAndTransfer
    }

  stringCallerAddress <- originate OriginateData
    { odName = "stringCaller"
    , odBalance = initStringCallerBalance
    , odStorage = chAddress failOrStoreAddress
    , odContract = stringCaller
    }

  initialConstAddrBalance <- getBalance constAddr

  -- Transfer 100 tokens to stringCaller, it should transfer 300 tokens
  -- to failOrStoreAndTransfer
  let
    transferData = TransferData
      { tdTo = stringCallerAddress
      , tdAmount = 100
      , tdEntrypoint = DefEpName
      , tdParameter = str
      }

    transferToStringCaller = transfer transferData
  transferToStringCaller

  -- Execute operations and check balances and storage of 'failOrStore'
  do
    let
      -- `string_caller.tz` transfers 300 mutez.
      -- 'fail_or_store_and_transfer.tz' transfers 5 tokens.
      -- Also 100 tokens are transferred from the @moneybag@ address.
      expectedStringCallerBalance = 500 - 300 + 100
      expectedFailOrStoreBalance = 900 + 300 - 5
      expectedConstAddrBalance = initialConstAddrBalance + 5

    getStorage @MText failOrStoreAddress @@== str
    getBalance failOrStoreAddress @@== expectedFailOrStoreBalance
    getBalance stringCallerAddress @@== expectedStringCallerBalance
    getBalance constAddr @@== expectedConstAddrBalance

  -- Now let's transfer 100 tokens to stringCaller again.
  -- This time execution should fail, because failOrStoreAndTransfer should fail
  -- because its balance is greater than 1300.
  expectFailedWith () $
    transferToStringCaller
  where
    stringCaller = $$(embedContract @MText @Address @() (inContractsDir "string_caller.tz"))
    failOrStoreAndTransfer =
      $$(embedContract @MText @MText @() (inContractsDir "fail_or_store_and_transfer.tz"))
    -- Address hardcoded in 'failOrStoreAndTransfer.tz'.
    constAddr = [ta|tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU|]