Adds more tests, fixes
All checks were successful
Build / Build (push) Successful in 1m7s

This commit is contained in:
2026-07-04 13:03:54 +02:00
parent 8fbf22a987
commit f9878e76ba
14 changed files with 1564 additions and 8 deletions

View File

@@ -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();
}
}