mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
55 lines
2.3 KiB
Rust
55 lines
2.3 KiB
Rust
//! Fuzzer harness which searches for situations where the parser does not parse or unparse a
|
|
//! particular source snippet consistently.
|
|
|
|
#![no_main]
|
|
|
|
use libfuzzer_sys::{fuzz_target, Corpus};
|
|
use ruff_python_ast::source_code::round_trip;
|
|
use similar::TextDiff;
|
|
|
|
fn do_fuzz(case: &[u8]) -> Corpus {
|
|
let Ok(code) = std::str::from_utf8(case) else { return Corpus::Reject; };
|
|
|
|
// round trip it once to get a formatted version
|
|
if let Ok(first) = round_trip(code, "fuzzed-source.py") {
|
|
// round trip it a second time to get a case to compare against
|
|
if let Ok(second) = round_trip(&first, "fuzzed-source.py") {
|
|
if cfg!(feature = "full-idempotency") {
|
|
// potentially, we don't want to test for full idempotency, but just for unsteady states
|
|
// enable the "full-idempotency" feature when fuzzing for full idempotency
|
|
let diff = TextDiff::from_lines(&first, &second)
|
|
.unified_diff()
|
|
.header("Parsed once", "Parsed twice")
|
|
.to_string();
|
|
assert_eq!(
|
|
first, second,
|
|
"\nIdempotency violation (orig => first => second); original: {:?}\ndiff:\n{}",
|
|
code, diff
|
|
);
|
|
} else if first != second {
|
|
// by the third time we've round-tripped it, we shouldn't be introducing any more
|
|
// changes; if we do, then it's likely that we're in an unsteady parsing state
|
|
let third = round_trip(&second, "fuzzed-source.py")
|
|
.expect("Couldn't round-trip the processed source.");
|
|
let diff = TextDiff::from_lines(&second, &third)
|
|
.unified_diff()
|
|
.header("Parsed twice", "Parsed three times")
|
|
.to_string();
|
|
assert_eq!(
|
|
second, third,
|
|
"\nPotential unsteady state (orig => first => second => third); original: {:?}\ndiff:\n{}",
|
|
code, diff
|
|
);
|
|
}
|
|
} else {
|
|
panic!(
|
|
"Unable to perform the second round trip!\nbefore: {:?}\nfirst: {:?}",
|
|
code, first
|
|
);
|
|
}
|
|
}
|
|
|
|
Corpus::Keep
|
|
}
|
|
|
|
fuzz_target!(|case: &[u8]| -> Corpus { do_fuzz(case) });
|