//! The Rust half of the OER differential fuzzer (`oer-conformance/fuzz_differential.py`).
//!
//! Reads a file of documents, one per line, each the document's text encoded as a JSON
//! string (so a line can carry text no parser would read: a lone surrogate, a repeated
//! member name, `NaN`). Prints one line per document, in the reference verifier's form:
//! `REFUSED` when the document is refused whole (extension §4), `NOFILE` when it has no
//! keys or vectors, `CRASH` if verification panicked, and otherwise each vector's
//! `name=reasons`, joined by ` | `. The fuzzer compares these lines with the reference's.
//!
//!   wai_oer_diff <cases.jsonl>

use std::io::{BufRead, Write};

fn main() {
    let Some(path) = std::env::args().nth(1) else {
        eprintln!("usage: wai_oer_diff <cases.jsonl>");
        std::process::exit(2);
    };
    let fail = |msg: String| -> ! {
        eprintln!("wai_oer_diff: {msg}");
        std::process::exit(2)
    };
    let file = std::fs::File::open(&path).unwrap_or_else(|e| fail(format!("{path}: {e}")));
    let out = std::io::stdout();
    let mut out = out.lock();
    // A panic while verifying is reported as CRASH, so its message is not printed.
    std::panic::set_hook(Box::new(|_| {}));
    for (n, line) in std::io::BufReader::new(file).lines().enumerate() {
        let line = line.unwrap_or_else(|e| fail(format!("line {}: {e}", n + 1)));
        let text: String = serde_json::from_str(&line)
            .unwrap_or_else(|e| fail(format!("line {}: not a JSON string: {e}", n + 1)));
        let verdict = std::panic::catch_unwind(|| match wai::oer::load(text.as_bytes()) {
            Err(_) => "REFUSED".to_string(),
            Ok(doc) => match wai::oer::run(&doc) {
                Err(_) => "NOFILE".to_string(),
                Ok(results) => results
                    .iter()
                    .map(|v| format!("{}={}", v.name, v.got.join(",")))
                    .collect::<Vec<_>>()
                    .join(" | "),
            },
        });
        writeln!(out, "{}", verdict.unwrap_or_else(|_| "CRASH".to_string())).expect("stdout");
    }
}
