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

Document Sn Foundry test utils #1085

Merged
merged 33 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6d373ee
Minor structure and code improvements
immrsd Aug 5, 2024
78eee6e
fix: openzeppelin_utils snforge dependency
ericnordelo Aug 6, 2024
f899efc
feat: update CHANGELOG
ericnordelo Aug 6, 2024
3c2387f
fix: linter issues
ericnordelo Aug 6, 2024
6387dec
Update the documentation
immrsd Aug 6, 2024
7e0807b
Add and improve the in-code documentation
immrsd Aug 6, 2024
f084555
Run linter
immrsd Aug 6, 2024
8e9786c
Merge snforge dependency fix
immrsd Aug 6, 2024
0bcc479
Support changes
immrsd Aug 6, 2024
81e6f2e
Move test utils doc to a separate page
immrsd Aug 6, 2024
5dcb50e
Fix success values in mocks
immrsd Aug 6, 2024
c1c0af3
Update packages/token/src/tests/erc20/test_erc20.cairo
ericnordelo Aug 6, 2024
cd1f97f
Update packages/token/src/tests/erc721/test_erc721.cairo
ericnordelo Aug 6, 2024
4f1ef39
Update packages/access/src/tests/test_ownable_twostep.cairo
ericnordelo Aug 6, 2024
67d9f08
Update packages/account/src/tests/test_account.cairo
ericnordelo Aug 6, 2024
054ab2d
Update packages/account/src/tests/test_signature.cairo
ericnordelo Aug 6, 2024
2b8eef3
Update packages/token/src/tests/erc1155/test_dual1155.cairo
ericnordelo Aug 6, 2024
d98ed48
Update packages/token/src/tests/erc1155/test_erc1155.cairo
ericnordelo Aug 6, 2024
a5538fa
feat: apply review updates
ericnordelo Aug 6, 2024
e038ebd
refactor: format files
ericnordelo Aug 6, 2024
443eeae
Merge branch 'fix/snforge-dependency-in-utils' of github.com:ericnord…
ericnordelo Aug 6, 2024
73c9469
fix: tests
ericnordelo Aug 6, 2024
94894a9
Merge changes
immrsd Aug 7, 2024
176aa1e
Update test utils module name in doc
immrsd Aug 7, 2024
ddb9ecf
Fix review issues
immrsd Aug 7, 2024
6cc0495
Improve structure of testing doc page
immrsd Aug 7, 2024
935819f
Merge main
immrsd Aug 7, 2024
0b470ce
Minor doc fixes
immrsd Aug 8, 2024
ca53681
Add hint on how to add openzeppelin_testing dependency
immrsd Aug 8, 2024
2d4f621
Change references to SnFoundry to snforge
immrsd Aug 8, 2024
d44341d
Change variable names in the example to more generic ones
immrsd Aug 8, 2024
1513373
Change back openzeppelin::utils module name in doc
immrsd Aug 8, 2024
98af8c2
Change module reference in doc from testutils to testing
immrsd Aug 8, 2024
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 docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
*** xref:/api/upgrades.adoc[API Reference]

** xref:/api/utilities.adoc[Utilities]
** xref:/api/testing.adoc[Test Utilities]

* xref:backwards-compatibility.adoc[Backwards Compatibility]
* xref:contracts::index.adoc[Contracts for Solidity]
298 changes: 298 additions & 0 deletions docs/modules/ROOT/pages/api/testing.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
= Testing

:stark: https://docs.starknet.io/architecture-and-concepts/cryptography/stark-curve/[Stark]
:secp256k1: https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/secp256k1.cairo[Secp256k1]

This module provides various helper functions for declaring, deploying,
and testing Smart Contracts using `snforge` toolchain from Starknet Foundry.

```cairo
use openzeppelin_testing;
```

The module isn't part of the `openzeppelin` package and to be accessible has to
be added as a separate dependency in `Scarb.toml`:

```
[dev-dependencies]
openzeppelin_testing = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.15.0-rc.0" }
```

== Test Utilities

[.contract]
[[testing-common]]
=== `++common++`

A module providing common test helpers.

```cairo
use openzeppelin_testing::common;
```

[.contract-index]
.Members
--
.Functions
* xref:#testing-common-panic_data_to_byte_array[`++panic_data_to_byte_array(panic_data)++`]
* xref:#testing-common-to_base_16_string[`++to_base_16_string(value)++`]
* xref:#testing-common-assert_entrypoint_not_found_error[`++assert_entrypoint_not_found_error(result, selector, contract_address)++`]

.Traits
* xref:#testing-common-IntoBase16StringTrait[`++IntoBase16StringTrait++`]
--

[#testing-common-Functions]
==== Functions

[.contract-item]
[[testing-common-panic_data_to_byte_array]]
===== `[.contract-item-name]#++panic_data_to_byte_array++#++(panic_data: Array<felt252>) → ByteArray++` [.item-kind]#function#

Converts panic data into a string (`ByteArray`).

`panic_data` is expected to be a valid serialized `ByteArray` with an extra `felt252` at the beginning, which is the BYTE_ARRAY_MAGIC.

[.contract-item]
[[testing-common-to_base_16_string]]
===== `[.contract-item-name]#++to_base_16_string++#++(value: felt252) → ByteArray++` [.item-kind]#function#

Converts a `felt252` to a `base16` string padded to 66 characters (including the `0x` prefix).

[.contract-item]
[[testing-common-assert_entrypoint_not_found_error]]
==== `[.contract-item-name]#++assert_entrypoint_not_found_error++#<T, +Drop<T>>(result: SyscallResult<T>, selector: felt252, contract_address: ContractAddress)` [.item-kind]#function#

Asserts that the syscall result of a call failed with an "Entrypoint not found" error,
following the Starknet Foundry emitted error format.

[#testing-common-Traits]
==== Traits

[.contract-item]
[[testing-common-IntoBase16StringTrait]]
==== `[.contract-item-name]#++IntoBase16StringTrait++#` [.item-kind]#trait#

A helper trait that enables a value to be represented as a `base16` string padded to 66 characters
(including the `0x` prefix). The type of the value must implement `Into<T, felt252>` to be
convertible to `felt252`.

Usage example:

```cairo
use openzeppelin_testing::common::IntoBase16String;

let expected_panic_message = format!(
"Entry point selector {} not found in contract {}",
selector.into_base_16_string(),
contract_address.into_base_16_string()
);
```

[.contract]
[[testing-deployment]]
=== `++deployment++`

```cairo
use openzeppelin_testing::deployment;
```

A module containing utilities that simplify declaring and deploying contracts using the `snforge` toolchain.

[.contract-index]
.Members
--
.Functions
* xref:#testing-deployment-declare_class[`++declare_class(contract_name)++`]
* xref:#testing-deployment-deploy[`++deploy(contract_class, calldata)++`]
* xref:#testing-deployment-deploy_at[`++deploy_at(contract_class, contract_address, calldata)++`]
* xref:#testing-deployment-deploy_another_at[`++deploy_another_at(existing, target_address, calldata)++`]
* xref:#testing-deployment-declare_and_deploy[`++declare_and_deploy(contract_name, calldata)++`]
* xref:#testing-deployment-declare_and_deploy_at[`++declare_and_deploy_at(contract_name, target_address, calldata)++`]
--

[#testing-deployment-Functions]
==== Functions

[.contract-item]
[[testing-deployment-declare_class]]
==== `[.contract-item-name]#++declare_class++#++(contract_name: ByteArray) → ContractClass++` [.item-kind]#function#

Declares a contract with a `snforge` `declare` call and unwraps the result.

[.contract-item]
[[testing-deployment-deploy]]
==== `[.contract-item-name]#++deploy++#++(contract_class: ContractClass, calldata: Array<felt252>) → ContractAddress++` [.item-kind]#function#

Deploys an instance of a contract and unwraps the result.

[.contract-item]
[[testing-deployment-deploy_at]]
==== `[.contract-item-name]#++deploy_at++#++(contract_class: ContractClass, target_address: ContractAddress, calldata: Array<felt252>)++` [.item-kind]#function#

Deploys an instance of a contract at a given address.

[.contract-item]
[[testing-deployment-deploy_another_at]]
==== `[.contract-item-name]#++deploy_another_at++#++(existing: ContractAddress, target_address: ContractAddress, calldata: Array<felt252>)++` [.item-kind]#function#

Deploys a contract using the class hash from another already-deployed contract.

Note that currently, `snforge` does not support redeclaring a contract class. Consequently,
there is no direct method to deploy a second instance of a contract if neither its `ContractClass`
nor its `class_hash` is available in the context. This helper function provides a solution by retrieving
the class hash from an existing contract and using it to facilitate the deployment.

```cairo
use openzeppelin_testing::deploy_another_at;

let alice_address = setup_account(array!['ALICE_PUBKEY']);
let bob_address = contract_address_const::<'BOB'>();
deploy_another_at(alice_address, bob_address, array!['BOB_PUBKEY']);
```

[.contract-item]
[[testing-deployment-declare_and_deploy]]
==== `[.contract-item-name]#++declare_and_deploy++#++(contract_name: ByteArray, calldata: Array<felt252>) → ContractAddress++` [.item-kind]#function#

Combines the declaration of a class and the deployment of a contract into one function call.

[.contract-item]
[[testing-deployment-declare_and_deploy_at]]
==== `[.contract-item-name]#++declare_and_deploy_at++#++(contract_name: ByteArray, target_address: ContractAddress, calldata: Array<felt252>)++` [.item-kind]#function#

Combines the declaration of a class and the deployment of a contract at the given address into one function call.

[.contract]
[[testing-events]]
=== `++events++`

```cairo
use openzeppelin_testing::events;
use openzeppelin_testing::events::EventSpyExt;
```

A module offering an extended set of functions for handling emitted events, enhancing the default
event utilities provided by `snforge`. These functions are accessible via the `EventSpyExt`
trait implemented on the `EventSpy` struct.

[.contract-index]
.Members
--
.Functions
* xref:#testing-events-assert_only_event[`++assert_only_event(self, from_address, event)++`]
* xref:#testing-events-assert_emitted_single[`++assert_emitted_single(self, from_address, expected_event)++`]
* xref:#testing-events-drop_event[`++drop_event(self)++`]
* xref:#testing-events-drop_n_events[`++drop_n_events(self, number_to_drop)++`]
* xref:#testing-events-drop_all_events[`++drop_all_events(self)++`]
* xref:#testing-events-assert_no_events_left[`++assert_no_events_left(self)++`]
* xref:#testing-events-assert_no_events_left_from[`++assert_no_events_left_from(self, from_address)++`]
* xref:#testing-events-count_events_from[`++count_events_from(self, from_address)++`]
--

[#testing-events-Functions]
==== Functions

[.contract-item]
[[testing-events-assert_only_event]]
==== `[.contract-item-name]#++assert_only_event++#++<T, +starknet::Event<T>, +Drop<T>>(ref self: EventSpy, from_address: ContractAddress, expected_event: T)++` [.item-kind]#function#

Ensures that `from_address` has emitted only the `expected_event` and no additional events.

[.contract-item]
[[testing-events-assert_emitted_single]]
==== `[.contract-item-name]#++assert_emitted_single++#++<T, +starknet::Event<T>, +Drop<T>>(ref self: EventSpy, from_address: ContractAddress, expected_event: T)++` [.item-kind]#function#

Ensures that `from_address` has emitted the `expected_event`.

[.contract-item]
[[testing-events-drop_event]]
==== `[.contract-item-name]#++drop_event++#++(ref self: EventSpy)++` [.item-kind]#function#

Removes a single event from the queue. If the queue is empty, the function will panic.

[.contract-item]
[[testing-events-drop_n_events]]
==== `[.contract-item-name]#++drop_n_events++#++(ref self: EventSpy, number_to_drop: u32)++` [.item-kind]#function#

Removes `number_to_drop` events from the queue. If the queue is empty, the function will panic.

[.contract-item]
[[testing-events-drop_all_events]]
==== `[.contract-item-name]#++drop_all_events++#++(ref self: EventSpy)++` [.item-kind]#function#

Removes all events remaining on the queue. If the queue is empty already, the function will do nothing.

[.contract-item]
[[testing-events-assert_no_events_left]]
==== `[.contract-item-name]#++assert_no_events_left++#++(ref self: EventSpy)++` [.item-kind]#function#

Ensures that there are no events remaining on the queue.

[.contract-item]
[[testing-events-assert_no_events_left_from]]
==== `[.contract-item-name]#++assert_no_events_left_from++#++(ref self: EventSpy, from_address: ContractAddress)++` [.item-kind]#function#

Ensures that there are no events emitted from the given address remaining on the queue.

[.contract-item]
[[testing-events-count_events_from]]
==== `[.contract-item-name]#++count_events_from++#++(ref self: EventSpy, from_address: ContractAddress) → u32++` [.item-kind]#function#

Counts the number of remaining events emitted from the given address.

[.contract]
[[testing-signing]]
=== `++signing++`

```cairo
use openzeppelin_testing::signing;
```

A module offering utility functions for easier management of key pairs and signatures.

[.contract-index]
.Members
--
.Functions
* xref:#testing-signing-get_stark_keys_from[`++get_stark_keys_from(private_key)++`]
* xref:#testing-signing-get_secp256k1_keys_from[`++get_secp256k1_keys_from(private_key)++`]

.Traits
* xref:#testing-signing-SerializedSigning[`++SerializedSigning++`]
--

[#testing-signing-Functions]
==== Functions

[.contract-item]
[[testing-signing-get_stark_keys_from]]
==== `[.contract-item-name]#++get_stark_keys_from++#++(private_key: felt252) → StarkKeyPair++` [.item-kind]#function#

Builds a {stark} key pair from a private key represented by a `felt252` value.

[.contract-item]
[[testing-signing-get_secp256k1_keys_from]]
==== `[.contract-item-name]#++get_secp256k1_keys_from++#++(private_key: u256) → Secp256k1KeyPair++` [.item-kind]#function#

Builds a {secp256k1} key pair from a private key represented by a `u256` value.

[#testing-signing-Traits]
==== Traits

[.contract-item]
[[testing-signing-SerializedSigning]]
==== `[.contract-item-name]#++SerializedSigning++#` [.item-kind]#trait#

A helper trait that facilitates signing and converting the result signature into a serialized format.

Usage example:

```cairo
use openzeppelin_testing::signing::{
StarkKeyPair, get_stark_keys_from, StarkSerializedSigning
};

let key_pair = get_stark_keys_from('SECRET_KEY');
let serialized_signature = key_pair.serialized_sign('TX_HASH');
```
Loading