diff --git a/compiler/noirc_frontend/src/hir/mod.rs b/compiler/noirc_frontend/src/hir/mod.rs index fea52be88bc..e85fa629d56 100644 --- a/compiler/noirc_frontend/src/hir/mod.rs +++ b/compiler/noirc_frontend/src/hir/mod.rs @@ -54,11 +54,11 @@ pub struct Context<'file_manager, 'parsed_files> { pub package_build_path: PathBuf, } -#[derive(Debug, Copy, Clone)] -pub enum FunctionNameMatch<'a> { +#[derive(Debug)] +pub enum FunctionNameMatch { Anything, - Exact(&'a str), - Contains(&'a str), + Exact(Vec), + Contains(Vec), } impl Context<'_, '_> { @@ -175,7 +175,7 @@ impl Context<'_, '_> { pub fn get_all_test_functions_in_crate_matching( &self, crate_id: &CrateId, - pattern: FunctionNameMatch, + pattern: &FunctionNameMatch, ) -> Vec<(String, TestFunction)> { let interner = &self.def_interner; let def_map = self.def_map(crate_id).expect("The local crate should be analyzed already"); @@ -187,10 +187,13 @@ impl Context<'_, '_> { self.fully_qualified_function_name(crate_id, &test_function.get_id()); match &pattern { FunctionNameMatch::Anything => Some((fully_qualified_name, test_function)), - FunctionNameMatch::Exact(pattern) => (&fully_qualified_name == pattern) + FunctionNameMatch::Exact(patterns) => patterns + .iter() + .any(|pattern| &fully_qualified_name == pattern) .then_some((fully_qualified_name, test_function)), - FunctionNameMatch::Contains(pattern) => fully_qualified_name - .contains(pattern) + FunctionNameMatch::Contains(patterns) => patterns + .iter() + .any(|pattern| fully_qualified_name.contains(pattern)) .then_some((fully_qualified_name, test_function)), } }) diff --git a/tooling/lsp/src/lib.rs b/tooling/lsp/src/lib.rs index 97a1c7ad27b..f8a4bd6b74a 100644 --- a/tooling/lsp/src/lib.rs +++ b/tooling/lsp/src/lib.rs @@ -215,7 +215,7 @@ fn get_package_tests_in_crate( let fm = &context.file_manager; let files = fm.as_file_map(); let tests = - context.get_all_test_functions_in_crate_matching(crate_id, FunctionNameMatch::Anything); + context.get_all_test_functions_in_crate_matching(crate_id, &FunctionNameMatch::Anything); let package_tests: Vec<_> = tests .into_iter() diff --git a/tooling/lsp/src/requests/code_lens_request.rs b/tooling/lsp/src/requests/code_lens_request.rs index 0c1877c156d..ab98ab8bf10 100644 --- a/tooling/lsp/src/requests/code_lens_request.rs +++ b/tooling/lsp/src/requests/code_lens_request.rs @@ -96,7 +96,7 @@ pub(crate) fn collect_lenses_for_package( let fm = &context.file_manager; let files = fm.as_file_map(); let tests = - context.get_all_test_functions_in_crate_matching(&crate_id, FunctionNameMatch::Anything); + context.get_all_test_functions_in_crate_matching(&crate_id, &FunctionNameMatch::Anything); for (func_name, test_function) in tests { let location = context.function_meta(&test_function.get_id()).name.location; let file_id = location.file; diff --git a/tooling/lsp/src/requests/test_run.rs b/tooling/lsp/src/requests/test_run.rs index bd53526298e..e2d8edd46c8 100644 --- a/tooling/lsp/src/requests/test_run.rs +++ b/tooling/lsp/src/requests/test_run.rs @@ -74,7 +74,7 @@ fn on_test_run_request_inner( let test_functions = context.get_all_test_functions_in_crate_matching( &crate_id, - FunctionNameMatch::Exact(function_name), + &FunctionNameMatch::Exact(vec![function_name.clone()]), ); let (_, test_function) = test_functions.into_iter().next().ok_or_else(|| { diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index 4ba734386fe..95ca2276d40 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -33,7 +33,7 @@ pub(crate) mod formatters; #[clap(visible_alias = "t")] pub(crate) struct TestCommand { /// If given, only tests with names containing this string will be run - test_name: Option, + test_names: Vec, /// Display output of `println` statements #[arg(long)] @@ -125,15 +125,12 @@ pub(crate) fn run(args: TestCommand, config: NargoConfig) -> Result<(), CliError insert_all_files_for_workspace_into_file_manager(&workspace, &mut file_manager); let parsed_files = parse_all(&file_manager); - let pattern = match &args.test_name { - Some(name) => { - if args.exact { - FunctionNameMatch::Exact(name) - } else { - FunctionNameMatch::Contains(name) - } - } - None => FunctionNameMatch::Anything, + let pattern = if args.test_names.is_empty() { + FunctionNameMatch::Anything + } else if args.exact { + FunctionNameMatch::Exact(args.test_names.clone()) + } else { + FunctionNameMatch::Contains(args.test_names.clone()) }; let formatter: Box = if let Some(format) = args.format { @@ -161,7 +158,7 @@ struct TestRunner<'a> { parsed_files: &'a ParsedFiles, workspace: Workspace, args: &'a TestCommand, - pattern: FunctionNameMatch<'a>, + pattern: FunctionNameMatch, num_threads: usize, formatter: Box, } @@ -186,15 +183,31 @@ impl<'a> TestRunner<'a> { if tests_count == 0 { match &self.pattern { - FunctionNameMatch::Exact(pattern) => { - return Err(CliError::Generic(format!( - "Found 0 tests matching input '{pattern}'.", - ))) + FunctionNameMatch::Exact(patterns) => { + if patterns.len() == 1 { + return Err(CliError::Generic(format!( + "Found 0 tests matching '{}'.", + patterns.first().unwrap() + ))); + } else { + return Err(CliError::Generic(format!( + "Found 0 tests matching any of {}.", + patterns.join(", "), + ))); + } } - FunctionNameMatch::Contains(pattern) => { - return Err(CliError::Generic( - format!("Found 0 tests containing '{pattern}'.",), - )) + FunctionNameMatch::Contains(patterns) => { + if patterns.len() == 1 { + return Err(CliError::Generic(format!( + "Found 0 tests containing '{}'.", + patterns.first().unwrap() + ))); + } else { + return Err(CliError::Generic(format!( + "Found 0 tests containing any of {}.", + patterns.join(", ") + ))); + } } // If we are running all tests in a crate, having none is not an error FunctionNameMatch::Anything => {} @@ -459,7 +472,7 @@ impl<'a> TestRunner<'a> { check_crate_and_report_errors(&mut context, crate_id, &self.args.compile_options)?; Ok(context - .get_all_test_functions_in_crate_matching(&crate_id, self.pattern) + .get_all_test_functions_in_crate_matching(&crate_id, &self.pattern) .into_iter() .map(|(test_name, _)| test_name) .collect()) @@ -483,8 +496,8 @@ impl<'a> TestRunner<'a> { check_crate(&mut context, crate_id, &self.args.compile_options) .expect("Any errors should have occurred when collecting test functions"); - let test_functions = context - .get_all_test_functions_in_crate_matching(&crate_id, FunctionNameMatch::Exact(fn_name)); + let pattern = FunctionNameMatch::Exact(vec![fn_name.to_string()]); + let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, &pattern); let (_, test_function) = test_functions.first().expect("Test function should exist"); let blackbox_solver = S::default(); diff --git a/tooling/nargo_cli/src/cli/test_cmd/formatters.rs b/tooling/nargo_cli/src/cli/test_cmd/formatters.rs index bc4621c92ea..91d6f0066b1 100644 --- a/tooling/nargo_cli/src/cli/test_cmd/formatters.rs +++ b/tooling/nargo_cli/src/cli/test_cmd/formatters.rs @@ -112,7 +112,7 @@ impl Formatter for PrettyFormatter { } }; - write!(writer, "[{}] Testing {}... ", &test_result.package_name, &test_result.name)?; + write!(writer, "[{}] Testing {} ... ", &test_result.package_name, &test_result.name)?; writer.flush()?; match &test_result.status { diff --git a/tooling/nargo_cli/tests/stdlib-tests.rs b/tooling/nargo_cli/tests/stdlib-tests.rs index 048de33f24c..17476e6dd5f 100644 --- a/tooling/nargo_cli/tests/stdlib-tests.rs +++ b/tooling/nargo_cli/tests/stdlib-tests.rs @@ -33,7 +33,7 @@ pub struct Options { impl Options { pub fn function_name_match(&self) -> FunctionNameMatch { match self.args.as_slice() { - [_test_name, lib] => FunctionNameMatch::Contains(lib.as_str()), + [_test_name, lib] => FunctionNameMatch::Contains(vec![lib.clone()]), _ => FunctionNameMatch::Anything, } } @@ -78,7 +78,7 @@ fn run_stdlib_tests(force_brillig: bool, inliner_aggressiveness: i64) { let test_functions = context.get_all_test_functions_in_crate_matching( context.stdlib_crate_id(), - opts.function_name_match(), + &opts.function_name_match(), ); let test_report: Vec<(String, TestStatus)> = test_functions