cleveland-0.1.0: Testing framework for Morley.
Safe HaskellNone
LanguageHaskell2010

Test.Cleveland

Description

Michelson contracts testing on a real Tezos network.

See the documentation for usage instructions.

Synopsis

Documentation

data ContractHandle (cp :: Type) (st :: Type) (vd :: Type) Source #

Handle to a contract.

This is what you get when originating a contract and that allows further operations with the contract within the test framework.

Note that this is part of the testing framework and exists solely in Haskell world, so it has no IsoValue and related instances and cannot be used in Lorentz code.

Constructors

(NiceParameterFull cp, NiceStorage st, NiceViewsDescriptor vd) => ContractHandle 

Fields

Instances

Instances details
(cp' ~ cp, vd ~ vd') => ToTAddress cp' vd' (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Methods

toTAddress :: ContractHandle cp st vd -> TAddress cp' vd'

ToContractRef arg (TAddress cp vd) => ToContractRef arg (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Methods

toContractRef :: ContractHandle cp st vd -> ContractRef arg

st ~ st' => ToStorageType st' (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Show (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Methods

showsPrec :: Int -> ContractHandle cp st vd -> ShowS #

show :: ContractHandle cp st vd -> String #

showList :: [ContractHandle cp st vd] -> ShowS #

Buildable (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Methods

build :: ContractHandle cp st vd -> Builder #

ToAddress (ContractHandle cp st vd) Source # 
Instance details

Defined in Test.Cleveland.Lorentz.Types

Methods

toAddress :: ContractHandle cp st vd -> Address #

data OriginateData param st vd Source #

Constructors

OriginateData 

Fields

  • odName :: AliasHint

    Alias for the originated contract.

  • odBalance :: Mutez

    Initial balance.

  • odStorage :: st

    Initial storage.

  • odContract :: Contract param st vd

    The contract itself.

    We are using Lorentz version here which is convenient. However, keep in mind that if someone wants to test a contract from .tz file, they should use UntypedOriginateData.

data UntypedOriginateData Source #

Untyped version of OriginateData. It can be used for interaction with raw Michelson contracts

Constructors

UntypedOriginateData 

Fields

data TransferData Source #

Information about transfer operation.

Constructors

forall v addr.(NiceParameter v, ToAddress addr) => TransferData 

Fields

  • tdTo :: addr

    Receiver address for this transaction.

  • tdAmount :: Mutez

    Amount to be transferred.

  • tdEntrypoint :: EpName

    An entrypoint to be called. Consider using ep in testing scenarios.

  • tdParameter :: v

    Parameter that will be used for a contract call. Set to () for transfers to key addresses.

data Scenario m Source #

A type representing a finalized scenario

data PureM a Source #

Instances

Instances details
Monad PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

(>>=) :: PureM a -> (a -> PureM b) -> PureM b #

(>>) :: PureM a -> PureM b -> PureM b #

return :: a -> PureM a #

Functor PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

fmap :: (a -> b) -> PureM a -> PureM b #

(<$) :: a -> PureM b -> PureM a #

Applicative PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

pure :: a -> PureM a #

(<*>) :: PureM (a -> b) -> PureM a -> PureM b #

liftA2 :: (a -> b -> c) -> PureM a -> PureM b -> PureM c #

(*>) :: PureM a -> PureM b -> PureM b #

(<*) :: PureM a -> PureM b -> PureM a #

MonadIO PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

liftIO :: IO a -> PureM a #

MonadCatch PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

catch :: Exception e => PureM a -> (e -> PureM a) -> PureM a #

MonadThrow PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

throwM :: Exception e => e -> PureM a #

MonadState PureState PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

get :: PureM PureState #

put :: PureState -> PureM () #

state :: (PureState -> (a, PureState)) -> PureM a #

MonadWriter LogsInfo PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Methods

writer :: (a, LogsInfo) -> PureM a #

tell :: LogsInfo -> PureM () #

listen :: PureM a -> PureM (a, LogsInfo) #

pass :: PureM (a, LogsInfo -> LogsInfo) -> PureM a #

MonadReader (IORef PureState) PureM Source # 
Instance details

Defined in Test.Cleveland.Internal.Pure

Validation

data TransferFailure Source #

Failures that could be expected in the execution of a transfer. These can be caught and handled with attempt.

Real network implementation based on tezos-client and RPC.

testScenario :: TestName -> (forall m. Monad m => Scenario m) -> TestTree Source #

Create a tasty test case from a Scenario.

This will create a test tree with 2 tests: one that runs the Scenario on the Morley.Michelson.Runtime emulator, and another that runs it on a real Tezos network.

The network config is read from the command line/environment variables. Use --help to see the available options.

If a TestTree contains many tests scheduled to run on a real Tezos network, those tests will be run sequentially.

testScenarioOnNetwork :: TestName -> Scenario ClientM -> TestTree Source #

Create a tasty test case from a Scenario.

This will create a test tree with 1 test, which will run the Scenario on real Tezos network.

scenario :: ClevelandT m () -> Scenario m Source #

Finalize a generic cleveland scenario.

Emulation tests

testScenarioOnEmulator :: TestName -> Scenario PureM -> TestTree Source #

Create a tasty test case from an emulated Scenario.

This will create a test tree with 1 test, which will run the Scenario on the Morley.Michelson.Runtime emulator.

scenarioEmulated :: EmulatedT PureM () -> Scenario PureM Source #

Finalize a scenario that needs emulator-only features.

withInitialNow :: Timestamp -> Scenario PureM -> Scenario PureM Source #

Use with an emulated Scenario to configure the initial now value in tests.

Example : > withInitialNow (Timestamp 10000000) $ testScenarioOnEmulator Testname $ scenarioEmulated $ tests > withInitialNow (Timestamp 10000000) $ testScenarioOnEmulator Testname $ scenario $ tests

withInitialLevel :: Natural -> Scenario PureM -> Scenario PureM Source #

Similar to withInitialNow but for the initial level

collectLogs :: LogsInfo -> MorleyLogs Source #

Collect logs produced by all contracts into the single list

logsForAddress :: (Each s s ScenarioLogs ScenarioLogs, ToAddress addr) => addr -> s -> [MorleyLogs] Source #

Get logs for a given address from LogsInfo

Cleveland actions

type MonadCleveland caps m = (m ~ ReaderT caps (ClevelandBaseMonad caps), HasClevelandCaps caps) Source #

Constraint for a monad in which we can do cleveland actions.

class Functor m => MonadOps m Source #

Typeclass for monads where operations-related actions can occur.

This is implemented for MonadCleveland and batch context.

Has Functor as a superclass constraint for convenience, all the related methods require it.

Minimal complete definition

withOpsCap

Instances

Instances details
MonadOps ClevelandOpsBatch Source # 
Instance details

Defined in Test.Cleveland.Internal.Actions

(HasClevelandCaps caps, ClevelandBaseMonad caps ~ m) => MonadOps (ReaderT caps m) Source # 
Instance details

Defined in Test.Cleveland.Internal.Actions

Methods

withOpsCap :: (ClevelandOpsImpl (ReaderT caps m) -> ReaderT caps m a) -> ReaderT caps m a Source #

type MonadEmulated caps m = (MonadCleveland caps m, HasEmulatedCaps caps) Source #

Constraint for a monad in which we can do cleveland actions that can't be run on a real network. It requires the EmulatedImpl capability.

type ClevelandT m = ReaderT (ClevelandCaps m) m Source #

Monad transformer that adds only the ClevelandCaps capabilities.

type EmulatedT m = ReaderT (EmulatedCaps m) m Source #

Monad transformer that adds both ClevelandCaps and EmulatedCaps capabilities.

withSender :: MonadCleveland caps m => Address -> m a -> m a Source #

Update the current sender on whose behalf transfers and originations are invoked.

withMoneybag :: MonadCleveland caps m => Address -> m a -> m a Source #

Update the current moneybag that transfers money on the newly created addresses. For the rare occasions when this is necessary.

runIO :: (HasCallStack, MonadCleveland caps m) => IO res -> m res Source #

Runs an IO action.

resolveAddress :: (HasCallStack, MonadCleveland caps m) => Alias -> m Address Source #

Get the address of the implicit account / contract associated with the given alias.

refillable :: MonadCleveland caps m => m Address -> m Address Source #

Simple combinator that marks address as "refillable".

If a refillable address lacks funds for the next operation, some funds will automatically be transferred to it.

newAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAliasHint -> m Address Source #

If the given alias is already associated with an existing address, that address will be reused and returned. Otherwise, generate a new secret key and record it with given alias.

If the account has too low of a balance, a small amount of XTZ will be transferred to it.

Notes:

  • By default, the XTZ is transferred from the account associated with the moneybag alias. This can be overriden with the --cleveland-moneybag-alias command line option, the TASTY_CLEVELAND_MONEYBAG_ALIAS env var, or withMoneybag.
  • Beware that if an "alias prefix" is set, it'll be prepended to the given alias hint. An "alias prefix" can be set using the --cleveland-alias-prefix command line option, the TASTY_CLEVELAND_ALIAS_PREFIX env var, or with setAliasPrefix. > do > addr1 <- newAddress "alias" > addr2 <- resolveAddress $ mkAlias "prefix.alias" > addr1 @== addr2

newFreshAddress :: (HasCallStack, MonadCleveland caps m) => SpecificOrDefaultAliasHint -> m Address Source #

Generate a new secret key and record it with given alias. If the alias is already known, the key will be overwritten. The address is guaranteed to be fresh, i. e. no operations on it have been made.

Notes:

  • Beware that if an "alias prefix" is set, it'll be prepended to the given alias. An "alias prefix" can be set using the --cleveland-alias-prefix command line option, the TASTY_CLEVELAND_ALIAS_PREFIX env var, or with setAliasPrefix. > do > addr1 <- newFreshAddress "alias" > addr2 <- resolveAddress $ mkAlias "prefix.alias" > addr1 @== addr2

signBytes :: (HasCallStack, MonadCleveland caps m) => ByteString -> Address -> m Signature Source #

Get the signature of the preapplied operation.

signBinary :: (HasCallStack, BytesLike bs, MonadCleveland caps m) => bs -> Address -> m (TSignature bs) Source #

Type-safer version of signBytes.

originate :: forall cp st vd m. (HasCallStack, MonadOps m) => OriginateData cp st vd -> m (ContractHandle cp st vd) Source #

Lorentz version for origination.

By default, the sender is the account associated with the moneybag alias. This can be overriden with the --cleveland-moneybag-alias command line option, the TASTY_CLEVELAND_MONEYBAG_ALIAS env var, or withSender.

originateSimple :: forall cp st vd m. (HasCallStack, MonadOps m) => AliasHint -> st -> Contract cp st vd -> m (ContractHandle cp st vd) Source #

A simplified version of the originate command. The contract will have 0 balance.

originateUntyped :: (HasCallStack, MonadOps m) => UntypedOriginateData -> m Address Source #

Originate a new raw Michelson contract with given data.

originateUntypedSimple :: (HasCallStack, MonadOps m) => AliasHint -> Value -> Contract -> m Address Source #

A simplified version of the originateUntyped command. The contract will have 0 balance.

originateTypedSimple :: forall cp st vd m. (HasCallStack, MonadOps m, NiceParameterFull cp, NiceStorage st, NiceViewsDescriptor vd) => AliasHint -> st -> Contract (ToT cp) (ToT st) -> m (ContractHandle cp st vd) Source #

Like originateUntypedSimple, but accepts typed contract and initial storage as a Haskell value.

originateLarge :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => OriginateData param st vd -> m (ContractHandle param st vd) Source #

Lorentz version for large origination.

originateLargeSimple :: forall param st vd m caps. (HasCallStack, MonadCleveland caps m) => AliasHint -> st -> Contract param st vd -> m (ContractHandle param st vd) Source #

A simplified version of the originateLarge command. The contract will have 0 balance.

originateLargeUntyped :: (HasCallStack, MonadCleveland caps m) => UntypedOriginateData -> m Address Source #

Originate a new Michelson contract that doesn't fit into the origination size limit, by executing multiple operation steps.

This operation cannot be batched (it simply may not fit).

originateLargeUntypedSimple :: (HasCallStack, MonadCleveland caps m) => AliasHint -> Value -> Contract -> m Address Source #

A simplified version of the originateLargeUntyped command. The contract will have 0 balance.

transfer :: (HasCallStack, MonadOps m) => TransferData -> m () Source #

Base method for making a transfer.

Avoid using this method in favour of transferMoney and call, unless you need the semantics of both in one operation.

transferMoney :: (HasCallStack, MonadOps m, ToAddress addr) => addr -> Mutez -> m () Source #

Simply transfer money to an address.

This assumes that target address is either an implicit address or has a default entrypoint with a unit argument; otherwise the call fails.

call :: forall param vd addr m epRef epArg. (HasCallStack, MonadOps m, ToTAddress param vd addr, HasEntrypointArg param epRef epArg, IsoValue epArg, Typeable epArg) => addr -> epRef -> epArg -> m () Source #

Call a certain entrypoint of the given contract.

By default, the sender is the account associated with the moneybag alias. This can be overriden with the --cleveland-moneybag-alias command line option, the TASTY_CLEVELAND_MONEYBAG_ALIAS env var, or withSender.

importUntypedContract :: (HasCallStack, MonadCleveland caps m) => FilePath -> m Contract Source #

Import an untyped contract from file.

importContract :: (HasCallStack, NiceParameterFull param, NiceStorage st, NiceViewsDescriptor vd, DemoteViewsDescriptor vd, MonadCleveland caps m) => FilePath -> m (Contract param st vd) Source #

Import a contract from file.

The compiler must be able to infer the types of parameter, storage and views. In case there are no views or you don't care, you can use noViews.

noViews :: forall k1 k2 contract (cp :: k1) (st :: k2). contract cp st () -> contract cp st () #

comment :: (HasCallStack, MonadCleveland caps m) => Text -> m () Source #

Print the given string verbatim as a comment. At the moment, this is a no-op in emulator tests.

getBalance :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m Mutez Source #

Get the balance of the given address.

getDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m (Maybe KeyHash) Source #

Get the delegate for the given contract. Fails on implicit contracts.

registerDelegate :: (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m () Source #

Register the given address as a valid delegate.

getMorleyLogs :: forall a caps m. MonadEmulated caps m => m a -> m (LogsInfo, a) Source #

Returns the result of the action with the logs it produced. Logs are messages printed by the morley instruction [PRINT](https:/gitlab.commorley-frameworkmorley-blobmastercodemorleydocslanguage/morleyInstructions.md#print)

This function can be combined either with lens-based accessors or helper functions to get more specific information about logs.

Examples:

(logsInfo, _) <- getMorleyLogs scenario
logsInfo ^.. each . logsL == [MorleyLogs ["log"], MorleyLogs ["log2"]]
logsInfo ^.. each . filterLogsByAddrL addr == [MorleyLogs ["log"]]
(logsInfo, _) <- getMorleyLogs scenario
collectLogs logsInfo == MorleyLogs ["log", "log2"]
logsForAddress logsInfo == [MorleyLogs ["log"]]

getMorleyLogs_ :: MonadEmulated caps m => m () -> m LogsInfo Source #

Version of getMorleyLogs for actions that don't return a result.

getStorage :: forall st addr caps m. (HasCallStack, MonadCleveland caps m, ToStorageType st addr, NiceUnpackedValue (AsRPC st)) => addr -> m (AsRPC st) Source #

Retrieve a contract's storage in its "RPC representation" (i.e., all its big_maps will be replaced by big_map IDs).

If the storage is of a user-defined type, then deriveRPC / deriveManyRPC should be used to create an RPC representation of the storage type.

data MyStorage = MyStorage { field1 :: Natural, field2 :: BigMap Integer MText }
deriveRPC "MyStorage"

getFullStorage :: forall st addr caps m. (HasCallStack, MonadEmulated caps m, ToStorageType st addr) => addr -> m st Source #

Retrieve a contract's full storage, including the contents of its big_maps.

This function can only be used in emulator-only tests.

getSomeStorage :: forall addr caps m. (HasCallStack, MonadCleveland caps m, ToAddress addr) => addr -> m SomeAnnotatedValue Source #

Similar to getStorage, but doesn't require knowing the storage type in advance.

Use the optics in AnnotatedValue to read data from the storage.

getAllBigMapValues :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> m [v] Source #

Like getAllBigMapValuesMaybe, but fails the tests instead of returning Nothing.

getAllBigMapValuesMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe [v]) Source #

Retrieve all big_map values, given a big_map ID. Returns Nothing when the big_map ID does not exist.

getBigMapSize :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> m Natural Source #

Like getBigMapSizeMaybe, but fails the tests instead of returning Nothing.

getBigMapSizeMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> m (Maybe Natural) Source #

Retrieve a big_map size, given a big_map ID. Returns Nothing when the big_map ID does not exist.

O(n), because it's implemented with getBigMapValues.

getBigMapValueMaybe :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v) => BigMapId k v -> k -> m (Maybe v) Source #

Retrieve a big_map value, given a big_map ID and a key. Returns Nothing when the big_map ID does not exist, or it exists but does not contain the given key.

getBigMapValue :: forall k v caps m. (HasCallStack, MonadCleveland caps m, NiceComparable k, NicePackedValue k, NiceUnpackedValue v, Buildable k) => BigMapId k v -> k -> m v Source #

Like getBigMapValueMaybe, but fails the tests instead of returning Nothing.

getPublicKey :: (HasCallStack, MonadCleveland caps m) => Address -> m PublicKey Source #

Get the public key associated with given address. Fail if given address is not an implicit account.

getChainId :: (HasCallStack, MonadCleveland caps m) => m ChainId Source #

Get the chain's ChainId.

advanceTime :: forall unit caps m. (HasCallStack, MonadCleveland caps m, KnownDivRat unit Second) => Time unit -> m () Source #

Advance at least the given amount of time, or until a new block is baked, whichever happens last.

On a real network, this is implemented using threadDelay, so it's advisable to use small amounts of time only.

advanceLevel :: forall caps m. (HasCallStack, MonadCleveland caps m) => Natural -> m () Source #

Wait till the provided number of levels is past.

advanceToLevel :: forall caps m. (HasCallStack, MonadCleveland caps m) => Natural -> m () Source #

Wait till the provided level is reached.

getNow :: (HasCallStack, MonadCleveland caps m) => m Timestamp Source #

Get the timestamp observed by the last block to be baked.

getLevel :: (HasCallStack, MonadCleveland caps m) => m Natural Source #

Get the current level observed by the last block to be baked.

getApproximateBlockInterval :: (HasCallStack, MonadCleveland caps m) => m (Time Second) Source #

Get approximate block interval in seconds. Note, that this value is minimal bound and real intervals can be larger, see http://tezos.gitlab.io/active/consensus.html#minimal-block-delay-function for more information about block delays.

branchout :: forall caps m. MonadEmulated caps m => [(Text, m ())] -> m () Source #

Execute multiple testing scenarios independently.

  • Actions performed before branchout will be observed by all branches.
  • Actions performed in branches will _not_ be observed by any actions performed after branchout.
  • Actions performed in one branch will _not_ be observed by another branch.
  • The test succeeds IFF all branches succeed.
  • If any branch fails, the test ends immediately and the remaining branches won't be executed.

The following property holds:

pre >> branchout [a, b, c] = branchout [pre >> a, pre >> b, pre >> c]

The list of branches must be non-empty.

offshoot :: forall caps m. MonadEmulated caps m => Text -> m () -> m () Source #

Execute one or more actions and roll them back afterwards. Actions performed in offshoot will _not_ be observed by any actions performed after offshoot.

Similar to branchout, but accepts one single branch.

setVotingPowers :: MonadEmulated caps m => VotingPowers -> m () Source #

Updates voting power accessible via VOTING_POWER and similar instructions.

getRunMode :: forall caps m. MonadCleveland caps m => m (RunMode caps) Source #

Check at runtime whether the test is being run against a network or the emulator.

Note that if you write a test suite that is executed in both modes, with this function you can conditionally perform some emulation-only actions.

getRunMode >>= case
  NetworkMode -> do
    ...
  EmulationMode -> do
    ...

data RunMode caps where Source #

In which mode the test suite is currently executed.

Constructors

NetworkMode :: RunMode caps

Test is run on-chain.

EmulationMode :: HasEmulatedCaps caps => RunMode caps

Test is run in Morley emulation.

whenEmulation :: HasClevelandCaps caps => (HasEmulatedCaps caps => ReaderT caps (ClevelandBaseMonad caps) ()) -> ReaderT caps (ClevelandBaseMonad caps) () Source #

Perform an action if we are currently in emulation mode. whenEmulation

inBatch :: (HasCallStack, MonadCleveland caps m) => ClevelandOpsBatch a -> m a Source #

Run operations in a batch. Best used with the ApplicativeDo GHC extension.

Example:


contract <- inBatch $ do
  contract <- originate ...
  for_ [1..3] i ->
    transfer ...
  return contract

Batched operations should be applied to chain faster, but note that batches have their own limits. For instance, at the moment of writing, the gas limit on a batch is 10x of gas limit applied to a single operation.

A context of a batch is only Applicative, not Monad. This means that:

  • Return values of one function cannot be passed to another function in the same batch, it can only be returned;
  • Sometimes the compiler does not recognize that only Applicative context is required, in case of any issues with that - follow the error messages.

Primitives re-exports

data EntrypointRef (mname :: Maybe Symbol) where #

Constructors

CallDefault :: EntrypointRef ('Nothing :: Maybe Symbol) 
Call :: forall (name :: Symbol). NiceEntrypointName name => EntrypointRef ('Just name) 

Instances

Instances details
(GetEntrypointArgCustom cp mname ~ arg, ParameterDeclaresEntrypoints cp) => HasEntrypointArg (cp :: Type) (EntrypointRef mname) arg 
Instance details

Defined in Lorentz.Entrypoints.Core

Methods

useHasEntrypointArg :: EntrypointRef mname -> (Dict (ParameterScope (ToT arg)), EpName)

Assertions

failure :: forall a caps m. (HasCallStack, MonadCleveland caps m) => Builder -> m a Source #

Fails the test with the given error message.

assert :: (HasCallStack, MonadCleveland caps m) => Bool -> Builder -> m () Source #

Fails the test with the given error message if the given condition is false.

(@==) infix 1 Source #

Arguments

:: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) 
=> a

The actual value.

-> a

The expected value.

-> m () 

x @== expected fails the test if x is not equal to expected.

(@/=) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => a -> a -> m () infix 1 Source #

Fails the test if the two given values are equal.

(@@==) infix 1 Source #

Arguments

:: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) 
=> m a

The actual value.

-> a

The expected value.

-> m () 

Monadic version of @==.

getBalance addr @@== 10

(@@/=) :: (HasCallStack, MonadCleveland caps m, Eq a, Buildable a) => m a -> a -> m () infix 1 Source #

Monadic version of @/=.

getBalance addr @@/= 10

checkCompares :: forall a b caps m. (HasCallStack, MonadCleveland caps m, Buildable a, Buildable b) => a -> (a -> b -> Bool) -> b -> m () Source #

Fails the test if the comparison operator fails when applied to the given arguments. Prints an error message with both arguments.

Example:

checkCompares 2 (>) 1

checkComparesWith :: forall a b caps m. (HasCallStack, MonadCleveland caps m) => (a -> Text) -> a -> (a -> b -> Bool) -> (b -> Text) -> b -> m () Source #

Like checkCompares, but with an explicit show function. This function does not have any constraint on the type parameters a and b.

For example, to print with pretty:

checkComparesWith pretty a (<) pretty b

evalJust :: (HasCallStack, MonadCleveland caps m) => Builder -> Maybe a -> m a Source #

Fails the test if the Maybe is Nothing, otherwise returns the value in the Just.

evalRight :: (HasCallStack, MonadCleveland caps m) => (a -> Builder) -> Either a b -> m b Source #

Fails the test if the Either is Left, otherwise returns the value in the Right.

newtype Showing a Source #

Derive a Buildable instance for a type using show.

Constructors

Showing a 

Instances

Instances details
Eq a => Eq (Showing a) Source # 
Instance details

Defined in Test.Cleveland.Util

Methods

(==) :: Showing a -> Showing a -> Bool #

(/=) :: Showing a -> Showing a -> Bool #

Show a => Show (Showing a) Source # 
Instance details

Defined in Test.Cleveland.Util

Methods

showsPrec :: Int -> Showing a -> ShowS #

show :: Showing a -> String #

showList :: [Showing a] -> ShowS #

Show a => Buildable (Showing a) Source # 
Instance details

Defined in Test.Cleveland.Util

Methods

build :: Showing a -> Builder #

Exception handling

attempt :: forall e caps m a. (HasCallStack, MonadCleveland caps m, Exception e) => m a -> m (Either e a) Source #

Attempt to run an action and return its result or, if interpretation fails, an error.

catchTransferFailure :: (HasCallStack, MonadCleveland caps m) => m a -> m TransferFailure Source #

Asserts that a transfer should fail, and returns the exception.

checkTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailure -> TransferFailurePredicate -> m () Source #

Check whether a given predicate holds for a given TransferFailure.

expectTransferFailure :: (HasCallStack, MonadCleveland caps m) => TransferFailurePredicate -> m a -> m () Source #

Asserts that a transfer should fail, and runs some TransferFailurePredicates over the exception.

expectTransferFailure (failedWith (constant @MText "NOT_ADMIN")) $
  call contractAddr (Call @"Ep") arg
call contractAddr (Call @"Ep") arg & expectTransferFailure
  ( failedWith (customError #tag 3) &&
    addressIs contractAddr
  )

expectFailedWith :: forall err a caps m. (HasCallStack, MonadCleveland caps m, NiceConstant err) => err -> m a -> m () Source #

Asserts that interpretation of a contract ended with FAILWITH, returning the given constant value.

expectError :: forall err a caps m. (HasCallStack, MonadCleveland caps m, IsError err) => err -> m a -> m () Source #

Asserts that interpretation of a contract ended with FAILWITH, returning the given lorentz error.

expectCustomError :: forall arg a tag caps m. (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag (MText, arg)) => Label tag -> arg -> m a -> m () Source #

Asserts that interpretation of a contract ended with FAILWITH, returning the given custom lorentz error.

expectCustomError_ :: (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag (MText, ())) => Label tag -> m a -> m () Source #

Version of expectCustomError for error with unit argument.

expectCustomErrorNoArg :: (HasCallStack, MonadCleveland caps m, IsError (CustomError tag), MustHaveErrorArg tag MText) => Label tag -> m a -> m () Source #

Version of expectCustomError specialized for expecting NoErrorArgs.

expectNumericError :: forall err a caps m. (HasCallStack, MonadCleveland caps m, IsError err) => ErrorTagMap -> err -> m a -> m () Source #

Asserts that interpretation of a contract ended with FAILWITH, returning the given lorentz numeric error.

clarifyErrors :: forall caps m a. MonadCleveland caps m => Builder -> m a -> m a Source #

Prefix scenario-custom error messages (i.e. CustomTestError either from pure or non-pure implementation), potentially thrown from the given code block.

The prefix will be put at a separate line before the main text, if text is multiline, otherwise it will be separated from the main text with : .

This affects errors produced by functions like failure, assert, @==, etc. Errors related to events in the chain will not be touched.

Example:

for [1..10] \i -> clarifyErrors ("For i=" +| i |+ "") $
  askContract i @@== i * 2

Exception predicates

data TransferFailurePredicate Source #

A predicate that checks whether a transfer operation failed for the expected reason.

Predicates can be combined using the && and || operators.

shiftOverflow :: TransferFailurePredicate Source #

Asserts that interpretation of a contract failed due to an overflow error.

emptyTransaction :: TransferFailurePredicate Source #

Asserts that an action failed due to an attempt to transfer 0tz towards a simple address.

badParameter :: TransferFailurePredicate Source #

Asserts that an action failed due to an attempt to call a contract with an invalid parameter.

gasExhaustion :: TransferFailurePredicate Source #

Asserts that interpretation of a contract failed due to gas exhaustion.

failedWith :: SomeConstant -> TransferFailurePredicate Source #

Asserts that interpretation of a contract ended with FAILWITH, throwing the given error.

This function should be used together with one of the "FAILWITH constructors" (e.g. constant, customError).

addressIs Source #

Arguments

:: ToAddress addr 
=> addr

The expected address.

-> TransferFailurePredicate 

Asserts that the error occurred while interpreting the contract with the given address.

FAILWITH errors

Convert the many error formats available in morley and lorentz to SomeConstant.

constant :: forall err. NiceConstant err => err -> SomeConstant Source #

A constant michelson value that a contract threw with FAILWITH.

lerror :: forall err. IsError err => err -> SomeConstant Source #

A lorentz error.

customError :: forall arg tag. (IsError (CustomError tag), MustHaveErrorArg tag (MText, arg)) => Label tag -> arg -> SomeConstant Source #

A custom lorentz error.

customError_ :: (IsError (CustomError tag), MustHaveErrorArg tag (MText, ())) => Label tag -> SomeConstant Source #

A custom lorentz error with a unit argument.

customErrorNoArg :: (IsError (CustomError tag), MustHaveErrorArg tag MText) => Label tag -> SomeConstant Source #

A custom lorentz error with no argument.

numericError :: forall err. IsError err => ErrorTagMap -> err -> SomeConstant Source #

A lorentz numeric error.

Helpers

auto :: SpecificOrDefaultAliasHint Source #

Helper to use automatically determined unique alias.

pattern DefEpName :: EpName #

ep :: HasCallStack => Text -> EpName Source #

A short partial constructor for EpName. It is supposed to be applied to string constants, so programmer is responsible for validity. And this code is for tests anyway, so each failure is a programmer mistake.

It is intentionally here and not in some deeper module because the name is really short and more suitable for writing scenarios.

(?-) :: Text -> a -> (Text, a) infixr 0 Source #

Make a tuple with name without extra syntactic noise.

Integration with hedgehog

testScenarioProps :: (HasCallStack, MonadIO m, MonadTest m) => Scenario PureM -> m () Source #

Run an Scenario via the Morley.Michelson.Runtime emulator, inside an hedgehog property.

Config (reexports)

type MorleyClientEnv = MorleyClientEnv' MorleyClientM #

data MorleyClientEnv' (m :: Type -> Type) #

Constructors

MorleyClientEnv 

Fields

Instances

Instances details
MonadReader MorleyClientEnv MorleyClientM 
Instance details

Defined in Morley.Client.Full

Methods

ask :: MorleyClientM MorleyClientEnv #

local :: (MorleyClientEnv -> MorleyClientEnv) -> MorleyClientM a -> MorleyClientM a #

reader :: (MorleyClientEnv -> a) -> MorleyClientM a #

HasLog MorleyClientEnv Message MorleyClientM 
Instance details

Defined in Morley.Client.Full

HasTezosClientEnv (MorleyClientEnv' m) 
Instance details

Defined in Morley.Client.Env

data NetworkEnv Source #

Constructors

NetworkEnv 

data MorleyLogs #

Instances

Instances details
Eq MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Show MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Generic MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Associated Types

type Rep MorleyLogs :: Type -> Type #

Semigroup MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Monoid MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

NFData MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Methods

rnf :: MorleyLogs -> () #

Buildable MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

Methods

build :: MorleyLogs -> Builder #

type Rep MorleyLogs 
Instance details

Defined in Morley.Michelson.Interpret

type Rep MorleyLogs = D1 ('MetaData "MorleyLogs" "Morley.Michelson.Interpret" "morley-1.16.2-inplace" 'True) (C1 ('MetaCons "MorleyLogs" 'PrefixI 'True) (S1 ('MetaSel ('Just "unMorleyLogs") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [Text])))

AsRPC

type family AsRPC (a :: k) :: k #

Instances

Instances details
type AsRPC 'TInt 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TInt = 'TInt
type AsRPC 'TNat 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TNat = 'TNat
type AsRPC 'TString 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TString = 'TString
type AsRPC 'TUnit 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TUnit = 'TUnit
type AsRPC 'TAddress 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TAddress = 'TAddress
type AsRPC 'TBls12381Fr 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TBls12381Fr = 'TBls12381Fr
type AsRPC 'TBls12381G1 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TBls12381G1 = 'TBls12381G1
type AsRPC 'TBls12381G2 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TBls12381G2 = 'TBls12381G2
type AsRPC 'TBool 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TBool = 'TBool
type AsRPC 'TBytes 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TBytes = 'TBytes
type AsRPC 'TChainId 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TChainId = 'TChainId
type AsRPC 'TChest 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TChest = 'TChest
type AsRPC 'TChestKey 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TChestKey = 'TChestKey
type AsRPC 'TKey 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TKey = 'TKey
type AsRPC 'TKeyHash 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TKeyHash = 'TKeyHash
type AsRPC 'TMutez 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TMutez = 'TMutez
type AsRPC 'TNever 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TNever = 'TNever
type AsRPC 'TOperation 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TOperation = 'TOperation
type AsRPC 'TSignature 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TSignature = 'TSignature
type AsRPC 'TTimestamp 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC 'TTimestamp = 'TTimestamp
type AsRPC ('TContract t :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TContract t :: T) = 'TContract t
type AsRPC ('TOption t :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TOption t :: T) = 'TOption (AsRPC t)
type AsRPC ('TSet t :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TSet t :: T) = 'TSet t
type AsRPC ('TTicket t :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TTicket t :: T) = 'TTicket t
type AsRPC ('TList t :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TList t :: T) = 'TList (AsRPC t)
type AsRPC ('TPair t1 t2 :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TPair t1 t2 :: T) = 'TPair (AsRPC t1) (AsRPC t2)
type AsRPC ('TBigMap _1 _2 :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TBigMap _1 _2 :: T) = 'TNat
type AsRPC ('TOr t1 t2 :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TOr t1 t2 :: T) = 'TOr (AsRPC t1) (AsRPC t2)
type AsRPC ('TMap k v :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TMap k v :: T) = 'TMap k (AsRPC v)
type AsRPC ('TLambda t1 t2 :: T) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ('TLambda t1 t2 :: T) = 'TLambda t1 t2
type AsRPC Bool 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Bool = Bool
type AsRPC Integer 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Natural 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC () 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC () = ()
type AsRPC ByteString 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC MText 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC MText = MText
type AsRPC Mutez 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Mutez = Mutez
type AsRPC ChainId 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ChainId = ChainId
type AsRPC Timestamp 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Timestamp = Timestamp
type AsRPC KeyHash 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC KeyHash = KeyHash
type AsRPC PublicKey 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC PublicKey = PublicKey
type AsRPC Signature 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Signature = Signature
type AsRPC Bls12381Fr 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Bls12381Fr = Bls12381Fr
type AsRPC Bls12381G1 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Bls12381G1 = Bls12381G1
type AsRPC Bls12381G2 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Bls12381G2 = Bls12381G2
type AsRPC Chest 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Chest = Chest
type AsRPC ChestKey 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ChestKey = ChestKey
type AsRPC Address 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Address = Address
type AsRPC EpAddress 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC EpAddress = EpAddress
type AsRPC Operation 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Operation = Operation
type AsRPC Never 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Never = Never
type AsRPC OpenChest 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC OpenChest = OpenChest
type AsRPC Empty 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC Empty = Empty
type AsRPC ([a] :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ([a] :: Type) = [AsRPC a]
type AsRPC (Maybe a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Maybe a :: Type) = Maybe (AsRPC a)
type AsRPC (Identity a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Identity a :: Type) = Identity (AsRPC a)
type AsRPC (Set a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Set a :: Type) = Set a
type AsRPC (ContractRef arg :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (ContractRef arg :: Type) = ContractRef arg
type AsRPC (FutureContract p :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (FutureContract p :: Type) = FutureContract p
type AsRPC (TSignature a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (TSignature a :: Type) = TSignature a
type AsRPC (Packed a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Packed a :: Type) = Packed a
type AsRPC (ShouldHaveEntrypoints a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (ShouldHaveEntrypoints a :: Type) = ShouldHaveEntrypoints a
type AsRPC (ChestT a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (ChestT a :: Type) = ChestT a
type AsRPC (OpenChestT a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (OpenChestT a :: Type) = OpenChestT a
type AsRPC (UParam entries :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (UParam entries :: Type) = UParam entries
type AsRPC (Either l r :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Either l r :: Type) = Either (AsRPC l) (AsRPC r)
type AsRPC ((a, b) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b) :: Type) = (AsRPC a, AsRPC b)
type AsRPC (Map k v :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Map k v :: Type) = Map k (AsRPC v)
type AsRPC (BigMap k v :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (BigMap k v :: Type) = BigMapId k v
type AsRPC (inp :-> out :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (inp :-> out :: Type) = inp :-> out
type AsRPC (Value' instr t :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Value' instr t :: Type) = Value' instr (AsRPC t)
type AsRPC (TAddress p vd :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (TAddress p vd :: Type) = TAddress p vd
type AsRPC (ParameterWrapper deriv cp :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (ParameterWrapper deriv cp :: Type) = ParameterWrapper deriv (AsRPC cp)
type AsRPC (Hash alg a :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Hash alg a :: Type) = Hash alg a
type AsRPC (View_ a r :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (View_ a r :: Type) = View_ a r
type AsRPC (Void_ a r :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Void_ a r :: Type) = Void_ a r
type AsRPC (Extensible x :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (Extensible x :: Type) = Extensible x
type AsRPC ((a, b, c) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b, c) :: Type) = (AsRPC a, AsRPC b, AsRPC c)
type AsRPC (NamedF Maybe a name :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (NamedF Maybe a name :: Type) = NamedF Maybe (AsRPC a) name
type AsRPC (NamedF Identity a name :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (NamedF Identity a name :: Type) = NamedF Identity (AsRPC a) name
type AsRPC ((a, b, c, d) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b, c, d) :: Type) = (AsRPC a, AsRPC b, AsRPC c, AsRPC d)
type AsRPC ((a, b, c, d, e) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b, c, d, e) :: Type) = (AsRPC a, AsRPC b, AsRPC c, AsRPC d, AsRPC e)
type AsRPC ((a, b, c, d, e, f) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b, c, d, e, f) :: Type) = (AsRPC a, AsRPC b, AsRPC c, AsRPC d, AsRPC e, AsRPC f)
type AsRPC ((a, b, c, d, e, f, g) :: Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC ((a, b, c, d, e, f, g) :: Type) = (AsRPC a, AsRPC b, AsRPC c, AsRPC d, AsRPC e, AsRPC f, AsRPC g)
type AsRPC (TAddress cp :: Type -> Type) 
Instance details

Defined in Morley.Client.RPC.AsRPC

type AsRPC (TAddress cp :: Type -> Type) = TAddress cp

deriveRPCWithStrategy :: String -> GenericStrategy -> Q [Dec] #

deriveManyRPCWithStrategy :: String -> [String] -> GenericStrategy -> Q [Dec] #

Utilities

mapEach :: (Each s t a b, Applicative m) => (a -> m b) -> s -> m t Source #

Version of mapM generalized with each.

Example:

(addr1, addr2, addr3) <- mapEach newAddress ("test1", "test2", "test3")

This is more type-safe than simple mapM since lists do not remember their length in types.

forEach :: (Each s t a b, Applicative m) => s -> (a -> m b) -> m t Source #

Version of mapEach with arguments flipped.