76 lines
3.0 KiB
C#
76 lines
3.0 KiB
C#
|
|
using Theriapolis.Core;
|
||
|
|
using Xunit;
|
||
|
|
|
||
|
|
namespace Theriapolis.Tests.Dungeons;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Phase 7 M0 — schema integrity tests for the Phase 7 constants. These
|
||
|
|
/// guard against silent regressions in:
|
||
|
|
/// - <see cref="C.SAVE_SCHEMA_VERSION"/> (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)
|
||
|
|
/// </summary>
|
||
|
|
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<ulong, string>();
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|