Skip to content

Commit

Permalink
Merge branch 'master' into spr/master/f00574d8
Browse files Browse the repository at this point in the history
  • Loading branch information
integraledelebesgue authored Oct 16, 2024
2 parents de17e1b + 9ea9d3a commit 864a57c
Show file tree
Hide file tree
Showing 18 changed files with 151 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
#### Fixed
- `account delete` command: It is no longer necessary to provide the `--url` argument each time. Either the `--url` or `--network` argument must be provided, but not both, as they are mutually exclusive.

### Forge

#### Changed

- When using test name filter with `--exact` flag, forge will try to compile only the selected test.

## [0.31.0] - 2024-09-26

### Cast
Expand Down
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.

32 changes: 22 additions & 10 deletions crates/forge/src/pretty_printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,33 @@ pub(crate) fn print_running_tests(test_target_location: TestTargetLocation, test
println!("{}", style(plain_text).bold());
}

pub(crate) fn print_test_summary(summaries: &[TestTargetSummary], filtered: usize) {
// TODO(#2574): Bring back "filtered out" number in tests summary when running with `--exact` flag
pub(crate) fn print_test_summary(summaries: &[TestTargetSummary], filtered: Option<usize>) {
let passed: usize = summaries.iter().map(TestTargetSummary::count_passed).sum();
let failed: usize = summaries.iter().map(TestTargetSummary::count_failed).sum();
let skipped: usize = summaries.iter().map(TestTargetSummary::count_skipped).sum();
let ignored: usize = summaries.iter().map(TestTargetSummary::count_ignored).sum();

println!(
"{}: {} passed, {} failed, {} skipped, {} ignored, {} filtered out",
style("Tests").bold(),
passed,
failed,
skipped,
ignored,
filtered,
);
if let Some(filtered) = filtered {
println!(
"{}: {} passed, {} failed, {} skipped, {} ignored, {} filtered out",
style("Tests").bold(),
passed,
failed,
skipped,
ignored,
filtered
);
} else {
println!(
"{}: {} passed, {} failed, {} skipped, {} ignored, other filtered out",
style("Tests").bold(),
passed,
failed,
skipped,
ignored
);
}
}

pub(crate) fn print_test_seed(seed: u64) {
Expand Down
11 changes: 8 additions & 3 deletions crates/forge/src/run_tests/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
load_test_artifacts, should_compile_starknet_contract_target,
},
shared_cache::FailedTestsCache,
test_filter::TestsFilter,
test_filter::{NameFilter, TestsFilter},
warn::{
warn_if_available_gas_used_with_incompatible_scarb_version,
warn_if_incompatible_rpc_version,
Expand Down Expand Up @@ -172,8 +172,13 @@ pub async fn run_for_package(
}
}

let filtered = all_tests - not_filtered;
pretty_printing::print_test_summary(&summaries, filtered);
// TODO(#2574): Bring back "filtered out" number in tests summary when running with `--exact` flag
if let NameFilter::ExactMatch(_) = tests_filter.name_filter {
pretty_printing::print_test_summary(&summaries, None);
} else {
let filtered = all_tests - not_filtered;
pretty_printing::print_test_summary(&summaries, Some(filtered));
}

let any_fuzz_test_was_run = summaries.iter().any(|test_target_summary| {
test_target_summary
Expand Down
22 changes: 22 additions & 0 deletions crates/forge/src/run_tests/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use scarb_api::{
target_dir_for_workspace, ScarbCommand,
};
use scarb_ui::args::PackagesFilter;
use shared::consts::SNFORGE_TEST_FILTER;
use std::env;

#[allow(clippy::too_many_lines)]
Expand Down Expand Up @@ -44,6 +45,15 @@ pub async fn run_for_workspace(args: TestArgs) -> Result<ExitStatus> {

let filter = PackagesFilter::generate_for::<Metadata>(packages.iter());

if args.exact {
let test_filter = args.test_filter.clone();
if let Some(last_filter) =
test_filter.and_then(|filter| filter.split("::").last().map(String::from))
{
set_forge_test_filter(last_filter);
}
}

build_artifacts_with_scarb(
filter.clone(),
args.features.clone(),
Expand Down Expand Up @@ -80,6 +90,10 @@ pub async fn run_for_workspace(args: TestArgs) -> Result<ExitStatus> {
pretty_printing::print_latest_blocks_numbers(block_number_map.get_url_to_latest_block_number());
pretty_printing::print_failures(&all_failed_tests);

if args.exact {
unset_forge_test_filter();
}

Ok(if all_failed_tests.is_empty() {
ExitStatus::Success
} else {
Expand All @@ -101,3 +115,11 @@ fn extract_failed_tests(
)
})
}

fn set_forge_test_filter(test_filter: String) {
env::set_var(SNFORGE_TEST_FILTER, test_filter);
}

fn unset_forge_test_filter() {
env::remove_var(SNFORGE_TEST_FILTER);
}
2 changes: 1 addition & 1 deletion crates/forge/src/test_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use forge_runner::TestCaseFilter;
// Specifies what tests should be included
pub struct TestsFilter {
// based on name
name_filter: NameFilter,
pub(crate) name_filter: NameFilter,
// based on `#[ignore]` attribute
ignored_filter: IgnoredFilter,
// based on rerun_failed flag
Expand Down
10 changes: 10 additions & 0 deletions crates/forge/tests/data/duplicated_test_names/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "duplicated_test_names"
version = "0.1.0"
edition = "2023_11"

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

[scripts]
test = "snforge test"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[test]
fn test_simple() {
assert(1 == 1, 'simple check');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[test]
fn test_simple() {
assert(1 == 1, 'simple check');
}
6 changes: 3 additions & 3 deletions crates/forge/tests/e2e/forking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn with_cache() {
Failure data:
0x42616c616e63652073686f756c642062652030 ('Balance should be 0')
Tests: 0 passed, 1 failed, 0 skipped, 0 ignored, 4 filtered out
Tests: 0 passed, 1 failed, 0 skipped, 0 ignored, other filtered out
Failures:
forking::tests::test_fork_simple
Expand Down Expand Up @@ -96,7 +96,7 @@ fn with_clean_cache() {
Collected 1 test(s) from forking package
Running 1 test(s) from src/
[PASS] forking::tests::test_fork_simple [..]
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, 4 filtered out
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, other filtered out
"},
);
}
Expand Down Expand Up @@ -124,7 +124,7 @@ fn printing_latest_block_number() {
Collected 1 test(s) from forking package
Running 1 test(s) from src/
[PASS] forking::tests::print_block_number_when_latest [..]
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, 4 filtered out
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, other filtered out
Latest block number = [..] for url = {node_rpc_url}
"},
Expand Down
28 changes: 27 additions & 1 deletion crates/forge/tests/e2e/running.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,33 @@ fn with_exact_filter() {
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] simple_package_integrationtest::test_simple::test_two [..]
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, 12 filtered out
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, other filtered out
"},
);
}

#[test]
fn with_exact_filter_and_duplicated_test_names() {
let temp = setup_package("duplicated_test_names");

let output = test_runner(&temp)
.arg("duplicated_test_names_integrationtest::tests_a::test_simple")
.arg("--exact")
.assert()
.success();

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]
Collected 1 test(s) from duplicated_test_names package
Running 0 test(s) from src/
Running 1 test(s) from tests/
[PASS] duplicated_test_names_integrationtest::tests_a::test_simple [..]
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, other filtered out
"},
);
}
Expand Down
1 change: 1 addition & 0 deletions crates/shared/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub const EXPECTED_RPC_VERSION: &str = "0.7.0";
pub const RPC_URL_VERSION: &str = "v0_7";
pub const SNFORGE_TEST_FILTER: &str = "SNFORGE_TEST_FILTER";
1 change: 1 addition & 0 deletions crates/snforge-scarb-plugin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ indoc.workspace = true
serde_json.workspace = true
smol_str.workspace = true
num-bigint.workspace = true
shared.workspace = true

[dev-dependencies]
lazy_static = "1.4.0"
Expand Down
31 changes: 26 additions & 5 deletions crates/snforge-scarb-plugin/src/attributes/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use crate::{
common::{into_proc_macro_result, with_parsed_values},
};
use cairo_lang_macro::{Diagnostic, Diagnostics, ProcMacroResult, TokenStream};
use cairo_lang_syntax::node::{ast::FunctionWithBody, db::SyntaxGroup, TypedSyntaxNode};
use cairo_lang_syntax::node::{ast::FunctionWithBody, db::SyntaxGroup, Terminal, TypedSyntaxNode};
use indoc::formatdoc;

use shared::consts::SNFORGE_TEST_FILTER;
use std::env::{self, VarError};
struct TestCollector;

impl AttributeInfo for TestCollector {
Expand Down Expand Up @@ -34,14 +36,33 @@ fn test_internal(
let config = InternalConfigStatementCollector::ATTR_NAME;

let func_item = func.as_syntax_node().get_text(db);
let name = func.declaration(db).name(db).text(db).to_string();

let result = formatdoc!(
"
let test_filter = get_forge_test_filter().ok();

let should_run_test = match test_filter {
Some(ref filter) => name.contains(filter),
None => true,
};

if should_run_test {
Ok(formatdoc!(
"
#[snforge_internal_test_executable]
#[{config}]
{func_item}
"
);
))
} else {
Ok(formatdoc!(
"
#[{config}]
{func_item}
"
))
}
}

Ok(result)
fn get_forge_test_filter() -> Result<String, VarError> {
env::var(SNFORGE_TEST_FILTER)
}
2 changes: 1 addition & 1 deletion docs/src/getting-started/first-steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Running 0 test(s) from src/
Running 2 test(s) from tests/
[PASS] tests::test_contract::test_increase_balance (gas: ~170)
[PASS] tests::test_contract::test_cannot_increase_balance_with_zero_value (gas: ~104)
Tests: 2 passed, 0 failed, 0 skipped, 0 ignored, 0 filtered out
Tests: 2 passed, 0 failed, 0 skipped, 0 ignored
```

## Using `snforge` With Existing Scarb Projects
Expand Down
7 changes: 6 additions & 1 deletion docs/src/testing/running-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ Tests: 2 passed, 0 failed, 0 skipped, 0 ignored, 1 filtered out
To run a specific test, you can pass a filter string along with an `--exact` flag.
Note, you have to use a fully qualified test name, including a module name.

> 📝 **Note**
>
> Running a specific test results in optimized compilation. `snforge` will try to compile only the desired test, unlike the case of running all tests where all of them are compiled.
>
```shell
$ snforge test package_name::tests::calling --exact
Collected 1 test(s) from package_name package
Running 1 test(s) from src/
[PASS] package_name::tests::calling
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, 2 filtered out
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, other filtered out
```

## Stopping Test Execution After First Failed Test
Expand Down
14 changes: 7 additions & 7 deletions docs/src/testing/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,20 @@ To mark a test as expected to fail, use the `#[should_panic]` attribute.
You can specify the expected failure message in three ways:

1. **With ByteArray**:
```rust
```rust
{{#include ../../listings/snforge_overview/crates/writing_tests/tests/expected_failures.cairo:byte_array}}
```
With this format, the expected error message needs to be a substring of the actual error message. This is particularly useful when the error message includes dynamic data such as a hash or address.
```
With this format, the expected error message needs to be a substring of the actual error message. This is particularly useful when the error message includes dynamic data such as a hash or address.

2. **With felt**
```rust
```rust
{{#include ../../listings/snforge_overview/crates/writing_tests/tests/expected_failures.cairo:felt}}
```
```

3. **With tuple of felts**:
```rust
```rust
{{#include ../../listings/snforge_overview/crates/writing_tests/tests/expected_failures.cairo:tuple}}
```
```


```shell
Expand Down

0 comments on commit 864a57c

Please sign in to comment.