diff --git a/src/simulator/crates/mc-turn/tests/serde_roundtrip.rs b/src/simulator/crates/mc-turn/tests/serde_roundtrip.rs index 7b22a4af..1ab46725 100644 --- a/src/simulator/crates/mc-turn/tests/serde_roundtrip.rs +++ b/src/simulator/crates/mc-turn/tests/serde_roundtrip.rs @@ -19,6 +19,9 @@ use mc_core::WonderId; use mc_economy::Treasury; use mc_happiness::pool::{GoldenAgeState, HappinessInput}; use mc_trade::relation::{Relation, RelationState}; +use mc_trade::{ + CourierRoute, DiplomaticAgreement, OpenBordersAgreement, SharedMapAgreement, TradeLedger, +}; use mc_turn::{GameState, MapUnit, PlayerState, TechState}; use std::collections::{BTreeMap, BTreeSet}; @@ -330,3 +333,75 @@ fn happiness_pool_json_roundtrip_is_stable() { assert_eq!(restored_g.golden_age_turns, 7); assert_eq!(restored_g.golden_age_count, 2); } + +/// TradeLedger schema migration (p3-01 c4) — agreements is now +/// `Vec`. Pin all three variants through JSON round-trip +/// so a future field addition surfaces immediately. +#[test] +fn trade_ledger_diplomatic_agreement_roundtrip() { + let mut ledger = TradeLedger { + next_agreement_id: 3, + agreements: vec![ + DiplomaticAgreement::LuxurySwap(mc_trade::TradeAgreement { + partners: (0, 1), + gives_a: "silk".into(), + gives_b: "wine".into(), + turn_started: 5, + }), + DiplomaticAgreement::OpenBorders(OpenBordersAgreement { + agreement_id: 0, + partners: (0, 2), + turn_started: 10, + turns_remaining: 8, + payment_gold: 50, + payment_luxury: Some("amber".into()), + }), + DiplomaticAgreement::SharedMap(SharedMapAgreement { + agreement_id: 1, + partners: (1, 2), + turn_started: 12, + duration: 6, + share_turns_remaining: 0, + payment_gold: 30, + payment_luxury: None, + courier_route: Some(CourierRoute { + sender: 1, + receiver: 2, + courier_era_tier: 3, + dispatched_turn: 12, + position: (4, 7), + eta_turn: Some(15), + delivered: false, + intercepted: false, + }), + }), + ], + }; + // Allocate one more id to verify counter survives round-trip. + let _ = ledger.alloc_agreement_id(); + assert_eq!(ledger.next_agreement_id, 4); + + let first = serde_json::to_string(&ledger).expect("TradeLedger serializes"); + let restored: TradeLedger = serde_json::from_str(&first).expect("TradeLedger deserializes"); + let second = serde_json::to_string(&restored).expect("restored TradeLedger re-serializes"); + assert_eq!(first, second, "TradeLedger round-trip drifted"); + + assert_eq!(restored.agreements.len(), 3); + assert_eq!(restored.next_agreement_id, 4); + + // Verify LuxurySwap variant fields survive. + assert!(matches!( + &restored.agreements[0], + DiplomaticAgreement::LuxurySwap(ta) if ta.gives_a == "silk" + )); + + // Verify SharedMap courier route fields survive. + if let DiplomaticAgreement::SharedMap(sm) = &restored.agreements[2] { + let route = sm.courier_route.as_ref().expect("courier_route present"); + assert_eq!(route.position, (4, 7)); + assert_eq!(route.courier_era_tier, 3); + assert!(!route.delivered); + } else { + panic!("expected SharedMap variant at index 2"); + } +}