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 add exclude pattern running tests #2361

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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 crates/forge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ pub struct TestArgs {
/// Number of maximum steps during a single test. For fuzz tests this value is applied to each subtest separately.
#[arg(long)]
max_n_steps: Option<u32>,

/// Exclude tests matching the specified filter pattern
#[arg(long)]
exclude_filter: Option<String>,
}

pub enum ExitStatus {
Expand Down
13 changes: 12 additions & 1 deletion 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,
},
shared_cache::FailedTestsCache,
test_filter::TestsFilter,
test_filter::{TestsFilter, NameFilter},
warn::{
warn_if_available_gas_used_with_incompatible_scarb_version,
warn_if_incompatible_rpc_version,
Expand Down Expand Up @@ -39,6 +39,7 @@ pub struct RunForPackageArgs {
pub forge_config: Arc<ForgeConfig>,
pub fork_targets: Vec<ForkTarget>,
pub package_name: String,
pub exclude_filter: Option<NameFilter>
julienbrs marked this conversation as resolved.
Show resolved Hide resolved
}

impl RunForPackageArgs {
Expand Down Expand Up @@ -79,14 +80,18 @@ impl RunForPackageArgs {
args.include_ignored,
args.rerun_failed,
FailedTestsCache::new(cache_dir),
args.exclude_filter.clone(),
);

let exclude_filter = args.exclude_filter.clone().map(NameFilter::Exclude);

Ok(RunForPackageArgs {
test_targets: raw_test_targets,
forge_config,
tests_filter: test_filter,
fork_targets: forge_config_from_scarb.fork,
package_name: package.name,
exclude_filter,
})
}
}
Expand Down Expand Up @@ -120,6 +125,7 @@ pub async fn run_for_package(
tests_filter,
fork_targets,
package_name,
exclude_filter,
julienbrs marked this conversation as resolved.
Show resolved Hide resolved
}: RunForPackageArgs,
block_number_map: &mut BlockNumberMap,
) -> Result<Vec<TestTargetSummary>> {
Expand All @@ -129,6 +135,11 @@ pub async fn run_for_package(

for test_target in &mut test_targets {
tests_filter.filter_tests(&mut test_target.test_cases)?;

// Exclude tests based on the exclude_filter option
if let Some(NameFilter::Exclude(filter)) = &exclude_filter {
test_target.test_cases.retain(|tc| !tc.name.contains(filter));
}
julienbrs marked this conversation as resolved.
Show resolved Hide resolved
}

warn_if_available_gas_used_with_incompatible_scarb_version(&test_targets)?;
Expand Down
9 changes: 7 additions & 2 deletions crates/forge/src/run_tests/test_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use forge_runner::{
use futures::{stream::FuturesUnordered, StreamExt};
use std::{collections::HashMap, sync::Arc};
use tokio::sync::mpsc::channel;
use crate::test_filter::TestsFilter;

#[non_exhaustive]
pub enum TestTargetRunResult {
Expand All @@ -23,7 +24,7 @@ pub enum TestTargetRunResult {
pub async fn run_for_test_target(
tests: TestTargetWithResolvedConfig,
forge_config: Arc<ForgeConfig>,
tests_filter: &impl TestCaseFilter,
tests_filter: &TestsFilter,
package_name: &str,
) -> Result<TestTargetRunResult> {
let sierra_program = &tests.sierra_program.program;
Expand Down Expand Up @@ -53,9 +54,13 @@ pub async fn run_for_test_target(
for case in tests.test_cases {
let case_name = case.name.clone();

// Check if the test case should be excluded
if tests_filter.is_excluded(&case) {
continue;
}

if !tests_filter.should_be_run(&case) {
tasks.push(tokio::task::spawn(async {
// TODO TestCaseType should also be encoded in the test case definition
julienbrs marked this conversation as resolved.
Show resolved Hide resolved
Ok(AnyTestCaseSummary::Single(TestCaseSummary::Ignored {
name: case_name,
}))
Expand Down
46 changes: 39 additions & 7 deletions crates/forge/src/test_filter.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::shared_cache::FailedTestsCache;
use anyhow::Result;
use forge_runner::package_tests::with_config_resolved::TestCaseWithResolvedConfig;
use forge_runner::TestCaseFilter;
use forge_runner::{package_tests::with_config_resolved::TestCaseWithResolvedConfig, TestCaseFilter};

#[derive(Debug, PartialEq)]
// Specifies what tests should be included
Expand All @@ -14,13 +13,16 @@ pub struct TestsFilter {
last_failed_filter: bool,

failed_tests_cache: FailedTestsCache,
// based on exclude filter
exclude_filter: Option<NameFilter>,
}

#[derive(Debug, PartialEq)]
pub(crate) enum NameFilter {
pub enum NameFilter {
All,
Match(String),
ExactMatch(String),
Exclude(String),
}

#[derive(Debug, PartialEq)]
Expand All @@ -40,6 +42,7 @@ impl TestsFilter {
include_ignored: bool,
rerun_failed: bool,
failed_tests_cache: FailedTestsCache,
exclude_filter: Option<String>,
) -> Self {
assert!(
!(only_ignored && include_ignored),
Expand All @@ -65,11 +68,14 @@ impl TestsFilter {
NameFilter::All
};

let exclude_filter = exclude_filter.map(NameFilter::Exclude);

Self {
name_filter,
ignored_filter,
last_failed_filter: rerun_failed,
failed_tests_cache,
exclude_filter,
}
}

Expand All @@ -86,6 +92,8 @@ impl TestsFilter {
NameFilter::ExactMatch(name) => {
test_cases.retain(|tc| tc.name == *name);
}

NameFilter::Exclude(_) => {}
};

if self.last_failed_filter {
Expand All @@ -97,6 +105,10 @@ impl TestsFilter {
}
}

if let Some(NameFilter::Exclude(filter)) = &self.exclude_filter {
test_cases.retain(|tc| !tc.name.contains(filter));
}

match self.ignored_filter {
// if NotIgnored (default) we filter ignored tests later and display them as ignored
IgnoredFilter::All | IgnoredFilter::NotIgnored => {}
Expand All @@ -107,6 +119,13 @@ impl TestsFilter {

Ok(())
}

pub(crate) fn is_excluded(&self, test_case: &TestCaseWithResolvedConfig) -> bool {
if let Some(NameFilter::Exclude(filter)) = &self.exclude_filter {
return test_case.name.contains(filter);
}
false
}
}

impl TestCaseFilter for TestsFilter {
Expand Down Expand Up @@ -149,13 +168,13 @@ mod tests {
#[test]
#[should_panic(expected = "Arguments only_ignored and include_ignored cannot be both true")]
fn from_flags_only_ignored_and_include_ignored_both_true() {
let _ = TestsFilter::from_flags(None, false, true, true, false, Default::default());
let _ = TestsFilter::from_flags(None, false, true, true, false, Default::default(), None);
}

#[test]
#[should_panic(expected = "Argument test_name_filter cannot be None with exact_match")]
fn from_flags_exact_match_true_without_test_filter_name() {
let _ = TestsFilter::from_flags(None, true, false, false, false, Default::default());
let _ = TestsFilter::from_flags(None, true, false, false, false, Default::default(), None);
}

#[test]
Expand Down Expand Up @@ -224,6 +243,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -253,6 +273,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -281,6 +302,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -347,6 +369,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand All @@ -361,6 +384,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -437,6 +461,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand All @@ -451,6 +476,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -525,6 +551,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand All @@ -539,6 +566,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand All @@ -553,6 +581,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -581,6 +610,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -609,6 +639,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand All @@ -623,6 +654,7 @@ mod tests {
false,
false,
Default::default(),
None
);

let mut filtered = mocked_tests.clone();
Expand Down Expand Up @@ -704,7 +736,7 @@ mod tests {
};

let tests_filter =
TestsFilter::from_flags(None, false, true, false, false, Default::default());
TestsFilter::from_flags(None, false, true, false, false, Default::default(), None);
let mut filtered = mocked_tests;
tests_filter.filter_tests(&mut filtered.test_cases).unwrap();

Expand Down Expand Up @@ -799,7 +831,7 @@ mod tests {
};

let tests_filter =
TestsFilter::from_flags(None, false, false, true, false, Default::default());
TestsFilter::from_flags(None, false, false, true, false, Default::default(), None);
let mut filtered = mocked_tests;
tests_filter.filter_tests(&mut filtered.test_cases).unwrap();

Expand Down
2 changes: 2 additions & 0 deletions crates/forge/test_utils/src/running_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub fn run_test_case(test: &TestCase) -> Vec<TestTargetSummary> {
false,
false,
Default::default(),
None,
),
forge_config: Arc::new(ForgeConfig {
test_runner_config: Arc::new(TestRunnerConfig {
Expand All @@ -79,6 +80,7 @@ pub fn run_test_case(test: &TestCase) -> Vec<TestTargetSummary> {
}),
}),
fork_targets: vec![],
exclude_filter: None,
},
&mut BlockNumberMap::default(),
))
Expand Down
43 changes: 43 additions & 0 deletions crates/forge/tests/e2e/running.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,49 @@ fn with_include_ignored_flag_and_filter() {
);
}

#[test]
fn with_exclude_filter_flag() {
let temp = setup_package("simple_package");

// Exclude the test "test_failing"
let output = test_runner(&temp)
.arg("--exclude-filter")
.arg("test_failing")
.assert()
.code(1); // Assuming no other test fails

assert_stdout_contains(
output,
indoc! {r"
[..]Compiling[..]
[..]Finished[..]

Collected 12 test(s) from simple_package package
Running 2 test(s) from src/
[IGNORE] simple_package::tests::ignored_test
[PASS] simple_package::tests::test_fib [..]
[IGNORE] simple_package_integrationtest::ext_function_test::ignored_test
[PASS] simple_package_integrationtest::test_simple::test_two (gas: ~1)
[FAIL] simple_package_integrationtest::test_simple::test_another_failing

Failure data:
0x6661696c696e6720636865636b ('failing check')

[PASS] simple_package_integrationtest::ext_function_test::test_my_test (gas: ~1)
[PASS] simple_package_integrationtest::test_simple::test_simple (gas: ~1)
[PASS] simple_package_integrationtest::ext_function_test::test_simple (gas: ~1)
[PASS] simple_package_integrationtest::without_prefix::five (gas: ~1)
[PASS] simple_package_integrationtest::test_simple::test_two_and_two (gas: ~1)
[PASS] simple_package_integrationtest::test_simple::test_simple2 (gas: ~1)
[PASS] simple_package_integrationtest::contract::call_and_invoke (gas: ~170)
Tests: 9 passed, 1 failed, 0 skipped, 2 ignored, 1 filtered out

Failures:
simple_package_integrationtest::test_simple::test_another_failing
"},
);
}

#[test]
fn with_rerun_failed_flag_without_cache() {
let temp = setup_package("simple_package");
Expand Down
Loading
Loading