using NUnit.Framework; using ProjectM.Server; using ProjectM.Simulation; using Unity.Entities; namespace ProjectM.Tests { /// /// Guards the ComponentSystemSorter "circular dependency" hazard that is INVISIBLE to the rest of the suite: /// every other fixture registers a single system then sorts, so a cross-system [UpdateBefore/After] cycle can /// never surface — it only throws at world creation in Play. This registers the REAL ordered server-sim set /// (every system that participates in an UpdateBefore/After relation, or its constraint is silently ignored) /// into one SimulationSystemGroup and sorts, reproducing the Play-time sort headlessly. Only SortSystems runs /// (never Update), so a bare world with no entities/singletons suffices. /// public class SystemOrderingCycleTests { [Test] public void RunCycleCombatChain_Sorts_Without_A_Dependency_Cycle() { using var world = new World("OrderCycleGuard"); var group = world.GetOrCreateSystemManaged(); void Add() where T : unmanaged, ISystem => group.AddSystemToUpdateList(world.GetOrCreateSystem()); // RPC-receive systems ordered before the run director Add(); Add(); Add(); Add(); Add(); Add(); Add(); // Run director + the systems ordered around it (the cycle/siege spine is deleted — LANTERN purge) Add(); Add(); Add(); Add(); Add(); // Combat sub-chain in the same group Add(); Add(); Add(); Add(); Assert.DoesNotThrow(() => group.SortSystems(), "A [UpdateBefore/After] cycle in the run/cycle/combat chain throws here instead of only at Play world-creation."); } [Test] public void PredictedCombatChain_Sorts_Without_A_Dependency_Cycle() { // Phase 1.7 added DashTrailDamageSystem ([UpdateAfter(DashSystem)][UpdateBefore(HealthApplyDamageSystem)]) // and KillRewardSystem ([UpdateAfter(HealthApplyDamageSystem)]) to the predicted combat chain. A cycle in // these [UpdateBefore/After] edges is INVISIBLE to per-system fixtures — it only throws at Play world // creation. Co-register the chain and sort to reproduce that headlessly (SortSystems only, never Update). using var world = new World("OrderCyclePredicted"); var group = world.GetOrCreateSystemManaged(); void Add() where T : unmanaged, ISystem => group.AddSystemToUpdateList(world.GetOrCreateSystem()); Add(); Add(); Add(); Add(); Add(); Add(); Add(); Add(); Add(); Assert.DoesNotThrow(() => group.SortSystems(), "A cycle in the Phase 1.7 predicted combat chain throws here instead of only at Play world-creation."); } } }