//! Additive-field hash stability (Embedding-ABI M1): adding
//! `FnDef.export: Option<String>` with
//! `#[serde(default, skip_serializing_if = "Option::is_none")]`
//! must leave every pre-M1 canonical-JSON hash bit-identical when
//! `export` is `None`. A round-trip-able fixture WITHOUT `export`
//! hashes identically to a hand-frozen pre-M1 golden.
//!
//! The hashing entry point is `ailang_core::hash::def_hash(&Def)` —
//! the exact one `crates/ailang-core/tests/hash_pin.rs` uses (the
//! plan's `content_hash_fn(&FnDef)` symbol does not exist; the plan
//! NOTE authorises mirroring `hash_pin.rs`'s entry point when the
//! name differs). The golden below was captured pre-field via
//! `def_hash` on the same `f : (Int)->Int / body=x` shape.

use ailang_core::ast::*;
use ailang_core::hash::def_hash;

#[test]
fn fn_without_export_hash_is_unchanged() {
    // A minimal pre-M1-shaped fn (no export). Its content hash must
    // equal the value captured before the field existed.
    let def = Def::Fn(FnDef {
        name: "f".into(),
        ty: Type::fn_owned(vec![Type::int()], Type::int(), vec![]),
        params: vec!["x".into()],
        body: Term::Var { name: "x".into() },
        doc: None,
        suppress: vec![],
        export: None,
    });
    // GOLDEN: captured pre-field (Step 2) from `def_hash` on this shape.
    let golden = "8ce080ee897b3f80";
    assert_eq!(def_hash(&def), golden,
        "pre-M1 fn hash drifted — additive-field invariant violated");
}
