Files
MVP1/Assets/Scripts/Modules/Tests/ModuleTests.cs
T

112 lines
4.1 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using Bogatyri.World;
using NUnit.Framework;
// Тесты модулей без Unity-сцены. Запуск: Window -> General -> Test Runner -> EditMode -> Run All.
// Список тестов, которые команда решила добавить (план от 19.10.2026), -- в Docs/Modules/README.md.
public class ModuleTests
{
[SetUp]
public void ResetCore()
{
GameServices.Clear();
EventBus.Clear();
SaveRegistry.Clear();
}
// ---------------- Армия: один солдат не может быть в двух местах ----------------
[Test]
public void ArmyMath_TakeProportional_NeverDoubleCountsOrLosesSoldiers()
{
var rnd = new Random(1);
for (int run = 0; run < 2000; run++)
{
var troops = new int[4];
int total = 0;
for (int i = 0; i < 4; i++) { troops[i] = rnd.Next(0, 50); total += troops[i]; }
if (total == 0) continue;
int count = rnd.Next(1, total + 1);
int[] taken = ArmyMath.TakeProportional(troops, count);
int sum = 0;
for (int i = 0; i < 4; i++)
{
Assert.That(taken[i], Is.InRange(0, troops[i]), "нельзя взять больше, чем есть в типе");
sum += taken[i];
}
Assert.AreEqual(count, sum, "в поход уходит ровно столько, сколько просили");
}
}
[Test]
public void ArmyMath_TakeMoreThanExists_ReturnsNull()
{
Assert.IsNull(ArmyMath.TakeProportional(new[] { 1, 1, 0, 0 }, 3));
}
[Test]
public void ArmyMath_SplitSurvivors_ReturnsExactlySurvivors()
{
int[] back = ArmyMath.SplitSurvivors(new[] { 10, 5, 0, 1 }, 9);
int sum = 0;
foreach (var b in back) { Assert.GreaterOrEqual(b, 0); sum += b; }
Assert.AreEqual(9, sum);
}
// ---------------- Боевая система ----------------
[Test]
public void Battle_MoreSoldiersWins_TieGoesToDefender()
{
var battle = new BattleSystem();
Assert.IsTrue(battle.Resolve(new BattleRequest { Attackers = 30, Defenders = 20 }).Victory);
Assert.IsFalse(battle.Resolve(new BattleRequest { Attackers = 20, Defenders = 20 }).Victory);
Assert.AreEqual(20, battle.Resolve(new BattleRequest { Attackers = 30, Defenders = 20 }).Survivors);
}
// ---------------- Глобальный мир: поход до конца, в том числе офлайн ----------------
[Test]
public void World_MarchResolvesAndReturns_EvenAfterLongOffline()
{
var world = new WorldSimulation(WorldMapLayout.CreateDefault(), new BattleSystem());
MarchData march = world.StartMarch("p", WorldMapLayout.PlayerCityId, WorldMapLayout.BossCastleId, 30, 0, out string error);
Assert.IsNotNull(march, error);
var events = new List<WorldEvent>();
world.Advance(3_600_000, events); // игра была закрыта час
Assert.AreEqual(2, events.Count, "бой и возвращение за один вызов");
Assert.AreEqual(WorldEventType.BattleResolved, events[0].Type);
Assert.AreEqual(WorldEventType.MarchReturned, events[1].Type);
Assert.AreEqual(0, world.Marches.Count);
}
// ---------------- Ядро ----------------
[Test]
public void EventBus_FailingSubscriberDoesNotBreakOthers()
{
int delivered = 0;
Exception caught = null;
EventBus.OnHandlerError = e => caught = e;
EventBus.Subscribe<MarchReturnedEvent>(_ => throw new InvalidOperationException("boom"));
EventBus.Subscribe<MarchReturnedEvent>(_ => delivered++);
EventBus.Publish(new MarchReturnedEvent { Survivors = 5 });
Assert.AreEqual(1, delivered);
Assert.IsNotNull(caught);
}
[Test]
public void GameServices_MissingModule_ThrowsClearError()
{
Assert.Throws<InvalidOperationException>(() => GameServices.Get<IArmy>());
Assert.IsFalse(GameServices.TryGet(out IArmy _));
}
}