Skip to content

Commit

Permalink
feat: allow usage of noir #[test] syntax in stdlib (#4553)
Browse files Browse the repository at this point in the history
# Description

## Problem\*

Resolves <!-- Link to GitHub Issue -->

## Summary\*

Running tests within the Noir stdlib is a little complicated as nargo
will not accept it as a regular crate as the stdlib uses features which
are disallowed in other crates. This means that in a number of cases
we're placing stdlib unit tests inside of the `test_programs` instead of
just using the `#[test]` format inside of the stdlib itself.

This is suboptimal as it separates the implementation from the tests in
the repository and once #4491 is
merged, it will be impossible to use this method to test any private
functions within the stdlib.

This PR then adds a new integration test which is equivalent to running
`nargo test` on the stdlib and moves some tests over to the stdlib as an
example.

## Additional Context



## Documentation\*

Check one:
- [ ] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[Exceptional Case]** Documentation to be submitted in a separate
PR.

# PR Checklist\*

- [ ] I have tested the changes locally.
- [ ] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
TomAFrench authored Mar 15, 2024
1 parent 4cf700b commit a8b7cdb
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 93 deletions.
78 changes: 78 additions & 0 deletions noir_stdlib/src/field/bn254.nr
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,81 @@ pub fn gt(a: Field, b: Field) -> bool {
pub fn lt(a: Field, b: Field) -> bool {
gt(b, a)
}

mod tests {
// TODO: Allow imports from "super"
use crate::field::bn254::{decompose_unsafe, decompose, lt_unsafe, assert_gt, gt, lt, TWO_POW_128, lte_unsafe, PLO, PHI};

#[test]
fn check_decompose_unsafe() {
assert_eq(decompose_unsafe(TWO_POW_128), (0, 1));
assert_eq(decompose_unsafe(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));
assert_eq(decompose_unsafe(0x1234567890), (0x1234567890, 0));
}

#[test]
fn check_decompose() {
assert_eq(decompose(TWO_POW_128), (0, 1));
assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1));
assert_eq(decompose(0x1234567890), (0x1234567890, 0));
}

#[test]
fn check_lt_unsafe() {
assert(lt_unsafe(0, 1, 16));
assert(lt_unsafe(0, 0x100, 16));
assert(lt_unsafe(0x100, TWO_POW_128 - 1, 16));
assert(!lt_unsafe(0, TWO_POW_128, 16));
}

#[test]
fn check_lte_unsafe() {
assert(lte_unsafe(0, 1, 16));
assert(lte_unsafe(0, 0x100, 16));
assert(lte_unsafe(0x100, TWO_POW_128 - 1, 16));
assert(!lte_unsafe(0, TWO_POW_128, 16));

assert(lte_unsafe(0, 0, 16));
assert(lte_unsafe(0x100, 0x100, 16));
assert(lte_unsafe(TWO_POW_128 - 1, TWO_POW_128 - 1, 16));
assert(lte_unsafe(TWO_POW_128, TWO_POW_128, 16));
}

#[test]
fn check_assert_gt() {
assert_gt(1, 0);
assert_gt(0x100, 0);
assert_gt((0 - 1), (0 - 2));
assert_gt(TWO_POW_128, 0);
assert_gt(0 - 1, 0);
}

#[test]
fn check_gt() {
assert(gt(1, 0));
assert(gt(0x100, 0));
assert(gt((0 - 1), (0 - 2)));
assert(gt(TWO_POW_128, 0));
assert(!gt(0, 0));
assert(!gt(0, 0x100));
assert(gt(0 - 1, 0 - 2));
assert(!gt(0 - 2, 0 - 1));
}

#[test]
fn check_plo_phi() {
assert_eq(PLO + PHI * TWO_POW_128, 0);
let p_bytes = crate::field::modulus_le_bytes();
let mut p_low: Field = 0;
let mut p_high: Field = 0;

let mut offset = 1;
for i in 0..16 {
p_low += (p_bytes[i] as Field) * offset;
p_high += (p_bytes[i + 16] as Field) * offset;
offset *= 256;
}
assert_eq(p_low, PLO);
assert_eq(p_high, PHI);
}
}

This file was deleted.

This file was deleted.

86 changes: 0 additions & 86 deletions test_programs/compile_success_empty/field_comparisons/src/main.nr

This file was deleted.

62 changes: 62 additions & 0 deletions tooling/nargo_cli/tests/stdlib-tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::{collections::BTreeMap, path::PathBuf};

use acvm::blackbox_solver::StubbedBlackBoxSolver;
use noirc_driver::{check_crate, file_manager_with_stdlib, CompileOptions};
use noirc_frontend::hir::FunctionNameMatch;

use nargo::{
ops::{report_errors, run_test, TestStatus},
package::{Package, PackageType},
parse_all, prepare_package,
};

#[test]
fn stdlib_noir_tests() {
let mut file_manager = file_manager_with_stdlib(&PathBuf::from("."));
file_manager.add_file_with_source_canonical_path(&PathBuf::from("main.nr"), "".to_owned());
let parsed_files = parse_all(&file_manager);

// We need a dummy package as we cannot compile the stdlib on its own.
let dummy_package = Package {
version: None,
compiler_required_version: None,
root_dir: PathBuf::from("."),
package_type: PackageType::Binary,
entry_path: PathBuf::from("main.nr"),
name: "dummy".parse().unwrap(),
dependencies: BTreeMap::new(),
};

let (mut context, dummy_crate_id) =
prepare_package(&file_manager, &parsed_files, &dummy_package);

let result = check_crate(&mut context, dummy_crate_id, true, false);
report_errors(result, &context.file_manager, true, false)
.expect("Error encountered while compiling standard library");

// We can now search within the stdlib for any test functions to compile.

let test_functions = context.get_all_test_functions_in_crate_matching(
context.stdlib_crate_id(),
FunctionNameMatch::Anything,
);

let test_report: Vec<(String, TestStatus)> = test_functions
.into_iter()
.map(|(test_name, test_function)| {
let status = run_test(
&StubbedBlackBoxSolver,
&mut context,
&test_function,
false,
None,
&CompileOptions::default(),
);

(test_name, status)
})
.collect();

assert!(!test_report.is_empty(), "Could not find any tests within the stdlib");
assert!(test_report.iter().all(|(_, status)| !status.failed()));
}

0 comments on commit a8b7cdb

Please sign in to comment.