test(engine-ambient): TestBattleScope + HeadlessFixture split for multi-instance
Step 6 of multi-instancing migration. HeadlessEngineEnv.EnsureInitialized is split into EnsureProcessGlobals (idempotent, process-once) + SeedCharaIdsOnCurrentAmbient (per-test). New TestBattleScope IDisposable sets up a fresh BattleAmbientContext per test. NonParallelizable removed from converted classes; assembly-level Parallelizable(Fixtures) enabled. SVSim.BattleEngine.Tests fully green under parallel test execution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
50
SVSim.BattleEngine.Tests/TestBattleScope.cs
Normal file
50
SVSim.BattleEngine.Tests/TestBattleScope.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using SVSim.BattleEngine.Ambient;
|
||||
|
||||
namespace SVSim.BattleEngine.Tests;
|
||||
|
||||
/// <summary>Per-test ambient scope. Each test that touches engine statics wraps its body
|
||||
/// in `using var scope = new TestBattleScope();` (or with an explicit Mgr/ViewerId).
|
||||
///
|
||||
/// The constructor enters a fresh <see cref="BattleAmbientContext"/> (carrying a brand-new
|
||||
/// <see cref="GameMgr"/> so per-test mgr/DataMgr writes never bleed across tests), then
|
||||
/// runs the per-ambient seeders that <see cref="HeadlessEngineEnv.EnsureProcessGlobals"/>
|
||||
/// no longer does (chara ids on DataMgr, NetworkUserInfoData). Process-globals
|
||||
/// (card master, LoadDetail, Crossover, Certification.udid) come from
|
||||
/// <see cref="HeadlessEngineEnv.EnsureProcessGlobals"/> which runs once per process.
|
||||
///
|
||||
/// Public surface (vs. internal) so SVSim.UnitTests can reuse it via the same project
|
||||
/// reference in Task 7.</summary>
|
||||
public sealed class TestBattleScope : IDisposable
|
||||
{
|
||||
private readonly BattleAmbient.Scope _scope;
|
||||
public BattleAmbientContext Ctx { get; }
|
||||
|
||||
public TestBattleScope(BattleManagerBase? mgr = null, int viewerId = 1001)
|
||||
{
|
||||
// Make sure process-globals are seeded before we enter; idempotent + cheap after first call.
|
||||
HeadlessEngineEnv.EnsureProcessGlobals();
|
||||
|
||||
Ctx = new BattleAmbientContext
|
||||
{
|
||||
Mgr = mgr,
|
||||
GameMgr = new GameMgr(),
|
||||
ViewerId = viewerId,
|
||||
IsForecast = true,
|
||||
IsRandomDraw = true,
|
||||
RecoveryInfo = (Wizard.BattleRecoveryInfo)FormatterServices
|
||||
.GetUninitializedObject(typeof(Wizard.BattleRecoveryInfo)),
|
||||
};
|
||||
_scope = BattleAmbient.Enter(Ctx);
|
||||
|
||||
// Per-ambient seeders MUST run AFTER scope entry so GameMgr.GetIns() resolves to this
|
||||
// scope's GameMgr (not a stray one). EnsureProcessGlobals used to do these writes against
|
||||
// the global GameMgr; now they're scoped.
|
||||
HeadlessEngineEnv.SeedCharaIdsOnCurrentAmbient();
|
||||
HeadlessEngineEnv.SeedNetUserOnCurrentAmbient();
|
||||
}
|
||||
|
||||
public void Dispose() => _scope.Dispose();
|
||||
}
|
||||
Reference in New Issue
Block a user