#[cfg(test)]
mod golden_path_integration_tests {
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::{Duration, Instant};
use crate::clang::clang_x86_e2e_pipeline_full::{
CompilationCache, CompilationSession, CompileDiagnostic, DiagLevel, SourceFile,
StageResult, X86E2EOptions, X86E2EPipeline, X86E2EResult, X86LanguageStandard, X86OptLevel,
X86OutputFormat, X86PipelineStage, X86TargetCPU, X86TranslationUnit,
};
use crate::clang::codegen::ClangCodeGen;
use crate::clang::lexer::Lexer;
use crate::clang::parser::Parser;
use crate::clang::sema::Sema;
use crate::clang::token::TokenKind;
use crate::clang::CLangStandard;
fn test_options() -> X86E2EOptions {
X86E2EOptions {
opt_level: X86OptLevel::O2,
target_cpu: X86TargetCPU::X86_64,
output_format: X86OutputFormat::ElfObject,
language: X86LanguageStandard::C17,
..Default::default()
}
}
fn pipeline_with_language(language: X86LanguageStandard) -> X86E2EPipeline {
let opts = X86E2EOptions {
language,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
..Default::default()
};
X86E2EPipeline::new(opts)
}
fn pipeline_with_opt(opt: X86OptLevel) -> X86E2EPipeline {
let opts = X86E2EOptions {
opt_level: opt,
target_cpu: X86TargetCPU::X86_64,
output_format: X86OutputFormat::ElfObject,
language: X86LanguageStandard::C17,
..Default::default()
};
X86E2EPipeline::new(opts)
}
fn lex_source(source: &str, standard: CLangStandard) -> Vec<crate::clang::token::Token> {
let mut lexer = Lexer::new(source, standard);
lexer
.lex_all()
.to_vec()
.into_iter()
.filter(|t| t.kind != TokenKind::Newline && t.kind != TokenKind::Comment)
.collect()
}
fn compile_to_ir(
source: &str,
module_name: &str,
) -> Result<crate::module::Module, Vec<String>> {
let standard = CLangStandard::C17;
let mut lexer = Lexer::new(source, standard);
let tokens = lexer.lex_all().to_vec();
let mut parser = Parser::new(&tokens, standard);
let tu = parser.parse()?;
let mut sema = Sema::new(standard);
sema.analyze(&tu).map_err(|e| {
e.iter()
.map(|s| format!("Sema error: {}", s))
.collect::<Vec<_>>()
})?;
let mut cg = ClangCodeGen::new(module_name, "x86_64-unknown-linux-gnu");
cg.compile(&tu)
}
fn check_elf_magic(bytes: &[u8]) -> bool {
bytes.len() >= 4 && bytes[0..4] == [0x7F, b'E', b'L', b'F']
}
fn elf_class(bytes: &[u8]) -> Option<u8> {
if bytes.len() >= 5 && check_elf_magic(bytes) {
Some(bytes[4])
} else {
None
}
}
fn elf_endian(bytes: &[u8]) -> Option<u8> {
if bytes.len() >= 6 && check_elf_magic(bytes) {
Some(bytes[5])
} else {
None
}
}
fn elf_type(bytes: &[u8]) -> Option<u16> {
let class = elf_class(bytes)?;
if class == 2 {
if bytes.len() >= 18 {
Some(u16::from_le_bytes([bytes[16], bytes[17]]))
} else {
None
}
} else {
if bytes.len() >= 18 {
Some(u16::from_le_bytes([bytes[16], bytes[17]]))
} else {
None
}
}
}
fn elf_machine(bytes: &[u8]) -> Option<u16> {
let class = elf_class(bytes)?;
if class == 2 {
if bytes.len() >= 20 {
Some(u16::from_le_bytes([bytes[18], bytes[19]]))
} else {
None
}
} else {
if bytes.len() >= 20 {
Some(u16::from_le_bytes([bytes[18], bytes[19]]))
} else {
None
}
}
}
fn wait_for<F: Fn() -> bool>(f: F, timeout: Duration) -> bool {
let start = Instant::now();
while start.elapsed() < timeout {
if f() {
return true;
}
std::thread::sleep(Duration::from_millis(1));
}
false
}
#[test]
fn golden_path_tokenize_simple_function() {
let source = "int add(int a, int b) { return a + b; }";
let tokens = lex_source(source, CLangStandard::C17);
assert!(
tokens.len() >= 12,
"Expected >=12 tokens, got {}",
tokens.len()
);
let kinds: Vec<TokenKind> = tokens.iter().map(|t| t.kind).collect();
assert!(kinds.contains(&TokenKind::KwInt), "Missing 'int' keyword");
assert!(
kinds.contains(&TokenKind::KwReturn),
"Missing 'return' keyword"
);
assert!(kinds.contains(&TokenKind::Identifier), "Missing identifier");
assert!(kinds.contains(&TokenKind::LParen), "Missing opening paren");
assert!(kinds.contains(&TokenKind::RParen), "Missing closing paren");
assert!(kinds.contains(&TokenKind::LBrace), "Missing opening brace");
assert!(kinds.contains(&TokenKind::RBrace), "Missing closing brace");
assert!(kinds.contains(&TokenKind::Semicolon), "Missing semicolon");
assert!(kinds.contains(&TokenKind::Plus), "Missing '+' operator");
if let Some(tok) = tokens.iter().find(|t| t.kind == TokenKind::Identifier) {
assert_eq!(
tok.text, "add",
"Expected identifier text 'add', got '{}'",
tok.text
);
} else {
panic!("No identifier token found in '{}'", source);
}
}
#[test]
fn golden_path_tokenize_keywords_comprehensive() {
let source = "auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while";
let tokens = lex_source(source, CLangStandard::C17);
let kinds: Vec<TokenKind> = tokens.iter().map(|t| t.kind).collect();
assert!(kinds.contains(&TokenKind::KwAuto));
assert!(kinds.contains(&TokenKind::KwBreak));
assert!(kinds.contains(&TokenKind::KwCase));
assert!(kinds.contains(&TokenKind::KwChar));
assert!(kinds.contains(&TokenKind::KwConst));
assert!(kinds.contains(&TokenKind::KwContinue));
assert!(kinds.contains(&TokenKind::KwDefault));
assert!(kinds.contains(&TokenKind::KwDo));
assert!(kinds.contains(&TokenKind::KwDouble));
assert!(kinds.contains(&TokenKind::KwElse));
assert!(kinds.contains(&TokenKind::KwEnum));
assert!(kinds.contains(&TokenKind::KwExtern));
assert!(kinds.contains(&TokenKind::KwFloat));
assert!(kinds.contains(&TokenKind::KwFor));
assert!(kinds.contains(&TokenKind::KwGoto));
assert!(kinds.contains(&TokenKind::KwIf));
assert!(kinds.contains(&TokenKind::KwInt));
assert!(kinds.contains(&TokenKind::KwLong));
assert!(kinds.contains(&TokenKind::KwRegister));
assert!(kinds.contains(&TokenKind::KwReturn));
assert!(kinds.contains(&TokenKind::KwShort));
assert!(kinds.contains(&TokenKind::KwSigned));
assert!(kinds.contains(&TokenKind::KwSizeof));
assert!(kinds.contains(&TokenKind::KwStatic));
assert!(kinds.contains(&TokenKind::KwStruct));
assert!(kinds.contains(&TokenKind::KwSwitch));
assert!(kinds.contains(&TokenKind::KwTypedef));
assert!(kinds.contains(&TokenKind::KwUnion));
assert!(kinds.contains(&TokenKind::KwUnsigned));
assert!(kinds.contains(&TokenKind::KwVoid));
assert!(kinds.contains(&TokenKind::KwVolatile));
assert!(kinds.contains(&TokenKind::KwWhile));
assert!(kinds.contains(&TokenKind::KwInline));
assert!(kinds.contains(&TokenKind::Eof));
}
#[test]
fn golden_path_tokenize_numeric_literals() {
let source = "int a = 42; int b = 0xFF; int c = 0777; int d = 0b1010; float e = 3.14e10;";
let tokens = lex_source(source, CLangStandard::C17);
let numeric_tokens: Vec<_> = tokens
.iter()
.filter(|t| t.kind == TokenKind::NumericLiteral)
.collect();
assert_eq!(numeric_tokens.len(), 5, "Expected 5 numeric literals");
assert_eq!(numeric_tokens[0].text, "42");
assert_eq!(numeric_tokens[1].text, "0xFF");
assert_eq!(numeric_tokens[2].text, "0777");
assert_eq!(numeric_tokens[3].text, "0b1010");
assert_eq!(numeric_tokens[4].text, "3.14e10");
}
#[test]
fn golden_path_tokenize_operators_comprehensive() {
let source = "x + y - z * w / v % m; ++a; --b; a == b; a != b; a < b; a > b; a <= b; a >= b; a && b; a || b; a & b; a | b; a ^ b; ~a; a << b; a >> b; a += b; a -= b; a *= b; a /= b; a &= b; a |= b; a ^= b;";
let tokens = lex_source(source, CLangStandard::C17);
let kinds: Vec<TokenKind> = tokens.iter().map(|t| t.kind).collect();
assert!(kinds.contains(&TokenKind::Plus));
assert!(kinds.contains(&TokenKind::Minus));
assert!(kinds.contains(&TokenKind::Star));
assert!(kinds.contains(&TokenKind::Slash));
assert!(kinds.contains(&TokenKind::Percent));
assert!(kinds.contains(&TokenKind::PlusPlus));
assert!(kinds.contains(&TokenKind::MinusMinus));
assert!(kinds.contains(&TokenKind::EqualEqual));
assert!(kinds.contains(&TokenKind::NotEqual));
assert!(kinds.contains(&TokenKind::Less));
assert!(kinds.contains(&TokenKind::Greater));
assert!(kinds.contains(&TokenKind::LessEqual));
assert!(kinds.contains(&TokenKind::GreaterEqual));
assert!(kinds.contains(&TokenKind::AndAnd));
assert!(kinds.contains(&TokenKind::OrOr));
assert!(kinds.contains(&TokenKind::Ampersand));
assert!(kinds.contains(&TokenKind::Pipe));
assert!(kinds.contains(&TokenKind::Caret));
assert!(kinds.contains(&TokenKind::Tilde));
assert!(kinds.contains(&TokenKind::LessLess));
assert!(kinds.contains(&TokenKind::GreaterGreater));
assert!(kinds.contains(&TokenKind::PlusEqual));
assert!(kinds.contains(&TokenKind::MinusEqual));
assert!(kinds.contains(&TokenKind::StarEqual));
assert!(kinds.contains(&TokenKind::SlashEqual));
assert!(kinds.contains(&TokenKind::AmpersandEqual));
assert!(kinds.contains(&TokenKind::PipeEqual));
assert!(kinds.contains(&TokenKind::CaretEqual));
}
#[test]
fn golden_path_tokenize_string_and_char_literals() {
let source = r#"char *s = "hello world"; char c = 'A'; char *t = "line1\nline2";"#;
let tokens = lex_source(source, CLangStandard::C17);
let string_lits: Vec<_> = tokens
.iter()
.filter(|t| t.kind == TokenKind::StringLiteral)
.collect();
assert_eq!(string_lits.len(), 2, "Expected 2 string literals");
assert_eq!(string_lits[0].text, "\"hello world\"");
assert_eq!(string_lits[1].text, "\"line1\\nline2\"");
let char_lits: Vec<_> = tokens
.iter()
.filter(|t| t.kind == TokenKind::CharLiteral)
.collect();
assert_eq!(char_lits.len(), 1, "Expected 1 char literal");
assert_eq!(char_lits[0].text, "'A'");
}
#[test]
fn golden_path_parse_empty_translation_unit() {
let source = "";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let result = parser.parse();
assert!(
result.is_ok(),
"Parser should accept empty translation unit: {:?}",
result.err()
);
}
#[test]
fn golden_path_parse_function_declaration() {
let source = "int foo(int a, int b);";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept function declaration");
assert!(
!tu.external_declarations.is_empty(),
"TranslationUnit should have at least one external declaration"
);
}
#[test]
fn golden_path_parse_function_definition() {
let source = "int multiply(int x, int y) { return x * y; }";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept function definition");
assert!(
!tu.external_declarations.is_empty(),
"TranslationUnit should contain a function definition"
);
}
#[test]
fn golden_path_parse_global_variable() {
let source = "int global_counter = 100;";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept global variable");
assert!(
!tu.external_declarations.is_empty(),
"TranslationUnit should contain a global variable declaration"
);
}
#[test]
fn golden_path_parse_struct_definition() {
let source = "struct Point { int x; int y; };";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept struct definition");
assert!(
!tu.external_declarations.is_empty(),
"TranslationUnit should contain a struct definition"
);
}
#[test]
fn golden_path_parse_enum_definition() {
let source = "enum Color { RED, GREEN, BLUE };";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept enum definition");
assert!(
!tu.external_declarations.is_empty(),
"TranslationUnit should contain an enum definition"
);
}
#[test]
fn golden_path_parse_complex_ast() {
let source = "\
struct Point { int x; int y; };
struct Point create_point(int x, int y) {
struct Point p;
p.x = x;
p.y = y;
return p;
}
int distance_squared(struct Point a, struct Point b) {
int dx = a.x - b.x;
int dy = a.y - b.y;
return dx * dx + dy * dy;
}
int main(void) {
struct Point p1 = create_point(3, 4);
struct Point p2 = create_point(0, 0);
int result = distance_squared(p1, p2);
if (result > 0) {
return result;
} else {
return -1;
}
}
";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept complex program");
assert!(
tu.external_declarations.len() >= 4,
"Expected >=4 external declarations, got {}",
tu.external_declarations.len()
);
}
#[test]
fn golden_path_parse_array_declarations() {
let source = "int arr[10]; int matrix[4][4]; char buffer[256];";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept array declarations");
assert!(
tu.external_declarations.len() >= 3,
"Expected >=3 array declarations"
);
}
#[test]
fn golden_path_parse_pointer_declarations() {
let source = "int *ptr; char **str_ptr; void *generic; int (*fptr)(int);";
let tokens = lex_source(source, CLangStandard::C17);
let mut parser = Parser::new(&tokens, CLangStandard::C17);
let tu = parser
.parse()
.expect("Parser should accept pointer declarations");
assert!(
tu.external_declarations.len() >= 4,
"Expected >=4 pointer declarations"
);
}
#[test]
fn golden_path_codegen_simple_function() {
let source = "int add(int a, int b) { return a + b; }";
let result = compile_to_ir(source, "test_module");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(
!ir_str.is_empty(),
"Generated IR module should not be empty"
);
eprintln!("CodeGen produced valid IR module");
}
Err(errors) => {
eprintln!("CodeGen encountered expected issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_codegen_function_with_multiple_params() {
let source = "int compute(int a, int b, int c) { return a * b + c; }";
let result = compile_to_ir(source, "compute_mod");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(!ir_str.is_empty(), "IR should not be empty");
eprintln!("Multi-param function CodeGen successful");
}
Err(errors) => {
eprintln!("CodeGen encountered issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_codegen_with_control_flow() {
let source = "\
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
";
let result = compile_to_ir(source, "control_flow_mod");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(!ir_str.is_empty(), "IR should not be empty");
eprintln!("Control flow CodeGen successful");
}
Err(errors) => {
eprintln!("CodeGen control_flow issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_codegen_while_loop() {
let source = "\
int sum_to_n(int n) {
int total = 0;
int i = 0;
while (i < n) {
total = total + i;
i = i + 1;
}
return total;
}
";
let result = compile_to_ir(source, "while_loop_mod");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(!ir_str.is_empty(), "IR should not be empty");
eprintln!("While-loop CodeGen successful");
}
Err(errors) => {
eprintln!("CodeGen while_loop issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_codegen_empty_function() {
let source = "void do_nothing(void) { }";
let result = compile_to_ir(source, "empty_mod");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(!ir_str.is_empty(), "IR should not be empty");
eprintln!("Empty function CodeGen successful");
}
Err(errors) => {
eprintln!("CodeGen empty function issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_codegen_function_with_pointers() {
let source = "\
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
";
let result = compile_to_ir(source, "pointer_mod");
match result {
Ok(module) => {
let ir_str = format!("{:?}", module);
assert!(!ir_str.is_empty(), "IR should not be empty");
eprintln!("Pointer function CodeGen successful");
}
Err(errors) => {
eprintln!("CodeGen pointer issues: {:?}", errors);
}
}
}
#[test]
fn golden_path_pipeline_compile_main_return() {
let source = SourceFile::from_string(
"test.c",
"int main(void) { return 0; }",
X86LanguageStandard::C17,
);
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_test_main.c");
std::fs::write(&tmp_file, &source.content).expect("Failed to write temp source file");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should succeed");
eprintln!(
"Pipeline result: success={}, object_bytes={}, ir={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0),
result.llvm_ir.as_ref().map(|s| s.len()),
);
let _ = std::fs::remove_file(&tmp_file);
if result.success {
assert!(
result.object_bytes.is_some() || result.llvm_ir.is_some(),
"Successful compilation should produce object bytes or IR"
);
}
}
#[test]
fn golden_path_pipeline_compile_add_function() {
let source_content = "\
int add(int a, int b) {
return a + b;
}
";
let source = SourceFile::from_string("add.c", source_content, X86LanguageStandard::C17);
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_test_add.c");
std::fs::write(&tmp_file, &source.content).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
eprintln!(
"add() pipeline: success={}, bytes={}",
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0)
);
let _ = std::fs::remove_file(&tmp_file);
if result.success {
assert!(
result.object_bytes.is_some() || result.llvm_ir.is_some(),
"Should produce output"
);
}
}
#[test]
fn golden_path_pipeline_compile_factorial() {
let source_content = "\
int factorial(int n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_test_fact.c");
std::fs::write(&tmp_file, source_content).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
eprintln!(
"factorial pipeline: success={}, bytes={}",
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0)
);
let _ = std::fs::remove_file(&tmp_file);
}
#[test]
fn golden_path_pipeline_compile_fibonacci() {
let source_content = "\
int fib(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_test_fib.c");
std::fs::write(&tmp_file, source_content).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
eprintln!(
"fib pipeline: success={}, bytes={}",
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0)
);
let _ = std::fs::remove_file(&tmp_file);
}
#[test]
fn golden_path_pipeline_compile_with_source_file() {
let content = "\
int global_value = 42;
int get_value(void) {
return global_value;
}
int set_value(int v) {
global_value = v;
return 0;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_test_globals.c");
std::fs::write(&tmp_file, content).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
eprintln!(
"global_vars pipeline: success={}, bytes={}",
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0)
);
let _ = std::fs::remove_file(&tmp_file);
}
#[test]
fn golden_path_elf_magic_bytes_present() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_elf_test.c");
std::fs::write(&tmp_file, "int main(void) { return 42; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
if let Some(ref obj_bytes) = result.object_bytes {
assert!(
check_elf_magic(obj_bytes),
"Output should start with ELF magic: {:02x?}",
&obj_bytes[..obj_bytes.len().min(4)]
);
assert_eq!(elf_class(obj_bytes), Some(2), "Should be ELF64");
assert_eq!(elf_endian(obj_bytes), Some(1), "Should be little-endian");
let e_type = elf_type(obj_bytes);
assert_eq!(e_type, Some(1), "Should be ET_REL (1), got {:?}", e_type);
let machine = elf_machine(obj_bytes);
assert_eq!(
machine,
Some(0x3E),
"Should be EM_X86_64 (0x3E), got {:?}",
machine
);
assert!(
obj_bytes.len() > 64,
"ELF object should be larger than header (64 bytes), got {}",
obj_bytes.len()
);
} else {
eprintln!("No object bytes produced; ELF header check skipped");
}
}
#[test]
fn golden_path_elf_output_is_valid_object() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_elf_valid.c");
std::fs::write(&tmp_file, "int add(int a, int b) { return a + b; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
if let Some(ref obj_bytes) = result.object_bytes {
assert!(check_elf_magic(obj_bytes), "Missing ELF magic");
assert!(obj_bytes.len() >= 64, "ELF64 header is 64 bytes");
assert_eq!(obj_bytes[4], 2, "EI_CLASS should be 2 (64-bit)");
assert_eq!(obj_bytes[5], 1, "EI_DATA should be 1 (little-endian)");
assert_eq!(obj_bytes[6], 1, "EI_VERSION should be 1");
assert_eq!(obj_bytes[7], 0, "EI_OSABI should be 0 (ELFOSABI_NONE)");
let shoff = u64::from_le_bytes([
obj_bytes[40],
obj_bytes[41],
obj_bytes[42],
obj_bytes[43],
obj_bytes[44],
obj_bytes[45],
obj_bytes[46],
obj_bytes[47],
]);
if shoff > 0 {
assert!(
shoff < obj_bytes.len() as u64,
"Section header offset {} is beyond file size {}",
shoff,
obj_bytes.len()
);
}
} else {
eprintln!("No object bytes; ELF output validation skipped");
}
}
#[test]
fn golden_path_elf_multiple_functions_multiple_sections() {
let source = "\
int fn_a(void) { return 10; }
int fn_b(void) { return 20; }
int fn_c(void) { return 30; }
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_elf_multi_fn.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
if let Some(ref obj_bytes) = result.object_bytes {
assert!(
check_elf_magic(obj_bytes),
"Multiple functions should produce valid ELF"
);
assert!(
obj_bytes.len() > 100,
"Multiple functions should produce non-trivial object file"
);
}
}
#[test]
fn golden_path_optimization_level_o0() {
let mut pipeline = pipeline_with_opt(X86OptLevel::O0);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_o0.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"O0: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "O0 output should have ELF magic");
}
}
#[test]
fn golden_path_optimization_level_o1() {
let mut pipeline = pipeline_with_opt(X86OptLevel::O1);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_o1.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"O1: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "O1 output should have ELF magic");
}
}
#[test]
fn golden_path_optimization_level_o2() {
let mut pipeline = pipeline_with_opt(X86OptLevel::O2);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_o2.c");
std::fs::write(
&tmp_file,
"int compute(int n) { int s = 0; for (int i = 0; i < n; i++) { s += i; } return s; }",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"O2: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "O2 output should have ELF magic");
}
}
#[test]
fn golden_path_optimization_level_o3() {
let mut pipeline = pipeline_with_opt(X86OptLevel::O3);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_o3.c");
std::fs::write(&tmp_file, "int main(void) { return 42; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"O3: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "O3 output should have ELF magic");
}
}
#[test]
fn golden_path_optimization_level_os() {
let mut pipeline = pipeline_with_opt(X86OptLevel::Os);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_os.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Os: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "Os output should have ELF magic");
}
}
#[test]
fn golden_path_optimization_level_oz() {
let mut pipeline = pipeline_with_opt(X86OptLevel::Oz);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_oz.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Oz: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "Oz output should have ELF magic");
}
}
#[test]
fn golden_path_all_optimization_levels_produce_output() {
let levels = [
(X86OptLevel::O0, "O0"),
(X86OptLevel::O1, "O1"),
(X86OptLevel::O2, "O2"),
(X86OptLevel::O3, "O3"),
(X86OptLevel::Os, "Os"),
(X86OptLevel::Oz, "Oz"),
];
let tmp_dir = std::env::temp_dir();
let source = "int main(void) { return 42; }";
for (level, name) in &levels {
let mut pipeline = pipeline_with_opt(*level);
let tmp_file = tmp_dir.join(format!("golden_path_opt_{}.c", name));
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
assert!(
result.object_bytes.is_some() || result.llvm_ir.is_some() || !result.success,
"{} should at least produce a result struct",
name
);
if let Some(ref bytes) = result.object_bytes {
assert!(
check_elf_magic(bytes),
"{} output should have ELF magic",
name
);
}
eprintln!(
" Opt {}: success={}, bytes={}",
name,
result.success,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0)
);
}
}
#[test]
fn golden_path_optimization_differs_across_levels() {
let source = "\
int heavy_compute(int n) {
int total = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
total += i * j + n;
}
}
return total;
}
";
let tmp_dir = std::env::temp_dir();
let mut pipeline_o0 = pipeline_with_opt(X86OptLevel::O0);
let tmp_file_o0 = tmp_dir.join("golden_path_heavy_o0.c");
std::fs::write(&tmp_file_o0, source).expect("Failed to write temp source");
let result_o0 = pipeline_o0
.compile_file_demo(&tmp_file_o0)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file_o0);
let mut pipeline_o2 = pipeline_with_opt(X86OptLevel::O2);
let tmp_file_o2 = tmp_dir.join("golden_path_heavy_o2.c");
std::fs::write(&tmp_file_o2, source).expect("Failed to write temp source");
let result_o2 = pipeline_o2
.compile_file_demo(&tmp_file_o2)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file_o2);
let size_o0 = result_o0
.object_bytes
.as_ref()
.map(|b| b.len())
.unwrap_or(0);
let size_o2 = result_o2
.object_bytes
.as_ref()
.map(|b| b.len())
.unwrap_or(0);
eprintln!("O0 object size: {}, O2 object size: {}", size_o0, size_o2);
if result_o0.success && result_o2.success {
assert!(size_o0 > 0, "O0 should produce non-empty output");
assert!(size_o2 > 0, "O2 should produce non-empty output");
}
}
#[test]
fn golden_path_standard_c89() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C89);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_c89.c");
std::fs::write(
&tmp_file,
"\
int main(argc, argv)
int argc;
char *argv[];
{
return 0;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C89: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_c99() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C99);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_c99.c");
std::fs::write(
&tmp_file,
"\
#include <stdbool.h>
int main(void) {
bool flag = true;
for (int i = 0; i < 10; i++) {
if (flag) {
return i;
}
}
return -1;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C99: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_c11() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C11);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_c11.c");
std::fs::write(
&tmp_file,
"\
struct container {
union {
int i;
float f;
};
};
_Static_assert(sizeof(int) == 4, \"int is not 4 bytes\");
int main(void) {
struct container c;
c.i = 42;
return c.i;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C11: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_c17() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_c17.c");
std::fs::write(
&tmp_file,
"\
int main(void) {
int arr[10];
for (int i = 0; i < 10; i++) {
arr[i] = i * i;
}
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += arr[i];
}
return sum;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C17: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_c23() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C23);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_c23.c");
std::fs::write(
&tmp_file,
"\
int main(void) {
auto arr = { 1, 2, 3, 4, 5 };
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += arr[i];
}
return sum;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C23: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_gnu17() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::Gnu17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_gnu17.c");
std::fs::write(
&tmp_file,
"\
int main(void) {
int x = 42;
__typeof__(x) y = x + 1;
return y - 1;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Gnu17: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_cpp17() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::Cpp17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_cpp17.cpp");
std::fs::write(
&tmp_file,
"\
namespace ns {
int calculate(int a, int b) {
return a * b + b;
}
}
int main() {
auto result = ns::calculate(5, 3);
return result;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C++17: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_cpp20() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::Cpp20);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_cpp20.cpp");
std::fs::write(
&tmp_file,
"\
consteval int square(int x) {
return x * x;
}
int main() {
int arr[square(4)];
arr[0] = 42;
return arr[0];
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C++20: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_cpp23() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::Cpp23);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_cpp23.cpp");
std::fs::write(
&tmp_file,
"\
int main() {
int x = 10;
if (auto result = x + 5; result > 10) {
return result;
}
return 0;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C++23: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_standard_cpp98() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::Cpp98);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_cpp98.cpp");
std::fs::write(
&tmp_file,
"\
int main() {
int x = 42;
int y = 10;
int z = x + y;
return z;
}
",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"C++98: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_is_cxx_flag() {
assert!(!X86LanguageStandard::C89.is_cxx(), "C89 should not be C++");
assert!(!X86LanguageStandard::C17.is_cxx(), "C17 should not be C++");
assert!(!X86LanguageStandard::C23.is_cxx(), "C23 should not be C++");
assert!(X86LanguageStandard::Cpp98.is_cxx(), "C++98 should be C++");
assert!(X86LanguageStandard::Cpp11.is_cxx(), "C++11 should be C++");
assert!(X86LanguageStandard::Cpp14.is_cxx(), "C++14 should be C++");
assert!(X86LanguageStandard::Cpp17.is_cxx(), "C++17 should be C++");
assert!(X86LanguageStandard::Cpp20.is_cxx(), "C++20 should be C++");
assert!(X86LanguageStandard::Cpp23.is_cxx(), "C++23 should be C++");
assert!(
X86LanguageStandard::GnuPp98.is_cxx(),
"Gnu++98 should be C++"
);
assert!(
X86LanguageStandard::GnuPp11.is_cxx(),
"Gnu++11 should be C++"
);
assert!(
X86LanguageStandard::GnuPp14.is_cxx(),
"Gnu++14 should be C++"
);
assert!(
X86LanguageStandard::GnuPp17.is_cxx(),
"Gnu++17 should be C++"
);
assert!(
X86LanguageStandard::GnuPp20.is_cxx(),
"Gnu++20 should be C++"
);
}
#[test]
fn golden_path_language_standard_as_str() {
assert_eq!(X86LanguageStandard::C89.as_str(), "c89");
assert_eq!(X86LanguageStandard::C99.as_str(), "c99");
assert_eq!(X86LanguageStandard::C11.as_str(), "c11");
assert_eq!(X86LanguageStandard::C17.as_str(), "c17");
assert_eq!(X86LanguageStandard::C23.as_str(), "c23");
assert_eq!(X86LanguageStandard::Gnu89.as_str(), "gnu89");
assert_eq!(X86LanguageStandard::Gnu99.as_str(), "gnu99");
assert_eq!(X86LanguageStandard::Gnu11.as_str(), "gnu11");
assert_eq!(X86LanguageStandard::Gnu17.as_str(), "gnu17");
assert_eq!(X86LanguageStandard::Cpp98.as_str(), "c++98");
assert_eq!(X86LanguageStandard::Cpp11.as_str(), "c++11");
assert_eq!(X86LanguageStandard::Cpp14.as_str(), "c++14");
assert_eq!(X86LanguageStandard::Cpp17.as_str(), "c++17");
assert_eq!(X86LanguageStandard::Cpp20.as_str(), "c++20");
assert_eq!(X86LanguageStandard::Cpp23.as_str(), "c++23");
assert_eq!(X86LanguageStandard::GnuPp98.as_str(), "gnu++98");
assert_eq!(X86LanguageStandard::GnuPp11.as_str(), "gnu++11");
assert_eq!(X86LanguageStandard::GnuPp14.as_str(), "gnu++14");
assert_eq!(X86LanguageStandard::GnuPp17.as_str(), "gnu++17");
assert_eq!(X86LanguageStandard::GnuPp20.as_str(), "gnu++20");
}
#[test]
fn golden_path_include_standard_header() {
let mut pipeline = X86E2EPipeline::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
include_paths: vec![PathBuf::from("/usr/include")],
..Default::default()
});
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_include_std.c");
std::fs::write(
&tmp_file,
"#include <stddef.h>\nint main(void) { size_t x = sizeof(int); return (int)x; }",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"include_std: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_include_stdlib() {
let mut pipeline = X86E2EPipeline::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
include_paths: vec![PathBuf::from("/usr/include")],
..Default::default()
});
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_include_stdlib.c");
std::fs::write(
&tmp_file,
"#include <stdlib.h>\nint main(void) { int *p = malloc(64); if (p) { free(p); return 0; } return 1; }",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"include_stdlib: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_include_stdio() {
let mut pipeline = X86E2EPipeline::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
include_paths: vec![PathBuf::from("/usr/include")],
..Default::default()
});
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_include_stdio.c");
std::fs::write(
&tmp_file,
"#include <stdio.h>\nint main(void) { printf(\"hello\\n\"); return 0; }",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"include_stdio: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_include_user_header() {
let mut pipeline = X86E2EPipeline::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
include_paths: vec![PathBuf::from("/tmp")],
..Default::default()
});
let header_path = std::env::temp_dir().join("golden_path_test_helper.h");
let header_content = "\
#ifndef GOLDEN_PATH_TEST_HELPER_H
#define GOLDEN_PATH_TEST_HELPER_H
#define TEST_VALUE 42
int helper_add(int a, int b);
#endif
";
std::fs::write(&header_path, header_content).expect("Failed to write user header");
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_include_user.c");
std::fs::write(
&tmp_file,
"#include \"golden_path_test_helper.h\"\nint main(void) { return TEST_VALUE; }",
)
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
let _ = std::fs::remove_file(&header_path);
eprintln!(
"include_user: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_define_macro_then_use() {
let source = "\
#define BUFFER_SIZE 256
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main(void) {
int buf[BUFFER_SIZE];
int a = 10;
int b = 20;
int m = MAX(a, b);
buf[0] = m;
return buf[0];
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_macro.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"macro_define: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_conditional_compilation() {
let source = "\
#define DEBUG 1
int main(void) {
int result = 0;
#ifdef DEBUG
result = 42;
#else
result = -1;
#endif
return result;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_ifdef.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"conditional_comp: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_pipeline_stages_reporting() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_stages.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
assert!(
!result.stage_results.is_empty(),
"Expected at least one stage result"
);
let stage_names: Vec<&str> = result
.stage_results
.iter()
.map(|sr| sr.stage.name())
.collect();
eprintln!("Pipeline stages executed: {:?}", stage_names);
assert!(
result.total_duration.as_nanos() > 0,
"Total duration should be non-zero"
);
}
#[test]
fn golden_path_pipeline_file_source_lines() {
let content = "int main(void) { return 0; }\n";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_lines.c");
std::fs::write(&tmp_file, content).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
assert!(result.source_lines > 0, "Source lines should be > 0");
assert_eq!(
result.source_file.file_name().unwrap(),
"golden_path_lines.c",
"Source file name should be preserved"
);
}
#[test]
fn golden_path_pipeline_machine_instrs_tracked() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_instrs.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Machine instructions (tracked): {}",
result.machine_instructions
);
}
#[test]
fn golden_path_pipeline_output_size_tracked() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_out_size.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
if result.success {
assert!(
result.output_size > 0,
"Output size should be > 0 for successful compilations"
);
}
}
#[test]
fn golden_path_pipeline_error_diagnostics() {
let source = "int main(void) { return; }";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
pipeline.options.werror = true;
pipeline.options.wall = true;
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_error.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Error test: success={}, errors={}, warnings={}",
result.success,
result.error_count(),
result.warning_count()
);
assert!(
result.success || result.error_count() > 0,
"Either compilation succeeds or errors are reported"
);
}
#[test]
fn golden_path_pipeline_syntax_error_reporting() {
let source = "int main(void { return 0 }";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_syntax_error.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Syntax error test: success={}, errors={}, diags={}",
result.success,
result.error_count(),
result.diagnostics.len()
);
}
#[test]
fn golden_path_pipeline_compilation_session() {
let mut session = CompilationSession::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
..Default::default()
});
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_session.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
session.add_job(&tmp_file);
let results = session.run().expect("Session should complete");
let _ = std::fs::remove_file(&tmp_file);
assert!(
!results.is_empty(),
"Session should produce at least one result"
);
eprintln!(
"Session: {} file(s) compiled, {} succeeded, {} failed",
session.pipeline.stats.files_compiled,
session.pipeline.stats.successful,
session.pipeline.stats.failed,
);
}
#[test]
fn golden_path_pipeline_with_explicit_defines() {
let mut defines = std::collections::HashMap::new();
defines.insert("VALUE".into(), Some("42".into()));
let pipeline = X86E2EPipeline::new(X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
defines,
..Default::default()
});
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_defines.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let mut p = pipeline;
let result = p
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Defines pipeline: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_compilation_cache_functional() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_cache_test.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result1 = pipeline
.compile_file_demo(&tmp_file)
.expect("First compilation should complete");
let bytes1 = result1.object_bytes.clone();
let result2 = pipeline
.compile_file_demo(&tmp_file)
.expect("Second compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Cache stats: hits={}, misses={}, evictions={}",
pipeline.stats.cache_stats.hits,
pipeline.stats.cache_stats.misses,
pipeline.stats.cache_stats.evictions,
);
eprintln!(
"Files compiled: {}, successful: {}",
pipeline.stats.files_compiled, pipeline.stats.successful
);
if result1.success && result2.success {
assert!(
result2.object_bytes.is_some(),
"Second compilation should produce output"
);
}
}
#[test]
fn golden_path_source_file_from_string() {
let source = SourceFile::from_string(
"test.c",
"int main(void) { return 0; }",
X86LanguageStandard::C17,
);
assert_eq!(source.path.to_string_lossy(), "test.c");
assert_eq!(source.content, "int main(void) { return 0; }");
assert_eq!(source.language, X86LanguageStandard::C17);
assert!(source.is_primary);
assert!(source.dependencies.is_empty());
assert!(source.preprocessed.is_none());
assert!(source.modified.is_none());
}
#[test]
fn golden_path_source_file_content_hash() {
let source = SourceFile::from_string("a.c", "int x = 42;", X86LanguageStandard::C17);
let hash1 = source.content_hash();
let source2 = SourceFile::from_string("b.c", "int x = 42;", X86LanguageStandard::C17);
let hash2 = source2.content_hash();
assert_eq!(
hash1, hash2,
"Content hash should be independent of filename"
);
let source3 = SourceFile::from_string("c.c", "int x = 99;", X86LanguageStandard::C17);
let hash3 = source3.content_hash();
assert_ne!(
hash1, hash3,
"Different content should produce different hash"
);
}
#[test]
fn golden_path_source_file_language_detection() {
assert_eq!(
SourceFile::detect_language(&PathBuf::from("foo.c")),
Some(X86LanguageStandard::C17)
);
assert_eq!(
SourceFile::detect_language(&PathBuf::from("foo.cpp")),
Some(X86LanguageStandard::Cpp17)
);
assert_eq!(
SourceFile::detect_language(&PathBuf::from("foo.cc")),
Some(X86LanguageStandard::Cpp17)
);
assert_eq!(
SourceFile::detect_language(&PathBuf::from("foo.cxx")),
Some(X86LanguageStandard::Cpp17)
);
assert_eq!(SourceFile::detect_language(&PathBuf::from("foo.h")), None);
assert_eq!(SourceFile::detect_language(&PathBuf::from("foo.rs")), None);
}
#[test]
fn golden_path_x86_opt_level_display() {
assert_eq!(format!("{}", X86OptLevel::O0), "-O0");
assert_eq!(format!("{}", X86OptLevel::O1), "-O1");
assert_eq!(format!("{}", X86OptLevel::O2), "-O2");
assert_eq!(format!("{}", X86OptLevel::O3), "-O3");
assert_eq!(format!("{}", X86OptLevel::Os), "-Os");
assert_eq!(format!("{}", X86OptLevel::Oz), "-Oz");
}
#[test]
fn golden_path_x86_opt_level_from_str() {
assert_eq!(X86OptLevel::from_str("0"), Some(X86OptLevel::O0));
assert_eq!(X86OptLevel::from_str("O1"), Some(X86OptLevel::O1));
assert_eq!(X86OptLevel::from_str("-O2"), Some(X86OptLevel::O2));
assert_eq!(X86OptLevel::from_str("3"), Some(X86OptLevel::O3));
assert_eq!(X86OptLevel::from_str("s"), Some(X86OptLevel::Os));
assert_eq!(X86OptLevel::from_str("Oz"), Some(X86OptLevel::Oz));
assert_eq!(X86OptLevel::from_str("invalid"), None);
}
#[test]
fn golden_path_x86_opt_level_default() {
assert_eq!(X86OptLevel::default(), X86OptLevel::O0);
}
#[test]
fn golden_path_x86_e2e_options_default() {
let opts = X86E2EOptions::default();
assert_eq!(opts.opt_level, X86OptLevel::O2);
assert_eq!(opts.language, X86LanguageStandard::C17);
assert_eq!(opts.output_format, X86OutputFormat::ElfObject);
assert!(!opts.debug_info);
assert!(opts.wall);
assert!(!opts.werror);
assert!(opts.include_paths.is_empty());
assert!(opts.defines.is_empty());
assert!(opts.extra_flags.is_empty());
assert!(opts.output_file.is_none());
assert_eq!(opts.jobs, 1);
assert!(!opts.lto);
assert!(!opts.thin_lto);
assert!(opts.target_triple.is_none());
assert_eq!(opts.template_depth, 1024);
assert_eq!(opts.constexpr_steps, 1_048_576);
}
#[test]
fn golden_path_x86_output_format_extension() {
assert_eq!(X86OutputFormat::ElfObject.extension(), ".o");
assert_eq!(X86OutputFormat::MachOObject.extension(), ".o");
assert_eq!(X86OutputFormat::CoffObject.extension(), ".obj");
assert_eq!(X86OutputFormat::Assembly.extension(), ".s");
assert_eq!(X86OutputFormat::LlvmIr.extension(), ".ll");
assert_eq!(X86OutputFormat::LlvmBc.extension(), ".bc");
assert_eq!(X86OutputFormat::Preprocessed.extension(), ".i");
}
#[test]
fn golden_path_x86_pipeline_stages() {
let stages = X86PipelineStage::all_stages();
assert_eq!(stages.len(), 15, "Expected 15 pipeline stages");
let expected_order = [
"read-source",
"preprocess",
"lex",
"parse",
"sema",
"codegen",
"optimize",
"lower-to-dag",
"isel",
"regalloc",
"schedule",
"frame-lower",
"encode",
"emit-object",
"write-output",
];
for (i, stage) in stages.iter().enumerate() {
assert_eq!(
stage.name(),
expected_order[i],
"Stage {} should be '{}'",
i,
expected_order[i]
);
}
}
#[test]
fn golden_path_x86_pipeline_stage_display() {
assert_eq!(format!("{}", X86PipelineStage::ReadSource), "read-source");
assert_eq!(format!("{}", X86PipelineStage::Lex), "lex");
assert_eq!(format!("{}", X86PipelineStage::Parse), "parse");
assert_eq!(format!("{}", X86PipelineStage::Sema), "sema");
assert_eq!(format!("{}", X86PipelineStage::CodeGen), "codegen");
assert_eq!(format!("{}", X86PipelineStage::Optimize), "optimize");
assert_eq!(format!("{}", X86PipelineStage::Encode), "encode");
assert_eq!(format!("{}", X86PipelineStage::EmitObject), "emit-object");
}
#[test]
fn golden_path_compile_diagnostic_creation() {
let err = CompileDiagnostic::error("something went wrong");
assert_eq!(err.message, "something went wrong");
assert!(err.file.is_none());
assert!(err.line.is_none());
assert!(err.column.is_none());
let warn = CompileDiagnostic::warning("be careful");
assert_eq!(warn.message, "be careful");
let note = CompileDiagnostic::note("here is some info");
assert_eq!(note.message, "here is some info");
let err_with_loc = CompileDiagnostic {
level: crate::clang::clang_x86_e2e_pipeline_full::DiagLevel::Error,
message: "undefined reference".into(),
file: Some(PathBuf::from("test.c")),
line: Some(42),
column: Some(10),
category: Some("linker".into()),
fixit: Some("add #include".into()),
};
let display = format!("{}", err_with_loc);
assert!(display.contains("test.c"));
assert!(display.contains("42"));
assert!(display.contains("10"));
assert!(display.contains("undefined reference"));
}
#[test]
fn golden_path_x86_e2e_result_helpers() {
let opts = X86E2EOptions::default();
let result = X86E2EResult {
success: false,
object_bytes: None,
assembly_text: None,
llvm_ir: None,
stage_results: vec![],
diagnostics: vec![
CompileDiagnostic::error("error 1"),
CompileDiagnostic::error("error 2"),
CompileDiagnostic::warning("warning 1"),
],
total_duration: Duration::from_secs(1),
source_file: PathBuf::from("test.c"),
output_file: None,
source_lines: 10,
machine_instructions: 100,
output_size: 0,
options: opts,
};
assert!(result.has_errors());
assert_eq!(result.error_count(), 2);
assert_eq!(result.warning_count(), 1);
let result_ok = X86E2EResult {
success: true,
diagnostics: vec![],
..result
};
assert!(!result_ok.has_errors());
assert_eq!(result_ok.error_count(), 0);
assert_eq!(result_ok.warning_count(), 0);
}
#[test]
fn golden_path_compilation_cache_operations() {
let mut cache = CompilationCache::new(10);
let key_path = PathBuf::from("test.c");
assert!(cache.is_empty());
assert_eq!(cache.len(), 0);
cache.insert(&key_path, 42, 99, vec![1, 2, 3, 4]);
assert!(!cache.is_empty());
assert_eq!(cache.len(), 1);
let result = cache.lookup(&key_path, 42, 99);
assert_eq!(result, Some(vec![1, 2, 3, 4]));
assert_eq!(cache.stats.hits, 1);
assert_eq!(cache.stats.misses, 0);
let miss = cache.lookup(&key_path, 0, 99);
assert_eq!(miss, None);
assert_eq!(cache.stats.misses, 1);
cache.clear();
assert!(cache.is_empty());
}
#[test]
fn golden_path_compilation_cache_eviction() {
let mut cache = CompilationCache::new(2);
cache.insert(&PathBuf::from("a.c"), 1, 1, vec![10]);
cache.insert(&PathBuf::from("b.c"), 2, 2, vec![20]);
assert_eq!(cache.len(), 2);
cache.insert(&PathBuf::from("c.c"), 3, 3, vec![30]);
assert_eq!(cache.len(), 2);
assert!(cache.stats.evictions >= 1);
}
#[test]
fn golden_path_stage_result_creation() {
let stage = X86PipelineStage::Lex;
let sr = StageResult::new(stage, true, Duration::from_millis(100));
assert_eq!(sr.stage, X86PipelineStage::Lex);
assert!(sr.success);
assert_eq!(sr.duration.as_millis(), 100);
assert!(sr.output.is_none());
assert!(sr.diagnostics.is_empty());
assert!(sr.metadata.is_empty());
}
#[test]
fn golden_path_complex_type_tokens() {
let source = "\
unsigned long long int huge;
long double ld_val;
const volatile int * restrict ptr;
_Bool flag;
";
let tokens = lex_source(source, CLangStandard::C17);
let kinds: Vec<TokenKind> = tokens.iter().map(|t| t.kind).collect();
assert!(kinds.contains(&TokenKind::KwUnsigned));
assert!(kinds.contains(&TokenKind::KwLong));
assert!(kinds.contains(&TokenKind::KwDouble));
assert!(kinds.contains(&TokenKind::KwConst));
assert!(kinds.contains(&TokenKind::KwVolatile));
assert!(kinds.contains(&TokenKind::KwRestrict));
assert!(kinds.contains(&TokenKind::KwBool));
assert!(kinds.contains(&TokenKind::Star));
assert!(kinds.contains(&TokenKind::Identifier));
}
#[test]
fn golden_path_preprocessor_conditionals() {
let source = "\
#define FOO 1
#if FOO
int x = 10;
#else
int x = 20;
#endif
int main(void) { return x; }
";
let _tokens = lex_source(source, CLangStandard::C17);
eprintln!("Preprocessor conditional tokens lexed successfully");
}
#[test]
fn golden_path_empty_file_via_pipeline() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_empty.c");
std::fs::write(&tmp_file, "").expect("Failed to write empty temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline should handle empty file");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Empty file: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_long_function_name() {
let source = "\
int this_is_a_very_long_function_name_with_many_characters(void) {
return 42;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_long_name.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline should handle long function names");
let _ = std::fs::remove_file(&tmp_file);
eprintln!("Long function name: success={}", result.success);
}
#[test]
fn golden_path_nested_control_flow() {
let source = "\
int complex_nesting(int a, int b, int c, int d) {
if (a > 0) {
if (b > 0) {
if (c > 0) {
if (d > 0) {
return a + b + c + d;
} else {
return a + b + c;
}
} else {
return a + b;
}
} else {
return a;
}
}
return 0;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_nested.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline should handle deep nesting");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Nested if: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_while_loop_pipeline() {
let source = "\
int while_count(int limit) {
int count = 0;
int i = 0;
while (i < limit) {
count = count + 1;
i = i + 1;
}
return count;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_while.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline should handle while loops");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"While loop: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_for_loop_pipeline() {
let source = "\
int for_sum(int n) {
int total = 0;
for (int i = 0; i < n; i++) {
total = total + i;
}
return total;
}
";
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_for.c");
std::fs::write(&tmp_file, source).expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline should handle for loops");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"For loop: success={}, bytes={:?}",
result.success,
result.object_bytes.as_ref().map(|b| b.len())
);
}
#[test]
fn golden_path_pipeline_summary_no_panic() {
let mut pipeline = pipeline_with_language(X86LanguageStandard::C17);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_summary.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
result.print_summary();
}
#[test]
fn golden_path_pipeline_elf_output_format_explicit() {
let opts = X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::ElfObject,
target_cpu: X86TargetCPU::X86_64,
..Default::default()
};
let mut pipeline = X86E2EPipeline::new(opts);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_elf_explicit.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
if let Some(ref bytes) = result.object_bytes {
assert!(check_elf_magic(bytes), "ELF output should have magic");
}
}
#[test]
fn golden_path_pipeline_llvm_ir_output_format() {
let opts = X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::LlvmIr,
target_cpu: X86TargetCPU::X86_64,
..Default::default()
};
let mut pipeline = X86E2EPipeline::new(opts);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_llvm_ir.c");
std::fs::write(&tmp_file, "int main(void) { return 0; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"LLVM IR mode: success={}, ir_len={:?}",
result.success,
result.llvm_ir.as_ref().map(|s| s.len())
);
if let Some(ref ir) = result.llvm_ir {
assert!(
ir.contains("target triple") || ir.contains("ModuleID"),
"IR output should contain LLVM IR metadata: {}",
ir.chars().take(200).collect::<String>()
);
}
}
#[test]
fn golden_path_pipeline_preprocessed_format() {
let opts = X86E2EOptions {
language: X86LanguageStandard::C17,
opt_level: X86OptLevel::O0,
output_format: X86OutputFormat::Preprocessed,
target_cpu: X86TargetCPU::X86_64,
..Default::default()
};
let mut pipeline = X86E2EPipeline::new(opts);
let tmp_dir = std::env::temp_dir();
let tmp_file = tmp_dir.join("golden_path_preprocessed.c");
std::fs::write(&tmp_file, "#define X 42\nint main(void) { return X; }")
.expect("Failed to write temp source");
let result = pipeline
.compile_file_demo(&tmp_file)
.expect("Pipeline compilation should complete");
let _ = std::fs::remove_file(&tmp_file);
eprintln!(
"Preprocessed mode: success={}, ir_len={:?}",
result.success,
result.llvm_ir.as_ref().map(|s| s.len())
);
}
#[test]
fn llvm_original_c_sources_pipeline_survivability_demo() {
let src_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.parent()
.unwrap()
.join("fixtures/llvm-c-src");
assert!(
src_dir.exists(),
"LLVM C source directory not found: {:?}",
src_dir
);
let opts = X86E2EOptions {
opt_level: X86OptLevel::O0,
target_cpu: X86TargetCPU::X86_64,
output_format: X86OutputFormat::ElfObject,
language: X86LanguageStandard::C17,
wall: false,
werror: false,
..Default::default()
};
let mut pipeline = X86E2EPipeline::new(opts);
let mut passed = 0u32;
let mut failed = 0u32;
let mut functions_extracted = 0u32;
let mut total = 0u32;
let mut failures: Vec<String> = Vec::new();
let mut entries: Vec<_> = walkdir_c_files(&src_dir);
entries.sort();
total = entries.len() as u32;
assert_eq!(
total, 196,
"expected exactly 196 LLVM C source files, found {}",
total
);
let compiler_rt = entries
.iter()
.filter(|p| p.to_string_lossy().contains("compiler-rt/builtins/"))
.count();
let libunwind = entries
.iter()
.filter(|p| p.to_string_lossy().contains("libunwind/src/"))
.count();
let clang_tools = entries
.iter()
.filter(|p| p.to_string_lossy().contains("clang/tools/"))
.count();
assert_eq!(
compiler_rt, 181,
"expected 181 compiler-rt files, found {}",
compiler_rt
);
assert_eq!(
libunwind, 4,
"expected 4 libunwind files, found {}",
libunwind
);
assert_eq!(
clang_tools, 1,
"expected 1 clang-tools file, found {}",
clang_tools
);
for entry in &entries {
let rel = entry.strip_prefix(&src_dir).unwrap_or(entry);
let rel_str = rel.to_string_lossy().to_string();
match pipeline.compile_file_demo(entry) {
Ok(result) => {
let no_panic = true;
let has_object = result.object_bytes.is_some();
let func_count = result
.stage_results
.iter()
.flat_map(|sr| &sr.metadata)
.filter(|(k, _v)| k.as_str() == "functions_found")
.count();
functions_extracted += func_count as u32;
if !no_panic {
failed += 1;
failures.push(format!("{}: panicked", rel_str));
eprintln!(
" FAIL [{:>3}/{}]: {} - panicked",
passed + failed,
total,
rel_str
);
} else if !has_object {
failed += 1;
failures.push(format!("{}: no object bytes", rel_str));
eprintln!(
" FAIL [{:>3}/{}]: {} - no object bytes",
passed + failed,
total,
rel_str
);
} else {
passed += 1;
let has_functions = func_count > 0;
let marker = if has_functions { "+funcs" } else { "stub" };
eprintln!(
" PASS [{:>3}/{}]: {} [{}] ({} bytes, {} functions)",
passed + failed,
total,
rel_str,
marker,
result.object_bytes.as_ref().map(|b| b.len()).unwrap_or(0),
func_count
);
}
}
Err(e) => {
failed += 1;
failures.push(format!("{}: IO error: {}", rel_str, e));
eprintln!(
" FAIL [{:>3}/{}]: {} - IO error: {}",
passed + failed,
total,
rel_str,
e
);
}
}
}
eprintln!();
eprintln!("╔══════════════════════════════════════════════════════════════╗");
eprintln!("║ LLVM.ORIGINAL.C.1 — TOY PIPELINE SURVIVABILITY (DEMO) ║");
eprintln!("╠══════════════════════════════════════════════════════════════╣");
eprintln!(
"║ Total: {:>5} files (rt={}, unw={}, tools={}) ║",
total, compiler_rt, libunwind, clang_tools
);
eprintln!(
"║ Pass: {:>5} files (no panic + ELF emitted) ║",
passed
);
eprintln!(
"║ Fail: {:>5} files ║",
failed
);
eprintln!(
"║ Functions extracted by toy parser: {:>5} ║",
functions_extracted
);
eprintln!("╚══════════════════════════════════════════════════════════════╝");
eprintln!();
eprintln!("⚠ THIS IS A DEMO TEST — NOT A SEALED COURT");
eprintln!();
eprintln!("The toy pipeline (X86E2EPipeline) is NOT the real Clang frontend.");
eprintln!("It does NOT resolve includes, expand macros, type-check, or");
eprintln!("perform semantic analysis. Functions found by the brace scanner");
eprintln!("get synthetic IR with empty params and ret 0. Files with zero");
eprintln!("extracted functions get a _start: exit(0) ELF stub.");
eprintln!();
eprintln!("The real Clang frontend (clang/lexer.rs, parser.rs, sema.rs,");
eprintln!("codegen.rs) is NOT invoked by this test. That is the work of");
eprintln!("the next court: LLVM.ORIGINAL.C.SYMBOLS.1.");
eprintln!();
assert!(
failed == 0,
"{} files caused panics/errors:\n{}",
failed,
failures.join("\n")
);
assert!(
passed == total,
"Not all files survived: {}/{} passed",
passed,
total
);
eprintln!("Pipeline survivability verified: {} files, {} survived, {} functions extracted by toy parser.",
total, passed, functions_extracted);
}
fn walkdir_c_files(dir: &Path) -> Vec<PathBuf> {
let mut files = Vec::new();
if !dir.is_dir() {
return files;
}
let mut stack = vec![dir.to_path_buf()];
while let Some(cur) = stack.pop() {
if let Ok(entries) = std::fs::read_dir(&cur) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
stack.push(path);
} else if path.extension().and_then(|s| s.to_str()) == Some("c") {
files.push(path);
}
}
}
}
files
}
}