File: ruff_parse_idempotency.rs

package info (click to toggle)
ruff 0.0.291%2Bdfsg1-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 27,672 kB
  • sloc: python: 30,930; sh: 189; makefile: 9
file content (57 lines) | stat: -rw-r--r-- 2,369 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//! 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_codegen::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) });