cargo-fuzztest: Add integration tests and test fixture crate. Add end-to-end integration test runner and dummy target crate for cargo-fuzztest. PiperOrigin-RevId: 964278964
diff --git a/Cargo.lock b/Cargo.lock index 01dc9bf..dbdb659 100644 --- a/Cargo.lock +++ b/Cargo.lock
@@ -100,6 +100,7 @@ dependencies = [ "anyhow", "clap", + "fuzztest", "fuzztest-options", "googletest", "serde",
diff --git a/rust/cargo_fuzztest/BUILD b/rust/cargo_fuzztest/BUILD index b7c52f1..a19e676 100644 --- a/rust/cargo_fuzztest/BUILD +++ b/rust/cargo_fuzztest/BUILD
@@ -57,3 +57,31 @@ ":cargo_fuzztest_bin", ], ) + +rust_test( + name = "dummy_fuzz_test_bin", + srcs = ["test_crates/dummy_fuzz_crate/src/lib.rs"], + edition = "2024", + tags = [ + "manual", + "notap", + ], + deps = [ + "@com_google_fuzztest//rust:fuzztest", + "@crate_index//:googletest", + ], +) + +rust_test( + name = "runner_test", + srcs = ["tests/runner_test.rs"], + data = [ + ":dummy_fuzz_test_bin", + ], + edition = "2024", + deps = [ + ":cargo_fuzztest", + "@crate_index//:anyhow", # v1 + "@crate_index//:googletest", + ], +)
diff --git a/rust/cargo_fuzztest/Cargo.toml b/rust/cargo_fuzztest/Cargo.toml index 9111901..e5727d9 100644 --- a/rust/cargo_fuzztest/Cargo.toml +++ b/rust/cargo_fuzztest/Cargo.toml
@@ -26,3 +26,14 @@ [dev-dependencies] googletest.workspace = true +fuzztest = { path = ".." } + +# Compiled as a [[test]] target so Cargo builds it with the test harness enabled +# (`rustc --test`) and exposes `CARGO_BIN_EXE_dummy_fuzz_test_bin` to `runner_test`. +[[test]] +name = "dummy_fuzz_test_bin" +path = "test_crates/dummy_fuzz_crate/src/lib.rs" + +[[test]] +name = "runner_test" +path = "tests/runner_test.rs"
diff --git a/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml new file mode 100644 index 0000000..7ac26a8 --- /dev/null +++ b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/Cargo.toml
@@ -0,0 +1,7 @@ +[package] +name = "dummy_fuzz_crate" +version = "0.1.0" +edition = "2024" + +[dependencies] +fuzztest = { path = "../../.." }
diff --git a/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs new file mode 100644 index 0000000..0ad6df5 --- /dev/null +++ b/rust/cargo_fuzztest/test_crates/dummy_fuzz_crate/src/lib.rs
@@ -0,0 +1,7 @@ +use fuzztest::domains::arbitrary::Arbitrary; +use fuzztest::fuzztest; + +#[fuzztest(data = Arbitrary::<i32>::default())] +fn dummy_fuzztest_target(data: i32) { + let _ = data; +}
diff --git a/rust/cargo_fuzztest/tests/runner_test.rs b/rust/cargo_fuzztest/tests/runner_test.rs new file mode 100644 index 0000000..c34d630 --- /dev/null +++ b/rust/cargo_fuzztest/tests/runner_test.rs
@@ -0,0 +1,77 @@ +use cargo_fuzztest::{CargoFuzzTestOptions, FuzztestRunner}; +use googletest::prelude::*; +use std::env; +use std::path::PathBuf; + +#[gtest] +fn test_runner_execution() { + let binary_path = get_dummy_fuzz_test_bin_path(); + + assert!(binary_path.exists(), "Dummy fuzz binary does not exist at {}", binary_path.display()); + + let options = CargoFuzzTestOptions::default(); + + let runner = FuzztestRunner::new("sample-host-triple".to_string(), options); + + let mut cmd = runner.build_run_command(&binary_path); + + let status = cmd.status().expect("Failed to execute test binary command"); + + expect_true!(status.success()); +} + +#[gtest] +fn test_runner_list_command() { + let binary_path = get_dummy_fuzz_test_bin_path(); + + assert!(binary_path.exists(), "Dummy fuzz binary does not exist at {}", binary_path.display()); + + let options = CargoFuzzTestOptions { list: true }; + + let runner = FuzztestRunner::new("sample-host-triple".to_string(), options); + + let cmd = runner.build_run_command(&binary_path); + + let args: Vec<String> = cmd.get_args().map(|a| a.to_string_lossy().to_string()).collect(); + expect_eq!(args, &["__fuzztest_mod__", "--list"]); +} + +fn get_dummy_fuzz_test_bin_path() -> PathBuf { + // 1. Cargo test: Check if CARGO_BIN_EXE_<name> is set + if let Ok(cargo_bin) = env::var("CARGO_BIN_EXE_dummy_fuzz_test_bin") { + return PathBuf::from(cargo_bin); + } + + // 2. Bazel/Blaze test: Fall back to TEST_SRCDIR and TEST_WORKSPACE + if let Ok(src_dir) = env::var("TEST_SRCDIR") { + let test_workspace = env::var("TEST_WORKSPACE").unwrap_or_else(|_| { + "_main".to_string() + }); + + const RELATIVE_BINARY_PATH: &str = + "rust/cargo_fuzztest/dummy_fuzz_test_bin"; + + let blaze_path = PathBuf::from(src_dir).join(test_workspace).join(RELATIVE_BINARY_PATH); + if blaze_path.exists() { + return blaze_path; + } + } + + // 2. Cargo test fallback: Query compiled test executable path via Cargo JSON compiler messages + if env::var("CARGO_MANIFEST_DIR").is_ok() { + let cargo_bin = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); + let output = std::process::Command::new(cargo_bin) + .args(["test", "--no-run", "--message-format=json", "--test", "dummy_fuzz_test_bin"]) + .output() + .expect("Failed to execute `cargo test --no-run --message-format=json` to locate test binary"); + + if output.status.success() { + let json_stdout = String::from_utf8_lossy(&output.stdout); + if let Ok(exe) = FuzztestRunner::parse_compiler_messages(&json_stdout) { + return exe; + } + } + } + + panic!("Could not locate dummy_fuzz_test_bin via CARGO_BIN_EXE, TEST_SRCDIR, or Cargo compiler messages"); +}