using PkmnLib.Dynamic.Models; using PkmnLib.Dynamic.ScriptHandling.Registry; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Plugin.Gen7.Scripts.Weather; using PkmnLib.Static; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior (Generation V onwards): "Growth now increases the user's Attack by one /// stage in addition to increasing Special Attack by one stage. In harsh sunlight, Growth raises Attack /// and Special Attack by two stages each." /// public class GrowthTests { private static (Growth script, IExecutingMove move, IPokemon user, IBattle battle) CreateTestSetup( StringKey? weather = null) { var script = new Growth(); var move = Substitute.For(); var battle = Substitute.For(); battle.WeatherName.Returns(weather); move.Battle.Returns(battle); var user = Substitute.For(); move.User.Returns(user); return (script, move, user, battle); } /// /// Helper to extract the arguments of the received ChangeStatBoost call for the given statistic, or /// null when that stat was not boosted. Received-call inspection is used instead of NSubstitute /// argument matchers because the trailing EventBatchId parameter cannot be bound by Arg.Any. /// private static object?[]? GetStatBoostArgs(IPokemon pokemon, Statistic stat) => pokemon.ReceivedCalls().Where(c => c.GetMethodInfo().Name == "ChangeStatBoost").Select(c => c.GetArguments()) .FirstOrDefault(args => (Statistic)args[0]! == stat); /// /// Bulbapedia: "Growth now increases the user's Attack by one stage in addition to increasing Special /// Attack by one stage." The boosts are self-inflicted. /// [Test, Arguments(Statistic.Attack), Arguments(Statistic.SpecialAttack)] public async Task OnSecondaryEffect_NoWeather_StatRaisedByOneStage(Statistic stat) { // Arrange var (script, move, user, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert var args = GetStatBoostArgs(user, stat); await Assert.That(args).IsNotNull(); await Assert.That((sbyte)args![1]!).IsEqualTo((sbyte)1); await Assert.That((bool)args[2]!).IsTrue(); // self-inflicted await Assert.That((bool)args[3]!).IsFalse(); // not forced } /// /// Bulbapedia: "In harsh sunlight, Growth raises Attack and Special Attack by two stages each." /// [Test, Arguments(Statistic.Attack), Arguments(Statistic.SpecialAttack)] public async Task OnSecondaryEffect_HarshSunlight_StatRaisedByTwoStages(Statistic stat) { // Arrange var (script, move, user, _) = CreateTestSetup(ScriptUtils.ResolveName()); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert var args = GetStatBoostArgs(user, stat); await Assert.That(args).IsNotNull(); await Assert.That((sbyte)args![1]!).IsEqualTo((sbyte)2); } /// /// Bulbapedia: the doubled boost only applies "in harsh sunlight" — a different weather still raises /// the stats by only one stage. /// [Test] public async Task OnSecondaryEffect_OtherWeather_StatsRaisedByOneStage() { // Arrange var (script, move, user, _) = CreateTestSetup(new StringKey("rain")); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert var args = GetStatBoostArgs(user, Statistic.Attack); await Assert.That(args).IsNotNull(); await Assert.That((sbyte)args![1]!).IsEqualTo((sbyte)1); } /// /// Bulbapedia: only Attack and Special Attack are raised — other stats stay untouched. /// [Test] public async Task OnSecondaryEffect_Always_OnlyAttackAndSpecialAttackRaised() { // Arrange var (script, move, user, _) = CreateTestSetup(); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert await Assert.That(GetStatBoostArgs(user, Statistic.Defense)).IsNull(); await Assert.That(GetStatBoostArgs(user, Statistic.SpecialDefense)).IsNull(); await Assert.That(GetStatBoostArgs(user, Statistic.Speed)).IsNull(); } }