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