Skip to content
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Forge

#### Added

- `get_current_step` function to get the current step from Cairo VM during test execution. For more see [docs](https://foundry-rs.github.io/starknet-foundry/snforge-library/testing/get_current_step.html)

#### Changed

- Gas values in fuzzing test output are now displayed as whole numbers without fractional parts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cairo_vm::vm::vm_core::VirtualMachine;
use config::RawForgeConfig;
use conversions::serde::deserialize::BufferReader;
use runtime::{CheatcodeHandlingResult, EnhancedHintError, ExtensionLogic, StarknetRuntime};
Expand All @@ -17,6 +18,7 @@ impl<'a> ExtensionLogic for ForgeConfigExtension<'a> {
selector: &str,
mut input_reader: BufferReader<'_>,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
macro_rules! config_cheatcode {
( $prop:ident) => {{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
selector: &str,
mut input_reader: BufferReader<'_>,
extended_runtime: &mut Self::Runtime,
vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
if let Some(oracle_selector) = self
.oracle_hint_service
Expand Down Expand Up @@ -552,6 +553,9 @@ impl<'a> ExtensionLogic for ForgeExtension<'a> {
.cheat_block_hash(block_number, operation);
Ok(CheatcodeHandlingResult::from_serializable(()))
}
"get_current_step" => Ok(CheatcodeHandlingResult::from_serializable(
vm.get_current_step(),
)),
_ => Ok(CheatcodeHandlingResult::Forwarded),
}
}
Expand Down
39 changes: 39 additions & 0 deletions crates/forge/tests/integration/get_current_step.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use forge_runner::forge_config::ForgeTrackedResource;
use indoc::indoc;
use std::path::Path;
use test_utils::runner::{Contract, assert_passed};
use test_utils::running_tests::run_test_case;
use test_utils::test_case;

#[test]
fn test_get_current_step() {
let test = test_case!(
indoc!(
r#"
use snforge_std::testing::get_current_step;
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare};

#[test]
fn check_current_step() {
let step_start = get_current_step();

let contract = declare("HelloStarknet").unwrap().contract_class().clone();
let _ = contract.deploy(@ArrayTrait::new()).unwrap();

let step_end = get_current_step();

assert!(step_end > step_start);
}
"#
),
Contract::from_code_path(
"HelloStarknet".to_string(),
Path::new("tests/data/contracts/hello_starknet.cairo"),
)
.unwrap()
);

let result = run_test_case(&test, ForgeTrackedResource::SierraGas);

assert_passed(&result);
}
1 change: 1 addition & 0 deletions crates/forge/tests/integration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod gas;
mod generate_random_felt;
mod get_available_gas;
mod get_class_hash;
mod get_current_step;
mod interact_with_state;
mod l1_handler_executor;
mod message_to_l1;
Expand Down
2 changes: 2 additions & 0 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ impl<Extension: ExtensionLogic> ExtendedRuntime<Extension> {
&selector,
BufferReader::new(&inputs),
&mut self.extended_runtime,
vm,
);

let res = match result {
Expand Down Expand Up @@ -423,6 +424,7 @@ pub trait ExtensionLogic {
_selector: &str,
_input_reader: BufferReader,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
Ok(CheatcodeHandlingResult::Forwarded)
}
Expand Down
1 change: 1 addition & 0 deletions crates/sncast/src/starknet_commands/script/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl<'a> ExtensionLogic for CastScriptExtension<'a> {
selector: &str,
mut input_reader: BufferReader,
_extended_runtime: &mut Self::Runtime,
_vm: &VirtualMachine,
) -> Result<CheatcodeHandlingResult, EnhancedHintError> {
match selector {
"call" => {
Expand Down
12 changes: 12 additions & 0 deletions docs/listings/testing_reference/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "testing_reference"
version = "0.1.0"
edition = "2024_07"

[dependencies]
starknet = "2.12.0"

[dev-dependencies]
snforge_std = { path = "../../../snforge_std" }

[[target.starknet-contract]]
27 changes: 27 additions & 0 deletions docs/listings/testing_reference/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#[starknet::interface]
pub trait ICounter<TContractState> {
fn increment(ref self: TContractState);
}

#[starknet::contract]
pub mod Counter {
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};

#[storage]
struct Storage {
i: felt252,
}

#[constructor]
fn constructor(ref self: ContractState) {
self.i.write(0);
}

#[abi(embed_v0)]
impl CounterImpl of super::ICounter<ContractState> {
fn increment(ref self: ContractState) {
let current_value = self.i.read();
self.i.write(current_value + 1);
}
}
}
30 changes: 30 additions & 0 deletions docs/listings/testing_reference/tests/tests.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use snforge_std::testing::get_current_step;
use snforge_std::{ContractClassTrait, DeclareResultTrait, declare};
use testing_reference::{ICounterSafeDispatcher, ICounterSafeDispatcherTrait};

#[feature("safe_dispatcher")]
fn setup() {
// Deploy contract
let (contract_address, _) = declare("Counter")
.unwrap()
.contract_class()
.deploy(@array![])
.unwrap();

let dispatcher = ICounterSafeDispatcher { contract_address };

// Increment counter a few times
dispatcher.increment();
dispatcher.increment();
dispatcher.increment();
}

#[test]
fn test_setup_steps() {
let steps_start = get_current_step();
setup();
let steps_end = get_current_step();

// Assert that setup used no more than 100 steps
assert!(steps_end - steps_start <= 100);
}
2 changes: 2 additions & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
* [env](appendix/snforge-library/env.md)
* [signature](appendix/snforge-library/signature.md)
* [fuzzable](appendix/snforge-library/fuzzable.md)
* [testing](appendix/snforge-library/testing.md)
* [get_current_step](appendix/snforge-library/testing/get_current_step.md)
* [`sncast` Commands](appendix/sncast.md)
* [common flags](appendix/sncast/common.md)
* [account](appendix/sncast/account/account.md)
Expand Down
7 changes: 7 additions & 0 deletions docs/src/appendix/snforge-library/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `testing` Module

Module containing functions useful for testing.

## Functions

* [`get_current_step`](./testing/get_current_step.md)
49 changes: 49 additions & 0 deletions docs/src/appendix/snforge-library/testing/get_current_step.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# `get_current_step`

Gets the current step from Cairo VM during test execution.

```rust
fn get_current_step() -> u32;
```

## Example

Let's consider a simple counter contract that increments a value stored in its storage.

```rust
{{#include ../../../../listings/testing_reference/src/lib.cairo}}
```

Now, let's define `setup` function which deploys this contract and increments the counter a few times and assert that `setup` function does not exceed a certain number of steps during its execution. This is particularly useful for performance testing and ensuring that our setup logic remains efficient.

```rust
{{#include ../../../../listings/testing_reference/tests/tests.cairo}}
```

<!-- { "package_name": "testing_reference" } -->
Let's run the test:
```shell
$ snforge test test_setup_steps
```

<details>
<summary>Output:</summary>

```shell
Collected 1 test(s) from testing_reference package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[FAIL] testing_reference_integrationtest::tests::test_setup_steps

Failure data:
"assertion failed: `steps_end - steps_start <= 100`."

Tests: 0 passed, 1 failed, 0 ignored, 0 filtered out

Failures:
testing_reference_integrationtest::tests::test_setup_steps
```
</details>
<br>

As we can see, the test fails because the `setup` function exceeded the allowed number of steps (100 in this case).
2 changes: 2 additions & 0 deletions snforge_std/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ pub mod fuzzable;

pub mod signature;

pub mod testing;

pub mod trace;

#[doc(hidden)]
Expand Down
6 changes: 6 additions & 0 deletions snforge_std/src/testing.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use crate::cheatcode::execute_cheatcode_and_deserialize;

/// Gets the current step from Cairo VM during test execution
pub fn get_current_step() -> u32 {
execute_cheatcode_and_deserialize::<'get_current_step', u32>(array![].span())
}
Loading