test(battle-engine M13): shared NetworkEmitFixtureBase teardown — close IsForecast/agent global leak
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,21 +10,11 @@ namespace SVSim.BattleEngine.Tests
|
||||
// without crashing, while the committed state still matches the M3 direct-ActionProcessor oracle.
|
||||
// Liveness only (E4); structural frame decoding + the RNG rand-list (M14) are deferred.
|
||||
[TestFixture]
|
||||
public class EmitPathReadOracleTests
|
||||
public class EmitPathReadOracleTests : NetworkEmitFixtureBase
|
||||
{
|
||||
// Reset the process globals this fixture mutates so no later fixture inherits them:
|
||||
// - ToolboxGame.RealTimeNetworkAgent: the injected agent (the solo oracles don't read it, but
|
||||
// clearing it is defensive, mirroring RandomDrawOracleTests.ResetRandomDrawGate).
|
||||
// - BattleManagerBase.IsForecast: the network emit harness sets this FALSE (the emit path needs it);
|
||||
// every solo oracle and EnsureInitialized assume it TRUE. EnsureInitialized only sets it once
|
||||
// (guarded), so without restoring it here a solo fixture running after this one would see
|
||||
// IsForecast=false and un-suppressed VFX. Restore the EnsureInitialized default.
|
||||
[TearDown]
|
||||
public void ResetGlobals()
|
||||
{
|
||||
Wizard.ToolboxGame.SetRealTimeNetworkBattle(null);
|
||||
BattleManagerBase.IsForecast = true;
|
||||
}
|
||||
// The process-global reset (IsForecast=true + clear injected agent) now lives in the shared
|
||||
// NetworkEmitFixtureBase.ResetNetworkEmitGlobals [TearDown], inherited here — see that file
|
||||
// for why the leak matters.
|
||||
|
||||
[Test]
|
||||
public void M3_spell_driven_via_OperateMgr_reaches_emit_without_crashing()
|
||||
|
||||
40
SVSim.BattleEngine.Tests/NetworkEmitFixtureBase.cs
Normal file
40
SVSim.BattleEngine.Tests/NetworkEmitFixtureBase.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace SVSim.BattleEngine.Tests
|
||||
{
|
||||
// Shared base for every network-emit test fixture (M13 EmitPathReadOracleTests, the
|
||||
// construction-probe's OnEmit seam test, and any M14+ network fixture to come).
|
||||
//
|
||||
// WHY this exists — the global-state leak it closes:
|
||||
// HeadlessEngineEnv.NewNetworkEmitBattle() mutates two PROCESS globals that no per-mgr
|
||||
// teardown reverts on its own:
|
||||
// - Wizard.ToolboxGame.RealTimeNetworkAgent: a non-null agent is injected so the engine's
|
||||
// NetworkBattleSender ToolboxGame.RealTimeNetworkAgent.* calls resolve (the capture seam).
|
||||
// - BattleManagerBase.IsForecast: the emit path needs this FALSE, so the harness flips it from
|
||||
// the EnsureInitialized default of TRUE.
|
||||
// HeadlessEngineEnv.EnsureInitialized() is _done-guarded — it sets IsForecast=true exactly once
|
||||
// and then NO-OPs forever after. So once a network-emit fixture leaves IsForecast=false behind,
|
||||
// nothing restores it: a later SOLO fixture (e.g. RandomDrawOracleTests) that assumes
|
||||
// IsForecast=true would silently run with IsForecast=false (un-suppressed VFX) and a stale
|
||||
// injected agent. Currently latent-benign, but a real hygiene gap M14's added network fixtures
|
||||
// could turn flaky.
|
||||
//
|
||||
// Deriving from this base means NUnit runs the base-class [TearDown] after EVERY test in the
|
||||
// derived fixture automatically, so the reset can never be forgotten when a new network-emit
|
||||
// fixture is added — inherit this, don't re-roll a local teardown.
|
||||
public abstract class NetworkEmitFixtureBase
|
||||
{
|
||||
[TearDown]
|
||||
public void ResetNetworkEmitGlobals()
|
||||
{
|
||||
// Clear the injected agent (the solo oracles don't read it, but clearing it is defensive,
|
||||
// mirroring RandomDrawOracleTests.ResetRandomDrawGate).
|
||||
Wizard.ToolboxGame.SetRealTimeNetworkBattle(null);
|
||||
// Restore the EnsureInitialized default. This is the load-bearing restore: every solo
|
||||
// oracle and EnsureInitialized assume IsForecast=TRUE, and EnsureInitialized only sets it
|
||||
// once (guarded), so without restoring it here a solo fixture running after a network-emit
|
||||
// fixture would see IsForecast=false and un-suppressed VFX.
|
||||
BattleManagerBase.IsForecast = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace SVSim.BattleEngine.Tests
|
||||
// _battleCamera, _backGround) + RegisterActionManager + OperateReceive — the largest new shim
|
||||
// surface since M5's prefab path. Isolate "ctor runs" before any play is driven.
|
||||
[TestFixture]
|
||||
public class NetworkMgrConstructionProbeTests
|
||||
public class NetworkMgrConstructionProbeTests : NetworkEmitFixtureBase
|
||||
{
|
||||
[Test]
|
||||
public void HeadlessNetworkBattleMgr_constructs_headless()
|
||||
|
||||
Reference in New Issue
Block a user