diff --git a/rust/cargo_fuzztest/BUILD b/rust/cargo_fuzztest/BUILD index 8152fc772..2b2fae5f1 100644 --- a/rust/cargo_fuzztest/BUILD +++ b/rust/cargo_fuzztest/BUILD @@ -22,6 +22,7 @@ rust_library( edition = "2024", visibility = ["@com_google_fuzztest//rust:__subpackages__"], deps = [ + "@com_google_fuzztest//rust/options:fuzztest_options", "@crate_index//:anyhow", # v1 "@crate_index//:clap", # v4 "@crate_index//:serde", # v1 @@ -36,6 +37,7 @@ rust_binary( visibility = ["@com_google_fuzztest//rust:__subpackages__"], deps = [ ":cargo_fuzztest", + "@com_google_fuzztest//rust/options:fuzztest_options", "@crate_index//:anyhow", # v1 "@crate_index//:clap", # v4 ], @@ -43,6 +45,7 @@ rust_binary( rust_test( name = "cargo_fuzztest_lib_test", + args = ["--test-threads=1"], crate = ":cargo_fuzztest", edition = "2024", deps = [ @@ -81,6 +84,7 @@ rust_test( edition = "2024", deps = [ ":cargo_fuzztest", + "@com_google_fuzztest//rust/options:fuzztest_options", "@crate_index//:anyhow", # v1 "@crate_index//:googletest", ], diff --git a/rust/cargo_fuzztest/src/lib.rs b/rust/cargo_fuzztest/src/lib.rs index 510cdc019..5e6254d16 100644 --- a/rust/cargo_fuzztest/src/lib.rs +++ b/rust/cargo_fuzztest/src/lib.rs @@ -17,6 +17,7 @@ use anyhow::{Context, Result}; use clap::Parser; +pub use fuzztest_options::{ExecutionMode, FuzzTestOptions}; use std::env; use std::ffi::OsString; use std::path::{Path, PathBuf}; @@ -28,31 +29,27 @@ fn get_cargo_bin() -> String { #[derive(Parser, Debug, Clone, Default)] pub struct CargoFuzzTestOptions { + #[command(flatten)] + pub fuzztest_options: FuzzTestOptions, + /// List all fuzz tests in the crate without running them. #[arg(long)] pub list: bool, } impl CargoFuzzTestOptions { - /// Returns the active domain `ExecutionMode` derived from CLI options. + /// Returns the `ExecutionMode` derived from CLI options. pub fn execution_mode(&self) -> ExecutionMode { if self.list { return ExecutionMode::ListFuzzTests; } + + // TODO(the-shank): add support for other modes. ExecutionMode::SmokeTest } } -/// Domain execution mode for `cargo-fuzztest`. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ExecutionMode { - /// List all discovered fuzz tests without running them. - ListFuzzTests, - - SmokeTest, -} - -/// Queries cargo via `cargo -vV` to discover the default host target triple (e.g. `x86_64-unknown-linux-gnu`). +/// Queries Cargo via `cargo -vV` to discover the default host target triple (e.g. `x86_64-unknown-linux-gnu`). pub fn get_host_target_triple() -> anyhow::Result { let cargo_bin = get_cargo_bin(); let output = Command::new(&cargo_bin) @@ -141,8 +138,11 @@ impl FuzztestRunner { continue; } if let Ok(val) = serde_json::from_str::(trimmed) { - let is_compiler_artifact = val["reason"] == "compiler-artifact"; - let is_test_profile = val["profile"]["test"].as_bool().unwrap_or(false); + let is_compiler_artifact = + val.get("reason").and_then(|r| r.as_str()) == Some("compiler-artifact"); + let is_test_profile = + val.get("profile").and_then(|p| p.get("test")).and_then(|t| t.as_bool()) + == Some(true); if is_compiler_artifact && is_test_profile @@ -178,6 +178,9 @@ impl FuzztestRunner { ExecutionMode::SmokeTest => { // nothing to be done } + _ => { + // TODO(the-shank): add support for other modes. + } } cmd @@ -253,7 +256,7 @@ mod tests { #[gtest] fn test_build_run_command_list() { - let options = CargoFuzzTestOptions { list: true }; + let options = CargoFuzzTestOptions { list: true, ..Default::default() }; let runner = FuzztestRunner::new("sample-host-triple".to_string(), options); let cmd = runner.build_run_command(Path::new("/tmp/test_bin")); let args: Vec = cmd.get_args().map(|a| a.to_string_lossy().to_string()).collect(); @@ -262,13 +265,13 @@ mod tests { #[gtest] fn test_execution_mode_smoke_test() { - let options = CargoFuzzTestOptions { list: false }; + let options = CargoFuzzTestOptions { list: false, ..Default::default() }; assert_eq!(options.execution_mode(), ExecutionMode::SmokeTest); } #[gtest] fn test_execution_mode_list_fuzz_tests() { - let options = CargoFuzzTestOptions { list: true }; + let options = CargoFuzzTestOptions { list: true, ..Default::default() }; assert_eq!(options.execution_mode(), ExecutionMode::ListFuzzTests); } diff --git a/rust/cargo_fuzztest/tests/runner_test.rs b/rust/cargo_fuzztest/tests/runner_test.rs index cad9800c8..344f1e53a 100644 --- a/rust/cargo_fuzztest/tests/runner_test.rs +++ b/rust/cargo_fuzztest/tests/runner_test.rs @@ -10,7 +10,6 @@ fn test_runner_execution() { assert!(binary_path.exists(), "Sample 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); @@ -26,7 +25,7 @@ fn test_runner_list_command() { assert!(binary_path.exists(), "Sample fuzz binary does not exist at {}", binary_path.display()); - let options = CargoFuzzTestOptions { list: true }; + let options = CargoFuzzTestOptions { list: true, ..Default::default() }; let runner = FuzztestRunner::new("sample-host-triple".to_string(), options); diff --git a/rust/options/src/lib.rs b/rust/options/src/lib.rs index 2e49538f6..f211dbcae 100644 --- a/rust/options/src/lib.rs +++ b/rust/options/src/lib.rs @@ -109,6 +109,10 @@ pub enum ExecutionMode { /// Replay corpus inputs for a specified duration. ReplayCorpus(ReplayCorpusOptions), + + /// List all discovered fuzz tests without running them. + /// Currently only supported via `cargo-fuzztest`. + ListFuzzTests, } impl ExecutionMode { diff --git a/rust/src/options.rs b/rust/src/options.rs index f7da7ee2e..073cde1d5 100644 --- a/rust/src/options.rs +++ b/rust/src/options.rs @@ -79,6 +79,9 @@ impl ExecutionModeExt for ExecutionMode { .context("while attempting to build CentipedeArgs for replay all crashes mode")?; Ok(ExecutionAction::ReplayAllCrashes { args: centipede_args, list_file }) } + ExecutionMode::ListFuzzTests => { + anyhow::bail!("ListFuzzTest mode is supported only in cargo-fuzztest"); + } } } } @@ -254,6 +257,7 @@ impl CentipedeArgs { add_arg(format!("--fuzztest_time_limit_per_test={time_limit}"))?; } ExecutionMode::SmokeTest => unreachable!(), + ExecutionMode::ListFuzzTests => unreachable!(), } Ok(Some(Self::new(args, opt_workdir)))