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;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
///
/// Tests for the move script and the side script it places.
/// Gen VII Bulbapedia behavior (Generation III onwards): "Mist now creates a Mist effect on the user's side
/// of the field that lasts for five turns. All Pokémon on the user's side of the field are protected while
/// Mist is active, including Pokémon switched in after it was created." "While Mist is in effect, other
/// Pokémon (including allies) cannot lower the stats of Pokémon protected by Mist using either moves or
/// Abilities (e.g. Intimidate)", though it does not prevent self-inflicted stat reductions.
///
public class MistTests
{
///
/// Creates a fully mocked test setup where the user's battle side has a real as
/// its volatile scripts, so the Mist side effect can actually be attached and inspected.
///
private static (Mist script, IExecutingMove move, IBattleSide side, IScriptSet sideScripts) CreateTestSetup()
{
var script = new Mist();
var move = Substitute.For();
var side = Substitute.For();
side.GetScripts().Returns(_ => new ScriptIterator(Array.Empty>()));
IScriptSet sideScripts = new ScriptSet(side);
side.VolatileScripts.Returns(sideScripts);
var user = Substitute.For();
move.User.Returns(user);
user.BattleSide.Returns(side);
return (script, move, side, sideScripts);
}
///
/// Bulbapedia: "Mist now creates a Mist effect on the user's side of the field that lasts for five
/// turns." — using the move attaches the side script to the user's side.
///
[Test]
public async Task OnSecondaryEffect_UserInBattle_AddsMistEffectToUsersSide()
{
// Arrange
var (script, move, _, sideScripts) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, Substitute.For(), 0);
// Assert
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName())).IsTrue();
}
///
/// Bulbapedia: "While Mist is in effect, other Pokémon (including allies) cannot lower the stats of
/// Pokémon protected by Mist using either moves or Abilities (e.g. Intimidate)." — a stat reduction
/// inflicted by another Pokémon is prevented by the side script.
///
[Test, Arguments(Statistic.Attack, (sbyte)-1), Arguments(Statistic.Defense, (sbyte)-2),
Arguments(Statistic.Speed, (sbyte)-6), Arguments(Statistic.Accuracy, (sbyte)-1)]
public async Task PreventStatBoostChange_StatLoweredByOpponent_Prevented(Statistic stat, sbyte amount)
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, stat, amount, false, ref prevent);
// Assert
await Assert.That(prevent).IsTrue();
}
///
/// Bulbapedia: Mist only stops other Pokémon from being able to "lower the stats of Pokémon protected by
/// Mist" — stat increases are not affected by Mist.
///
[Test, Arguments((sbyte)1), Arguments((sbyte)2), Arguments((sbyte)6)]
public async Task PreventStatBoostChange_StatIncrease_NotPrevented(sbyte amount)
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Attack, amount, false, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
///
/// Technical test: a stat change of zero stages is not a stat reduction, so Mist does not prevent it.
///
[Test]
public async Task PreventStatBoostChange_ZeroChange_NotPrevented()
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Attack, 0, false, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
///
/// Bulbapedia: "While Mist is in effect, other Pokémon (including allies) cannot lower the stats of
/// Pokémon protected by Mist" — Mist does not prevent self-inflicted stat reductions (such as the
/// Defense/Special Defense drops from the protected Pokémon's own Superpower or Close Combat).
///
[Test]
public async Task PreventStatBoostChange_SelfInflictedReduction_NotPrevented()
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Defense, -1, true, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
///
/// Bulbapedia: "Mist now creates a Mist effect on the user's side of the field that lasts for five
/// turns." — after five end-of-turn ticks the removes itself from the side.
///
[Test]
public async Task MistEffect_AfterFiveEndOfTurns_EffectExpires()
{
// Arrange
var (script, move, side, sideScripts) = CreateTestSetup();
script.OnSecondaryEffect(move, Substitute.For(), 0);
var effect = sideScripts.Get();
await Assert.That(effect).IsNotNull();
// Act - five turns pass
var battle = Substitute.For();
if (effect is IScriptOnEndTurn endTurn)
{
for (var i = 0; i < 5; i++)
endTurn.OnEndTurn(side, battle);
}
// Assert
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName())).IsFalse();
}
}