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;
///
/// Tests for the move script and the 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.
///
public class MagicRoomTests
{
///
/// Creates a fully mocked test setup for Magic Room tests. The battle gets a real
/// as its volatile set, so the applied effect can be inspected.
///
private static (MagicRoom script, IExecutingMove move, IPokemon target, IBattle battle, IScriptSet battleVolatile)
CreateTestSetup()
{
var script = new MagicRoom();
var move = Substitute.For();
var target = Substitute.For();
var battle = Substitute.For();
battle.GetScripts().Returns(_ => new ScriptIterator(new List>()));
var battleVolatile = new ScriptSet(battle);
battle.Volatile.Returns(battleVolatile);
var battleData = Substitute.For();
battleData.Battle.Returns(battle);
var user = Substitute.For();
user.BattleData.Returns(battleData);
move.User.Returns(user);
return (script, move, target, battle, battleVolatile);
}
///
/// Bulbapedia: "Magic Room suppresses the effect of all items held by the Pokémon on the field."
/// The move script applies the volatile, which implements the item
/// suppression, to the battle.
///
[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()).IsNotNull();
}
///
/// 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.
///
[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);
}
///
/// 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.
///
[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) -----
///
/// 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.
///
[Test]
public async Task PreventHeldItemConsume_MagicRoomActive_ItemConsumptionPrevented()
{
// Arrange
var effect = new MagicRoomEffect();
var pokemon = Substitute.For();
var item = Substitute.For();
var prevented = false;
// Act
effect.PreventHeldItemConsume(pokemon, item, ref prevented);
// Assert
await Assert.That(prevented).IsTrue();
}
///
/// 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.
///
[Test]
public async Task OnBeforeAnyHookInvoked_NullCategoryList_SuppressesItemBattleTriggers()
{
// Arrange
var effect = new MagicRoomEffect();
List? suppressedCategories = null;
// Act
effect.OnBeforeAnyHookInvoked(ref suppressedCategories);
// Assert
await Assert.That(suppressedCategories).IsNotNull();
await Assert.That(suppressedCategories!.Contains(ScriptCategory.ItemBattleTrigger)).IsTrue();
}
///
/// 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.
///
[Test]
public async Task OnBeforeAnyHookInvoked_ExistingCategoryList_AddsItemBattleTriggerSuppression()
{
// Arrange
var effect = new MagicRoomEffect();
List? 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();
}
///
/// 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.
///
[Test]
public async Task OnEndTurn_AfterFiveEndOfTurns_EffectHasEnded()
{
// Arrange
var (script, move, target, battle, battleVolatile) = CreateTestSetup();
script.OnSecondaryEffect(move, target, 0);
var effect = battleVolatile.Get()!;
// 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();
}
}