Exercise strike delivery across movement and save restore
build / mod (push) Failing after 18s

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
2026-11-02 23:53:14 +03:00
parent c775f31544
commit 952a10f360
3 changed files with 185 additions and 0 deletions
+76
View File
@@ -2540,6 +2540,82 @@ mod tests {
use super::*;
fn test_mod() -> AirDef {
AirDef {
sim: Sim::new(1),
ground: Ground::default(),
dirty: false,
next_save: 0,
hud_shown: false,
monitor: None,
monitor_shown: false,
grid: false,
grid_ids: Vec::new(),
wave: wave::WaveConfig::default(),
presentation: presentation::Session::default(),
block_log: None,
time_view: false,
film_prev: None,
smoke: Default::default(),
far: true,
acoustics: None,
moving: None,
hd: false,
world: None,
health_mark: 0,
menu: None,
listener: DVec3::ZERO,
punch: 0.0,
pending: Vec::new(),
engines: engines::Engines::default(),
engine_gen: u32::MAX,
engines_replay: false,
model_ids: std::collections::HashMap::new(),
model_generation: u32::MAX,
by_id: Vec::new(),
map: map::MapUi::default(),
}
}
#[test]
fn delivery_request_and_cargo_survive_full_state_round_trip() {
struct Flat;
impl sim::world::WorldSource for Flat {
fn solid(&self, _: i32, y: i32, _: i32) -> Option<bool> { Some(y < 64) }
}
let mut before = test_mod();
for (kind, x) in [(SamKind::Depot, 0.0), (SamKind::S400, 160.0), (SamKind::Tzm, 30.0)] {
let id = before.sim.id();
before.sim.sams.push(Sam::new(id, kind, DVec3::new(x, 64.0, 0.0), 0.0));
}
before.sim.sams[1].ground_request = true;
before.sim.sams[1].ground_rounds = 1;
before.sim.sams[1].missiles = 3;
before.sim.sams[2].ground_stock = 1;
before.sim.order_move(2, DVec3::new(100.0, 64.0, 0.0));
let text = before.state_text(false, false);
let mut after = test_mod();
after.apply_state(&text).unwrap();
assert_eq!((after.sim.sams[0].ground_stock, after.sim.sams[1].ground_rounds, after.sim.sams[1].missiles), (0, 1, 3));
assert!(after.sim.sams[1].ground_request);
assert_eq!(after.sim.sams[2].ground_stock, 1);
assert!(after.sim.sams[2].moving());
let mut out = Out::default();
for _ in 0..6000 {
let now = after.sim.tick;
let cols = after.ground.take_wanted().into_iter().map(|(x, z)| (x, z, 64)).collect();
after.ground.answer(cols, now);
let sections = after.ground.world.take_wanted(now);
after.ground.world.serve(&Flat, sections, now);
after.sim.step(&mut after.ground, None, &mut out);
if after.sim.sams[0].air_48n6_stock == 1 { break; }
out = Out::default();
}
assert_eq!((after.sim.sams[1].ground_rounds, after.sim.sams[1].missiles), (2, 2));
assert!(!after.sim.sams[1].ground_request);
assert_eq!((after.sim.sams[0].air_48n6_stock, after.sim.sams[2].ground_stock, after.sim.sams[2].air_48n6_stock), (1, 0, 0));
}
/// #83: while an export records no other replay or film replaces it; after it, they may.
#[test]
fn typed_ammunition_changes_mark_the_state_dirty() {
+24
View File
@@ -261,4 +261,28 @@ mod tests {
assert_eq!((sim.sams[0].air_48n6_stock, sim.sams[2].air_48n6_stock), (1, 0));
assert!(sim.load_ground_round(1).is_err());
}
#[test]
fn pending_delivery_waits_for_compatible_type_and_cell_after_unload() {
let mut sim = Sim::new(2);
for kind in [SamKind::Depot, SamKind::S400, SamKind::Tzm] {
let id = sim.id(); sim.sams.push(Sam::new(id, kind, DVec3::ZERO, 0.0));
}
sim.sams[1].ground_request = true;
sim.sams[2].ground_stock = 1;
sim.sams[1].kind = SamKind::Patriot;
sim.tick = 2;
for _ in 0..4 { sim.step_supply(&mut Out::default()); }
assert_eq!(sim.sams[2].ground_stock, 1);
assert_eq!(sim.sams[1].ground_rounds, 0);
sim.sams[1].kind = SamKind::S400;
sim.sams[1].missiles = 0;
sim.sams[1].ground_rounds = 4;
for _ in 0..4 { sim.step_supply(&mut Out::default()); }
assert_eq!(sim.sams[2].ground_stock, 1);
sim.unload_ground_round(1).unwrap();
for _ in 0..4 { sim.step_supply(&mut Out::default()); }
assert_eq!((sim.sams[1].ground_rounds, sim.sams[2].ground_stock, sim.sams[0].ground_stock), (4, 0, 1));
assert!(!sim.sams[1].ground_request);
}
}
+85
View File
@@ -1767,3 +1767,88 @@ fn a_blast_in_the_blocks_waits_for_the_games_word() {
let s = ground.world.stats;
assert_eq!((s.blasts_asked, s.blasts_confirmed, s.blasts_unchanged, s.blasts_unloaded), (3, 1, 0, 2));
}
#[test]
fn strike_round_truck_drives_from_depot_to_carrier_and_returns_air_round() {
let mut sim = Sim::new(5);
for (kind, x) in [(SamKind::Depot, 0.0), (SamKind::S400, 160.0), (SamKind::Tzm, 0.0)] {
let id = sim.id();
sim.sams.push(Sam::new(id, kind, DVec3::new(x, 64.0, 0.0), 0.0));
}
sim.sams[0].ground_stock = 1;
sim.load_ground_round(1).unwrap();
let (mut ground, land) = (Ground::default(), sites::testland::Land(|_, _| 64));
let mut out = Out::default();
let mut seen_loaded = false;
let mut furthest: f64 = 0.0;
for _ in 0..6000 {
sites::testland::step(&mut sim, &mut ground, &land, &mut out);
seen_loaded |= sim.sams[2].ground_stock == 1;
furthest = furthest.max(sim.sams[2].pos.x);
if sim.sams[0].air_48n6_stock == 1 { break; }
out = Out::default();
}
assert!(seen_loaded, "truck never loaded RM48U");
assert!(furthest > 140.0, "truck did not drive to carrier: {furthest}");
assert_eq!((sim.sams[0].ground_stock, sim.sams[0].air_48n6_stock), (0, 1));
assert_eq!((sim.sams[1].missiles, sim.sams[1].ground_rounds), (3, 1));
assert_eq!((sim.sams[2].ground_stock, sim.sams[2].air_48n6_stock), (0, 0));
assert!(!sim.sams[1].ground_request);
assert!(sim.load_ground_round(1).is_err());
}
#[test]
fn strike_delivery_waits_while_carrier_moves_and_resumes_after_repair() {
let mut sim = Sim::new(8);
for (kind, x) in [(SamKind::Depot, 0.0), (SamKind::S400, 160.0), (SamKind::Tzm, 0.0)] {
let id = sim.id();
sim.sams.push(Sam::new(id, kind, DVec3::new(x, 64.0, 0.0), 0.0));
}
sim.sams[0].ground_stock = 1;
sim.load_ground_round(1).unwrap();
let (mut ground, land) = (Ground::default(), sites::testland::Land(|_, _| 64));
let mut out = Out::default();
for _ in 0..300 {
sites::testland::step(&mut sim, &mut ground, &land, &mut out);
if sim.sams[2].ground_stock == 1 { break; }
out = Out::default();
}
assert_eq!(sim.sams[2].ground_stock, 1);
assert!(sim.order_move(1, DVec3::new(220.0, 64.0, 0.0)));
// Repair cancels both marches but preserves the outstanding request and truck's load.
sim.repair();
assert!(sim.sams[1].ground_request);
assert_eq!(sim.sams[2].ground_stock, 1);
assert!(sim.order_move(1, DVec3::new(220.0, 64.0, 0.0)));
for _ in 0..100 {
sites::testland::step(&mut sim, &mut ground, &land, &mut out);
out = Out::default();
}
assert_eq!(sim.sams[1].ground_rounds, 0);
for _ in 0..6000 {
sites::testland::step(&mut sim, &mut ground, &land, &mut out);
if sim.sams[1].ground_rounds == 1 { break; }
out = Out::default();
}
assert_eq!((sim.sams[1].ground_rounds, sim.sams[1].missiles), (1, 3));
assert!(!sim.sams[1].ground_request);
}
#[test]
fn destroying_a_pending_carrier_and_loaded_truck_does_not_restore_stock_on_repair() {
let mut sim = Sim::new(8);
for (kind, x) in [(SamKind::Depot, 0.0), (SamKind::S400, 160.0), (SamKind::Tzm, 80.0)] {
let id = sim.id();
sim.sams.push(Sam::new(id, kind, DVec3::new(x, 64.0, 0.0), 0.0));
}
sim.sams[1].ground_request = true;
sim.sams[2].ground_stock = 1;
let mut out = Out::default();
sim.direct_hit(sim.sams[1].pos + DVec3::Y, DVec3::ZERO, 1, &mut out);
sim.direct_hit(sim.sams[2].pos + DVec3::Y, DVec3::ZERO, 1, &mut out);
assert!(!sim.sams[1].alive());
assert!(!sim.sams[2].alive());
sim.repair();
assert!(!sim.sams[1].ground_request);
assert_eq!((sim.sams[0].ground_stock, sim.sams[2].ground_stock), (0, 0));
}