diff --git a/Cargo.lock b/Cargo.lock index 96c0a2bafa1..b5c7352e3de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.1", ] [[package]] @@ -323,14 +323,14 @@ dependencies = [ "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.30.2", + "object 0.30.3", "rustc-demangle", ] [[package]] name = "barretenberg_static_lib" version = "0.1.0" -source = "git+https://github.com/noir-lang/aztec_backend?rev=c673a14be33e445d98b35969716ac59c682036d6#c673a14be33e445d98b35969716ac59c682036d6" +source = "git+https://github.com/noir-lang/aztec_backend?rev=b7349851d7afcffef4171e4d3a30b163ea37e579#b7349851d7afcffef4171e4d3a30b163ea37e579" dependencies = [ "barretenberg_wrapper", "blake2", @@ -350,7 +350,7 @@ dependencies = [ [[package]] name = "barretenberg_wasm" version = "0.1.0" -source = "git+https://github.com/noir-lang/aztec_backend?rev=c673a14be33e445d98b35969716ac59c682036d6#c673a14be33e445d98b35969716ac59c682036d6" +source = "git+https://github.com/noir-lang/aztec_backend?rev=b7349851d7afcffef4171e4d3a30b163ea37e579#b7349851d7afcffef4171e4d3a30b163ea37e579" dependencies = [ "blake2", "common", @@ -472,15 +472,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cexpr" @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "common" version = "0.1.0" -source = "git+https://github.com/noir-lang/aztec_backend?rev=c673a14be33e445d98b35969716ac59c682036d6#c673a14be33e445d98b35969716ac59c682036d6" +source = "git+https://github.com/noir-lang/aztec_backend?rev=b7349851d7afcffef4171e4d3a30b163ea37e579#b7349851d7afcffef4171e4d3a30b163ea37e579" dependencies = [ "acvm", "blake2", @@ -940,9 +940,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -970,9 +970,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if 1.0.0", ] @@ -1131,9 +1131,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -1146,9 +1146,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -1156,15 +1156,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -1173,15 +1173,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -1190,21 +1190,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -1272,9 +1272,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "git-version" @@ -1441,9 +1441,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" dependencies = [ "bytes", "futures-channel", @@ -1542,9 +1542,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -1932,9 +1932,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.2" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -2047,9 +2047,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4257b4a04d91f7e9e6290be5d3da4804dd5784fafde3a497d73eb2b4a158c30a" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ "thiserror", "ucd-trie", @@ -2247,9 +2247,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -2499,9 +2499,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.8.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -2826,9 +2826,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.24.2" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" +checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" dependencies = [ "autocfg", "bytes", @@ -2933,9 +2933,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "unicode-bidi" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046be40136ef78dc325e0edefccf84ccddacd0afcc1ca54103fa3c61bbdab1d" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -3011,9 +3011,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if 1.0.0", "serde", @@ -3023,9 +3023,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -3038,9 +3038,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -3050,9 +3050,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3060,9 +3060,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -3073,15 +3073,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-bindgen-test" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d" +checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3093,9 +3093,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7" +checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9" dependencies = [ "proc-macro2", "quote", @@ -3103,9 +3103,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ab2fe77b325731603297debb4573e002d06ae0aa1f4dc108585c81961e0609" +checksum = "ef126be0e14bdf355ac1a8b41afc89195289e5c7179f80118e3abddb472f0810" dependencies = [ "leb128", ] @@ -3349,9 +3349,9 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "wast" -version = "51.0.0" +version = "52.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f621e6e9af96438d3e05f0699da5b1dae59f2df964a2982166aa9b03c5b599" +checksum = "707a9fd59b0144c530f0a31f21737036ffea6ece492918cae0843dd09b6f9bc9" dependencies = [ "leb128", "memchr", @@ -3361,18 +3361,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd18c1168d7e8743d9b4f713c0203924f5dcc4a3983eb5e584de9614f9fccde" +checksum = "91d73cbaa81acc2f8a3303e2289205c971d99c89245c2f56ab8765c4daabc2be" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/crates/nargo/Cargo.toml b/crates/nargo/Cargo.toml index 6691f604f73..c26c2a4491c 100644 --- a/crates/nargo/Cargo.toml +++ b/crates/nargo/Cargo.toml @@ -31,8 +31,8 @@ termcolor = "1.1.2" tempdir = "0.3.7" # Backends -aztec_backend = { optional = true, package = "barretenberg_static_lib", git = "https://github.com/noir-lang/aztec_backend", rev = "c673a14be33e445d98b35969716ac59c682036d6" } -aztec_wasm_backend = { optional = true, package = "barretenberg_wasm", git = "https://github.com/noir-lang/aztec_backend", rev = "c673a14be33e445d98b35969716ac59c682036d6" } +aztec_backend = { optional = true, package = "barretenberg_static_lib", git = "https://github.com/noir-lang/aztec_backend", rev = "b7349851d7afcffef4171e4d3a30b163ea37e579" } +aztec_wasm_backend = { optional = true, package = "barretenberg_wasm", git = "https://github.com/noir-lang/aztec_backend", rev = "b7349851d7afcffef4171e4d3a30b163ea37e579" } marlin_arkworks_backend = { optional = true, git = "https://github.com/noir-lang/marlin_arkworks_backend", rev = "144378edad821bfaa52bf2cacca8ecc87514a4fc" } [features] diff --git a/crates/nargo/src/cli/check_cmd.rs b/crates/nargo/src/cli/check_cmd.rs index 9fda8a01550..27324926511 100644 --- a/crates/nargo/src/cli/check_cmd.rs +++ b/crates/nargo/src/cli/check_cmd.rs @@ -26,7 +26,11 @@ pub fn check_from_path>(p: P, allow_warnings: bool) -> Result<(), let mut driver = Resolver::resolve_root_config(p.as_ref(), backend.np_language())?; add_std_lib(&mut driver); - driver.check(allow_warnings); + + if driver.check_crate(allow_warnings).is_err() { + std::process::exit(1); + } + // XXX: We can have a --overwrite flag to determine if you want to overwrite the Prover/Verifier.toml files if let Some(abi) = driver.compute_abi() { // XXX: The root config should return an enum to determine if we are looking for .json or .toml diff --git a/crates/nargo/src/cli/compile_cmd.rs b/crates/nargo/src/cli/compile_cmd.rs index 5e130a59822..f9edbf63084 100644 --- a/crates/nargo/src/cli/compile_cmd.rs +++ b/crates/nargo/src/cli/compile_cmd.rs @@ -25,17 +25,14 @@ pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { let mut circuit_path = PathBuf::new(); circuit_path.push(TARGET_DIR); - let result = generate_circuit_and_witness_to_disk( + generate_circuit_and_witness_to_disk( circuit_name, current_dir, circuit_path, witness, allow_warnings, - ); - match result { - Ok(_) => Ok(()), - Err(e) => Err(e), - } + ) + .map(|_| ()) } #[allow(deprecated)] @@ -78,8 +75,8 @@ pub fn compile_circuit>( let backend = crate::backends::ConcreteBackend; let mut driver = Resolver::resolve_root_config(program_dir.as_ref(), backend.np_language())?; add_std_lib(&mut driver); - let compiled_program = - driver.into_compiled_program(backend.np_language(), show_ssa, allow_warnings); - Ok(compiled_program) + driver + .into_compiled_program(backend.np_language(), show_ssa, allow_warnings) + .map_err(|_| std::process::exit(1)) } diff --git a/crates/nargo/src/cli/mod.rs b/crates/nargo/src/cli/mod.rs index 02bc8fc7d0e..e0707a0184d 100644 --- a/crates/nargo/src/cli/mod.rs +++ b/crates/nargo/src/cli/mod.rs @@ -26,6 +26,7 @@ mod contract_cmd; mod gates_cmd; mod new_cmd; mod prove_cmd; +mod test_cmd; mod verify_cmd; const SHORT_GIT_HASH: &str = git_version!(prefix = "git:"); @@ -74,6 +75,15 @@ pub fn start_cli() { .arg(show_ssa.clone()) .arg(allow_warnings.clone()), ) + .subcommand( + App::new("test") + .about("Run the tests for this program") + .arg( + Arg::with_name("test_name") + .help("If given, only tests with names containing this string will be run"), + ) + .arg(allow_warnings.clone()), + ) .subcommand( App::new("compile") .about("Compile the program and its secret execution trace into ACIR format") @@ -104,6 +114,7 @@ pub fn start_cli() { Some("compile") => compile_cmd::run(matches), Some("verify") => verify_cmd::run(matches), Some("gates") => gates_cmd::run(matches), + Some("test") => test_cmd::run(matches), Some(x) => Err(CliError::Generic(format!("unknown command : {x}"))), _ => unreachable!(), }; diff --git a/crates/nargo/src/cli/test_cmd.rs b/crates/nargo/src/cli/test_cmd.rs new file mode 100644 index 00000000000..0a46f35e585 --- /dev/null +++ b/crates/nargo/src/cli/test_cmd.rs @@ -0,0 +1,94 @@ +use std::{collections::BTreeMap, io::Write}; + +use acvm::{PartialWitnessGenerator, ProofSystemCompiler}; +use clap::ArgMatches; +use noirc_driver::Driver; +use noirc_frontend::node_interner::FuncId; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +use crate::{errors::CliError, resolver::Resolver}; + +use super::add_std_lib; + +pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { + let args = args.subcommand_matches("test").unwrap(); + let test_name = args.value_of("test_name").unwrap_or(""); + let allow_warnings = args.is_present("allow-warnings"); + run_tests(test_name, allow_warnings) +} + +fn run_tests(test_name: &str, allow_warnings: bool) -> Result<(), CliError> { + let backend = crate::backends::ConcreteBackend; + + let package_dir = std::env::current_dir().unwrap(); + let mut driver = Resolver::resolve_root_config(&package_dir, backend.np_language())?; + add_std_lib(&mut driver); + + if driver.check_crate(allow_warnings).is_err() { + std::process::exit(1); + } + + let test_functions = driver.get_all_test_functions_in_crate_matching(test_name); + println!("Running {} test functions...", test_functions.len()); + let mut failing = 0; + + let writer = StandardStream::stderr(ColorChoice::Always); + let mut writer = writer.lock(); + + for test_function in test_functions { + let test_name = driver.function_name(test_function); + write!(writer, "Testing {test_name}... ").expect("Failed to write to stdout"); + writer.flush().ok(); + + match run_test(test_name, test_function, &driver, allow_warnings) { + Ok(_) => { + writer.set_color(ColorSpec::new().set_fg(Some(Color::Green))).ok(); + writeln!(writer, "ok").ok(); + } + // Assume an error was already printed to stdout + Err(_) => failing += 1, + } + writer.reset().ok(); + } + + if failing == 0 { + writer.set_color(ColorSpec::new().set_fg(Some(Color::Green))).unwrap(); + writeln!(writer, "All tests passed").ok(); + } else { + let plural = if failing == 1 { "" } else { "s" }; + writer.set_color(ColorSpec::new().set_fg(Some(Color::Red))).unwrap(); + writeln!(writer, "{failing} test{plural} failed").ok(); + std::process::exit(1); + } + + writer.reset().ok(); + Ok(()) +} + +fn run_test( + test_name: &str, + main: FuncId, + driver: &Driver, + allow_warnings: bool, +) -> Result<(), CliError> { + let backend = crate::backends::ConcreteBackend; + let language = backend.np_language(); + + let program = driver + .compile_no_check(language, false, allow_warnings, Some(main)) + .map_err(|_| CliError::Generic(format!("Test '{test_name}' failed to compile")))?; + + let mut solved_witness = BTreeMap::new(); + + // Run the backend to ensure the PWG evaluates functions like std::hash::pedersen, + // otherwise constraints involving these expressions will not error. + if let Err(error) = backend.solve(&mut solved_witness, program.circuit.opcodes) { + let writer = StandardStream::stderr(ColorChoice::Always); + let mut writer = writer.lock(); + writer.set_color(ColorSpec::new().set_fg(Some(Color::Red))).ok(); + writeln!(writer, "failed").ok(); + writer.reset().ok(); + return Err(error.into()); + } + Ok(()) +} diff --git a/crates/noirc_driver/src/lib.rs b/crates/noirc_driver/src/lib.rs index 1a822e9bcb7..19814f27c28 100644 --- a/crates/noirc_driver/src/lib.rs +++ b/crates/noirc_driver/src/lib.rs @@ -3,12 +3,13 @@ use acvm::acir::circuit::Circuit; use acvm::Language; use fm::FileType; use noirc_abi::Abi; -use noirc_errors::{DiagnosableError, Reporter}; +use noirc_errors::{DiagnosableError, ReportedError, Reporter}; use noirc_evaluator::create_circuit; use noirc_frontend::graph::{CrateId, CrateName, CrateType, LOCAL_CRATE}; use noirc_frontend::hir::def_map::CrateDefMap; use noirc_frontend::hir::Context; use noirc_frontend::monomorphization::monomorphize; +use noirc_frontend::node_interner::FuncId; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; @@ -34,7 +35,10 @@ impl Driver { pub fn compile_file(root_file: PathBuf, np_language: acvm::Language) -> CompiledProgram { let mut driver = Driver::new(&np_language); driver.create_local_crate(root_file, CrateType::Binary); - driver.into_compiled_program(np_language, false, false) + + driver + .into_compiled_program(np_language, false, false) + .unwrap_or_else(|_| std::process::exit(1)) } /// Compiles a file and returns true if compilation was successful @@ -126,13 +130,9 @@ impl Driver { } } - // NOTE: Maybe build could be skipped given that now it is a pass through method. - /// Statically analyzes the local crate - pub fn check(&mut self, allow_warnings: bool) { - self.analyze_crate(allow_warnings) - } - - fn analyze_crate(&mut self, allow_warnings: bool) { + /// Run the lexing, parsing, name resolution, and type checking passes, + /// returning Err(FrontendError) and printing any errors that were found. + pub fn check_crate(&mut self, allow_warnings: bool) -> Result<(), ReportedError> { let mut errs = vec![]; CrateDefMap::collect_defs(LOCAL_CRATE, &mut self.context, &mut errs); let mut error_count = 0; @@ -145,7 +145,7 @@ impl Driver { ); } - Reporter::finish(error_count); + Reporter::finish(error_count) } pub fn compute_abi(&self) -> Option { @@ -159,15 +159,26 @@ impl Driver { Some(abi) } - #[allow(deprecated)] pub fn into_compiled_program( mut self, np_language: acvm::Language, show_ssa: bool, allow_warnings: bool, - ) -> CompiledProgram { - self.check(allow_warnings); + ) -> Result { + self.check_crate(allow_warnings)?; + self.compile_no_check(np_language, show_ssa, allow_warnings, None) + } + /// Compile the current crate. Assumes self.check_crate is called beforehand! + #[allow(deprecated)] + pub fn compile_no_check( + &self, + np_language: acvm::Language, + show_ssa: bool, + allow_warnings: bool, + // Optional override to provide a different `main` function to start execution + main_function: Option, + ) -> Result { // Check the crate type // We don't panic here to allow users to `evaluate` libraries // which will do nothing @@ -180,39 +191,46 @@ impl Driver { let local_crate = self.context.def_map(LOCAL_CRATE).unwrap(); // All Binaries should have a main function - let main_function = - local_crate.main_function().expect("cannot compile a program with no main function"); + let main_function = main_function.unwrap_or_else(|| { + local_crate.main_function().expect("cannot compile a program with no main function") + }); // Create ABI for main function let func_meta = self.context.def_interner.function_meta(&main_function); let abi = func_meta.into_abi(&self.context.def_interner); - let program = monomorphize(main_function, self.context.def_interner); + let program = monomorphize(main_function, &self.context.def_interner); - // Compile Program - let circuit = match create_circuit( - program, - np_language.clone(), - acvm::default_is_blackbox_supported(np_language), - show_ssa, - ) { - Ok(circuit) => circuit, + let blackbox_supported = acvm::default_is_blackbox_supported(np_language.clone()); + match create_circuit(program, np_language, blackbox_supported, show_ssa) { + Ok(circuit) => Ok(CompiledProgram { circuit, abi: Some(abi) }), Err(err) => { // The FileId here will be the file id of the file with the main file // Errors will be shown at the call site without a stacktrace let file_id = err.location.map(|loc| loc.file); - let error_count = Reporter::with_diagnostics( - file_id, - &self.context.file_manager, - &[err.to_diagnostic()], - allow_warnings, - ); - Reporter::finish(error_count); - unreachable!("reporter will exit before this point") + let error = &[err.to_diagnostic()]; + let files = &self.context.file_manager; + + let error_count = Reporter::with_diagnostics(file_id, files, error, allow_warnings); + Reporter::finish(error_count)?; + Err(ReportedError) } - }; + } + } + + /// Returns a list of all functions in the current crate marked with #[test] + /// whose names contain the given pattern string. An empty pattern string + /// will return all functions marked with #[test]. + pub fn get_all_test_functions_in_crate_matching(&self, pattern: &str) -> Vec { + let interner = &self.context.def_interner; + interner + .get_all_test_functions() + .filter_map(|id| interner.function_name(&id).contains(pattern).then_some(id)) + .collect() + } - CompiledProgram { circuit, abi: Some(abi) } + pub fn function_name(&self, id: FuncId) -> &str { + self.context.def_interner.function_name(&id) } } diff --git a/crates/noirc_driver/src/main.rs b/crates/noirc_driver/src/main.rs index 5663d745898..1ae9afe497a 100644 --- a/crates/noirc_driver/src/main.rs +++ b/crates/noirc_driver/src/main.rs @@ -18,5 +18,5 @@ fn main() { driver.add_dep(LOCAL_CRATE, crate_id1, "coo4"); driver.add_dep(LOCAL_CRATE, crate_id2, "coo3"); - driver.into_compiled_program(acvm::Language::R1CS, false, false); + driver.into_compiled_program(acvm::Language::R1CS, false, false).ok(); } diff --git a/crates/noirc_errors/src/lib.rs b/crates/noirc_errors/src/lib.rs index 9d9d51b57b6..a4d412dd82b 100644 --- a/crates/noirc_errors/src/lib.rs +++ b/crates/noirc_errors/src/lib.rs @@ -8,6 +8,10 @@ pub trait DiagnosableError { fn to_diagnostic(&self) -> CustomDiagnostic; } +/// Returned when the Reporter finishes after reporting errors +#[derive(Copy, Clone)] +pub struct ReportedError; + #[derive(Debug, PartialEq, Eq)] pub struct CollectedErrors { pub file_id: fm::FileId, diff --git a/crates/noirc_errors/src/reporter.rs b/crates/noirc_errors/src/reporter.rs index e626af589cd..60a5e07fcaf 100644 --- a/crates/noirc_errors/src/reporter.rs +++ b/crates/noirc_errors/src/reporter.rs @@ -1,4 +1,4 @@ -use crate::Span; +use crate::{ReportedError, Span}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ @@ -147,16 +147,18 @@ impl Reporter { error_count } - pub fn finish(error_count: usize) { + pub fn finish(error_count: usize) -> Result<(), ReportedError> { if error_count != 0 { let writer = StandardStream::stderr(ColorChoice::Always); let mut writer = writer.lock(); writer.set_color(ColorSpec::new().set_fg(Some(Color::Red))).unwrap(); - writeln!(&mut writer, "error: aborting due to {error_count} previous errors").unwrap(); + writer.reset().ok(); // Ignore any IO errors, we're exiting at this point anyway - std::process::exit(1); + Err(ReportedError) + } else { + Ok(()) } } } diff --git a/crates/noirc_evaluator/src/ssa/context.rs b/crates/noirc_evaluator/src/ssa/context.rs index 55be0a578a8..4a7dcf612c7 100644 --- a/crates/noirc_evaluator/src/ssa/context.rs +++ b/crates/noirc_evaluator/src/ssa/context.rs @@ -741,8 +741,8 @@ impl SsaContext { if enable_logging { Acir::print_circuit(&evaluator.opcodes); println!("DONE"); + println!("ACIR opcodes generated : {}", evaluator.opcodes.len()); } - println!("ACIR opcodes generated : {}", evaluator.opcodes.len()); Ok(()) } diff --git a/crates/noirc_frontend/src/ast/function.rs b/crates/noirc_frontend/src/ast/function.rs index 02ef4bf27bb..ad3594a23ae 100644 --- a/crates/noirc_frontend/src/ast/function.rs +++ b/crates/noirc_frontend/src/ast/function.rs @@ -77,6 +77,7 @@ impl From for NoirFunction { Some(Attribute::Builtin(_)) => FunctionKind::Builtin, Some(Attribute::Foreign(_)) => FunctionKind::LowLevel, Some(Attribute::Alternative(_)) => FunctionKind::Normal, + Some(Attribute::Test) => FunctionKind::Normal, None => FunctionKind::Normal, }; diff --git a/crates/noirc_frontend/src/hir/resolution/errors.rs b/crates/noirc_frontend/src/hir/resolution/errors.rs index bc9449de438..01fe6f755a9 100644 --- a/crates/noirc_frontend/src/hir/resolution/errors.rs +++ b/crates/noirc_frontend/src/hir/resolution/errors.rs @@ -42,6 +42,8 @@ pub enum ResolverError { NoSuchNumericTypeVariable { path: crate::Path }, #[error("Closures cannot capture mutable variables")] CapturedMutableVariable { span: Span }, + #[error("Test functions are not allowed to have any parameters")] + TestFunctionHasParameters { span: Span }, } impl ResolverError { @@ -201,6 +203,11 @@ impl ResolverError { "Mutable variable".into(), span, ), + ResolverError::TestFunctionHasParameters { span } => Diagnostic::simple_error( + "Test functions cannot have any parameters".into(), + "Try removing the parameters or moving the test into a wrapper function".into(), + span, + ), } } } diff --git a/crates/noirc_frontend/src/hir/resolution/resolver.rs b/crates/noirc_frontend/src/hir/resolution/resolver.rs index 5b6e592907f..5db43e09edf 100644 --- a/crates/noirc_frontend/src/hir/resolution/resolver.rs +++ b/crates/noirc_frontend/src/hir/resolution/resolver.rs @@ -23,6 +23,7 @@ use crate::hir_def::expr::{ HirIndexExpression, HirInfixExpression, HirLambda, HirLiteral, HirMemberAccess, HirMethodCallExpression, HirPrefixExpression, }; +use crate::token::Attribute; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::rc::Rc; @@ -530,6 +531,12 @@ impl<'a> Resolver<'a> { self.push_err(ResolverError::NecessaryPub { ident: func.name_ident().clone() }) } + if attributes == Some(Attribute::Test) && !parameters.is_empty() { + self.push_err(ResolverError::TestFunctionHasParameters { + span: func.name_ident().span(), + }) + } + let mut typ = Type::Function(parameter_types, return_type); if !generics.is_empty() { diff --git a/crates/noirc_frontend/src/lexer/token.rs b/crates/noirc_frontend/src/lexer/token.rs index 9f0a1fa65c0..75df6e526e3 100644 --- a/crates/noirc_frontend/src/lexer/token.rs +++ b/crates/noirc_frontend/src/lexer/token.rs @@ -319,6 +319,7 @@ pub enum Attribute { Foreign(String), Builtin(String), Alternative(String), + Test, } impl fmt::Display for Attribute { @@ -327,6 +328,7 @@ impl fmt::Display for Attribute { Attribute::Foreign(ref k) => write!(f, "#[foreign({k})]"), Attribute::Builtin(ref k) => write!(f, "#[builtin({k})]"), Attribute::Alternative(ref k) => write!(f, "#[alternative({k})]"), + Attribute::Test => write!(f, "#[test]"), } } } @@ -341,7 +343,14 @@ impl Attribute { .collect(); if word_segments.len() != 2 { - return Err(LexerErrorKind::MalformedFuncAttribute { span, found: word.to_owned() }); + if word_segments.len() == 1 && word_segments[0] == "test" { + return Ok(Token::Attribute(Attribute::Test)); + } else { + return Err(LexerErrorKind::MalformedFuncAttribute { + span, + found: word.to_owned(), + }); + } } let attribute_type = word_segments[0]; @@ -360,21 +369,22 @@ impl Attribute { pub fn builtin(self) -> Option { match self { - Attribute::Foreign(_) | Attribute::Alternative(_) => None, Attribute::Builtin(name) => Some(name), + _ => None, } } pub fn foreign(self) -> Option { match self { Attribute::Foreign(name) => Some(name), - Attribute::Builtin(_) | Attribute::Alternative(_) => None, + _ => None, } } pub fn is_foreign(&self) -> bool { matches!(self, Attribute::Foreign(_)) } + pub fn is_low_level(&self) -> bool { matches!(self, Attribute::Foreign(_) | Attribute::Builtin(_)) } @@ -386,6 +396,7 @@ impl AsRef for Attribute { Attribute::Foreign(string) => string, Attribute::Builtin(string) => string, Attribute::Alternative(string) => string, + Attribute::Test => "", } } } diff --git a/crates/noirc_frontend/src/monomorphization/mod.rs b/crates/noirc_frontend/src/monomorphization/mod.rs index 1aefd2246ad..43ab1a31dbb 100644 --- a/crates/noirc_frontend/src/monomorphization/mod.rs +++ b/crates/noirc_frontend/src/monomorphization/mod.rs @@ -18,7 +18,7 @@ use self::ast::{Definition, FuncId, Function, LocalId, Program}; pub mod ast; pub mod printer; -struct Monomorphizer { +struct Monomorphizer<'interner> { // Store monomorphized globals and locals separately, // only locals are cleared on each function call and only globals are monomorphized. // Nested HashMaps in globals lets us avoid cloning HirTypes when calling .get() @@ -30,7 +30,7 @@ struct Monomorphizer { finished_functions: BTreeMap, - interner: NodeInterner, + interner: &'interner NodeInterner, next_local_id: u32, next_function_id: u32, @@ -38,7 +38,7 @@ struct Monomorphizer { type HirType = crate::Type; -pub fn monomorphize(main: node_interner::FuncId, interner: NodeInterner) -> Program { +pub fn monomorphize(main: node_interner::FuncId, interner: &NodeInterner) -> Program { let mut monomorphizer = Monomorphizer::new(interner); let abi = monomorphizer.compile_main(main); @@ -55,8 +55,8 @@ pub fn monomorphize(main: node_interner::FuncId, interner: NodeInterner) -> Prog Program::new(functions, abi) } -impl Monomorphizer { - fn new(interner: NodeInterner) -> Monomorphizer { +impl<'interner> Monomorphizer<'interner> { + fn new(interner: &'interner NodeInterner) -> Self { Monomorphizer { globals: HashMap::new(), locals: HashMap::new(), @@ -135,7 +135,7 @@ impl Monomorphizer { self.function(main_id, new_main_id); let main_meta = self.interner.function_meta(&main_id); - main_meta.into_abi(&self.interner) + main_meta.into_abi(self.interner) } fn function(&mut self, f: node_interner::FuncId, id: FuncId) { diff --git a/crates/noirc_frontend/src/node_interner.rs b/crates/noirc_frontend/src/node_interner.rs index 9cdc03253ad..6b05ebed6ec 100644 --- a/crates/noirc_frontend/src/node_interner.rs +++ b/crates/noirc_frontend/src/node_interner.rs @@ -18,6 +18,7 @@ use crate::hir_def::{ function::{FuncMeta, HirFunction}, stmt::HirStatement, }; +use crate::token::Attribute; use crate::{Shared, TypeBinding, TypeBindings, TypeVariableId}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] @@ -568,4 +569,11 @@ impl NodeInterner { pub fn take_delayed_type_check_functions(&mut self) -> Vec { std::mem::take(&mut self.delayed_type_checks) } + + pub fn get_all_test_functions(&self) -> impl Iterator + '_ { + self.func_meta.iter().filter_map(|(id, meta)| { + let is_test = meta.attributes.as_ref()? == &Attribute::Test; + is_test.then_some(*id) + }) + } }