-
Notifications
You must be signed in to change notification settings - Fork 359
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Document Sn Foundry test utils (#1085)
* Minor structure and code improvements * fix: openzeppelin_utils snforge dependency * feat: update CHANGELOG * fix: linter issues * Update the documentation * Add and improve the in-code documentation * Run linter * Support changes * Move test utils doc to a separate page * Fix success values in mocks * Update packages/token/src/tests/erc20/test_erc20.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/token/src/tests/erc721/test_erc721.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/access/src/tests/test_ownable_twostep.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/account/src/tests/test_account.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/account/src/tests/test_signature.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/token/src/tests/erc1155/test_dual1155.cairo Co-authored-by: Andrew Fleming <[email protected]> * Update packages/token/src/tests/erc1155/test_erc1155.cairo Co-authored-by: Andrew Fleming <[email protected]> * feat: apply review updates * refactor: format files * fix: tests * Update test utils module name in doc * Fix review issues * Improve structure of testing doc page * Minor doc fixes * Add hint on how to add openzeppelin_testing dependency * Change references to SnFoundry to snforge * Change variable names in the example to more generic ones * Change back openzeppelin::utils module name in doc * Change module reference in doc from testutils to testing --------- Co-authored-by: Eric Nordelo <[email protected]> Co-authored-by: Andrew Fleming <[email protected]>
- Loading branch information
1 parent
a13bae3
commit c2c1b41
Showing
16 changed files
with
367 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | ||
``` |
Oops, something went wrong.