Tests: END-2 win/lose + final-siege arming + SaveData v5 (342/342 EditMode)

EndgameWinLoseTests: arms-once+enter, Charge clamp, Victory/Loss edges, the END-1 soft-loss regression (normal overrun stays soft), restored-Victory-no-rearm, SiegeTimeout-not-culling-final, the full ThreatDirector->CyclePhase->GoalReached pipeline (arm-not-stomped-by-scheduler), and FinalSiegeMultiplier override + sub-1 floor. SavePersistenceTests: RunOutcome v5 round-trip + pre-v5 default-to-InProgress. TuningConfigTests: FinalSiegeMultiplier default pin. See DR-036.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 12:38:36 -07:00
parent 4f0b4e8087
commit aac1813a93
4 changed files with 420 additions and 2 deletions
@@ -108,7 +108,7 @@ namespace ProjectM.Tests
{
var data = new SaveData { Structures = new[] { new StructureSave { Type = 1, CellX = 1, CellZ = 2, HP = 37f } } };
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(data));
Assert.AreEqual(SaveData.CurrentVersion, back.Version, "new saves write the current version (v4 since END-1).");
Assert.AreEqual(SaveData.CurrentVersion, back.Version, "new saves write the current version (v5 since END-2; v4 added Core, v3 HP).");
Assert.AreEqual(1, back.Structures.Length);
Assert.AreEqual(37f, back.Structures[0].HP, 1e-4f, "the wounded HP round-trips through JSON.");
}
@@ -147,7 +147,7 @@ namespace ProjectM.Tests
{
var data = new SaveData { GoalCharge = 1, GoalTarget = 10, CoreCurrent = 63 };
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(data));
Assert.AreEqual(SaveData.CurrentVersion, back.Version, "END-1: new saves write v4.");
Assert.AreEqual(SaveData.CurrentVersion, back.Version, "new saves write the current version (v5 since END-2).");
Assert.AreEqual(63, back.CoreCurrent, "the wounded Core integrity round-trips through JSON.");
}
@@ -162,6 +162,27 @@ namespace ProjectM.Tests
Assert.LessOrEqual(back.Version, SaveData.CurrentVersion);
}
[Test]
public void RunOutcome_RoundTrips_And_Writes_Current_Version()
{
var data = new SaveData { GoalCharge = 1, GoalTarget = 4, RunOutcome = RunOutcomeId.Victory };
var back = JsonUtility.FromJson<SaveData>(JsonUtility.ToJson(data));
Assert.AreEqual(SaveData.CurrentVersion, back.Version, "END-2: new saves write v5.");
Assert.AreEqual(5, SaveData.CurrentVersion, "SaveData is at v5 (END-2 added RunOutcome).");
Assert.AreEqual((int)RunOutcomeId.Victory, back.RunOutcome, "the latched terminal outcome round-trips through JSON.");
}
[Test]
public void Pre_END2_Save_Missing_RunOutcome_Defaults_To_InProgress()
{
// A pre-END-2 (v4) save JSON lacks RunOutcome -> JsonUtility defaults it to 0 (InProgress) -> the run loads
// as in-progress, NOT a finished run. Additive: no field, no break; v4 stays within the load floor.
var back = JsonUtility.FromJson<SaveData>("{\"Version\":4,\"GoalCharge\":2,\"GoalTarget\":10,\"CoreCurrent\":50}");
Assert.AreEqual((int)RunOutcomeId.InProgress, back.RunOutcome, "missing RunOutcome -> 0 (InProgress).");
Assert.GreaterOrEqual(back.Version, SaveData.MinLoadableVersion, "v4 stays within the additive load floor.");
Assert.LessOrEqual(back.Version, SaveData.CurrentVersion);
}
}
}