dreamstack/compiler/ds-cli/tests/compile_examples.rs

90 lines
3.1 KiB
Rust

/// Integration test — compile every example .ds file through the full pipeline.
/// This is the ultimate regression guard: if any of the 51 examples break, this test catches it.
use std::fs;
use std::path::PathBuf;
/// Get the workspace root (two levels up from ds-cli's Cargo.toml).
fn workspace_root() -> PathBuf {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
manifest.parent().unwrap().parent().unwrap().to_path_buf()
}
/// Compile a .ds source string through the full pipeline (lex → parse → analyze → codegen).
fn compile_source(source: &str) -> Result<String, String> {
let mut lexer = ds_parser::Lexer::new(source);
let tokens = lexer.tokenize();
for tok in &tokens {
if let ds_parser::TokenKind::Error(msg) = &tok.kind {
return Err(format!("Lexer error at line {}: {}", tok.line, msg));
}
}
let mut parser = ds_parser::Parser::with_source(tokens, source);
let program = parser.parse_program().map_err(|e| e.to_string())?;
let graph = ds_analyzer::SignalGraph::from_program(&program);
let views = ds_analyzer::SignalGraph::analyze_views(&program);
let html = ds_codegen::JsEmitter::emit_html(&program, &graph, &views, false);
Ok(html)
}
#[test]
fn test_compile_all_examples() {
// Spawn with 8MB stack to handle deeply nested examples
let builder = std::thread::Builder::new()
.name("compile_examples".into())
.stack_size(8 * 1024 * 1024);
let handle = builder.spawn(|| {
let examples_dir = workspace_root().join("examples");
assert!(examples_dir.exists(), "examples/ directory not found at {:?}", examples_dir);
let mut ds_files: Vec<PathBuf> = fs::read_dir(&examples_dir)
.expect("cannot read examples/")
.filter_map(|e| e.ok())
.map(|e| e.path())
.filter(|p| p.extension().map_or(false, |ext| ext == "ds"))
.collect();
ds_files.sort();
assert!(!ds_files.is_empty(), "no .ds files found in examples/");
let mut pass = 0;
let mut fail = 0;
let mut failures = Vec::new();
for path in &ds_files {
let source = fs::read_to_string(path)
.unwrap_or_else(|e| panic!("cannot read {}: {}", path.display(), e));
let name = path.file_name().unwrap().to_str().unwrap();
match compile_source(&source) {
Ok(html) => {
assert!(!html.is_empty(), "{}: produced empty output", name);
pass += 1;
}
Err(e) => {
failures.push(format!(" {}{}", name, e));
fail += 1;
}
}
}
eprintln!("\n Examples: {} passed, {} failed, {} total", pass, fail, ds_files.len());
if !failures.is_empty() {
panic!(
"\n{} example(s) failed to compile:\n{}\n",
fail,
failures.join("\n")
);
}
}).expect("failed to spawn test thread");
handle.join().expect("test thread panicked");
}