using Theriapolis.Core; using Xunit; namespace Theriapolis.Tests.Dungeons; /// /// Phase 7 M0 — schema integrity tests for the Phase 7 constants. These /// guard against silent regressions in: /// - (must == 8 at Phase 7 ship) /// - The 4 new RNG sub-streams (must be unique vs every existing stream) /// - Dungeon size bands (must be a coherent ladder) /// - Movement-cost multipliers (must be ≥ 1.0; squeezing must dominate) /// public sealed class Phase7ConstantsTests { [Fact] public void SaveSchemaVersion_IsEight() { Assert.Equal(8, C.SAVE_SCHEMA_VERSION); } [Fact] public void DungeonRngSubStreams_AreDistinctFromAllExistingStreams() { // Collect every named ulong RNG sub-stream by reflection. Each // must be unique — a collision means two independent streams share // a seed, breaking the dice contract. var fields = typeof(C).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static) .Where(f => f.IsLiteral && f.FieldType == typeof(ulong)) .ToArray(); var seen = new Dictionary(); foreach (var f in fields) { ulong value = (ulong)f.GetRawConstantValue()!; if (seen.TryGetValue(value, out var prior)) Assert.Fail($"RNG sub-stream collision: {f.Name} == {prior} ({value:X})"); seen[value] = f.Name; } // Belt-and-braces: assert the four Phase 7 streams exist. Assert.Contains(C.RNG_DUNGEON_LAYOUT, seen.Keys); Assert.Contains(C.RNG_ROOM_PICK, seen.Keys); Assert.Contains(C.RNG_DUNGEON_POPULATE, seen.Keys); Assert.Contains(C.RNG_DUNGEON_LOOT, seen.Keys); } [Fact] public void DungeonSizeBands_FormCoherentLadder() { Assert.True(C.DUNGEON_SMALL_ROOMS_MIN <= C.DUNGEON_SMALL_ROOMS_MAX); Assert.True(C.DUNGEON_MED_ROOMS_MIN <= C.DUNGEON_MED_ROOMS_MAX); Assert.True(C.DUNGEON_LARGE_ROOMS_MIN <= C.DUNGEON_LARGE_ROOMS_MAX); // Ladders don't overlap — a small dungeon's max < medium's min. Assert.True(C.DUNGEON_SMALL_ROOMS_MAX < C.DUNGEON_MED_ROOMS_MIN); Assert.True(C.DUNGEON_MED_ROOMS_MAX < C.DUNGEON_LARGE_ROOMS_MIN); } [Fact] public void MovementCostMultipliers_AreOrdered() { Assert.True(C.MOVE_COST_MISMATCH_LIGHT >= 1.0f, "Mismatch must never give a speed bonus."); Assert.True(C.MOVE_COST_MISMATCH_LIGHT < C.MOVE_COST_MISMATCH_MED); Assert.True(C.MOVE_COST_MISMATCH_MED < C.MOVE_COST_MISMATCH_HEAVY); } [Fact] public void LockAndTrapDcs_AreOrdered() { Assert.True(C.LOCK_DC_TRIVIAL < C.LOCK_DC_EASY); Assert.True(C.LOCK_DC_EASY < C.LOCK_DC_MEDIUM); Assert.True(C.LOCK_DC_MEDIUM < C.LOCK_DC_HARD); Assert.True(C.TRAP_DC_TRIVIAL < C.TRAP_DC_EASY); Assert.True(C.TRAP_DC_EASY < C.TRAP_DC_MEDIUM); } }