use rlox::backend::interpreter::{EvaluateInterpreter, Interpreter}; use rlox::frontend::lexer::Lexer; use rlox::frontend::parser::Parser; use rlox::frontend::source_registry::SourceRegistry; use std::fs; use std::path::Path; #[test] fn test_all_examples() { let examples_dir = Path::new("examples"); // Trova tutti i file .lox nella directory examples let entries = fs::read_dir(examples_dir).expect("Failed to read examples directory"); let mut test_files_passed = Vec::new(); let mut test_files_failed = Vec::new(); let mut fail_files_passed = Vec::new(); let mut fail_files_failed = Vec::new(); for entry in entries { let entry = entry.expect("Failed to read directory entry"); let path = entry.path(); // Controlla se รจ un file .lox if path.extension().and_then(|s| s.to_str()) == Some("lox") { let file_name = path.file_name().unwrap().to_str().unwrap().to_string(); // Ignora i file che non iniziano con test_ o fail_ if !file_name.starts_with("test_") && !file_name.starts_with("fail_") { continue; } // Leggi il contenuto del file let source = match fs::read_to_string(&path) { Ok(content) => content, Err(e) => { if file_name.starts_with("test_") { test_files_failed.push((file_name, format!("Failed to read file: {}", e))); } else { fail_files_failed.push((file_name, format!("Failed to read file: {}", e))); } continue; } }; // Esegui il file e categorizza il risultato match run_lox_file(source, &file_name) { Ok(_) => { if file_name.starts_with("test_") { test_files_passed.push(file_name); } else { fail_files_passed.push(file_name); } } Err(error) => { if file_name.starts_with("test_") { test_files_failed.push((file_name, error)); } else { fail_files_failed.push((file_name, error)); } } } } } // Stampa i risultati println!("\n========== TEST RESULTS =========="); // File test_ (dovrebbero passare) if !test_files_passed.is_empty() || !test_files_failed.is_empty() { println!("\n๐Ÿ“ TEST FILES (should pass):"); if !test_files_passed.is_empty() { println!(" โœ… Passed ({}):", test_files_passed.len()); for file in &test_files_passed { println!(" - {}", file); } } if !test_files_failed.is_empty() { println!(" โŒ Failed ({}):", test_files_failed.len()); for (file, error) in &test_files_failed { println!("\n - {}", file); println!("{}", error); } } } // File fail_ (dovrebbero fallire) if !fail_files_failed.is_empty() || !fail_files_passed.is_empty() { println!("\n๐Ÿšซ FAIL FILES (should fail):"); if !fail_files_failed.is_empty() { println!(" โœ… Failed as expected ({}):", fail_files_failed.len()); for (file, error) in &fail_files_failed { println!("\n - {}", file); println!("{}", error); } } if !fail_files_passed.is_empty() { println!(" โŒ Passed unexpectedly ({}):", fail_files_passed.len()); for file in &fail_files_passed { println!(" - {} (should have failed but passed!)", file); } } } println!("\n=================================="); // Riepilogo let total_test_files = test_files_passed.len() + test_files_failed.len(); let total_fail_files = fail_files_passed.len() + fail_files_failed.len(); let total_files = total_test_files + total_fail_files; println!("Summary:"); if total_test_files > 0 { println!( " test_ files: {}/{} passed", test_files_passed.len(), total_test_files ); } if total_fail_files > 0 { println!( " fail_ files: {}/{} failed (as expected)", fail_files_failed.len(), total_fail_files ); } println!(" Total files tested: {}", total_files); // Assicurati che almeno un file sia stato testato assert!( total_files > 0, "No test_ or fail_ .lox files found in examples directory" ); // Asserzioni per far fallire il test se le aspettative non sono rispettate if !test_files_failed.is_empty() { println!("\nโŒ TEST FAILURE: The following test_ files failed but should have passed:"); for (file, _) in &test_files_failed { println!(" - {}", file); } panic!( "{} test_ files failed unexpectedly", test_files_failed.len() ); } if !fail_files_passed.is_empty() { println!("\nโŒ TEST FAILURE: The following fail_ files passed but should have failed:"); for file in &fail_files_passed { println!(" - {}", file); } panic!( "{} fail_ files passed unexpectedly", fail_files_passed.len() ); } println!( "\nโœ… All {} test/fail files behaved as expected!", total_files ); } fn run_lox_file(source: String, _filename: &str) -> Result<(), String> { // Crea un source registry e mantienilo per il pretty printing degli errori let mut source_registry = SourceRegistry::new(); // Aggiungi il source con il nome del file corretto let source_id = match source_registry.add_source_string(source.clone()) { Ok(id) => id, Err(e) => return Err(format!("Failed to add source: {}", e)), }; // Tokenizza let source_content = source_registry.get_by_id(source_id).content.clone(); let mut lexer = Lexer::new(source_content, source_id); let tokens = match lexer.scans_tokens() { Ok(tokens) => tokens, Err(err) => { // Usa il pretty printing con source context return Err(err.display_with_source(&source_registry)); } }; // Parsa let ast = match Parser::new(tokens).parse() { Ok(ast) => ast, Err(err) => { // Usa il pretty printing con source context return Err(err.display_with_source(&source_registry)); } }; // Esegui let mut interpreter = Interpreter::new(); for stmt in ast.iter() { match interpreter.evaluate(stmt.clone()) { Ok(_) => {} Err(err) => { // Usa il pretty printing con source context return Err(err.display_with_source(&source_registry)); } } } Ok(()) }