Fix all Clippy warnings across the server codebase (2411 insertions, 1341 deletions). Raise type-complexity-threshold to 750 and too-many-arguments to 12 in .clippy.toml for idiomatic Bevy ECS system signatures. The server now passes `cargo clippy -- --deny warnings` cleanly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
161 lines
5.3 KiB
Rust
161 lines
5.3 KiB
Rust
//! Integration test: contamination activation mechanic (#254).
|
|
//!
|
|
//! Verifies that the storyteller activates contamination after the configured
|
|
//! delay and that all ActiveFork triangles receive pressure.
|
|
|
|
use bevy_ecs::prelude::*;
|
|
use bevy_ecs::schedule::Schedule;
|
|
use std::collections::BTreeMap;
|
|
|
|
use settled_reach_server::knowledge::types::StableId;
|
|
use settled_reach_server::simulation::tier::ActiveSim;
|
|
use settled_reach_server::simulation::time::SimulationTime;
|
|
use settled_reach_server::simulation::triangle::{
|
|
RoleId, TemplateId, TriangleClassification, TriangleId, TrianglePhase, TriangleState,
|
|
};
|
|
use settled_reach_server::storyteller::{
|
|
tick_contamination_activation, ContaminationActive, ContaminationEventQueue,
|
|
CONTAMINATION_DELAY_TICKS, CONTAMINATION_PRESSURE_DELTA,
|
|
};
|
|
|
|
fn make_triangle(
|
|
slug: &str,
|
|
classification: TriangleClassification,
|
|
base_ids: [u64; 3],
|
|
) -> TriangleState {
|
|
let mut role_assignments = BTreeMap::new();
|
|
role_assignments.insert(RoleId::new("role-a"), StableId(base_ids[0]));
|
|
role_assignments.insert(RoleId::new("role-b"), StableId(base_ids[1]));
|
|
role_assignments.insert(RoleId::new("role-c"), StableId(base_ids[2]));
|
|
|
|
TriangleState {
|
|
triangle_id: TriangleId::from_seed_and_slug(0, slug),
|
|
role_assignments,
|
|
tension: 0,
|
|
phase: match classification {
|
|
TriangleClassification::ActiveFork => TrianglePhase::Simmering,
|
|
TriangleClassification::PassiveTension => TrianglePhase::Dormant,
|
|
},
|
|
tension_rate: 1,
|
|
template_id: TemplateId::from_seed_and_slug(0, "authored"),
|
|
classification,
|
|
}
|
|
}
|
|
|
|
/// Acceptance test: run past CONTAMINATION_DELAY_TICKS, assert ContaminationActive
|
|
/// is set and all ActiveFork TriangleState entities have tension > 0.
|
|
#[test]
|
|
fn contamination_activates_after_delay() {
|
|
let mut world = World::new();
|
|
world.init_resource::<SimulationTime>();
|
|
world.init_resource::<ContaminationActive>();
|
|
world.init_resource::<ContaminationEventQueue>();
|
|
|
|
// Spawn 3 ActiveFork + 2 PassiveTension triangles (matching real content)
|
|
let fork1 = world
|
|
.spawn((
|
|
make_triangle("hub-power", TriangleClassification::ActiveFork, [1, 2, 3]),
|
|
ActiveSim,
|
|
))
|
|
.id();
|
|
let fork2 = world
|
|
.spawn((
|
|
make_triangle(
|
|
"bar-tensions",
|
|
TriangleClassification::ActiveFork,
|
|
[4, 5, 6],
|
|
),
|
|
ActiveSim,
|
|
))
|
|
.id();
|
|
let fork3 = world
|
|
.spawn((
|
|
make_triangle(
|
|
"informant-question",
|
|
TriangleClassification::ActiveFork,
|
|
[7, 8, 9],
|
|
),
|
|
ActiveSim,
|
|
))
|
|
.id();
|
|
let passive1 = world
|
|
.spawn((
|
|
make_triangle(
|
|
"worried-knowledge",
|
|
TriangleClassification::PassiveTension,
|
|
[10, 11, 12],
|
|
),
|
|
ActiveSim,
|
|
))
|
|
.id();
|
|
let passive2 = world
|
|
.spawn((
|
|
make_triangle(
|
|
"worried-partner",
|
|
TriangleClassification::PassiveTension,
|
|
[13, 14, 15],
|
|
),
|
|
ActiveSim,
|
|
))
|
|
.id();
|
|
|
|
let mut schedule = Schedule::default();
|
|
schedule.add_systems(tick_contamination_activation);
|
|
|
|
// Simulate past the delay threshold (CONTAMINATION_DELAY_TICKS = 300)
|
|
for tick in 0..=CONTAMINATION_DELAY_TICKS {
|
|
world.resource_mut::<SimulationTime>().tick = tick;
|
|
schedule.run(&mut world);
|
|
}
|
|
|
|
// Assert ContaminationActive is set
|
|
assert!(
|
|
world.resource::<ContaminationActive>().0,
|
|
"ContaminationActive must be true after CONTAMINATION_DELAY_TICKS ({}) ticks",
|
|
CONTAMINATION_DELAY_TICKS
|
|
);
|
|
|
|
// Assert all ActiveFork triangles have tension > 0
|
|
for (label, entity) in [
|
|
("hub-power", fork1),
|
|
("bar-tensions", fork2),
|
|
("informant-question", fork3),
|
|
] {
|
|
let state = world
|
|
.get::<TriangleState>(entity)
|
|
.unwrap_or_else(|| panic!("{} triangle entity should exist", label));
|
|
assert!(
|
|
state.tension > 0,
|
|
"ActiveFork triangle '{}' should have tension > 0 after contamination, got {}",
|
|
label,
|
|
state.tension
|
|
);
|
|
assert_eq!(
|
|
state.tension, CONTAMINATION_PRESSURE_DELTA,
|
|
"ActiveFork triangle '{}' tension should be exactly {} (contamination delta)",
|
|
label, CONTAMINATION_PRESSURE_DELTA
|
|
);
|
|
}
|
|
|
|
// Assert PassiveTension triangles were NOT pressured
|
|
for (label, entity) in [
|
|
("worried-knowledge", passive1),
|
|
("worried-partner", passive2),
|
|
] {
|
|
let state = world
|
|
.get::<TriangleState>(entity)
|
|
.unwrap_or_else(|| panic!("{} triangle entity should exist", label));
|
|
assert_eq!(
|
|
state.tension, 0,
|
|
"PassiveTension triangle '{}' should have tension 0 (not affected by contamination)",
|
|
label
|
|
);
|
|
}
|
|
|
|
// Assert exactly one ContaminationEvent was emitted
|
|
let events = world.resource_mut::<ContaminationEventQueue>().drain();
|
|
assert_eq!(events.len(), 1, "exactly one ContaminationEvent expected");
|
|
assert_eq!(events[0].tick, CONTAMINATION_DELAY_TICKS);
|
|
assert_eq!(events[0].triangles_affected, 3);
|
|
}
|