Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/MistTests.cs
Deukhoofd d2a82b5fe3
All checks were successful
Build / Build (push) Successful in 3m12s
Many more tests and fixes
2026-08-27 17:11:12 +02:00

181 lines
6.9 KiB
C#

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;
/// <summary>
/// Tests for the <see cref="Mist"/> move script and the <see cref="MistEffect"/> 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.
/// </summary>
public class MistTests
{
/// <summary>
/// Creates a fully mocked test setup where the user's battle side has a real <see cref="ScriptSet"/> as
/// its volatile scripts, so the Mist side effect can actually be attached and inspected.
/// </summary>
private static (Mist script, IExecutingMove move, IBattleSide side, IScriptSet sideScripts) CreateTestSetup()
{
var script = new Mist();
var move = Substitute.For<IExecutingMove>();
var side = Substitute.For<IBattleSide>();
side.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
IScriptSet sideScripts = new ScriptSet(side);
side.VolatileScripts.Returns(sideScripts);
var battleData = Substitute.For<IPokemonBattleData>();
battleData.BattleSide.Returns(side);
var user = Substitute.For<IPokemon>();
user.BattleData.Returns(battleData);
move.User.Returns(user);
return (script, move, side, sideScripts);
}
/// <summary>
/// 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 <see cref="MistEffect"/> side script to the user's side.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UserInBattle_AddsMistEffectToUsersSide()
{
// Arrange
var (script, move, _, sideScripts) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
// Assert
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<MistEffect>())).IsTrue();
}
/// <summary>
/// Technical test: without battle data on the user (outside of battle) the effect does nothing and does
/// not throw.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UserHasNoBattleData_DoesNothing()
{
// Arrange
var (script, move, _, sideScripts) = CreateTestSetup();
move.User.BattleData.Returns((IPokemonBattleData?)null);
// Act
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
// Assert
await Assert.That(sideScripts.Count).IsEqualTo(0);
}
/// <summary>
/// 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 <see cref="MistEffect"/> side script.
/// </summary>
[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<IPokemon>();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, stat, amount, false, ref prevent);
// Assert
await Assert.That(prevent).IsTrue();
}
/// <summary>
/// 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.
/// </summary>
[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<IPokemon>();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Attack, amount, false, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
/// <summary>
/// Technical test: a stat change of zero stages is not a stat reduction, so Mist does not prevent it.
/// </summary>
[Test]
public async Task PreventStatBoostChange_ZeroChange_NotPrevented()
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For<IPokemon>();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Attack, 0, false, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
/// <summary>
/// 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).
/// </summary>
[Test]
public async Task PreventStatBoostChange_SelfInflictedReduction_NotPrevented()
{
// Arrange
var effect = new MistEffect();
var target = Substitute.For<IPokemon>();
var prevent = false;
// Act
effect.PreventStatBoostChange(target, Statistic.Defense, -1, true, ref prevent);
// Assert
await Assert.That(prevent).IsFalse();
}
/// <summary>
/// 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 <see cref="MistEffect"/> removes itself from the side.
/// </summary>
[Test]
public async Task MistEffect_AfterFiveEndOfTurns_EffectExpires()
{
// Arrange
var (script, move, side, sideScripts) = CreateTestSetup();
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
var effect = sideScripts.Get<MistEffect>();
await Assert.That(effect).IsNotNull();
// Act - five turns pass
var battle = Substitute.For<IBattle>();
if (effect is IScriptOnEndTurn endTurn)
{
for (var i = 0; i < 5; i++)
endTurn.OnEndTurn(side, battle);
}
// Assert
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<MistEffect>())).IsFalse();
}
}