Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/FocusEnergyTests.cs

125 lines
5.2 KiB
C#

using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="FocusEnergy"/> script, which implements Focus Energy.
/// Behavior is verified against the Bulbapedia page for Focus Energy (Generation VII behavior: the
/// Generation II base effect with the Generation III change applied).
/// The lasting part of the effect (the raised critical hit ratio) is implemented by the
/// <see cref="FocusEnergyEffect"/> volatile script, which the move script is responsible for attaching
/// to the user.
/// </summary>
public class FocusEnergyTests
{
/// <summary>
/// Creates a fully mocked test setup for Focus Energy tests.
/// </summary>
private static (FocusEnergy focusEnergy, IExecutingMove move, IBattlePokemon target, IScriptSet volatileSet,
IHitData hitData) CreateTestSetup()
{
var focusEnergy = new FocusEnergy();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IBattlePokemon>();
var hitData = Substitute.For<IHitData>();
move.GetHitData(target, 0).Returns(hitData);
var volatileSet = Substitute.For<IScriptSet>();
target.Volatile.Returns(volatileSet);
return (focusEnergy, move, target, volatileSet, hitData);
}
/// <summary>
/// Helper to extract the script passed to the volatile set's Add call.
/// </summary>
private static Script? GetAddedScript(IScriptSet volatileSet)
{
var call = volatileSet.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Add");
return call?.GetArguments()[0] as Script;
}
/// <summary>
/// Bulbapedia (Generation II): "Focus Energy now permanently increases the user's critical hit ratio."
/// The lasting effect is implemented by attaching a <see cref="FocusEnergyEffect"/> volatile script to the
/// target of the move (Focus Energy is self-targeted, so the target is the user).
/// </summary>
[Test]
public async Task OnSecondaryEffect_Called_AddsFocusEnergyEffectToTargetVolatile()
{
// Arrange
var (focusEnergy, move, target, volatileSet, _) = CreateTestSetup();
// Act
focusEnergy.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(GetAddedScript(volatileSet) is FocusEnergyEffect).IsTrue();
}
/// <summary>
/// Bulbapedia (Generations III to V, unchanged through Generation VII): "Focus Energy now increases the
/// user's critical hit ratio by two stages instead of one."
/// The volatile effect applied by <see cref="FocusEnergy"/> must therefore raise the critical hit stage
/// by two when the affected Pokémon attacks.
/// </summary>
[Test, Arguments((byte)0, (byte)2), Arguments((byte)1, (byte)3), Arguments((byte)2, (byte)4)]
public async Task OnSecondaryEffect_AppliedEffect_RaisesCriticalHitStageByTwoStages(byte initialStage,
byte expectedStage)
{
// Arrange
var (focusEnergy, move, target, volatileSet, _) = CreateTestSetup();
focusEnergy.OnSecondaryEffect(move, target, 0);
var addedScript = GetAddedScript(volatileSet);
await Assert.That(addedScript is IScriptChangeCriticalStage).IsTrue();
// Act - run the applied effect's critical stage hook, as would happen when the user attacks
var stage = initialStage;
((IScriptChangeCriticalStage)addedScript!).ChangeCriticalStage(move, target, 0, ref stage);
// Assert
await Assert.That(stage).IsEqualTo(expectedStage);
}
/// <summary>
/// Bulbapedia: "The effect of Focus Energy cannot stack, and it will fail if the user is already under its
/// effect." (Stated for Generation I and never reverted by a later generational change, so still the
/// behavior in Generation VII.)
/// When the user already has the <see cref="FocusEnergyEffect"/> volatile script, the hit must fail.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UserAlreadyUnderEffect_HitFails()
{
// Arrange
var (focusEnergy, move, target, volatileSet, hitData) = CreateTestSetup();
volatileSet.Contains<FocusEnergyEffect>().Returns(true);
// Act
focusEnergy.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsTrue();
}
/// <summary>
/// Bulbapedia: "The effect of Focus Energy cannot stack". A second use on a user that is already under the
/// effect must not attach a second <see cref="FocusEnergyEffect"/> volatile script, which would otherwise
/// stack another two critical hit stages on top of the existing ones.
/// </summary>
[Test]
public async Task OnSecondaryEffect_UserAlreadyUnderEffect_DoesNotAddEffectAgain()
{
// Arrange
var (focusEnergy, move, target, volatileSet, _) = CreateTestSetup();
volatileSet.Contains<FocusEnergyEffect>().Returns(true);
// Act
focusEnergy.OnSecondaryEffect(move, target, 0);
// Assert
await Assert.That(GetAddedScript(volatileSet)).IsNull();
}
}