verit 0.2.0

Exavian Veritate — zero-copy, self-describing, schema-evolvable binary serialization, safe on untrusted bytes, no unsafe, byte-identical across independent implementations.
Documentation
//! Structural conformance for the TypeScript / Go / C++ emitters. The full
//! byte-identity proof (generate → compile → run → diff bytes across all five
//! languages) lives in the cross-language CI harness
//! (`deploy/ci/emitter_conformance.sh`); these in-process checks keep
//! `cargo test` honest without a Node/Go/C++ toolchain: every emitter embeds
//! the exact canonical schema and 128-bit id (the wire contract), names every
//! type and field, is deterministic, and rejects non-identifier names.

use verit::{codegen, Dt, SchemaBuilder};

fn schema() -> verit::Schema {
    SchemaBuilder::new()
        .add_enum("Level", vec![(0, "Debug"), (1, "Info"), (2, "Error")])
        .add_dense_struct("Point", vec![(1, "x", Dt::F64), (2, "y", Dt::F64)])
        .add_struct(
            "Order",
            vec![
                (1, "id", Dt::U64),
                (2, "item", Dt::Str),
                (3, "qty", Dt::U32),
                (4, "tags", Dt::list(Dt::Str)),
                (5, "origin", Dt::named("Point")),
                (6, "level", Dt::named("Level")),
                (7, "blob", Dt::Bytes),
                (8, "grid", Dt::list(Dt::list(Dt::U16))),
            ],
        )
        .build("Order")
        .unwrap()
}

/// The canonical schema bytes rendered as the `n, n, n` decimal list the
/// emitters embed — the same bytes every language decodes back into the schema.
fn canonical_decimals(schema: &verit::Schema) -> String {
    schema
        .canonical_bytes()
        .iter()
        .map(|b| b.to_string())
        .collect::<Vec<_>>()
        .join(", ")
}

#[test]
fn every_emitter_embeds_the_schema_id_and_canonical_bytes() {
    let s = schema();
    let id = format!("{:032x}", s.id());
    let decimals = canonical_decimals(&s);

    for (lang, code) in [
        ("ts", codegen::generate_ts(&s).unwrap()),
        ("go", codegen::generate_go(&s).unwrap()),
        ("cpp", codegen::generate_cpp(&s).unwrap()),
        ("python", codegen::generate_python(&s).unwrap()),
    ] {
        assert!(code.contains(&id), "{lang}: missing schema id {id}");
        assert!(
            code.contains(&decimals),
            "{lang}: missing canonical schema bytes"
        );
        // The struct types (not the enum — enums are leaf u32) are all named.
        assert!(code.contains("Point"), "{lang}: missing Point");
        assert!(code.contains("Order"), "{lang}: missing Order");
        // Every field name is present (Go exports fields as PascalCase, so
        // compare case-insensitively).
        let lower = code.to_lowercase();
        for f in [
            "id", "item", "qty", "tags", "origin", "level", "blob", "grid",
        ] {
            assert!(lower.contains(f), "{lang}: missing field {f}");
        }
    }
}

#[test]
fn emitters_are_deterministic() {
    let s = schema();
    assert_eq!(
        codegen::generate_ts(&s).unwrap(),
        codegen::generate_ts(&s).unwrap()
    );
    assert_eq!(
        codegen::generate_go(&s).unwrap(),
        codegen::generate_go(&s).unwrap()
    );
    assert_eq!(
        codegen::generate_cpp(&s).unwrap(),
        codegen::generate_cpp(&s).unwrap()
    );
}

#[test]
fn cpp_defines_nested_structs_before_they_are_used_by_value() {
    // `Order` holds `origin: Point` by value (std::optional<Point>), so the C++
    // emitter must define Point first or the header won't compile. Assert the
    // dependency order the emitter guarantees.
    let code = codegen::generate_cpp(&schema()).unwrap();
    let point_def = code.find("struct Point {").expect("Point defined");
    let order_def = code.find("struct Order {").expect("Order defined");
    assert!(point_def < order_def, "Point must be defined before Order");
}

#[test]
fn emitters_reject_non_identifier_names() {
    // A field name that is not a usable cross-language identifier is refused by
    // every emitter, rather than emitting code that won't compile.
    let bad = SchemaBuilder::new()
        .add_struct("S", vec![(1, "has space", Dt::U8)])
        .build("S")
        .unwrap();
    assert!(codegen::generate_ts(&bad).is_err());
    assert!(codegen::generate_go(&bad).is_err());
    assert!(codegen::generate_cpp(&bad).is_err());
}