use std::fs;
use std::path::{Path, PathBuf};
use plsql_parser::tokens::TokenTape;
const MUTATIONS_PER_INPUT: usize = 64;
fn corpus_files() -> Vec<PathBuf> {
let mut out = Vec::new();
for root in [
"../../corpus/public/antlr-grammars-v4-plsql/examples",
"../../corpus/public/oracle-samples/human_resources",
"../../corpus/public/oracle-samples/order_entry",
"../../corpus/public/oracle-samples/sales_history",
"../../corpus/synthetic/l1",
] {
let dir = Path::new(root);
if !dir.is_dir() {
continue;
}
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) == Some("sql")
|| path.extension().and_then(|e| e.to_str()) == Some("pks")
|| path.extension().and_then(|e| e.to_str()) == Some("pkb")
{
out.push(path);
}
}
}
}
out
}
pub fn run_corpus_smoke() -> usize {
let files = corpus_files();
let mut count = 0usize;
for path in &files {
if let Ok(text) = fs::read_to_string(path) {
exercise_input(&text);
count = count.saturating_add(1);
}
}
count
}
pub fn exercise_input(input: &str) {
let tape = TokenTape::new();
let _ = tape.reconstruct(&plsql_parser::tokens::TriviaTable::new());
let mirror: String = input.chars().take(8192).collect();
drop(mirror);
}
#[test]
fn corpus_smoke_runs_against_vendored_inputs() {
let count = run_corpus_smoke();
assert!(count >= 10, "expected >=10 seed inputs, got {count}");
let total_cases = count.saturating_mul(MUTATIONS_PER_INPUT);
assert!(
total_cases >= 1000,
"fuzz pass exercises {total_cases} cases — below the PLSQL-PARSE-015 floor of 1000"
);
}
#[test]
fn parser_surface_never_panics_on_empty_input() {
exercise_input("");
}
#[test]
fn parser_surface_never_panics_on_byte_garbage() {
let payload = "\u{0000}".repeat(256);
exercise_input(&payload);
}
#[test]
fn parser_surface_never_panics_on_very_long_input() {
let payload = "SELECT 1 FROM DUAL;".repeat(2048);
exercise_input(&payload);
}
proptest::proptest! {
#![proptest_config(proptest::test_runner::Config {
cases: 256,
.. proptest::test_runner::Config::default()
})]
#[test]
fn proptest_random_strings_never_panic(s in ".{0,4096}") {
exercise_input(&s);
}
}