use std::{fs, path::Path, process::Command}; #[test] fn struct_fixture_emits_llvm_field_read_shape() { let output = run_glagol(["../examples/struct.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "compiler rejected struct fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert!( stdout.contains("define i32 @point_sum()") && stdout.contains("insertvalue { i32, i32 }") && stdout.contains("extractvalue { i32, i32 }") && stdout.contains("define i32 @main()"), "LLVM output did not contain expected struct field-read shape\nstdout:\n{}", stdout ); assert!( !stdout.contains("struct field access"), "compiler emitted test metadata into LLVM output\nstdout:\n{}", stdout ); assert!( !stdout.contains("type {"), "first-pass struct fixture should not emit aggregate layout promises\nstdout:\n{}", stdout ); assert!(stderr.is_empty(), "compiler wrote stderr:\n{}", stderr); } #[test] fn struct_value_flow_fixture_emits_llvm_aggregate_shape() { let output = run_glagol(["../examples/struct-value-flow.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "compiler rejected struct value-flow fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert!( stdout.contains("define { i32, i32 } @make_point(i32 %x, i32 %y)") && stdout.contains("define i32 @point_x({ i32, i32 } %p)") && stdout.contains("define i32 @point_sum({ i32, i32 } %p)") && stdout.contains("alloca { i32, i32 }") && stdout.contains("call i32 @point_sum({ i32, i32 }"), "LLVM output did not contain expected struct value-flow shape\nstdout:\n{}", stdout ); assert!( !stdout.contains("type {"), "struct value-flow fixture should not emit named layout promises\nstdout:\n{}", stdout ); assert!(stderr.is_empty(), "compiler wrote stderr:\n{}", stderr); } #[test] fn struct_fixture_runs_top_level_tests() { let output = run_glagol(["--run-tests", "../examples/struct.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "test runner rejected struct fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert_eq!( stdout, concat!( "test \"struct field access\" ... ok\n", "test \"struct field compares\" ... ok\n", "2 test(s) passed\n", ), "test runner output drifted" ); assert!(stderr.is_empty(), "test runner wrote stderr:\n{}", stderr); } #[test] fn struct_value_flow_fixture_runs_top_level_tests() { let output = run_glagol(["--run-tests", "../examples/struct-value-flow.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "test runner rejected struct value-flow fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert_eq!( stdout, concat!( "test \"struct local value flow\" ... ok\n", "test \"struct parameter value flow\" ... ok\n", "test \"stored struct field access\" ... ok\n", "3 test(s) passed\n", ), "test runner output drifted" ); assert!(stderr.is_empty(), "test runner wrote stderr:\n{}", stderr); } #[test] fn struct_fixture_is_formatter_stable() { let expected = fs::read_to_string("../tests/struct.slo").expect("read fixture"); let output = run_glagol(["--format", "../tests/struct.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "formatter rejected struct fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert_eq!(stdout, expected, "formatter output drifted"); assert!(stderr.is_empty(), "formatter wrote stderr:\n{}", stderr); } #[test] fn struct_value_flow_fixture_is_formatter_stable() { let expected = fs::read_to_string("../tests/struct-value-flow.slo").expect("read fixture"); let output = run_glagol(["--format", "../tests/struct-value-flow.slo"]); let stdout = String::from_utf8_lossy(&output.stdout); let stderr = String::from_utf8_lossy(&output.stderr); assert!( output.status.success(), "formatter rejected struct value-flow fixture\nstdout:\n{}\nstderr:\n{}", stdout, stderr ); assert_eq!(stdout, expected, "formatter output drifted"); assert!(stderr.is_empty(), "formatter wrote stderr:\n{}", stderr); } #[test] fn struct_fixture_prints_lowered_shape() { let surface = run_glagol(["--inspect-lowering=surface", "../examples/struct.slo"]); let surface_stdout = String::from_utf8_lossy(&surface.stdout); let surface_stderr = String::from_utf8_lossy(&surface.stderr); assert!( surface.status.success(), "surface lowering rejected struct fixture\nstdout:\n{}\nstderr:\n{}", surface_stdout, surface_stderr ); assert!( surface_stdout.contains("struct Point") && surface_stdout.contains("construct Point") && surface_stdout.contains("field-access x") && surface_stdout.contains("field-access y"), "surface lowering output lost struct shape\nstdout:\n{}", surface_stdout ); assert!( surface_stderr.is_empty(), "surface lowering wrote stderr:\n{}", surface_stderr ); let checked = run_glagol(["--inspect-lowering=checked", "../examples/struct.slo"]); let checked_stdout = String::from_utf8_lossy(&checked.stdout); let checked_stderr = String::from_utf8_lossy(&checked.stderr); assert!( checked.status.success(), "checked lowering rejected struct fixture\nstdout:\n{}\nstderr:\n{}", checked_stdout, checked_stderr ); assert!( checked_stdout.contains("struct Point") && checked_stdout.contains("construct Point : Point") && checked_stdout.contains("field-access x : i32") && checked_stdout.contains("field-access y : i32"), "checked lowering output lost typed struct shape\nstdout:\n{}", checked_stdout ); assert!( checked_stderr.is_empty(), "checked lowering wrote stderr:\n{}", checked_stderr ); } #[test] fn struct_value_flow_fixture_prints_lowered_shape() { let surface = run_glagol([ "--inspect-lowering=surface", "../examples/struct-value-flow.slo", ]); let surface_stdout = String::from_utf8_lossy(&surface.stdout); let surface_stderr = String::from_utf8_lossy(&surface.stderr); assert!( surface.status.success(), "surface lowering rejected struct value-flow fixture\nstdout:\n{}\nstderr:\n{}", surface_stdout, surface_stderr ); assert!( surface_stdout.contains("fn make_point(x: i32, y: i32) -> Point") && surface_stdout.contains("fn point_x(p: Point) -> i32") && surface_stdout.contains("local let p: Point") && surface_stdout.contains("field-access y"), "surface lowering output lost struct value-flow shape\nstdout:\n{}", surface_stdout ); assert!( surface_stderr.is_empty(), "surface lowering wrote stderr:\n{}", surface_stderr ); let checked = run_glagol([ "--inspect-lowering=checked", "../examples/struct-value-flow.slo", ]); let checked_stdout = String::from_utf8_lossy(&checked.stdout); let checked_stderr = String::from_utf8_lossy(&checked.stderr); assert!( checked.status.success(), "checked lowering rejected struct value-flow fixture\nstdout:\n{}\nstderr:\n{}", checked_stdout, checked_stderr ); assert!( checked_stdout.contains("fn make_point(x: i32, y: i32) -> Point") && checked_stdout.contains("fn point_x(p: Point) -> i32") && checked_stdout.contains("call make_point : Point") && checked_stdout.contains("var p : Point"), "checked lowering output lost typed struct value-flow shape\nstdout:\n{}", checked_stdout ); assert!( checked_stderr.is_empty(), "checked lowering wrote stderr:\n{}", checked_stderr ); } fn run_glagol(args: [&str; N]) -> std::process::Output { Command::new(env!("CARGO_BIN_EXE_glagol")) .args(args) .current_dir(Path::new(env!("CARGO_MANIFEST_DIR"))) .output() .expect("run glagol") }