using PkmnLib.Dynamic.Models; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: Floral Healing restores up to half of the target's maximum HP, or up to /// two thirds when Grassy Terrain is in effect. /// public class FloralHealingTests { private static (FloralHealing script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint maxHp, string? terrainName = null, bool isFainted = false) { var script = new FloralHealing(); var move = Substitute.For(); var battle = Substitute.For(); battle.TerrainName.Returns(terrainName == null ? null : new StringKey?(new StringKey(terrainName))); var target = Substitute.For(); target.IsFainted.Returns(isFainted); target.BoostedStats.Returns(new StatisticSet(maxHp, 0, 0, 0, 0, 0)); target.Battle.Returns(battle); return (script, move, target); } /// /// Helper to extract the heal amount from the target's received Heal calls. /// private static uint? GetHealAmount(IBattlePokemon target) { var call = target.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Heal"); return call != null ? (uint)call.GetArguments()[0]! : null; } /// /// Bulbapedia: "Floral Healing restores up to ½ of the target's maximum HP." /// [Test] public async Task OnSecondaryEffect_NoTerrain_HealsHalfOfMaximumHp() { // Arrange var (script, move, target) = CreateTestSetup(100); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(GetHealAmount(target)!.Value).IsEqualTo(50u); } /// /// Bulbapedia: "Floral Healing restores up to ½ of the target's maximum HP." /// Various maximum HP values verify the fractional amount is truncated to a whole number. /// [Test, Arguments(200u, 100u), Arguments(101u, 50u), Arguments(99u, 49u), Arguments(3u, 1u)] public async Task OnSecondaryEffect_NoTerrain_HealCalculation(uint maxHp, uint expectedHeal) { // Arrange var (script, move, target) = CreateTestSetup(maxHp); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(GetHealAmount(target)!.Value).IsEqualTo(expectedHeal); } /// /// Bulbapedia: "If Grassy Terrain is in effect, Floral Healing will restore up to ⅔ of the target's /// maximum HP." /// [Test, Arguments(99u, 66u), Arguments(100u, 66u), Arguments(3u, 2u)] public async Task OnSecondaryEffect_GrassyTerrain_HealsTwoThirdsOfMaximumHp(uint maxHp, uint expectedHeal) { // Arrange var (script, move, target) = CreateTestSetup(maxHp, "grassy_terrain"); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(GetHealAmount(target)!.Value).IsEqualTo(expectedHeal); } /// /// Bulbapedia: only "If Grassy Terrain is in effect" is the restored amount increased to ⅔; any other /// terrain keeps the regular ½ of maximum HP. /// [Test] public async Task OnSecondaryEffect_OtherTerrain_HealsHalfOfMaximumHp() { // Arrange var (script, move, target) = CreateTestSetup(100, "misty_terrain"); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(GetHealAmount(target)!.Value).IsEqualTo(50u); } /// /// Bulbapedia: Floral Healing "restores" HP of the target; a fainted Pokémon can no longer be healed, /// so no heal is applied when the target . /// [Test] public async Task OnSecondaryEffect_TargetFainted_DoesNotHeal() { // Arrange var (script, move, target) = CreateTestSetup(100, isFainted: true); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Heal")).IsFalse(); } }