use super::super::*;
#[test]
fn domain_allocator_checker_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no allocator annotations should pass");
}
#[test]
fn domain_allocator_checker_direct_api() {
let mut checker = AllocatorChecker::new();
checker.record_alloc("buf".into(), None, 0..1);
let errors = checker.check_unpaired();
assert_eq!(errors.len(), 1);
assert_eq!(errors[0].code, "A22001");
}
#[test]
fn domain_circular_buffer_checker_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no circular_buffer annotations should pass");
}
#[test]
fn domain_circular_buffer_checker_direct_api() {
let mut checker = CircularBufferChecker::new();
checker.declare("ring".into(), 8);
checker.check_read("ring", &(0..1)).unwrap();
assert_eq!(
checker
.check_read("ring", &(0..1))
.as_ref()
.map(|e| e.code.as_str()),
Some("A23003")
);
}
#[test]
fn domain_callback_reentrancy_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no callback annotations should pass");
}
#[test]
fn domain_callback_reentrancy_direct_api() {
let mut checker = CallbackReentrancyChecker::new();
checker.mark_non_reentrant("handler".into(), 0..1);
let errs = checker.enter_call("handler", &(0..1));
assert!(errs.is_empty());
let errs2 = checker.enter_call("handler", &(0..1));
assert_eq!(errs2.len(), 1);
assert_eq!(errs2[0].code, "A24001");
}
#[test]
fn domain_temporal_deadline_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no deadline annotations should pass");
}
#[test]
fn domain_temporal_deadline_direct_api() {
let mut checker = TemporalDeadlineChecker::new();
checker.register_bound("slow_op".into(), 200);
assert!(checker.enter_deadline("d1".into(), 100, &(0..1)).is_none());
let err = checker.check_operation("slow_op", &(0..1));
assert_eq!(err.unwrap().code.as_str(), "A25001");
}
#[test]
fn domain_binary_format_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no binary_format annotations should pass");
}
#[test]
fn domain_binary_format_direct_api() {
let mut checker = BinaryFormatChecker::new();
checker.add_field(BinaryField {
name: "hdr".into(),
offset: 0,
size: 4,
endianness: None,
span: 0..1,
});
let errs = checker.check_endianness();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A26003");
}
#[test]
fn domain_bit_level_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no bit_field annotations should pass");
}
#[test]
fn domain_string_encoding_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no encoding annotations should pass");
}
#[test]
fn domain_string_encoding_direct_api() {
let mut checker = StringEncodingChecker::new();
checker.declare("raw_data".into(), StringEncoding::RawBytes);
let err = checker.check_use_as_string("raw_data", &(0..1));
assert_eq!(err.unwrap().code.as_str(), "A28001");
}
#[test]
fn domain_checksum_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no checksum annotations should pass");
}
#[test]
fn domain_checksum_direct_api() {
let mut checker = ChecksumChecker::new();
checker.declare_region("data".into(), ChecksumAlgorithm::Crc32, 0, 100);
let err = checker.check_use_before_verify("data", &(0..1));
assert_eq!(err.unwrap().code.as_str(), "A29001");
}
#[test]
fn domain_protocol_grammar_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no protocol annotations should pass");
}
#[test]
fn domain_opaque_function_no_annotation_passes() {
let src = r#"fn helper(n: Int) -> Int { ensures { result >= 0 } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no opaque annotations should pass");
}
#[test]
fn domain_opaque_function_direct_api() {
let mut checker = OpaqueFunctionChecker::new();
checker.declare_opaque("secret_fn".into(), false, 0..1);
let err = checker.check_call("secret_fn", &(0..1));
assert_eq!(err.unwrap().code.as_str(), "A32001");
}
#[test]
fn domain_crash_recovery_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no crash_safe annotations should pass");
}
#[test]
fn domain_crash_recovery_direct_api() {
let mut checker = CrashRecoveryChecker::new();
checker.begin_write("w1".into());
checker.write_data("w1");
let errs = checker.check_write_ahead();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A33001");
}
#[test]
fn domain_page_cache_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no page_cache annotations should pass");
}
#[test]
fn domain_page_cache_direct_api() {
let mut checker = PageCacheChecker::new(2);
checker.load_page(1);
checker.pin(1);
let err = checker.evict(1);
assert_eq!(err.unwrap().code.as_str(), "A34001");
}
#[test]
fn domain_mvcc_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no mvcc annotations should pass");
}
#[test]
fn domain_mvcc_direct_api() {
let mut checker = MvccChecker::new();
let t1 = checker.begin_txn();
let t2 = checker.begin_txn();
checker.write_version("key1".into(), t1);
checker.write_version("key1".into(), t2);
let errs = checker.check_write_conflicts();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A35001");
}
#[test]
fn domain_rollback_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no rollback annotations should pass");
}
#[test]
fn domain_rollback_direct_api() {
let mut checker = RollbackChecker::new();
let err = checker.rollback_to("nonexistent");
assert_eq!(err.unwrap().code.as_str(), "A36001");
}
#[test]
fn domain_monotonic_state_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no monotonic annotations should pass");
}
#[test]
fn domain_monotonic_state_direct_api() {
let mut checker = MonotonicStateChecker::new();
checker.declare(
"counter".into(),
MonotonicDirection::StrictlyIncreasing,
0,
0..1,
);
let err = checker.update("counter", 0);
assert_eq!(err.unwrap().code.as_str(), "A37001");
}
#[test]
fn domain_storage_failure_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no failure_model annotations should pass");
}
#[test]
fn domain_storage_failure_direct_api() {
let mut checker = StorageFailureChecker::new();
checker.declare_failure_mode(FailureMode::PartialWrite);
let errs = checker.check_unhandled();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A38001");
}
#[test]
fn domain_numerical_precision_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no precision annotations should pass");
}
#[test]
fn domain_numerical_precision_direct_api() {
let mut checker = NumericalPrecisionChecker::new();
checker.declare("x".into(), 64, 1e-15, 0..1);
let err = checker.check_precision_loss("x", 32);
assert_eq!(err.unwrap().code.as_str(), "A42001");
}
#[test]
fn domain_precomputed_table_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no precomputed_table annotations should pass");
}
#[test]
fn domain_precomputed_table_direct_api() {
let mut checker = PrecomputedTableChecker::new();
checker.declare_table("crc".into(), 256, "gen_crc".into(), 0..1);
let errs = checker.check_coverage();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A43001");
}
#[test]
fn domain_platform_abstraction_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no platform annotations should pass");
}
#[test]
fn domain_platform_abstraction_direct_api() {
let mut checker = PlatformAbstractionChecker::new();
checker.add_platform("linux".into());
checker.declare_abstraction("fs".into(), vec![]);
let errs = checker.check_coverage();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A44001");
}
#[test]
fn domain_feature_flag_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no feature_flag annotations should pass");
}
#[test]
fn domain_feature_flag_direct_api() {
let mut checker = FeatureFlagChecker::new();
checker.declare("experimental".into(), false, vec![]);
let errs = checker.check_unused();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A45001");
}
#[test]
fn domain_resource_limit_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no resource_limit annotations should pass");
}
#[test]
fn domain_resource_limit_direct_api() {
let mut checker = ResourceLimitChecker::new();
checker.declare_limit("mem".into(), 1024, "bytes".into());
checker.record_usage("mem", 2000);
let errs = checker.check_limits();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A46001");
}
#[test]
fn domain_unsafe_escape_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no unsafe blocks should pass");
}
#[test]
fn domain_unsafe_escape_direct_api() {
let mut checker = UnsafeEscapeChecker::new();
checker.declare_unsafe("raw_ptr".into(), vec!["valid_ptr".into()], 0..1);
let errs = checker.check_unproven();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A47001");
}
#[test]
fn domain_complexity_bound_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no complexity annotations should pass");
}
#[test]
fn domain_complexity_bound_direct_api() {
let mut checker = ComplexityBoundChecker::new();
checker.declare_bound("sort".into(), ComplexityClass::NLogN, 0..1);
checker.record_measured("sort", ComplexityClass::Quadratic);
let errs = checker.check_bounds();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A48001");
}
#[test]
fn domain_behavioral_equivalence_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no equivalence annotations should pass");
}
#[test]
fn domain_behavioral_equivalence_direct_api() {
let mut checker = BehavioralEquivalenceChecker::new();
checker.declare(
"eq1".into(),
"implA".into(),
"implB".into(),
"contract1".into(),
0..1,
);
let errs = checker.check_unverified();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A49001");
}
#[test]
fn domain_multi_pass_refinement_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no refinement_pass annotations should pass");
}
#[test]
fn domain_multi_pass_refinement_direct_api() {
let mut checker = MultiPassRefinementChecker::new();
checker.add_pass("p1".into(), "L0".into(), "L1".into(), 5, 0..1);
let errs = checker.check_complete();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A50001");
}
#[test]
fn domain_incremental_contract_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no contract_version annotations should pass");
}
#[test]
fn domain_incremental_contract_direct_api() {
let mut checker = IncrementalContractChecker::new();
checker.add_version("c1".into(), 1, 2, 3, 0..1);
checker.add_version("c1".into(), 2, 5, 3, 0..1);
let errs = checker.check_precondition_weakening();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A51001");
}
#[test]
fn domain_scoped_invariant_no_annotation_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no scoped invariant annotations should pass");
}
#[test]
fn domain_scoped_invariant_direct_api() {
let mut checker = ScopedInvariantChecker::new();
checker.declare_invariant("balance_positive".into());
assert!(checker.suspend("balance_positive").is_none());
let errs = checker.check_all_restored();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A52001");
}
#[test]
fn domain_contract_composition_no_extends_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no extends annotations should pass");
}
#[test]
fn domain_contract_composition_direct_api() {
let mut checker = ContractCompositionChecker::new();
checker.declare("Child".into(), vec!["MissingParent".into()], 1);
let errs = checker.check_extends();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A54001");
}
#[test]
fn domain_contract_library_no_library_passes() {
let src = r#"contract Simple { requires { true } }"#;
let resolved = resolve_ok(src);
type_check(resolved).expect("no library blocks should pass");
}
#[test]
fn domain_contract_library_direct_api() {
let mut checker = ContractLibraryChecker::new();
checker.declare_library("mylib".into(), "1.0.0".into());
let errs = checker.check_empty_exports();
assert_eq!(errs.len(), 1);
assert_eq!(errs[0].code, "A55001");
}
#[test]
fn domain_allocator_checker_pipeline_rejects_unpaired_alloc() {
let src = r#"contract AllocTest { alloc buf requires { buf > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A22001"),
"expected A22001 for unpaired allocation, got: {errs:?}"
);
}
#[test]
fn domain_circular_buffer_pipeline_rejects_empty_read() {
let src = r#"contract BufTest { circular_buffer buf requires { buf > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A23003"),
"expected A23003 for read from empty circular buffer, got: {errs:?}"
);
}
#[test]
fn domain_callback_reentrancy_pipeline_rejects_reentrant_call() {
let src = r#"contract Guard { non_reentrant handler requires { handler > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A24001"),
"expected A24001 for re-entrant call, got: {errs:?}"
);
}
#[test]
fn domain_temporal_deadline_pipeline_rejects_unbounded_op() {
let src = r#"contract Timed { deadline respond requires { compute > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A25003"),
"expected A25003 for unbounded operation in deadline context, got: {errs:?}"
);
}
#[test]
fn domain_binary_format_pipeline_rejects_field_overflow() {
let src = r#"contract Header { binary_format buf field length }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A26001"),
"expected A26001 for field exceeding buffer length, got: {errs:?}"
);
}
#[test]
fn domain_bit_level_pipeline_rejects_width_mismatch() {
let src = r#"contract Flags { bit_layout flags bit_field status }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A27003"),
"expected A27003 for bit width mismatch, got: {errs:?}"
);
}
#[test]
fn domain_string_encoding_pipeline_rejects_raw_bytes_as_string() {
let src = r#"contract Decode { encoding data ensures { data > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A28001"),
"expected A28001 for raw bytes used as string, got: {errs:?}"
);
}
#[test]
fn domain_checksum_pipeline_rejects_use_before_verify() {
let src = r#"contract Integrity { checksum payload requires { payload > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A29001"),
"expected A29001 for use before checksum verify, got: {errs:?}"
);
}
#[test]
fn domain_protocol_grammar_pipeline_rejects_invalid_send() {
let src = r#"contract Handshake { protocol init send hello }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A30002"),
"expected A30002 for send in wrong state, got: {errs:?}"
);
}
#[test]
fn domain_opaque_function_pipeline_rejects_body_access() {
let src = "fn helper(x: Int) -> Int\n opaque marker\n ensures { helper > 0 }";
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A32002"),
"expected A32002 for opaque function body access, got: {errs:?}"
);
}
#[test]
fn domain_crash_recovery_pipeline_rejects_no_wal() {
let src = r#"contract SafeWrite { wal txn1 write_data txn1 }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A33001"),
"expected A33001 for data write without WAL, got: {errs:?}"
);
}
#[test]
fn domain_page_cache_pipeline_wired_in() {
let src = r#"contract Cache { page_cache pool }"#;
let resolved = resolve_ok(src);
let result = type_check(resolved);
match &result {
Ok(_) => {} Err(errs) => {
assert!(
errs.iter().all(|e| e.code.as_str().starts_with("A34")),
"unexpected non-page-cache errors: {errs:?}"
);
}
}
}
#[test]
fn domain_mvcc_pipeline_wired_in() {
let src = r#"contract Txn { snapshot_isolation db ensures { db > 0 } }"#;
let resolved = resolve_ok(src);
let result = type_check(resolved);
match &result {
Ok(_) => {} Err(errs) => {
assert!(
errs.iter().all(|e| e.code.as_str().starts_with("A35")),
"unexpected non-mvcc errors: {errs:?}"
);
}
}
}
#[test]
fn domain_rollback_pipeline_rejects_duplicate_savepoint() {
let src = r#"contract TxnSafe { rollback sp1 savepoint sp1 }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A36003"),
"expected A36003 for duplicate savepoint name, got: {errs:?}"
);
}
#[test]
fn domain_monotonic_state_pipeline_rejects_undeclared_access() {
let src = r#"contract Counter { monotonic seq_num ensures { other_var > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A37003"),
"expected A37003 for access to undeclared monotonic variable, got: {errs:?}"
);
}
#[test]
fn domain_storage_failure_pipeline_rejects_unhandled() {
let src = r#"contract DurableWrite { storage_failure partial_write }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A38001"),
"expected A38001 for unhandled storage failure mode, got: {errs:?}"
);
}
#[test]
fn domain_numerical_precision_pipeline_rejects_cancellation() {
let src = r#"contract Compute { precision x ensures { x > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A42003"),
"expected A42003 for potential catastrophic cancellation, got: {errs:?}"
);
}
#[test]
fn domain_precomputed_table_pipeline_rejects_no_generator() {
let src = r#"contract Lookup { precomputed_table crc_table }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A43002"),
"expected A43002 for table without generator function, got: {errs:?}"
);
}
#[test]
fn domain_platform_abstraction_pipeline_rejects_missing_impl() {
let src = r#"contract Portable {
platform linux
abstraction fs_ops
platform windows
}"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A44001"),
"expected A44001 for missing platform implementation, got: {errs:?}"
);
}
#[test]
fn domain_feature_flag_pipeline_rejects_unused() {
let src = r#"contract Features { feature_flag debug_mode }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A45001"),
"expected A45001 for unused feature flag, got: {errs:?}"
);
}
#[test]
fn domain_resource_limit_pipeline_rejects_unbounded() {
let src = r#"contract Bounded { resource_limit mem ensures { other > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A46002"),
"expected A46002 for resource used without declared limit, got: {errs:?}"
);
}
#[test]
fn domain_unsafe_escape_pipeline_rejects_no_proof() {
let src = "fn risky(p: Int) -> Int\n unsafe_escape marker\n requires { p > 0 }\n ensures { result > 0 }";
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A47001"),
"expected A47001 for unsafe without safety proof, got: {errs:?}"
);
}
#[test]
fn domain_complexity_bound_pipeline_rejects_unverified() {
let src = r#"contract Search { complexity linear requires { true } ensures { true } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A48002"),
"expected A48002 for unverified complexity bound, got: {errs:?}"
);
}
#[test]
fn domain_behavioral_equivalence_pipeline_rejects_unverified() {
let src = r#"contract Equiv { equivalent impl_a == impl_b requires { true } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A49001"),
"expected A49001 for unverified behavioral equivalence, got: {errs:?}"
);
}
#[test]
fn domain_multi_pass_refinement_pipeline_rejects_incomplete() {
let src = r#"contract Refine { refinement_pass step1 requires { true } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A50001"),
"expected A50001 for incomplete refinement obligations, got: {errs:?}"
);
}
#[test]
fn domain_incremental_contract_pipeline_rejects_version_gap() {
let src = r#"
contract V1 { version foo }
contract V2 { version foo }
"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A51003"),
"expected A51003 for version gap, got: {errs:?}"
);
}
#[test]
fn domain_scoped_invariant_pipeline_rejects_suspended_use() {
let src = r#"contract Maintenance { suspend_invariant sorted requires { sorted > 0 } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A52001"),
"expected A52001 for suspended invariant use, got: {errs:?}"
);
}
#[test]
fn domain_contract_composition_pipeline_rejects_unknown_extends() {
let src = r#"contract Child { extends NonExistent requires { true } }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A54001"),
"expected A54001 for extends unknown contract, got: {errs:?}"
);
}
#[test]
fn domain_contract_library_pipeline_rejects_empty_exports() {
let src = r#"library mylib { }"#;
let resolved = resolve_ok(src);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A55001"),
"expected A55001 for library with no exports, got: {errs:?}"
);
}
#[test]
fn liveness_block_missing_prove_emits_a_core_030() {
let source = r#"
liveness BadBlock {
assume: fair
}
"#;
let resolved = resolve_ok(source);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A31006"),
"expected A31006 for liveness block with no prove clause, got: {errs:?}"
);
}
#[test]
fn liveness_block_with_prove_is_valid() {
let source = r#"
liveness GoodBlock {
assume: fair
prove: eventually(done)
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
if let Err(errs) = &result {
assert!(
!errs.iter().any(|e| e.code == "A31006"),
"should not emit A31006 when prove clause is present, got: {errs:?}"
);
}
}
#[test]
fn liveness_leads_to_without_fair_emits_a_core_031() {
let source = r#"
liveness LeadsToNoFair {
prove: leads_to(waiting, served)
}
"#;
let resolved = resolve_ok(source);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A31007"),
"expected A31007 for leads_to without assume fair, got: {errs:?}"
);
}
#[test]
fn liveness_leads_to_with_assume_fair_ok() {
let source = r#"
liveness LeadsToWithFair {
assume: fair
prove: leads_to(waiting, served)
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
assert!(
result.is_ok()
|| result
.as_ref()
.err()
.is_some_and(|errs| !errs.iter().any(|e| e.code == "A31007")),
"should not emit A31007 when assume fair is present, got: {result:?}"
);
}
#[test]
fn ordering_relaxed_with_ensures_emits_a_conc_016() {
let source = r#"
contract RelaxedRead {
input(counter: Int)
ordering: relaxed
ensures { counter >= 0 }
}
"#;
let resolved = resolve_ok(source);
let errs = type_check(resolved).unwrap_err();
assert!(
errs.iter().any(|e| e.code == "A23016"),
"expected A23016 for relaxed ordering with ensures, got: {errs:?}"
);
}
#[test]
fn ordering_acquire_with_ensures_no_a23016() {
let source = r#"
contract AcquireRead {
input(counter: Int)
ordering: acquire
ensures { counter >= 0 }
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
if let Err(errs) = &result {
assert!(
!errs.iter().any(|e| e.code == "A23016"),
"unexpected A23016 for acquire ordering: {errs:?}"
);
}
}
#[test]
fn ordering_relaxed_without_ensures_no_a23016() {
let source = r#"
contract RelaxedNoEnsures {
input(counter: Int)
ordering: relaxed
requires { counter >= 0 }
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
if let Err(errs) = &result {
assert!(
!errs.iter().any(|e| e.code == "A23016"),
"unexpected A23016 without ensures clause: {errs:?}"
);
}
}
#[test]
fn ordering_seq_cst_with_ensures_no_a23016() {
let source = r#"
contract SeqCstRead {
input(counter: Int)
ordering: seq_cst
ensures { counter >= 0 }
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
if let Err(errs) = &result {
assert!(
!errs.iter().any(|e| e.code == "A23016"),
"unexpected A23016 for seq_cst ordering: {errs:?}"
);
}
}
#[test]
fn codec_registry_overlapping_magic_a52001() {
let source = r#"
codec_registry Formats {
output: Output,
codec Png {
magic: [0x89, 0x50, 0x4E, 0x47],
decoder: decode_png
}
codec PngAlt {
magic: [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A],
decoder: decode_png_alt
}
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
match result {
Err(errs) => {
assert!(
errs.iter().any(|e| e.code == "A52001"),
"expected A52001 for overlapping magic patterns, got: {errs:?}"
);
}
Ok(_) => panic!("expected type error A52001 for overlapping magic patterns"),
}
}
#[test]
fn codec_registry_no_overlap_ok() {
let source = r#"
codec_registry Formats {
output: Output,
codec Png {
magic: [0x89, 0x50, 0x4E, 0x47],
decoder: decode_png
}
codec Jpeg {
magic: [0xFF, 0xD8, 0xFF],
decoder: decode_jpeg
}
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
match &result {
Ok(_) => {}
Err(errs) => {
assert!(
!errs.iter().any(|e| e.code == "A52001"),
"unexpected A52001: {errs:?}"
);
}
}
}
#[test]
fn codec_registry_empty_decoder_a52002() {
let source = r#"
codec_registry Formats {
output: Output,
codec Bad {
magic: [0x89, 0x50]
}
}
"#;
let resolved = resolve_ok(source);
let result = type_check(resolved);
match result {
Err(errs) => {
assert!(
errs.iter().any(|e| e.code == "A52002"),
"expected A52002 for missing decoder, got: {errs:?}"
);
}
Ok(_) => panic!("expected type error A52002 for missing decoder"),
}
}
#[test]
fn error_type_suppresses_field_access() {
let mut env = TypeEnv::new();
env.insert("e".into(), Type::Error);
let expr = Spanned::no_span(AstExpr::Field(
Box::new(Spanned::no_span(AstExpr::Ident("e".into()))),
"foo".into(),
));
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Error);
}
#[test]
fn error_type_suppresses_method_call() {
let mut env = TypeEnv::new();
env.insert("e".into(), Type::Error);
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("e".into()))),
method: "anything".into(),
args: vec![],
});
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Error);
}
#[test]
fn error_type_suppresses_index() {
let mut env = TypeEnv::new();
env.insert("e".into(), Type::Error);
let expr = Spanned::no_span(AstExpr::Index {
expr: Box::new(Spanned::no_span(AstExpr::Ident("e".into()))),
index: Box::new(Spanned::no_span(AstExpr::Literal(
assura_parser::ast::Literal::Int("0".into()),
))),
});
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Error);
}
#[test]
fn error_type_suppresses_call() {
let mut env = TypeEnv::new();
env.insert("f".into(), Type::Error);
let expr = Spanned::no_span(AstExpr::Call {
func: Box::new(Spanned::no_span(AstExpr::Ident("f".into()))),
args: vec![],
});
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Error);
}
#[test]
fn error_compatible_with_any_type() {
assert!(types_compatible(&Type::Error, &Type::Int));
assert!(types_compatible(&Type::Bool, &Type::Error));
assert!(types_compatible(&Type::Error, &Type::Error));
}
#[test]
fn is_indeterminate_works() {
assert!(Type::Unknown.is_indeterminate());
assert!(Type::Error.is_indeterminate());
assert!(!Type::Int.is_indeterminate());
assert!(!Type::Bool.is_indeterminate());
assert!(!Type::Named("Foo".into()).is_indeterminate());
}
#[test]
fn option_map_with_known_function() {
let mut env = TypeEnv::new();
env.insert("opt".into(), Type::Option(Box::new(Type::Int)));
env.insert(
"to_string_fn".into(),
Type::Fn {
params: vec![Type::Int],
ret: Box::new(Type::String),
},
);
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("opt".into()))),
method: "map".into(),
args: vec![Spanned::no_span(AstExpr::Ident("to_string_fn".into()))],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::Option(Box::new(Type::String))
);
}
#[test]
fn result_map_with_known_function() {
let mut env = TypeEnv::new();
env.insert(
"r".into(),
Type::Result(Box::new(Type::Int), Box::new(Type::String)),
);
env.insert(
"double".into(),
Type::Fn {
params: vec![Type::Int],
ret: Box::new(Type::Float),
},
);
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("r".into()))),
method: "map".into(),
args: vec![Spanned::no_span(AstExpr::Ident("double".into()))],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::Result(Box::new(Type::Float), Box::new(Type::String))
);
}
#[test]
fn result_map_err_with_known_function() {
let mut env = TypeEnv::new();
env.insert(
"r".into(),
Type::Result(Box::new(Type::Int), Box::new(Type::String)),
);
env.insert(
"wrap_err".into(),
Type::Fn {
params: vec![Type::String],
ret: Box::new(Type::Named("AppError".into())),
},
);
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("r".into()))),
method: "map_err".into(),
args: vec![Spanned::no_span(AstExpr::Ident("wrap_err".into()))],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::Result(
Box::new(Type::Int),
Box::new(Type::Named("AppError".into()))
)
);
}
#[test]
fn option_filter_preserves_type() {
let mut env = TypeEnv::new();
env.insert("opt".into(), Type::Option(Box::new(Type::Int)));
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("opt".into()))),
method: "filter".into(),
args: vec![],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::Option(Box::new(Type::Int))
);
}
#[test]
fn option_or_else_preserves_type() {
let mut env = TypeEnv::new();
env.insert("opt".into(), Type::Option(Box::new(Type::Int)));
let expr = Spanned::no_span(AstExpr::MethodCall {
receiver: Box::new(Spanned::no_span(AstExpr::Ident("opt".into()))),
method: "or_else".into(),
args: vec![],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::Option(Box::new(Type::Int))
);
}
#[test]
fn type_param_call_returns_type_param() {
let mut env = TypeEnv::new();
env.insert("T".into(), Type::TypeParam("T".into()));
let expr = Spanned::no_span(AstExpr::Call {
func: Box::new(Spanned::no_span(AstExpr::Ident("T".into()))),
args: vec![Spanned::no_span(AstExpr::Literal(
assura_parser::ast::Literal::Int("1".into()),
))],
});
assert_eq!(
infer_expr(&expr, &env).unwrap(),
Type::TypeParam("T".into())
);
}
#[test]
fn block_empty_returns_unit() {
let env = TypeEnv::new();
let expr = Spanned::no_span(AstExpr::Block(vec![]));
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Unit);
}
#[test]
fn block_returns_last_expr_type() {
let env = TypeEnv::new();
let expr = Spanned::no_span(AstExpr::Block(vec![
Spanned::no_span(AstExpr::Literal(assura_parser::ast::Literal::Int(
"1".into(),
))),
Spanned::no_span(AstExpr::Literal(assura_parser::ast::Literal::Bool(true))),
]));
assert_eq!(infer_expr(&expr, &env).unwrap(), Type::Bool);
}