Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions rust/cargo_fuzztest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ mod tests {
.expect("valid replay options should parse successfully");

assert_eq!(parsed.fuzztest_options.replay_id.as_deref(), Some("crash_12345"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some("/tmp/corpus_db"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some(Path::new("/tmp/corpus_db")));

let mode = parsed.execution_mode().expect("valid execution mode");
assert_eq!(
Expand Down Expand Up @@ -475,7 +475,7 @@ mod tests {
let options = CargoFuzzTestOptions {
fuzztest_options: FuzzTestOptions {
replay_id: Some("crash_12345".to_string()),
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
..Default::default()
Expand All @@ -490,7 +490,7 @@ mod tests {
let options = CargoFuzzTestOptions {
fuzztest_options: FuzzTestOptions {
replay_id: Some("crash_12345".to_string()),
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
centipede_binary_path: Some("/custom/centipede".to_string()),
Expand Down Expand Up @@ -531,7 +531,7 @@ mod tests {
.expect("valid replay-findings options should parse successfully");

assert!(parsed.fuzztest_options.replay_findings);
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some("/tmp/corpus_db"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some(Path::new("/tmp/corpus_db")));

let mode = parsed.execution_mode().expect("valid execution mode");
assert_eq!(mode, ExecutionMode::ReplayAllCrashes);
Expand All @@ -542,7 +542,7 @@ mod tests {
let options = CargoFuzzTestOptions {
fuzztest_options: FuzzTestOptions {
replay_findings: true,
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
..Default::default()
Expand All @@ -557,7 +557,7 @@ mod tests {
let options = CargoFuzzTestOptions {
fuzztest_options: FuzzTestOptions {
replay_findings: true,
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
centipede_binary_path: Some("/custom/centipede".to_string()),
Expand Down Expand Up @@ -600,7 +600,7 @@ mod tests {

assert_eq!(parsed.fuzztest_options.replay_corpus_for, Some("10s".parse().unwrap()));
assert_eq!(parsed.fuzztest_options.time_budget_type, TimeBudgetType::PerTest);
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some("/tmp/corpus_db"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some(Path::new("/tmp/corpus_db")));

let mode = parsed.execution_mode().expect("valid execution mode");
assert_eq!(
Expand Down Expand Up @@ -628,7 +628,7 @@ mod tests {

assert_eq!(parsed.fuzztest_options.replay_corpus_for, Some(RunDuration::Indefinitely));
assert_eq!(parsed.fuzztest_options.time_budget_type, TimeBudgetType::PerTest);
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some("/tmp/corpus_db"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some(Path::new("/tmp/corpus_db")));

let mode = parsed.execution_mode().expect("valid execution mode");
assert_eq!(
Expand Down Expand Up @@ -700,7 +700,7 @@ mod tests {
let options = CargoFuzzTestOptions {
fuzztest_options: FuzzTestOptions {
replay_corpus_for: Some("10s".parse().unwrap()),
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
..Default::default()
Expand All @@ -716,7 +716,7 @@ mod tests {
fuzztest_options: FuzzTestOptions {
replay_corpus_for: Some("10s".parse().unwrap()),
time_budget_type: TimeBudgetType::Total,
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
centipede_binary_path: Some("/custom/centipede".to_string()),
Expand Down Expand Up @@ -765,7 +765,7 @@ mod tests {
parsed.fuzztest_options.list_crash_ids_file.as_deref(),
Some("/tmp/crashes.txt")
);
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some("/tmp/corpus_db"));
assert_eq!(parsed.fuzztest_options.corpus_db.as_deref(), Some(Path::new("/tmp/corpus_db")));

let mode = parsed.execution_mode().expect("valid execution mode");
assert_eq!(
Expand Down Expand Up @@ -797,7 +797,7 @@ mod tests {
fuzztest_options: FuzzTestOptions {
list_crash_ids: true,
list_crash_ids_file: Some("/tmp/crashes.txt".to_string()),
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
..Default::default()
Expand All @@ -813,7 +813,7 @@ mod tests {
fuzztest_options: FuzzTestOptions {
list_crash_ids: true,
list_crash_ids_file: Some("/tmp/crashes.txt".to_string()),
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
centipede_binary_path: Some("/custom/centipede".to_string()),
Expand Down Expand Up @@ -850,7 +850,7 @@ mod tests {
fuzztest_options: FuzzTestOptions {
replay_corpus_for: Some(RunDuration::Indefinitely),
time_budget_type: TimeBudgetType::Total,
corpus_db: Some("/tmp/corpus_db".to_string()),
corpus_db: Some("/tmp/corpus_db".into()),
..Default::default()
},
centipede_binary_path: Some("/custom/centipede".to_string()),
Expand Down
18 changes: 9 additions & 9 deletions rust/cargo_fuzztest/tests/runner_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn test_runner_build_run_command_with_replay_id() {
let binary_path = get_sample_test_bin_path("sample_fuzz_crate");
let fuzztest_options = FuzzTestOptions {
replay_id: Some("crash_12345".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions {
Expand Down Expand Up @@ -194,7 +194,7 @@ fn test_execution_mode_replay_id_missing_corpus_db_errors() {
fn test_execution_mode_replay_id_missing_centipede_binary_path_errors() {
let fuzztest_options = FuzzTestOptions {
replay_id: Some("crash_12345".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions { fuzztest_options, ..Default::default() };
Expand All @@ -209,7 +209,7 @@ fn test_runner_build_run_command_with_replay_findings() {
let binary_path = get_sample_test_bin_path("sample_fuzz_crate");
let fuzztest_options = FuzzTestOptions {
replay_findings: true,
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions {
Expand Down Expand Up @@ -239,7 +239,7 @@ fn test_runner_build_run_command_with_replay_findings() {
fn test_execution_mode_replay_findings_missing_centipede_binary_path_errors() {
let fuzztest_options = FuzzTestOptions {
replay_findings: true,
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions { fuzztest_options, ..Default::default() };
Expand All @@ -255,7 +255,7 @@ fn test_runner_build_run_command_with_replay_corpus() {
let fuzztest_options = FuzzTestOptions {
replay_corpus_for: Some("10s".parse().expect("valid duration")),
time_budget_type: TimeBudgetType::Total,
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions {
Expand Down Expand Up @@ -292,7 +292,7 @@ fn test_runner_build_run_command_with_replay_corpus_indefinitely() {
let fuzztest_options = FuzzTestOptions {
replay_corpus_for: Some(RunDuration::Indefinitely),
time_budget_type: TimeBudgetType::Total,
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions {
Expand Down Expand Up @@ -327,7 +327,7 @@ fn test_runner_build_run_command_with_replay_corpus_indefinitely() {
fn test_execution_mode_replay_corpus_missing_centipede_binary_path_errors() {
let fuzztest_options = FuzzTestOptions {
replay_corpus_for: Some("10s".parse().expect("valid duration")),
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions { fuzztest_options, ..Default::default() };
Expand Down Expand Up @@ -359,7 +359,7 @@ fn test_runner_build_run_command_with_list_crash_ids() {
let fuzztest_options = FuzzTestOptions {
list_crash_ids: true,
list_crash_ids_file: Some("/custom/path/to/crash_ids.txt".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions {
Expand Down Expand Up @@ -412,7 +412,7 @@ fn test_execution_mode_list_crash_ids_missing_centipede_binary_path_errors() {
let fuzztest_options = FuzzTestOptions {
list_crash_ids: true,
list_crash_ids_file: Some("/custom/path/to/crash_ids.txt".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".to_string()),
corpus_db: Some("/custom/path/to/corpus_db".into()),
..Default::default()
};
let options = CargoFuzzTestOptions { fuzztest_options, ..Default::default() };
Expand Down
44 changes: 32 additions & 12 deletions rust/options/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,31 @@

use anyhow::Context;
use clap::{Parser, ValueEnum};
use std::env;
use std::fmt;
use std::fmt::Display;
use std::fmt::Formatter;
use std::path::{Path, PathBuf};
use std::str::FromStr;

/// If a relative path is provided while executing inside a Bazel/Blaze test sandbox
/// (detected via the `TEST_SRCDIR` environment variable), the path is automatically
/// resolved relative to the runfiles root directory.
fn parse_corpus_db_path(raw: &str) -> Result<PathBuf, String> {
if raw.is_empty() {
return Err("corpus_db path cannot be empty".to_string());
}

let path = PathBuf::from(raw);
if path.is_absolute() {
Ok(path)
} else if let Ok(test_src_dir) = env::var("TEST_SRCDIR") {
Ok(Path::new(&test_src_dir).join(path))
} else {
Ok(path)
}
}

/// Time budget calculation type for replay corpus mode.
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TimeBudgetType {
Expand Down Expand Up @@ -100,8 +120,8 @@ pub struct FuzzTestOptions {
///
/// If set to non-empty, updates/queries the corpus database that contains coverage,
/// regression, and crashing inputs for each test binary and fuzz test.
#[arg(env = "FUZZTEST_CORPUS_DB", long)]
pub corpus_db: Option<String>,
#[arg(env = "FUZZTEST_CORPUS_DB", long, value_parser = parse_corpus_db_path)]
pub corpus_db: Option<PathBuf>,
}

/// Strongly-typed domain execution mode for test runs.
Expand Down Expand Up @@ -316,7 +336,7 @@ mod tests {
let options =
result.expect("parsing should succeed when both replay_id and corpus_db are present");
expect_that!(options.replay_id.as_deref(), eq(Some("my_crash_123")));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
}

#[gtest]
Expand Down Expand Up @@ -419,8 +439,8 @@ mod tests {
fn test_replay_findings_with_corpus_db_succeeds() {
// SAFETY: Testing environment parsing in single-threaded context.
unsafe {
std::env::set_var("FUZZTEST_REPLAY_FINDINGS", "true");
std::env::set_var("FUZZTEST_CORPUS_DB", "/tmp/corpus_db");
env::set_var("FUZZTEST_REPLAY_FINDINGS", "true");
env::set_var("FUZZTEST_CORPUS_DB", "/tmp/corpus_db");
}

let result = FuzzTestOptions::try_parse_from(std::iter::empty::<OsString>());
Expand All @@ -434,7 +454,7 @@ mod tests {
let options = result
.expect("parsing should succeed when both replay_findings and corpus_db are present");
expect_that!(options.replay_findings, eq(true));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
}

#[gtest]
Expand Down Expand Up @@ -478,7 +498,7 @@ mod tests {
options.replay_corpus_for,
eq(Some("10s".parse().expect("valid duration string")))
);
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
expect_that!(options.time_budget_type, eq(TimeBudgetType::PerTest));
}

Expand All @@ -502,7 +522,7 @@ mod tests {
"parsing should succeed when replay_corpus_for is inf and corpus_db is present",
);
expect_that!(options.replay_corpus_for, eq(Some(RunDuration::Indefinitely)));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
}

#[gtest]
Expand All @@ -525,7 +545,7 @@ mod tests {
"parsing should succeed when replay_corpus_for is infinity and corpus_db is present",
);
expect_that!(options.replay_corpus_for, eq(Some(RunDuration::Indefinitely)));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
}

#[gtest]
Expand All @@ -551,7 +571,7 @@ mod tests {
options.replay_corpus_for,
eq(Some("10s".parse().expect("valid duration string")))
);
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
expect_that!(options.time_budget_type, eq(TimeBudgetType::Total));
}

Expand All @@ -575,7 +595,7 @@ mod tests {

let options = result.expect("parsing should succeed with total time budget type and inf");
expect_that!(options.replay_corpus_for, eq(Some(RunDuration::Indefinitely)));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));
expect_that!(options.time_budget_type, eq(TimeBudgetType::Total));
}

Expand Down Expand Up @@ -665,7 +685,7 @@ mod tests {
);
expect_that!(options.list_crash_ids, eq(true));
expect_that!(options.list_crash_ids_file.as_deref(), eq(Some("/tmp/crashes.txt")));
expect_that!(options.corpus_db.as_deref(), eq(Some("/tmp/corpus_db")));
expect_that!(options.corpus_db.as_deref(), eq(Some(Path::new("/tmp/corpus_db"))));

let mode = ExecutionMode::from_fuzztest_options(&options);
expect_that!(
Expand Down
Loading
Loading