use super::*;
use assura_ast::Spanned;
#[test]
fn ghost_fn_produces_no_output() {
let project =
codegen_ok("ghost fn spec_helper(x: Int) -> Bool\n ensures { result == true }\n");
let lib = &project.files[0].1;
assert!(
!lib.contains("fn spec_helper"),
"ghost fn should not appear in generated Rust code"
);
}
#[test]
fn non_ghost_fn_still_generated() {
let project = codegen_ok("fn normal_helper(x: Int) -> Int\n ensures { result >= 0 }\n");
let lib = &project.files[0].1;
assert!(
lib.contains("fn normal_helper"),
"non-ghost fn should appear in generated Rust code"
);
}
#[test]
fn ghost_block_erased_in_expr() {
let expr = Spanned::no_span(Expr::Ghost(Box::new(Spanned::no_span(Expr::Literal(
Literal::Bool(true),
)))));
let rust = expr_to_rust(&expr);
assert!(
rust.contains("ghost erased"),
"ghost block should generate erased marker, got: {rust}"
);
}
#[test]
fn lemma_fn_produces_no_output() {
let project = codegen_ok("lemma add_comm(a: Int, b: Int)\n ensures { a + b == b + a }\n");
let lib = &project.files[0].1;
assert!(
!lib.contains("fn add_comm"),
"lemma fn should not appear in generated Rust code"
);
}
#[test]
fn apply_expr_erased_in_codegen() {
let expr = Spanned::no_span(Expr::Apply {
lemma_name: "my_lemma".into(),
args: vec![Spanned::no_span(Expr::Literal(Literal::Int("42".into())))],
});
let rust = expr_to_rust(&expr);
assert!(
rust.contains("lemma my_lemma applied"),
"apply should generate erased comment, got: {rust}"
);
}
#[test]
fn match_expr_codegen() {
let expr = Spanned::no_span(Expr::Match {
scrutinee: Box::new(Spanned::no_span(Expr::Ident("status".into()))),
arms: vec![
assura_ast::MatchArm {
pattern: assura_ast::Pattern::Ident("Active".into()),
body: Spanned::no_span(Expr::Literal(Literal::Int("1".into()))),
},
assura_ast::MatchArm {
pattern: assura_ast::Pattern::Wildcard,
body: Spanned::no_span(Expr::Literal(Literal::Int("0".into()))),
},
],
});
let rust = expr_to_rust(&expr);
assert!(
rust.contains("match status"),
"should have match keyword: {rust}"
);
assert!(
rust.contains("Active => 1"),
"should have Active arm: {rust}"
);
assert!(rust.contains("_ => 0"), "should have wildcard arm: {rust}");
}
#[test]
fn match_without_wildcard_gets_fallback() {
let expr = Spanned::no_span(Expr::Match {
scrutinee: Box::new(Spanned::no_span(Expr::Ident("color".into()))),
arms: vec![
assura_ast::MatchArm {
pattern: assura_ast::Pattern::Constructor {
name: "Red".into(),
fields: vec![],
},
body: Spanned::no_span(Expr::Literal(Literal::Int("1".into()))),
},
assura_ast::MatchArm {
pattern: assura_ast::Pattern::Constructor {
name: "Blue".into(),
fields: vec![],
},
body: Spanned::no_span(Expr::Literal(Literal::Int("2".into()))),
},
],
});
let rust = expr_to_rust(&expr);
assert!(
rust.contains("_ => unreachable!"),
"match without wildcard should get fallback: {rust}"
);
}
#[test]
fn non_lemma_fn_still_generated() {
let project = codegen_ok("fn helper(n: Int) -> Int\n ensures { result >= 0 }\n");
let lib = &project.files[0].1;
assert!(
lib.contains("fn helper"),
"non-lemma fn should appear in generated Rust code"
);
}