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: unit test external call mock #14

Open
wants to merge 29 commits into
base: main
Choose a base branch
from

Conversation

qalisander
Copy link
Member

@qalisander qalisander commented Dec 19, 2024

Based on this pr (OpenZeppelin/rust-contracts-stylus#423)

Resolves #8 , Resolves #12

PR Checklist

  • Tests
  • Documentation
  • Changelog

@qalisander qalisander changed the title feat(test): unit test external call mock POC feat: unit test external call mock POC Dec 19, 2024
@qalisander qalisander changed the title feat: unit test external call mock POC feat: unit test external call mock Dec 19, 2024
@qalisander qalisander force-pushed the unit-tests/multiple-contract-deployment branch from 3838020 to feb635a Compare December 23, 2024 18:48
…ontract-deployment

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/motsu/README.md
@qalisander
Copy link
Member Author

Update documentation for the new test case structure

@qalisander qalisander marked this pull request as ready for review January 15, 2025 12:16
Copy link
Collaborator

@0xNeshi 0xNeshi left a comment

Choose a reason for hiding this comment

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

This is my first pass, really good work! 💪

@@ -15,57 +15,45 @@ pub(crate) fn test(_attr: &TokenStream, input: TokenStream) -> TokenStream {
let fn_block = &item_fn.block;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I left my feedback on motsu::test macro in our group chat, but the gist of it is that with the new context design in this PR, contracts/EOAs can be safely manually instantiated with little effort, and fuzzing crates like proptest work with motsu out-of-the-box (no need for special macro wrappers).

However, there are arguments to be made that we need to keep this attribute:

  1. Backward compatibility.
  2. Enables us to easily add additional features in the future.
  3. A/B testing - we document ways for devs to instantiate contracts/EOAs (injected as is now, and manual), and after some time we investigate how the devs actually prefer to use the crate - if either of the approaches gains drastically more adoption, we can always drop the other.

/// The key is the test [`Context`], an id of the test thread.
///
/// The value is the [`MockStorage`], a storage of the test case.
static STORAGE: Lazy<DashMap<Context, MockStorage>> = Lazy::new(DashMap::new);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I really like the way parallelism is supported. Did you test the speed execution difference during tests?

/// The key is the test [`Context`], an id of the test thread.
///
/// The value is the [`MockStorage`], a storage of the test case.
static STORAGE: Lazy<DashMap<Context, MockStorage>> = Lazy::new(DashMap::new);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to check if I understood correctly, our context logic will have to be changed after the Stylus team implements their host mocking logic, right?

Comment on lines +359 to +361
pub fn random() -> Self {
Self::new(Address::random())
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Although I understand the reason for having this function, I think the name random is a bit misleading - when I saw it in the context of motsu::test, I thought it generates a contract with its storage fields instantiated with random values.

I think keeping random() is fine, so it can be used in #[motsu::test], but it's also worth having additional functions with clearer names.
I'd suggest any combination of the below, where the first function just calls random() internally:

  1. Contract::new() and Contract::new_at(Address)
  2. Contract::mock() and Contract::mock_at(Address)
  3. Contract::deploy() and Contract::deploy_at(Address)

P.S. the same argument applies to Account::random.

Comment on lines +150 to +151
let msg_sender =
Context::current().get_msg_sender().expect("msg_sender should be set");
Copy link
Collaborator

Choose a reason for hiding this comment

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

With the current design, it's no longer necessary for other devs to redefine their own pub unsafe extern "C" fn msg_sender as was the case initially (if I remember correctly)?
They can just use our library by annotating their tests with #[motsu::test]?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature]: Allow setting msg::sender in unit tests [Feature]: Mock another contract in #[motsu::test]
2 participants