This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
using PkmnLib.Plugin.Gen7.Scripts;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Weather;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the <see cref="AuroraVeil"/> move script.
|
||||
/// Gen VII Bulbapedia behavior: "Aurora Veil reduces the damage done to the user by physical and special
|
||||
/// moves for five turns [...]. The move cannot be activated unless hail [...] is present. [...] Holding
|
||||
/// Light Clay extends the duration from 5 to 8 turns."
|
||||
/// </summary>
|
||||
public class AuroraVeilTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Test helper script that extends the Aurora Veil duration through the custom trigger, the same way the
|
||||
/// Light Clay item script does.
|
||||
/// </summary>
|
||||
[Script(ScriptCategory.Pokemon, "test_aurora_veil_duration_extender")]
|
||||
private class DurationExtender : Script, IScriptCustomTrigger
|
||||
{
|
||||
public void CustomTrigger(StringKey eventName, ICustomTriggerArgs args)
|
||||
{
|
||||
if (eventName == CustomTriggers.AuroraVeilDuration && args is CustomTriggers.AuroraVeilDurationArgs d)
|
||||
d.Duration = 8;
|
||||
}
|
||||
}
|
||||
|
||||
private static (AuroraVeil script, IExecutingMove move, IPokemon target, IPokemon user, IScriptSet sideScripts,
|
||||
IHitData hitData) CreateTestSetup(StringKey? weather)
|
||||
{
|
||||
var script = new AuroraVeil();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.WeatherName.Returns(weather);
|
||||
|
||||
var sideScripts = Substitute.For<IScriptSet>();
|
||||
// Mimic the real ScriptSet: invoke the factory and hand back a container holding the new script.
|
||||
sideScripts.StackOrAdd(Arg.Any<StringKey>(), Arg.Any<Func<Script?>>())
|
||||
.Returns(ci => new ScriptContainer(ci.Arg<Func<Script?>>()()!));
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.VolatileScripts.Returns(sideScripts);
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, target, user, sideScripts, hitData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the effect script instance created through StackOrAdd on the side's volatile scripts.
|
||||
/// </summary>
|
||||
private static AuroraVeilEffect? GetAddedEffect(IScriptSet sideScripts)
|
||||
{
|
||||
var call = sideScripts.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "StackOrAdd");
|
||||
if (call == null)
|
||||
return null;
|
||||
var factory = (Func<Script?>)call.GetArguments()[1]!;
|
||||
return factory() as AuroraVeilEffect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The move cannot be activated unless hail [...] is present."
|
||||
/// Without any weather, the move fails and no effect is added to the side.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoWeather_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, sideScripts, hitData) = CreateTestSetup(null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
hitData.Received(1).Fail();
|
||||
await Assert.That(sideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "StackOrAdd")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The move cannot be activated unless hail [...] is present."
|
||||
/// Under a different weather (e.g. rain), the move also fails.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NonHailWeather_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, sideScripts, hitData) = CreateTestSetup(new StringKey("rain"));
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
hitData.Received(1).Fail();
|
||||
await Assert.That(sideScripts.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "StackOrAdd")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Aurora Veil reduces the damage done to the user by physical and special moves for five
|
||||
/// turns". During hail, the Aurora Veil effect is added to the user's side with a duration of 5 turns.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_Hail_AddsEffectWithFiveTurns()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, sideScripts, hitData) = CreateTestSetup(ScriptUtils.ResolveName<Hail>());
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
var effect = GetAddedEffect(sideScripts);
|
||||
await Assert.That(effect).IsNotNull();
|
||||
await Assert.That(effect!.NumberOfTurns).IsEqualTo(5);
|
||||
hitData.DidNotReceive().Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "If a Light Clay is held when Aurora Veil is used, it will extend the duration of Aurora
|
||||
/// Veil from 5 to 8 turns." The duration extension flows through the AuroraVeilDuration custom trigger;
|
||||
/// a script on the user that sets the duration to 8 results in an effect lasting 8 turns.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_DurationExtendedByTrigger_AddsEffectWithEightTurns()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, user, sideScripts, _) = CreateTestSetup(ScriptUtils.ResolveName<Hail>());
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>
|
||||
{
|
||||
new ScriptContainer(new DurationExtender()),
|
||||
}));
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert - the created effect is initialized with the extended duration
|
||||
var call = sideScripts.ReceivedCalls().First(c => c.GetMethodInfo().Name == "StackOrAdd");
|
||||
var effect = (AuroraVeilEffect)((Func<Script?>)call.GetArguments()[1]!)()!;
|
||||
await Assert.That(effect.NumberOfTurns).IsEqualTo(8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) the script returns without throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var script = new AuroraVeil();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert - no hit data was touched
|
||||
await Assert.That(move.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "GetHitData")).IsFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user