use super::*;
fn parse_ok(src: &str) -> assura_parser::ast::SourceFile {
assura_parser::parse_unwrap(src)
}
#[test]
fn complexity_no_annotation_produces_no_errors() {
let source = parse_ok("contract Plain { requires { true } }");
let errs = run_complexity_bound_checks(&source);
assert!(
errs.is_empty(),
"no complexity clause should yield no errors"
);
}
#[test]
fn complexity_linear_unverified_produces_a48002() {
let source =
parse_ok(r#"contract Search { complexity linear requires { true } ensures { true } }"#);
let errs = run_complexity_bound_checks(&source);
assert!(
errs.iter().any(|e| e.code == "A48002"),
"expected A48002 for unverified complexity bound, got: {errs:?}"
);
}
#[test]
fn complexity_verified_does_not_produce_a48002() {
let source = parse_ok(
r#"contract Sort {
complexity linear
measured_complexity linear
requires { true }
}"#,
);
let errs = run_complexity_bound_checks(&source);
assert!(
!errs.iter().any(|e| e.code == "A48002"),
"verified bound should not emit A48002, got: {errs:?}"
);
}
#[test]
fn composition_no_extends_produces_no_errors() {
let source = parse_ok("contract Standalone { requires { true } }");
let errs = run_contract_composition_checks(&source);
assert!(
errs.is_empty(),
"no extends clause should yield no errors, got: {errs:?}"
);
}
#[test]
fn composition_extends_unknown_produces_a54001() {
let source = parse_ok(r#"contract Child { extends NonExistent requires { true } }"#);
let errs = run_contract_composition_checks(&source);
assert!(
errs.iter().any(|e| e.code == "A54001"),
"expected A54001 for extends unknown contract, got: {errs:?}"
);
}
#[test]
fn composition_extends_known_does_not_produce_a54001() {
let source = parse_ok(
r#"
contract Parent { requires { true } }
contract Child { extends Parent requires { true } }
"#,
);
let errs = run_contract_composition_checks(&source);
assert!(
!errs.iter().any(|e| e.code == "A54001"),
"extending a known contract should not emit A54001, got: {errs:?}"
);
}
#[test]
fn scoped_invariant_no_annotation_produces_no_errors() {
let source = parse_ok("contract Clean { requires { true } }");
let errs = run_scoped_invariant_checks(&source);
assert!(
errs.is_empty(),
"no suspend_invariant should yield no errors, got: {errs:?}"
);
}
#[test]
fn scoped_invariant_suspended_ref_in_ensures_produces_a52001() {
let source =
parse_ok(r#"contract Maintenance { suspend_invariant sorted requires { sorted > 0 } }"#);
let errs = run_scoped_invariant_checks(&source);
assert!(
errs.iter().any(|e| e.code == "A52001"),
"expected A52001 for suspended invariant referenced in clause, got: {errs:?}"
);
}
#[test]
fn scoped_invariant_restored_does_not_produce_a52001() {
let source = parse_ok(
r#"contract Maintenance {
suspend_invariant sorted
restore_invariant sorted
requires { sorted > 0 }
}"#,
);
let errs = run_scoped_invariant_checks(&source);
assert!(
!errs.iter().any(|e| e.code == "A52001"),
"restored invariant should not emit A52001, got: {errs:?}"
);
}
#[test]
fn behavioral_equivalence_no_annotation_produces_no_errors() {
let source = parse_ok("contract Simple { requires { true } }");
let errs = run_behavioral_equivalence_checks(&source);
assert!(
errs.is_empty(),
"no equivalent clause should yield no errors, got: {errs:?}"
);
}
#[test]
fn behavioral_equivalence_unverified_produces_a49001() {
let source = parse_ok(r#"contract Equiv { equivalent impl_a == impl_b requires { true } }"#);
let errs = run_behavioral_equivalence_checks(&source);
assert!(
errs.iter().any(|e| e.code == "A49001"),
"expected A49001 for unverified behavioral equivalence, got: {errs:?}"
);
}
#[test]
fn behavioral_equivalence_self_equiv_produces_a49002() {
let source = parse_ok(r#"contract Equiv { equivalent same == same requires { true } }"#);
let errs = run_behavioral_equivalence_checks(&source);
assert!(
errs.iter().any(|e| e.code == "A49002"),
"expected A49002 for trivial self-equivalence, got: {errs:?}"
);
}