mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
fuzz: improve readability of fuzzer output, add colors
This commit is contained in:
parent
d86a7fb593
commit
5d952afa3d
4 changed files with 135 additions and 24 deletions
20
fuzz/Cargo.lock
generated
20
fuzz/Cargo.lock
generated
|
@ -292,6 +292,19 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120133d4db2ec47efe2e26502ee984747630c67f51974fca0b6c1340cf2368d3"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width 0.2.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.18"
|
||||
|
@ -450,6 +463,12 @@ version = "1.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
|
@ -1355,6 +1374,7 @@ dependencies = [
|
|||
name = "uucore-fuzz"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"console",
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"rand 0.9.0",
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
console = "0.15.0"
|
||||
libfuzzer-sys = "0.4.7"
|
||||
libc = "0.2.153"
|
||||
tempfile = "3.15.0"
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use console::Style;
|
||||
use libc::STDIN_FILENO;
|
||||
use libc::{close, dup, dup2, pipe, STDERR_FILENO, STDOUT_FILENO};
|
||||
use pretty_print::{
|
||||
print_diff, print_end_with_status, print_or_empty, print_section, print_with_style,
|
||||
};
|
||||
use rand::prelude::IndexedRandom;
|
||||
use rand::Rng;
|
||||
use similar::TextDiff;
|
||||
use std::env::temp_dir;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
|
@ -18,6 +21,8 @@ use std::sync::atomic::Ordering;
|
|||
use std::sync::{atomic::AtomicBool, Once};
|
||||
use std::{io, thread};
|
||||
|
||||
pub mod pretty_print;
|
||||
|
||||
/// Represents the result of running a command, including its standard output,
|
||||
/// standard error, and exit code.
|
||||
pub struct CommandResult {
|
||||
|
@ -315,8 +320,8 @@ pub fn compare_result(
|
|||
gnu_result: &CommandResult,
|
||||
fail_on_stderr_diff: bool,
|
||||
) {
|
||||
println!("Test Type: {}", test_type);
|
||||
println!("Input: {}", input);
|
||||
print_section(format!("Compare result for: {} {}", test_type, input));
|
||||
|
||||
if let Some(pipe) = pipe_input {
|
||||
println!("Pipe: {}", pipe);
|
||||
}
|
||||
|
@ -326,49 +331,58 @@ pub fn compare_result(
|
|||
|
||||
if rust_result.stdout.trim() != gnu_result.stdout.trim() {
|
||||
discrepancies.push("stdout differs");
|
||||
println!("Rust stdout: {}", rust_result.stdout);
|
||||
println!("GNU stdout: {}", gnu_result.stdout);
|
||||
println!("Rust stdout:",);
|
||||
print_or_empty(rust_result.stdout.as_str());
|
||||
println!("GNU stdout:",);
|
||||
print_or_empty(gnu_result.stdout.as_ref());
|
||||
print_diff(&rust_result.stdout, &gnu_result.stdout);
|
||||
should_panic = true;
|
||||
}
|
||||
|
||||
if rust_result.stderr.trim() != gnu_result.stderr.trim() {
|
||||
discrepancies.push("stderr differs");
|
||||
println!("Rust stderr: {}", rust_result.stderr);
|
||||
println!("GNU stderr: {}", gnu_result.stderr);
|
||||
println!("Rust stderr:",);
|
||||
print_or_empty(rust_result.stderr.as_str());
|
||||
println!("GNU stderr:",);
|
||||
print_or_empty(gnu_result.stderr.as_str());
|
||||
print_diff(&rust_result.stderr, &gnu_result.stderr);
|
||||
if fail_on_stderr_diff {
|
||||
should_panic = true;
|
||||
}
|
||||
}
|
||||
|
||||
if rust_result.exit_code != gnu_result.exit_code {
|
||||
discrepancies.push("exit code differs");
|
||||
println!("Rust exit code: {}", rust_result.exit_code);
|
||||
println!("GNU exit code: {}", gnu_result.exit_code);
|
||||
println!(
|
||||
"Different exit code: (Rust: {}, GNU: {})",
|
||||
rust_result.exit_code, gnu_result.exit_code
|
||||
);
|
||||
should_panic = true;
|
||||
}
|
||||
|
||||
if discrepancies.is_empty() {
|
||||
println!("All outputs and exit codes matched.");
|
||||
print_end_with_status("Same behavior", true);
|
||||
} else {
|
||||
println!("Discrepancy detected: {}", discrepancies.join(", "));
|
||||
print_with_style(
|
||||
format!("Discrepancies detected: {}", discrepancies.join(", ")),
|
||||
Style::new().red(),
|
||||
);
|
||||
if should_panic {
|
||||
panic!("Test failed for {}: {}", test_type, input);
|
||||
print_end_with_status(
|
||||
format!("Test failed and will panic for: {} {}", test_type, input),
|
||||
false,
|
||||
);
|
||||
panic!("Test failed for: {} {}", test_type, input);
|
||||
} else {
|
||||
println!(
|
||||
"Test completed with discrepancies for {}: {}",
|
||||
test_type, input
|
||||
print_end_with_status(
|
||||
format!(
|
||||
"Test completed with discrepancies for: {} {}",
|
||||
test_type, input
|
||||
),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When we have different outputs, print the diff
|
||||
fn print_diff(rust_output: &str, gnu_output: &str) {
|
||||
println!("Diff=");
|
||||
let diff = TextDiff::from_lines(rust_output, gnu_output);
|
||||
for change in diff.iter_all_changes() {
|
||||
print!("{}{}", change.tag(), change);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
|
@ -414,3 +428,10 @@ pub fn generate_random_file() -> Result<String, std::io::Error> {
|
|||
|
||||
Ok(file_path.to_str().unwrap().to_string())
|
||||
}
|
||||
|
||||
pub fn replace_fuzz_binary_name(cmd: &str, result: &mut CommandResult) {
|
||||
let fuzz_bin_name = format!("fuzz/target/x86_64-unknown-linux-gnu/release/fuzz_{cmd}");
|
||||
|
||||
result.stdout = result.stdout.replace(&fuzz_bin_name, cmd);
|
||||
result.stderr = result.stderr.replace(&fuzz_bin_name, cmd);
|
||||
}
|
69
fuzz/fuzz_targets/fuzz_common/pretty_print.rs
Normal file
69
fuzz/fuzz_targets/fuzz_common/pretty_print.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use console::{style, Style};
|
||||
use similar::TextDiff;
|
||||
|
||||
pub fn print_section<S: fmt::Display>(s: S) {
|
||||
println!("{}", style(format!("=== {}", s)).bold());
|
||||
}
|
||||
|
||||
pub fn print_subsection<S: fmt::Display>(s: S) {
|
||||
println!("{}", style(format!("--- {}", s)).bright());
|
||||
}
|
||||
|
||||
pub fn print_test_begin<S: fmt::Display>(msg: S) {
|
||||
println!(
|
||||
"{} {} {}",
|
||||
style("===").bold(), // Kind of gray
|
||||
style("TEST").black().on_yellow().bold(),
|
||||
style(msg).bold()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn print_end_with_status<S: fmt::Display>(msg: S, ok: bool) {
|
||||
let ok = if ok {
|
||||
style(" OK ").black().on_green().bold()
|
||||
} else {
|
||||
style(" KO ").black().on_red().bold()
|
||||
};
|
||||
|
||||
println!(
|
||||
"{} {} {}",
|
||||
style("===").bold(), // Kind of gray
|
||||
ok,
|
||||
style(msg).bold()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn print_or_empty(s: &str) {
|
||||
let to_print = if s.is_empty() { "(empty)" } else { s };
|
||||
|
||||
println!("{}", style(to_print).dim());
|
||||
}
|
||||
|
||||
pub fn print_with_style<S: fmt::Display>(msg: S, style: Style) {
|
||||
println!("{}", style.apply_to(msg));
|
||||
}
|
||||
|
||||
pub fn print_diff<'a, 'b>(got: &'a str, expected: &'b str) {
|
||||
let diff = TextDiff::from_lines(got, expected);
|
||||
|
||||
print_subsection("START diff");
|
||||
|
||||
for change in diff.iter_all_changes() {
|
||||
let (sign, style) = match change.tag() {
|
||||
similar::ChangeTag::Equal => (" ", Style::new().dim()),
|
||||
similar::ChangeTag::Delete => ("-", Style::new().red()),
|
||||
similar::ChangeTag::Insert => ("+", Style::new().green()),
|
||||
};
|
||||
print!("{}{}", style.apply_to(sign).bold(), style.apply_to(change));
|
||||
}
|
||||
|
||||
print_subsection("END diff");
|
||||
println!();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue