Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add event checks to motsu #441

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion contracts/src/utils/pausable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ impl Pausable {

#[cfg(all(test, feature = "std"))]
mod tests {
use crate::utils::pausable::{Error, Pausable};
use stylus_sdk::msg;

use crate::utils::pausable::{Error, Pausable, Paused, Unpaused};

#[motsu::test]
fn paused_works(contract: Pausable) {
Expand Down Expand Up @@ -204,6 +206,10 @@ mod tests {
let res = contract.pause();
assert!(res.is_ok());
assert_eq!(contract.paused(), true);
let expected_event = Paused { account: msg::sender() };
assert!(motsu::emits_event(expected_event.clone()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing logic for motsu::emits_event, that it would take an event from collection in case of match. No need in calling motsu::clear_events() after.

motsu::clear_events();
assert!(!motsu::emits_event(expected_event));
}

#[motsu::test]
Expand All @@ -225,6 +231,8 @@ mod tests {
let res = contract.unpause();
assert!(res.is_ok());
assert_eq!(contract.paused(), false);

assert!(motsu::emits_event(Unpaused { account: msg::sender() }));
}

#[motsu::test]
Expand Down
4 changes: 2 additions & 2 deletions examples/erc1155/src/constructor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ pragma solidity ^0.8.24;
contract Erc1155Example {
mapping(address => mapping(uint256 => uint256)) private _balanceOf;
mapping(address => mapping(address => bool)) private _isApprovedForAll;

string private _uri;

constructor(string memory uri_) {
_uri = uri_;
}
Expand Down
1 change: 1 addition & 0 deletions lib/motsu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ repository.workspace = true
version = "0.2.0"

[dependencies]
alloy-sol-types.workspace = true
const-hex.workspace = true
once_cell.workspace = true
tiny-keccak.workspace = true
Expand Down
109 changes: 0 additions & 109 deletions lib/motsu/src/context.rs

This file was deleted.

83 changes: 83 additions & 0 deletions lib/motsu/src/context/environment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! Module with unit test EVM environment for Stylus contracts.

/// Block Timestamp - Epoch timestamp: 1st January 2025 `00::00::00`.
const BLOCK_TIMESTAMP: u64 = 1_735_689_600;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good! Seems rational for me to move these constants to the other module

/// Arbitrum's CHAID ID.
const CHAIN_ID: u64 = 42161;

/// Dummy contract address set for tests.
const CONTRACT_ADDRESS: &[u8; 42] =
b"0xdCE82b5f92C98F27F116F70491a487EFFDb6a2a9";

/// Externally Owned Account (EOA) code hash.
const EOA_CODEHASH: &[u8; 66] =
b"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";

/// Dummy msg sender set for tests.
const MSG_SENDER: &[u8; 42] = b"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF";

pub(crate) struct Environment {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember, that the whole reason of MockStorage was to store not just storage bytes (contract_storage), but also fields that you've put into Environment struct

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because these data are also "mocked" values for our test cases

account_codehash: [u8; 66],
block_timestamp: u64,
chain_id: u64,
contract_address: [u8; 42],
events: Vec<Vec<u8>>,
Copy link
Member

@qalisander qalisander Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would better create wrapper type for event, to store them like Vec<Event> (or Vec<EncodedEvent>)

msg_sender: [u8; 42],
}

impl Default for Environment {
/// Creates default environment for a test case.
fn default() -> Environment {
Self {
account_codehash: *EOA_CODEHASH,
block_timestamp: BLOCK_TIMESTAMP,
chain_id: CHAIN_ID,
contract_address: *CONTRACT_ADDRESS,
events: Vec::new(),
msg_sender: *MSG_SENDER,
}
}
}

impl Environment {
/// Gets the code hash of the account at the given address.
pub(crate) fn account_codehash(&self) -> [u8; 66] {
self.account_codehash
}

/// Gets a bounded estimate of the Unix timestamp at which the Sequencer
/// sequenced the transaction.
pub(crate) fn block_timestamp(&self) -> u64 {
self.block_timestamp
}

/// Gets the chain ID of the current chain.
pub(crate) fn chain_id(&self) -> u64 {
self.chain_id
}

/// Gets the address of the current program.
pub(crate) fn contract_address(&self) -> [u8; 42] {
self.contract_address
}

/// Gets the address of the account that called the program.
pub(crate) fn msg_sender(&self) -> [u8; 42] {
self.msg_sender
}

/// Stores emitted event.
pub(crate) fn store_event(&mut self, event: &[u8]) {
self.events.push(Vec::from(event));
}

/// Removes all the stored events.
pub(crate) fn clear_events(&mut self) {
self.events.clear();
}

/// Gets all emitted events.
pub(crate) fn events(&self) -> Vec<Vec<u8>> {
self.events.clone()
}
}
Loading