morley-0.1.0.2: test/Test/Interpreter/StringCaller.hs
-- | Tests for the 'stringCaller.tz' contract and its interaction with
-- the 'idString.tz' contract. Both of them have comments describing
-- their behavior.
module Test.Interpreter.StringCaller
( stringCallerSpec
) where
import Test.Hspec (Spec, it, parallel)
import Test.Hspec.QuickCheck (modifyMaxSuccess, prop)
import Test.QuickCheck.Instances.Text ()
import Michelson.Typed
import qualified Michelson.Untyped as Untyped
import Morley.Aliases (UntypedContract)
import Morley.Runtime.GState
import Morley.Test (specWithContract)
import Morley.Test.Integrational
import Tezos.Address
import Tezos.Core
stringCallerSpec :: Spec
stringCallerSpec =
parallel $
specWithContract "contracts/stringCaller.tz" $ \stringCaller ->
specWithContract "contracts/idString.tz" $ \idString ->
specImpl stringCaller idString
specImpl ::
(UntypedContract, Contract ('Tc 'CString) ('Tc 'CAddress))
-> (UntypedContract, Contract ('Tc 'CString) ('Tc 'CString))
-> Spec
specImpl (uStringCaller, _stringCaller) (uIdString, _idString) = do
let scenario = integrationalScenario uStringCaller uIdString
let suffix =
" and properly updates balances. But fails if idString's balance is ≥ \
\1000 and NOW is ≥ 500"
it ("stringCaller calls idString and updates its storage with a constant"
<> suffix) $
integrationalTestExpectation (scenario constStr)
-- The test is trivial, so it's kinda useless to run it many times
modifyMaxSuccess (const 2) $
prop ("stringCaller calls idString and updates its storage with an arbitrary value"
<> suffix) $
\str -> integrationalTestProperty (scenario str)
where
constStr = "caller"
integrationalScenario :: UntypedContract -> UntypedContract -> Text -> IntegrationalScenario
integrationalScenario stringCaller idString str = do
let
initIdStringBalace = unsafeMkMutez 900
initStringCallerBalance = unsafeMkMutez 500
-- Originate both contracts
idStringAddress <-
originate idString (Untyped.ValueString "hello") initIdStringBalace
stringCallerAddress <-
originate stringCaller (Untyped.ValueString $ formatAddress idStringAddress)
initStringCallerBalance
-- NOW = 500, so stringCaller shouldn't fail
setNow (timestampFromSeconds @Int 500)
-- Transfer 100 tokens to stringCaller, it should transfer 300 tokens
-- to idString
let
newValue = Untyped.ValueString str
txData = TxData
{ tdSenderAddress = genesisAddress
, tdParameter = newValue
, tdAmount = unsafeMkMutez 100
}
transferToStringCaller = transfer txData stringCallerAddress
transferToStringCaller
-- Execute operations and check balances and storage of 'idString'
do
let
-- `stringCaller.tz` transfers 300 mutez.
-- 'idString.tz' transfers 5 tokens.
-- Also 100 tokens are transferred from the genesis address.
expectedStringCallerBalance = unsafeMkMutez (500 - 300 + 100)
expectedIdStringBalance = unsafeMkMutez (900 + 300 - 5)
expectedConstAddrBalance = unsafeMkMutez 5
updatesValidator :: SuccessValidator
updatesValidator = composeValidatorsList
[ expectStorageUpdateConst idStringAddress newValue
, expectBalance idStringAddress expectedIdStringBalance
, expectBalance stringCallerAddress expectedStringCallerBalance
, expectBalance constAddr expectedConstAddrBalance
]
validate (Right updatesValidator)
-- Now let's transfer 100 tokens to stringCaller again.
transferToStringCaller
-- This time execution should fail, because idString should fail
-- because its balance is greater than 1000.
void $ validate (Left $ expectMichelsonFailed idStringAddress)
-- We can also send tokens from idString to tz1 address directly
let
txDataToConst = TxData
{ tdSenderAddress = idStringAddress
, tdParameter = Untyped.ValueUnit
, tdAmount = unsafeMkMutez 200
}
transfer txDataToConst constAddr
-- Let's check balance of idString and tz1 address
do
let
expectedIdStringBalance = unsafeMkMutez (900 + 300 - 5 - 200)
expectedConstAddrBalance = unsafeMkMutez (5 + 200)
updatesValidator :: SuccessValidator
updatesValidator = composeValidatorsList
[ expectBalance idStringAddress expectedIdStringBalance
, expectBalance constAddr expectedConstAddrBalance
]
void $ validate (Right updatesValidator)
-- Now we can transfer to stringCaller again and it should succeed
-- this time, because the balance of idString decreased
transferToStringCaller
-- Let's simply assert that it should succeed to keep the scenario shorter
void $ validate (Right expectAnySuccess)
-- Now let's set NOW to 600 and expect stringCaller to fail
setNow (timestampFromSeconds @Int 600)
transferToStringCaller
validate (Left $ expectMichelsonFailed stringCallerAddress)
-- Address hardcoded in 'idString.tz'.
constAddr :: Address
constAddr = unsafeParseAddress "tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"