Many more tests and fixes
All checks were successful
Build / Build (push) Successful in 3m12s

This commit is contained in:
2026-08-27 17:11:12 +02:00
parent 32b3ef9c4a
commit d2a82b5fe3
204 changed files with 20255 additions and 242 deletions

View File

@@ -0,0 +1,176 @@
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Scripts.Battle;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Static;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="MagicRoom"/> move script and the <see cref="MagicRoomEffect"/> battle volatile it
/// applies. Gen VII Bulbapedia behavior: "Magic Room suppresses the effect of all items held by the Pokémon on
/// the field. This effect lasts for five turns." Using the move again while active removes the effect
/// immediately.
/// </summary>
public class MagicRoomTests
{
/// <summary>
/// Creates a fully mocked test setup for Magic Room tests. The battle gets a real
/// <see cref="ScriptSet"/> as its volatile set, so the applied effect can be inspected.
/// </summary>
private static (MagicRoom script, IExecutingMove move, IPokemon target, IBattle battle, IScriptSet battleVolatile)
CreateTestSetup()
{
var script = new MagicRoom();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IPokemon>();
var battle = Substitute.For<IBattle>();
battle.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
var battleVolatile = new ScriptSet(battle);
battle.Volatile.Returns(battleVolatile);
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
var user = Substitute.For<IPokemon>();
user.BattleData.Returns(battleData);
move.User.Returns(user);
return (script, move, target, battle, battleVolatile);
}
/// <summary>
/// Bulbapedia: "Magic Room suppresses the effect of all items held by the Pokémon on the field."
/// The move script applies the <see cref="MagicRoomEffect"/> volatile, which implements the item
/// suppression, to the battle.
/// </summary>
[Test]
public async Task OnSecondaryEffect_MoveUsed_AddsMagicRoomEffectToBattleVolatile()
{
// Arrange
var (script, move, target, _, battleVolatile) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(battleVolatile.Get<MagicRoomEffect>()).IsNotNull();
}
/// <summary>
/// Bulbapedia: Magic Room affects "the Pokémon on the field"; a user without battle data has no field to
/// affect, so no effect is applied and no exception is thrown.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UserHasNoBattleData_NoEffectAdded()
{
// Arrange
var (script, move, target, _, battleVolatile) = CreateTestSetup();
move.User.BattleData.Returns((IPokemonBattleData?)null);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(battleVolatile.Count).IsEqualTo(0);
}
/// <summary>
/// Bulbapedia: "If Magic Room is used while it is already in effect, it will end immediately."
/// Using the move a second time must remove the active effect from the battle instead of leaving it in
/// place.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UsedWhileActive_RemovesEffectImmediately()
{
// Arrange
var (script, move, target, _, battleVolatile) = CreateTestSetup();
// Act - second use while the effect is active
script.OnSecondaryEffect(move, target, 0);
script.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(battleVolatile.Contains("magic_room")).IsFalse();
}
// ----- MagicRoomEffect behavior (the volatile the move applies) -----
/// <summary>
/// Bulbapedia: "Magic Room suppresses the effect of all items held by the Pokémon on the field."
/// While the effect is active no Pokémon can consume its held item.
/// </summary>
[Test]
public async Task PreventHeldItemConsume_MagicRoomActive_ItemConsumptionPrevented()
{
// Arrange
var effect = new MagicRoomEffect();
var pokemon = Substitute.For<IPokemon>();
var item = Substitute.For<IItem>();
var prevented = false;
// Act
effect.PreventHeldItemConsume(pokemon, item, ref prevented);
// Assert
await Assert.That(prevented).IsTrue();
}
/// <summary>
/// Bulbapedia: "Magic Room suppresses the effect of all items held by the Pokémon on the field."
/// The effect suppresses all item battle trigger scripts while active.
/// </summary>
[Test]
public async Task OnBeforeAnyHookInvoked_NullCategoryList_SuppressesItemBattleTriggers()
{
// Arrange
var effect = new MagicRoomEffect();
List<ScriptCategory>? suppressedCategories = null;
// Act
effect.OnBeforeAnyHookInvoked(ref suppressedCategories);
// Assert
await Assert.That(suppressedCategories).IsNotNull();
await Assert.That(suppressedCategories!.Contains(ScriptCategory.ItemBattleTrigger)).IsTrue();
}
/// <summary>
/// Bulbapedia: "Magic Room suppresses the effect of all items held by the Pokémon on the field."
/// When other suppressions are already present, the item suppression is added to the existing list.
/// </summary>
[Test]
public async Task OnBeforeAnyHookInvoked_ExistingCategoryList_AddsItemBattleTriggerSuppression()
{
// Arrange
var effect = new MagicRoomEffect();
List<ScriptCategory>? suppressedCategories = [ScriptCategory.Weather];
// Act
effect.OnBeforeAnyHookInvoked(ref suppressedCategories);
// Assert
await Assert.That(suppressedCategories!.Contains(ScriptCategory.ItemBattleTrigger)).IsTrue();
await Assert.That(suppressedCategories!.Contains(ScriptCategory.Weather)).IsTrue();
}
/// <summary>
/// Bulbapedia: "This effect lasts for five turns." The turn Magic Room is used counts as the first turn,
/// so after five end-of-turn ticks the effect must have removed itself from the battle.
/// </summary>
[Test]
public async Task OnEndTurn_AfterFiveEndOfTurns_EffectHasEnded()
{
// Arrange
var (script, move, target, battle, battleVolatile) = CreateTestSetup();
script.OnSecondaryEffect(move, target, 0);
var effect = battleVolatile.Get<MagicRoomEffect>()!;
// Act - five end-of-turn ticks, the duration of the effect
for (var i = 0; i < 5; i++)
effect.OnEndTurn(battle, battle);
// Assert
await Assert.That(battleVolatile.Contains("magic_room")).IsFalse();
}
}