From 28cdf8169ea493a7895f52b6eb3e24ecd9016293 Mon Sep 17 00:00:00 2001 From: Natalie Date: Mon, 11 May 2026 03:02:17 -0700 Subject: [PATCH] =?UTF-8?q?feat(@projects/@magic-civilization):=20?= =?UTF-8?q?=E2=9C=A8=20add=20bench=20tests=20for=20diplomacy=20and=20promo?= =?UTF-8?q?tion=20actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../crates/mc-player-api/src/dispatch.rs | 107 +++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/src/simulator/crates/mc-player-api/src/dispatch.rs b/src/simulator/crates/mc-player-api/src/dispatch.rs index 9b31c8cc..b5052519 100644 --- a/src/simulator/crates/mc-player-api/src/dispatch.rs +++ b/src/simulator/crates/mc-player-api/src/dispatch.rs @@ -1320,13 +1320,116 @@ mod tests { } #[test] - fn open_borders_offer_returns_not_yet_implemented() { + fn open_borders_offer_signs_agreement_on_bench() { + // p2-67 Phase 8: bench-cheat semantics — Offer signs immediately + // (counterparty AI doesn't yet model acceptance). The ledger + // grows by one DiplomaticAgreement::OpenBorders entry. let mut state = GameState::default(); - let err = apply_action( + // Need at least 2 player slots for the target to be in-range. + state.players.push(PlayerState::default()); + state.players.push(PlayerState::default()); + let events = apply_action( &mut state, 0, &PlayerAction::OfferOpenBorders { to: 1 }, ) + .unwrap(); + assert!(events.is_empty(), "bench Offer emits no events synchronously"); + assert_eq!(state.trade_ledger.agreements.len(), 1, "agreement signed"); + match &state.trade_ledger.agreements[0] { + mc_trade::DiplomaticAgreement::OpenBorders(ag) => { + assert_eq!(ag.partners, (0, 1)); + } + other => panic!("expected OpenBorders, got {other:?}"), + } + } + + #[test] + fn shared_map_offer_signs_agreement_on_bench() { + let mut state = GameState::default(); + state.players.push(PlayerState::default()); + state.players.push(PlayerState::default()); + let events = apply_action( + &mut state, + 0, + &PlayerAction::OfferSharedMap { to: 1 }, + ) + .unwrap(); + assert!(events.is_empty()); + assert_eq!(state.trade_ledger.agreements.len(), 1); + assert!(matches!( + &state.trade_ledger.agreements[0], + mc_trade::DiplomaticAgreement::SharedMap(_) + )); + } + + #[test] + fn promote_sets_pending_promotion_and_emits_event() { + let mut state = empty_state_with_one_unit(42); + let events = apply_action( + &mut state, + 0, + &PlayerAction::Promote(crate::action::PromotionPick { + unit_id: "42".into(), + promotion_id: "shock".into(), + }), + ) + .unwrap(); + assert_eq!(events.len(), 1); + assert!(matches!(events[0], Event::UnitPromoted { .. })); + let u = &state.players[0].units[0]; + assert_eq!(u.pending_promotion.as_deref(), Some("shock")); + } + + #[test] + fn promote_empty_promotion_id_returns_illegal() { + let mut state = empty_state_with_one_unit(42); + let err = apply_action( + &mut state, + 0, + &PlayerAction::Promote(crate::action::PromotionPick { + unit_id: "42".into(), + promotion_id: String::new(), + }), + ) + .unwrap_err(); + assert!(matches!(err, ActionError::IllegalAction { .. })); + } + + #[test] + fn split_from_formation_queues_request() { + let mut state = empty_state_with_one_unit(42); + let _ = apply_action( + &mut state, + 0, + &PlayerAction::SplitFromFormation { unit_id: "42".into() }, + ) + .unwrap(); + assert_eq!(state.pending_split_requests.len(), 1); + assert_eq!(state.pending_split_requests[0].unit_id, 42); + } + + #[test] + fn set_auto_join_queues_request() { + let mut state = empty_state_with_one_unit(42); + let _ = apply_action( + &mut state, + 0, + &PlayerAction::SetAutoJoin { unit_id: "42".into(), enabled: false }, + ) + .unwrap(); + assert_eq!(state.pending_auto_join_requests.len(), 1); + assert!(!state.pending_auto_join_requests[0].enabled); + } + + #[test] + fn set_rally_returns_not_yet_implemented() { + let mut state = empty_state_with_one_unit(42); + let err = apply_action( + &mut state, + 0, + &PlayerAction::SetRallyPoint { unit_id: "42".into(), to: [3, 3] }, + ) .unwrap_err(); assert!(matches!(err, ActionError::NotYetImplemented { .. })); }