Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper

This commit is contained in:
2026-08-28 15:20:26 +02:00
parent 942be8eaeb
commit 8a2733a0a9
859 changed files with 4408 additions and 5331 deletions

View File

@@ -20,24 +20,22 @@ public class IceFangTests
/// Creates a fully mocked test setup for Ice Fang tests. The target has not yet moved this turn when
/// <paramref name="queue"/> contains a choice for it.
/// </summary>
private static (IceFang script, IExecutingMove move, IPokemon user, IPokemon target, IBattleRandom random,
IScriptSet targetVolatile) CreateTestSetup(BattleChoiceQueue? queue)
private static (IceFang script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IBattleRandom
random, IScriptSet targetVolatile) CreateTestSetup(BattleChoiceQueue? queue)
{
var script = new IceFang();
var move = Substitute.For<IExecutingMove>();
var user = Substitute.For<IPokemon>();
var user = Substitute.For<IBattlePokemon>();
move.User.Returns(user);
var random = Substitute.For<IBattleRandom>();
var battle = Substitute.For<IBattle>();
battle.Random.Returns(random);
battle.ChoiceQueue.Returns(queue);
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
var target = Substitute.For<IPokemon>();
target.BattleData.Returns(battleData);
var target = Substitute.For<IBattlePokemon>();
var targetVolatile = Substitute.For<IScriptSet>();
target.Battle.Returns(battle);
target.Volatile.Returns(targetVolatile);
return (script, move, user, target, random, targetVolatile);
@@ -46,7 +44,7 @@ public class IceFangTests
/// <summary>
/// Creates a choice queue containing a single yet-to-execute move choice for the given Pokémon.
/// </summary>
private static BattleChoiceQueue CreateQueueWithChoiceFor(IPokemon pokemon)
private static BattleChoiceQueue CreateQueueWithChoiceFor(IBattlePokemon pokemon)
{
var choice = Substitute.For<IMoveChoice>();
choice.User.Returns(pokemon);
@@ -58,7 +56,7 @@ public class IceFangTests
/// matchers cannot be used for <see cref="EventBatchId"/> parameters: its parameterless constructor
/// generates a random Guid, which breaks NSubstitute's argument specification binding.)
/// </summary>
private static bool ReceivedSetStatus(IPokemon pokemon) =>
private static bool ReceivedSetStatus(IBattlePokemon pokemon) =>
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus");
/// <summary>
@@ -126,7 +124,7 @@ public class IceFangTests
// Arrange
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
var queue = CreateQueueWithChoiceFor(target);
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
target.Battle.ChoiceQueue.Returns(queue);
random.EffectChance(10, move, target, 0).Returns(true, true);
// Act
@@ -147,7 +145,7 @@ public class IceFangTests
// Arrange
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
var queue = CreateQueueWithChoiceFor(target);
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
target.Battle.ChoiceQueue.Returns(queue);
// First roll (freeze) fails, second roll (flinch) succeeds.
random.EffectChance(10, move, target, 0).Returns(false, true);
@@ -170,8 +168,8 @@ public class IceFangTests
// Arrange
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
// The queue only holds a choice for some other Pokémon; the target's choice already executed.
var queue = CreateQueueWithChoiceFor(Substitute.For<IPokemon>());
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
var queue = CreateQueueWithChoiceFor(Substitute.For<IBattlePokemon>());
target.Battle.ChoiceQueue.Returns(queue);
random.EffectChance(10, move, target, 0).Returns(true, true);
// Act
@@ -199,26 +197,4 @@ public class IceFangTests
target.Received(1).SetStatus("frozen", user);
targetVolatile.DidNotReceive().Add(Arg.Any<Script>());
}
/// <summary>
/// Technical test: if the target has no <see cref="IPokemon.BattleData"/>, the script does nothing.
/// </summary>
[Test]
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
{
// Arrange
var script = new IceFang();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IPokemon>();
target.BattleData.Returns((IPokemonBattleData?)null);
var targetVolatile = Substitute.For<IScriptSet>();
target.Volatile.Returns(targetVolatile);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(ReceivedSetStatus(target)).IsFalse();
targetVolatile.DidNotReceive().Add(Arg.Any<Script>());
}
}