using PkmnLib.Dynamic.Models; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static; using PkmnLib.Static.Species; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: "Captivate lowers the Special Attack stat of the target by two stages, /// if it is the opposite gender of the user." Gender-unknown Pokémon and Pokémon with the Oblivious /// Ability cannot be affected, and the move fails when used by a gender-unknown Pokémon. /// public class CaptivateTests { private static (Captivate script, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData) CreateTestSetup(Gender userGender, Gender targetGender) { var script = new Captivate(); var move = Substitute.For(); var user = Substitute.For(); user.Gender.Returns(userGender); move.User.Returns(user); var target = Substitute.For(); target.Gender.Returns(targetGender); var hitData = Substitute.For(); move.GetHitData(target, 0).Returns(hitData); return (script, move, user, target, hitData); } /// /// Helper that checks whether a stat boost change was applied to the given Pokémon. /// private static bool ReceivedStatBoost(IPokemon pokemon, Statistic stat, sbyte amount) => pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost" && (Statistic)c.GetArguments()[0]! == stat && (sbyte)c.GetArguments()[1]! == amount); /// /// Bulbapedia: "Captivate lowers the Special Attack stat of the target by two stages, if it is the /// opposite gender of the user." /// [Test, Arguments(Gender.Male, Gender.Female), Arguments(Gender.Female, Gender.Male)] public async Task OnSecondaryEffect_OppositeGender_LowersTargetSpecialAttackByTwoStages(Gender userGender, Gender targetGender) { // Arrange var (script, move, _, target, hitData) = CreateTestSetup(userGender, targetGender); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(ReceivedStatBoost(target, Statistic.SpecialAttack, -2)).IsTrue(); hitData.DidNotReceive().Fail(); } /// /// Bulbapedia: Captivate only affects a target "if it is the opposite gender of the user" — against a /// same-gender target the move fails and no stat is lowered. /// [Test, Arguments(Gender.Male), Arguments(Gender.Female)] public async Task OnSecondaryEffect_SameGender_Fails(Gender gender) { // Arrange var (script, move, _, target, hitData) = CreateTestSetup(gender, gender); // Act script.OnSecondaryEffect(move, target, 0); // Assert hitData.Received(1).Fail(); await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse(); } /// /// Bulbapedia: "Pokémon that are gender-unknown [...] cannot be affected." /// [Test] public async Task OnSecondaryEffect_GenderlessTarget_Fails() { // Arrange var (script, move, _, target, hitData) = CreateTestSetup(Gender.Male, Gender.Genderless); // Act script.OnSecondaryEffect(move, target, 0); // Assert hitData.Received(1).Fail(); await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse(); } /// /// Bulbapedia: "those with the Oblivious ability cannot be affected." /// [Test] public async Task OnSecondaryEffect_TargetHasOblivious_Fails() { // Arrange var (script, move, _, target, hitData) = CreateTestSetup(Gender.Male, Gender.Female); var ability = Substitute.For(); ability.Name.Returns(new StringKey("oblivious")); target.ActiveAbility.Returns(ability); // Act script.OnSecondaryEffect(move, target, 0); // Assert hitData.Received(1).Fail(); await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse(); } /// /// Bulbapedia: "The move fails automatically if used by a gender-unknown Pokémon." A genderless user /// against a gendered target must fail rather than lower the target's Special Attack. /// [Test] public async Task OnSecondaryEffect_GenderlessUser_Fails() { // Arrange var (script, move, _, target, hitData) = CreateTestSetup(Gender.Genderless, Gender.Female); // Act script.OnSecondaryEffect(move, target, 0); // Assert hitData.Received(1).Fail(); await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse(); } }