diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 2ab7e176387..f8b7664df43 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -201,11 +201,12 @@ impl CrateDefMap { self.modules.iter().flat_map(|(_, module)| { module.value_definitions().filter_map(|id| { if let Some(func_id) = id.as_function() { + let has_arguments = !interner.function_meta(&func_id).parameters.is_empty(); let attributes = interner.function_attributes(&func_id); match attributes.function().map(|attr| &attr.kind) { Some(FunctionAttributeKind::Test(scope)) => { let location = interner.function_meta(&func_id).name.location; - Some(TestFunction::new(func_id, scope.clone(), location)) + Some(TestFunction::new(func_id, scope.clone(), location, has_arguments)) } _ => None, } @@ -375,11 +376,12 @@ pub struct TestFunction { id: FuncId, scope: TestScope, location: Location, + has_arguments: bool, } impl TestFunction { - fn new(id: FuncId, scope: TestScope, location: Location) -> Self { - TestFunction { id, scope, location } + fn new(id: FuncId, scope: TestScope, location: Location, has_arguments: bool) -> Self { + TestFunction { id, scope, location, has_arguments } } /// Returns the function id of the test function @@ -391,6 +393,10 @@ impl TestFunction { self.location.file } + pub fn has_arguments(&self) -> bool { + self.has_arguments + } + /// Returns true if the test function has been specified to fail /// This is done by annotating the function with `#[test(should_fail)]` /// or `#[test(should_fail_with = "reason")]` diff --git a/tooling/nargo_cli/src/cli/test_cmd.rs b/tooling/nargo_cli/src/cli/test_cmd.rs index 2307202d4cc..644f6cff59a 100644 --- a/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/tooling/nargo_cli/src/cli/test_cmd.rs @@ -23,7 +23,7 @@ use nargo::{ }; use nargo_toml::PackageSelection; use noirc_driver::{CompileOptions, check_crate}; -use noirc_frontend::hir::{FunctionNameMatch, ParsedFiles}; +use noirc_frontend::hir::{FunctionNameMatch, ParsedFiles, def_map::TestFunction}; use crate::errors::CliError; @@ -71,6 +71,14 @@ pub(crate) struct TestCommand { /// Display one character per test instead of one line #[clap(short = 'q', long = "quiet")] quiet: bool, + + /// Do not run fuzz tests (tests that have arguments) + #[clap(long, conflicts_with("only_fuzz"))] + no_fuzz: bool, + + /// Only run fuzz tests (tests that have arguments) + #[clap(long, conflicts_with("no_fuzz"))] + only_fuzz: bool, } impl WorkspaceCommand for TestCommand { @@ -470,7 +478,7 @@ impl<'a> TestRunner<'a> { let tests: Vec = test_functions .into_iter() - .map(|test_name| { + .map(|(test_name, test_function)| { let test_name_copy = test_name.clone(); let root_path = root_path.clone(); let package_name_clone = package_name.clone(); @@ -479,6 +487,7 @@ impl<'a> TestRunner<'a> { self.run_test::( package, &test_name, + test_function.has_arguments(), foreign_call_resolver_url, root_path, package_name_clone.clone(), @@ -492,16 +501,15 @@ impl<'a> TestRunner<'a> { } /// Compiles a single package and returns all of its test names - fn get_tests_in_package(&'a self, package: &'a Package) -> Result, CliError> { + fn get_tests_in_package( + &'a self, + package: &'a Package, + ) -> Result, CliError> { let (mut context, crate_id) = prepare_package(self.file_manager, self.parsed_files, package); 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) - .into_iter() - .map(|(test_name, _)| test_name) - .collect()) + Ok(context.get_all_test_functions_in_crate_matching(&crate_id, &self.pattern)) } /// Runs a single test and returns its status together with whatever was printed to stdout @@ -510,10 +518,15 @@ impl<'a> TestRunner<'a> { &'a self, package: &Package, fn_name: &str, + has_arguments: bool, foreign_call_resolver_url: Option<&str>, root_path: Option, package_name: String, ) -> (TestStatus, String) { + if (self.args.no_fuzz && has_arguments) || (self.args.only_fuzz && !has_arguments) { + return (TestStatus::Skipped, String::new()); + } + // This is really hacky but we can't share `Context` or `S` across threads. // We then need to construct a separate copy for each test.