using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.ScriptHandling; using PkmnLib.Dynamic.ScriptHandling.Registry; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Plugin.Gen7.Scripts.Side; using PkmnLib.Static; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: "Defog lowers the target's evasion by one stage" and clears field effects: /// "It removes Spikes, Toxic Spikes, Stealth Rock, and Sticky Web from both sides, while Light Screen, /// Reflect, Safeguard, Mist, and Aurora Veil are cleared from the target's side only." /// public class DefogTests { /// /// Creates a fully mocked test setup where the target is on side 1 and the user on side 0. /// private static (Defog script, IExecutingMove move, IPokemon target, IScriptSet targetSideScripts, IScriptSet userSideScripts) CreateTestSetup() { var script = new Defog(); var move = Substitute.For(); var userSideScripts = Substitute.For(); var userSide = Substitute.For(); userSide.VolatileScripts.Returns(userSideScripts); var targetSideScripts = Substitute.For(); var targetSide = Substitute.For(); targetSide.VolatileScripts.Returns(targetSideScripts); var battle = Substitute.For(); battle.Sides.Returns(new[] { userSide, targetSide }); var user = Substitute.For(); var userBattleData = Substitute.For(); userBattleData.Battle.Returns(battle); userBattleData.SideIndex.Returns((byte)0); user.BattleData.Returns(userBattleData); move.User.Returns(user); var target = Substitute.For(); var targetBattleData = Substitute.For(); targetBattleData.Battle.Returns(battle); targetBattleData.SideIndex.Returns((byte)1); target.BattleData.Returns(targetBattleData); return (script, move, target, targetSideScripts, userSideScripts); } /// /// Bulbapedia: "Light Screen, Reflect, Safeguard, Mist, and Aurora Veil are cleared from the target's /// side only." The screen and protection effects (, /// , , ) are removed /// from the target's side. /// [Test, Arguments("light_screen"), Arguments("reflect"), Arguments("safe_guard"), Arguments("mist")] public async Task OnSecondaryEffect_ScreenOnTargetSide_RemovesEffectFromTargetSide(string scriptName) { // Arrange var (script, move, target, targetSideScripts, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert targetSideScripts.Received(1).Remove(new StringKey(scriptName)); await Assert.That(targetSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue(); } /// /// Bulbapedia: "It removes Spikes, Toxic Spikes, Stealth Rock, and Sticky Web" — the entry hazards /// (, , , /// ) are removed from the target's side. /// [Test, Arguments("spikes"), Arguments("toxic_spikes"), Arguments("stealth_rock"), Arguments("sticky_web")] public async Task OnSecondaryEffect_HazardOnTargetSide_RemovesHazardFromTargetSide(string scriptName) { // Arrange var (script, move, target, targetSideScripts, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert targetSideScripts.Received(1).Remove(new StringKey(scriptName)); await Assert.That(targetSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue(); } /// /// Bulbapedia (Generations VI and VII): "It removes Spikes, Toxic Spikes, Stealth Rock, and Sticky Web /// from both sides" — the entry hazards must also be removed from the user's own side. /// [Test, Arguments("spikes"), Arguments("toxic_spikes"), Arguments("stealth_rock"), Arguments("sticky_web")] public async Task OnSecondaryEffect_HazardOnUserSide_RemovesHazardFromUserSide(string scriptName) { // Arrange var (script, move, target, _, userSideScripts) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert userSideScripts.Received(1).Remove(new StringKey(scriptName)); await Assert.That(userSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue(); } /// /// Bulbapedia (Generations VI and VII): "Light Screen, Reflect, Safeguard, Mist, and Aurora Veil are /// cleared from the target's side only." The must be removed as well. /// [Test] public async Task OnSecondaryEffect_AuroraVeilOnTargetSide_RemovesAuroraVeilFromTargetSide() { // Arrange var (script, move, target, targetSideScripts, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert targetSideScripts.Received(1).Remove(new StringKey("aurora_veil")); await Assert.That(targetSideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Remove")).IsTrue(); } /// /// Bulbapedia: "Defog lowers the target's evasion by one stage". Neither the script nor the move data /// applies the evasion drop, so the target's evasion is never lowered. /// [Test] public async Task OnSecondaryEffect_Always_LowersTargetEvasionByOneStage() { // Arrange var (script, move, target, _, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost" && (Statistic)c.GetArguments()[0]! == Statistic.Evasion && (sbyte)c.GetArguments()[1]! == -1)).IsTrue(); } /// /// Technical test: without battle data (outside of battle) the secondary effect does nothing and does /// not throw. /// [Test] public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNotThrow() { // Arrange var script = new Defog(); var move = Substitute.For(); var target = Substitute.For(); target.BattleData.Returns((IPokemonBattleData?)null); // Act & Assert await Assert.That(() => script.OnSecondaryEffect(move, target, 0)).ThrowsNothing(); } }