Skip to content
Merged
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
12 changes: 9 additions & 3 deletions compiler/noirc_frontend/src/hir/def_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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
Expand All @@ -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")]`
Expand Down
29 changes: 21 additions & 8 deletions tooling/nargo_cli/src/cli/test_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -470,7 +478,7 @@ impl<'a> TestRunner<'a> {

let tests: Vec<Test> = 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();
Expand All @@ -479,6 +487,7 @@ impl<'a> TestRunner<'a> {
self.run_test::<S>(
package,
&test_name,
test_function.has_arguments(),
foreign_call_resolver_url,
root_path,
package_name_clone.clone(),
Expand All @@ -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<Vec<String>, CliError> {
fn get_tests_in_package(
&'a self,
package: &'a Package,
) -> Result<Vec<(String, TestFunction)>, 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
Expand All @@ -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<PathBuf>,
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.

Expand Down
Loading