More unit tests, fixes

This commit is contained in:
2026-07-05 13:01:12 +02:00
parent f9878e76ba
commit 16a1990486
23 changed files with 3204 additions and 13 deletions

View File

@@ -0,0 +1,180 @@
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Plugin.Gen7.Scripts.Side;
using PkmnLib.Static.Utils;
using TUnit.Assertions.AssertConditions.Throws;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="BrickBreak"/> move script.
/// Gen VII Bulbapedia behavior: "Brick Break removes Light Screen and Reflect", from Generation IV onward
/// "from the target's side of the field, even if the target is an ally", and from Generation V onwards
/// "Brick Break can also remove Aurora Veil."
/// </summary>
public class BrickBreakTests
{
/// <summary>
/// Creates a mocked Pokémon whose <see cref="IPokemonBattleData.BattleSide"/> is the given side.
/// </summary>
private static IPokemon CreatePokemonOnSide(IBattleSide side)
{
var pokemon = Substitute.For<IPokemon>();
var battleData = Substitute.For<IPokemonBattleData>();
battleData.BattleSide.Returns(side);
pokemon.BattleData.Returns(battleData);
return pokemon;
}
/// <summary>
/// Creates a fully mocked test setup where the user targets a Pokémon on the opposing side.
/// </summary>
private static (BrickBreak script, IExecutingMove move, IPokemon user, IScriptSet userSideScripts, IScriptSet
targetSideScripts) CreateTestSetup()
{
var script = new BrickBreak();
var move = Substitute.For<IExecutingMove>();
var userSideScripts = Substitute.For<IScriptSet>();
var userSide = Substitute.For<IBattleSide>();
userSide.VolatileScripts.Returns(userSideScripts);
var targetSideScripts = Substitute.For<IScriptSet>();
var targetSide = Substitute.For<IBattleSide>();
targetSide.VolatileScripts.Returns(targetSideScripts);
var user = CreatePokemonOnSide(userSide);
move.User.Returns(user);
var target = CreatePokemonOnSide(targetSide);
move.Targets.Returns(new IPokemon?[] { target });
return (script, move, user, userSideScripts, targetSideScripts);
}
/// <summary>
/// Bulbapedia (Generation IV onward): "Brick Break now removes Light Screen and Reflect from the target's
/// side of the field, even if the target is an ally." The screen effects are removed from the target's
/// side before the move hits. The script names match <see cref="ReflectEffect"/> and
/// <see cref="LightScreenEffect"/>.
/// </summary>
[Test, Arguments("reflect"), Arguments("light_screen")]
public async Task OnBeforeMove_ScreenOnTargetSide_RemovesScreenFromTargetSide(string screenScriptName)
{
// Arrange
var (script, move, _, _, targetSideScripts) = CreateTestSetup();
// Act
script.OnBeforeMove(move);
// Assert
targetSideScripts.Received(1).Remove(new StringKey(screenScriptName));
await Assert.That(targetSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue();
}
/// <summary>
/// Bulbapedia (Generation V onwards): "Brick Break can also remove Aurora Veil."
/// The <see cref="AuroraVeilEffect"/> is removed from the target's side as well.
/// </summary>
[Test]
public async Task OnBeforeMove_AuroraVeilOnTargetSide_RemovesAuroraVeilFromTargetSide()
{
// Arrange
var (script, move, _, _, targetSideScripts) = CreateTestSetup();
// Act
script.OnBeforeMove(move);
// Assert
targetSideScripts.Received(1).Remove(new StringKey("aurora_veil"));
await Assert.That(targetSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue();
}
/// <summary>
/// Bulbapedia (Generation IV onward): "Brick Break now removes Light Screen and Reflect from the target's
/// side of the field". When the target is an opponent, screens on the user's own side stay up.
/// </summary>
[Test]
public async Task OnBeforeMove_ScreensOnUserSide_DoesNotRemoveScreensFromUserSide()
{
// Arrange
var (script, move, _, userSideScripts, _) = CreateTestSetup();
// Act
script.OnBeforeMove(move);
// Assert
await Assert.That(userSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsFalse();
}
/// <summary>
/// Bulbapedia (Generation IV onward): "Brick Break now removes Light Screen and Reflect from the target's
/// side of the field, even if the target is an ally." An ally shares the user's side, so targeting an ally
/// removes the screens from the user's own side.
/// </summary>
[Test,
TestFailing("BrickBreak.OnBeforeMove excludes the user's own side unconditionally, so targeting an " +
"ally removes nothing (Bulbapedia: 'removes Light Screen and Reflect from the target's " +
"side of the field, even if the target is an ally')")]
public async Task OnBeforeMove_AllyTargetOnUserSide_RemovesScreensFromUserSide()
{
// Arrange
var (script, move, user, userSideScripts, _) = CreateTestSetup();
var ally = CreatePokemonOnSide(user.BattleData!.BattleSide);
move.Targets.Returns(new IPokemon?[] { ally });
// Act
script.OnBeforeMove(move);
// Assert
await Assert.That(userSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue();
}
/// <summary>
/// Bulbapedia: "Brick Break removes Light Screen and Reflect [...], then inflicts damage."
/// When no screens are up there is nothing to remove; the move simply proceeds without error and the
/// sides remain unaffected.
/// </summary>
[Test]
public async Task OnBeforeMove_NoScreensPresent_LeavesSidesUnchanged()
{
// Arrange
var script = new BrickBreak();
var move = Substitute.For<IExecutingMove>();
// Real, empty script sets so the removals (if any wrongly happen) would be observable as mutations.
var userSideScripts = new ScriptSet(Substitute.For<IBattleSide>());
var targetSideScripts = new ScriptSet(Substitute.For<IBattleSide>());
var userSide = Substitute.For<IBattleSide>();
userSide.VolatileScripts.Returns(userSideScripts);
var targetSide = Substitute.For<IBattleSide>();
targetSide.VolatileScripts.Returns(targetSideScripts);
var user = CreatePokemonOnSide(userSide);
move.User.Returns(user);
var target = CreatePokemonOnSide(targetSide);
move.Targets.Returns(new IPokemon?[] { target });
// Act
script.OnBeforeMove(move);
// Assert
await Assert.That(userSideScripts.Count).IsEqualTo(0);
await Assert.That(targetSideScripts.Count).IsEqualTo(0);
}
/// <summary>
/// Technical test: without any targets (e.g. outside of battle) the script does nothing and does not throw.
/// </summary>
[Test]
public async Task OnBeforeMove_NoTargets_DoesNotThrow()
{
// Arrange
var script = new BrickBreak();
var move = Substitute.For<IExecutingMove>();
var user = Substitute.For<IPokemon>();
user.BattleData.Returns((IPokemonBattleData?)null);
move.User.Returns(user);
move.Targets.Returns(Array.Empty<IPokemon?>());
// Act & Assert
await Assert.That(() => script.OnBeforeMove(move)).ThrowsNothing();
}
}