This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
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, IPokemon target, IScriptSet volatileSet, IHitData
|
||||
hitData) CreateTestSetup()
|
||||
{
|
||||
var focusEnergy = new FocusEnergy();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user