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(); } }