Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(debugger): Integration tests #3938

Merged
Merged
38 changes: 38 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions tooling/debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ authors.workspace = true
edition.workspace = true
license.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
rustc_version = "0.4.0"
build-data.workspace = true

[dependencies]
acvm.workspace = true
Expand All @@ -22,5 +24,8 @@ easy-repl = "0.2.1"
owo-colors = "3"
serde_json.workspace = true

[dev_dependencies]
tempfile.workspace = true
[dev-dependencies]
assert_cmd = "2.0.12"
rexpect = "0.5.0"
test-binary = "3.0.1"
tempfile.workspace = true
74 changes: 74 additions & 0 deletions tooling/debugger/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use rustc_version::{version, Version};
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::{env, fs};

fn check_rustc_version() {
assert!(
version().unwrap() >= Version::parse("1.71.1").unwrap(),
"The minimal supported rustc version is 1.71.1."
);
}

const GIT_COMMIT: &&str = &"GIT_COMMIT";

fn main() {
// Rebuild if the tests have changed
println!("cargo:rerun-if-changed=tests");

check_rustc_version();

// Only use build_data if the environment variable isn't set
// The environment variable is always set when working via Nix
if std::env::var(GIT_COMMIT).is_err() {
build_data::set_GIT_COMMIT();
build_data::set_GIT_DIRTY();
build_data::no_debug_rebuilds();
}

let out_dir = env::var("OUT_DIR").unwrap();
let destination = Path::new(&out_dir).join("debug.rs");
let mut test_file = File::create(destination).unwrap();

// Try to find the directory that Cargo sets when it is running; otherwise fallback to assuming the CWD
// is the root of the repository and append the crate path
let root_dir = match std::env::var("CARGO_MANIFEST_DIR") {
Ok(dir) => PathBuf::from(dir).parent().unwrap().parent().unwrap().to_path_buf(),
Err(_) => std::env::current_dir().unwrap(),
};
let test_dir = root_dir.join("test_programs");

generate_debugger_tests(&mut test_file, &test_dir);
}

fn generate_debugger_tests(test_file: &mut File, test_data_dir: &Path) {
let test_sub_dir = "execution_success";
let test_data_dir = test_data_dir.join(test_sub_dir);

let test_case_dirs =
fs::read_dir(test_data_dir).unwrap().flatten().filter(|c| c.path().is_dir());

for test_dir in test_case_dirs {
let test_name =
test_dir.file_name().into_string().expect("Directory can't be converted to string");
if test_name.contains('-') {
panic!(
"Invalid test directory: {test_name}. Cannot include `-`, please convert to `_`"
);
};
let test_dir = &test_dir.path();

write!(
test_file,
r#"
#[test]
fn debug_{test_name}() {{
debugger_execution_success("{test_dir}");
}}
"#,
test_dir = test_dir.display(),
)
.expect("Could not write templated test file.");
}
}
1 change: 1 addition & 0 deletions tooling/debugger/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> {
);
}
}

print_source_code_location(self.debug_artifact, &location);
}
}
Expand Down
55 changes: 55 additions & 0 deletions tooling/debugger/tests/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#[cfg(test)]
mod tests {
// Some of these imports are consumed by the injected tests
use assert_cmd::cargo::cargo_bin;

use rexpect::spawn_bash;

test_binary::build_test_binary_once!(mock_backend, "../backend_interface/test-binaries");

// include tests generated by `build.rs`
include!(concat!(env!("OUT_DIR"), "/debug.rs"));

pub fn debugger_execution_success(test_program_dir: &str) {
let nargo_bin =
cargo_bin("nargo").into_os_string().into_string().expect("Cannot parse nargo path");

let mock_backend_path =
path_to_mock_backend().into_string().expect("Cannot parse mock_backend path");

let mut dbg_session = spawn_bash(Some(10000)).expect("Could not start bash session");

dbg_session
.send_line(&format!("export NARGO_BACKEND_PATH={}", mock_backend_path))
.expect("Could not export NARGO_BACKEND_PATH.");
dbg_session.wait_for_prompt().expect("Could not export NARGO_BACKEND_PATH.");

// Start debugger and test that it loads for the given program.
dbg_session
.execute(
&format!("{} debug --program-dir {}", nargo_bin, test_program_dir),
&format!(".*\\Starting debugger.*"),
)
.expect("Could not start debugger");

// While running the debugger, issue a "continue" cmd,
// which should run to the program to end given
// we haven't set any breakpoints.
// ">" is the debugger's prompt, so finding one
// after running "continue" indicates that the
// debugger has not panicked until the end of the program.
dbg_session
.send_line("c")
.expect("Debugger panicked while attempting to step through program.");
dbg_session
.exp_string(">")
.expect("Failed while waiting for debugger to step through program.");

// Run the "quit" command, then check that the debugger confirms
// having successfully solved the circuit witness.
dbg_session.send_line("quit").expect("Failed to quit debugger");
dbg_session
.exp_regex(&format!(".*Circuit witness successfully solved.*"))
.expect("Expected circuit witness to be successfully solved.");
}
}
Loading