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:
gamer147
2026-06-07 22:24:21 -04:00
parent 1ba75c565a
commit 8af1be6555
22 changed files with 238 additions and 39 deletions

View File

@@ -20,14 +20,25 @@ namespace SVSim.BattleEngine.Tests
Path.Combine(AppContext.BaseDirectory, "Data", "cards.json");
// Every id ever requested this process. Load is CUMULATIVE: each call rebuilds the master from
// the union, so a later Load(subset) never evicts cards an earlier Load (e.g. EnsureInitialized's
// the union, so a later Load(subset) never evicts cards an earlier Load (e.g. EnsureProcessGlobals's
// oracle set) installed. Without this, the static CardMaster is shared mutable state across the
// whole NUnit run and a Load(deck) in one test silently breaks an oracle test that runs after.
private static readonly HashSet<int> _everLoaded = new();
// Serialise Load: assembly-level Parallelizable(Fixtures) means concurrent fixtures race here,
// and HashSet<int>.Add + the static CardMaster install are not thread-safe.
private static readonly object _loadGate = new object();
// Load the given card ids (empty = none) into a CardMaster registered as Default, MERGED with all
// previously-loaded ids.
public static void Load(params int[] cardIds)
{
lock (_loadGate)
{
LoadCore(cardIds);
}
}
private static void LoadCore(int[] cardIds)
{
foreach (var id in cardIds) _everLoaded.Add(id);
var want = new HashSet<int>(_everLoaded);