use std::fs;
use std::path::Path;
#[cfg(feature = "wasm")]
use metadol::WasmCompiler;
use metadol::{parse_file_all, validate};
#[derive(Debug)]
struct TestResult {
name: String,
level: String,
parse: Result<usize, String>, validate: Result<(), String>,
wasm: Result<(), String>,
}
impl TestResult {
fn parse_ok(&self) -> bool {
self.parse.is_ok()
}
fn validate_ok(&self) -> bool {
self.validate.is_ok()
}
fn wasm_ok(&self) -> bool {
self.wasm.is_ok()
}
fn error_msg(&self) -> String {
if let Err(e) = &self.parse {
return e.clone();
}
if let Err(e) = &self.validate {
return e.clone();
}
if let Err(e) = &self.wasm {
return e.clone();
}
String::new()
}
}
fn test_file(path: &Path) -> TestResult {
let name = path.file_name().unwrap().to_string_lossy().to_string();
let level = path
.parent()
.and_then(|p| p.file_name())
.map(|s| s.to_string_lossy().to_string())
.unwrap_or_else(|| "unknown".to_string());
let source = match fs::read_to_string(path) {
Ok(s) => s,
Err(e) => {
return TestResult {
name,
level,
parse: Err(format!("Read: {}", e)),
validate: Err("N/A".into()),
wasm: Err("N/A".into()),
}
}
};
let decls = match parse_file_all(&source) {
Ok(d) if d.is_empty() => {
return TestResult {
name,
level,
parse: Err("No declarations".into()),
validate: Err("N/A".into()),
wasm: Err("N/A".into()),
}
}
Ok(d) => d,
Err(e) => {
return TestResult {
name,
level,
parse: Err(format!("{}", e)),
validate: Err("N/A".into()),
wasm: Err("N/A".into()),
}
}
};
let parse_count = decls.len();
let mut validation_errors = Vec::new();
for decl in &decls {
let result = validate(decl);
for err in &result.errors {
validation_errors.push(format!("{:?}", err));
}
}
let validate_result = if validation_errors.is_empty() {
Ok(())
} else {
Err(validation_errors.join("; "))
};
#[cfg(feature = "wasm")]
let wasm_result = {
let mut compiler = WasmCompiler::new();
let mut wasm_success = false;
let mut wasm_error = String::from("No functions");
for decl in &decls {
match compiler.compile(decl) {
Ok(bytes) => {
wasm_success = true;
wasm_error = format!("{} bytes", bytes.len());
break;
}
Err(e) => {
wasm_error = e.message;
}
}
}
if wasm_success {
Ok(())
} else {
Err(wasm_error)
}
};
#[cfg(not(feature = "wasm"))]
let wasm_result = Err("WASM feature disabled".into());
TestResult {
name,
level,
parse: Ok(parse_count),
validate: validate_result,
wasm: wasm_result,
}
}
fn main() {
let test_dirs = [
"test-cases/level1-minimal",
"test-cases/level2-basic",
"test-cases/level3-types",
"test-cases/level4-control",
"test-cases/level5-advanced",
];
println!("========================================");
println!(" DOL -> WASM Pipeline Stress Test");
println!("========================================\n");
let mut results = Vec::new();
for dir in &test_dirs {
let path = Path::new(dir);
if let Ok(entries) = fs::read_dir(path) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().map(|e| e == "dol").unwrap_or(false) {
results.push(test_file(&path));
}
}
}
}
results.sort_by(|a, b| a.level.cmp(&b.level).then_with(|| a.name.cmp(&b.name)));
println!(
"{:<30} | {:^7} | {:^8} | {:^6} | Error",
"Test File", "Parse", "Validate", "WASM"
);
println!(
"{:-<30}-+-{:-^7}-+-{:-^8}-+-{:-^6}-+-{:-<50}",
"", "", "", "", ""
);
let mut stats = (0, 0, 0, 0, 0, 0);
for r in &results {
let parse_str = if r.parse_ok() { "PASS" } else { "FAIL" };
let validate_str = if r.validate_ok() {
"PASS"
} else if r.parse_ok() {
"FAIL"
} else {
"-"
};
let wasm_str = if r.wasm_ok() {
"PASS"
} else if r.parse_ok() {
"N/A"
} else {
"-"
};
let err = r.error_msg();
let err_display = if err.len() > 50 {
format!("{}...", &err[..47])
} else {
err
};
println!(
"{:<30} | {:^7} | {:^8} | {:^6} | {}",
r.name, parse_str, validate_str, wasm_str, err_display
);
if r.parse_ok() {
stats.0 += 1;
} else {
stats.1 += 1;
}
if r.validate_ok() {
stats.2 += 1;
} else if r.parse_ok() {
stats.3 += 1;
}
if r.wasm_ok() {
stats.4 += 1;
} else if r.parse_ok() {
stats.5 += 1;
}
}
println!("\n========================================");
println!(" Summary");
println!("========================================");
println!("Total tests: {}", results.len());
println!("Parse: {} passed, {} failed", stats.0, stats.1);
println!("Validate: {} passed, {} failed", stats.2, stats.3);
println!(
"WASM Compile: {} passed, {} N/A (non-function)",
stats.4, stats.5
);
println!();
let working_dir = Path::new("test-cases/working");
let failing_dir = Path::new("test-cases/failing");
fs::create_dir_all(working_dir).ok();
fs::create_dir_all(failing_dir).ok();
for r in &results {
let src_path = Path::new("test-cases").join(&r.level).join(&r.name);
if r.parse_ok() && r.validate_ok() {
let dst = working_dir.join(&r.name);
fs::copy(&src_path, &dst).ok();
} else {
let dst = failing_dir.join(&r.name);
fs::copy(&src_path, &dst).ok();
}
}
println!("Tests organized into test-cases/working/ and test-cases/failing/");
}