//! Byte-equivalence: the Rust KDL emitter (driven by the proc macros) //! against `protocol/mizan-codegen/tests/fixtures/afi_ir.kdl` (canonical //! Python-emitted reference). //! //! This is the Phase-2 verifier — the AFI fixture is authored against the //! real consumer surface (`#[derive(Mizan)] / #[mizan::context] / //! #[mizan::client]`), not hand-built static specs. use mizan_core as mizan; use mizan_core::prelude::*; use mizan_core::RequestHandle; use serde::{Deserialize, Serialize}; use std::path::PathBuf; // ─── Output / shared types ────────────────────────────────────────────────── #[derive(Mizan, Serialize, Deserialize, Debug, Clone)] pub struct EchoOutput { pub message: String, } #[derive(Mizan, Serialize, Deserialize, Debug, Clone)] pub struct WhoamiOutput { pub email: String, pub authenticated: bool, } #[derive(Mizan, Serialize, Deserialize, Debug, Clone)] pub struct ProfileOutput { pub user_id: i64, pub name: String, } #[derive(Mizan, Serialize, Deserialize, Debug, Clone)] pub struct OrderOutput { pub id: i64, pub user_id: i64, pub total: i64, } #[derive(Mizan, Serialize, Deserialize, Debug, Clone)] pub struct StatusOutput { pub ok: bool, } #[mizan::context("user")] pub struct UserCtx; // ─── Fixture functions (mirroring tests/afi/fixture.py) ──────────────────── #[mizan::client] pub async fn echo(_req: &RequestHandle<'_>, text: String) -> EchoOutput { EchoOutput { message: format!("echo: {text}"), } } #[mizan::client] pub async fn whoami(_req: &RequestHandle<'_>) -> WhoamiOutput { WhoamiOutput { email: "anon@example.com".into(), authenticated: false, } } #[mizan::client(context = UserCtx)] pub async fn user_profile(_req: &RequestHandle<'_>, user_id: i64) -> ProfileOutput { ProfileOutput { user_id, name: "placeholder".into(), } } #[mizan::client(context = UserCtx)] pub async fn user_orders(_req: &RequestHandle<'_>, _user_id: i64) -> Vec { vec![] } #[mizan::client(affects = UserCtx)] pub async fn update_profile( _req: &RequestHandle<'_>, _user_id: i64, _name: String, ) -> StatusOutput { StatusOutput { ok: true } } #[mizan::client] pub async fn find_user(_req: &RequestHandle<'_>, _user_id: i64) -> Option { None } #[mizan::client(merge = UserCtx)] pub async fn rename_user( _req: &RequestHandle<'_>, user_id: i64, name: String, ) -> ProfileOutput { ProfileOutput { user_id, name } } // ─── The byte-equivalence test ────────────────────────────────────────────── fn canonical_kdl_path() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("../../protocol/mizan-codegen/tests/fixtures/afi_ir.kdl") } #[test] fn build_ir_matches_canonical_afi_kdl() { let expected = std::fs::read_to_string(canonical_kdl_path()).expect("read canonical KDL"); let actual = mizan_core::build_ir(); if actual != expected { for (lineno, (a, b)) in actual.lines().zip(expected.lines()).enumerate() { if a != b { panic!( "KDL diverges at line {}:\n expected: {b:?}\n actual: {a:?}", lineno + 1, ); } } panic!( "KDL diverges in length: actual_len={} expected_len={}", actual.len(), expected.len(), ); } }