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.Moves;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
///
/// Tests for the move script and the it
/// applies. Gen VII Bulbapedia behavior: "Crafty Shield protects all Pokémon on the user's side of the
/// field from status moves."
///
public class CraftyShieldTests
{
private static (CraftyShield script, IExecutingMove move, IScriptSet sideVolatile) CreateTestSetup()
{
var script = new CraftyShield();
var side = Substitute.For();
// Use a real script set so the side script added by Crafty Shield can be inspected afterwards.
var sideVolatile = new ScriptSet(side);
side.VolatileScripts.Returns(sideVolatile);
side.GetScripts().Returns(_ => new ScriptIterator(new List>()));
var battle = Substitute.For();
battle.Sides.Returns(new[] { side });
var battleData = Substitute.For();
battleData.Battle.Returns(battle);
battleData.SideIndex.Returns((byte)0);
var user = Substitute.For();
user.BattleData.Returns(battleData);
var move = Substitute.For();
move.User.Returns(user);
return (script, move, sideVolatile);
}
private static IExecutingMove CreateExecutingMoveOfCategory(MoveCategory category)
{
var useMove = Substitute.For();
useMove.Category.Returns(category);
var move = Substitute.For();
move.UseMove.Returns(useMove);
return move;
}
///
/// Bulbapedia: "Crafty Shield protects all Pokémon on the user's side of the field" — using the move
/// attaches the to the user's side.
///
[Test]
public async Task OnSecondaryEffect_Used_AddsCraftyShieldEffectToUsersSide()
{
// Arrange
var (script, move, sideVolatile) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, Substitute.For(), 0);
// Assert
await Assert.That(sideVolatile.Contains(ScriptUtils.ResolveName())).IsTrue();
}
///
/// Bulbapedia: the shield protects "from status moves" — an incoming status move is stopped.
///
[Test]
public async Task CraftyShieldEffect_StatusMove_IsStopped()
{
// Arrange
var effect = new CraftyShieldEffect();
var move = CreateExecutingMoveOfCategory(MoveCategory.Status);
var stop = false;
// Act
effect.StopBeforeMove(move, ref stop);
// Assert
await Assert.That(stop).IsTrue();
}
///
/// Bulbapedia: Crafty Shield only blocks status moves — damaging moves go through it unhindered.
///
[Test, Arguments(MoveCategory.Physical), Arguments(MoveCategory.Special)]
public async Task CraftyShieldEffect_DamagingMove_IsNotStopped(MoveCategory category)
{
// Arrange
var effect = new CraftyShieldEffect();
var move = CreateExecutingMoveOfCategory(category);
var stop = false;
// Act
effect.StopBeforeMove(move, ref stop);
// Assert
await Assert.That(stop).IsFalse();
}
///
/// Technical test: outside of battle (no battle data) no shield can be raised and nothing happens.
///
[Test]
public async Task OnSecondaryEffect_NoBattleData_DoesNothing()
{
// Arrange
var (script, move, sideVolatile) = CreateTestSetup();
move.User.BattleData.Returns((IPokemonBattleData?)null);
// Act
script.OnSecondaryEffect(move, Substitute.For(), 0);
// Assert - no effect is added
await Assert.That(sideVolatile.Contains(ScriptUtils.ResolveName())).IsFalse();
}
}