Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/CoreEnforcerTests.cs
Deukhoofd 6a82c20cf2
All checks were successful
Build / Build (push) Successful in 1m57s
More tests, more fixes
2026-07-05 18:26:55 +02:00

181 lines
6.8 KiB
C#

using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.Models.Choices;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Static.Species;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="CoreEnforcer"/> move script.
/// Gen VII Bulbapedia behavior: "Core Enforcer deals damage. If the target has already used a move or had
/// a Bag item used on it by its Trainer in the same turn, Core Enforcer also suppresses the target's
/// Ability while it remains in battle."
/// </summary>
public class CoreEnforcerTests
{
private static (CoreEnforcer script, IExecutingMove move, IMoveChoice currentChoice, IPokemon target, IHitData
hitData, IBattle battle) CreateTestSetup()
{
var script = new CoreEnforcer();
var battle = Substitute.For<IBattle>();
var battleData = Substitute.For<IPokemonBattleData>();
battleData.Battle.Returns(battle);
var target = Substitute.For<IPokemon>();
target.BattleData.Returns(battleData);
var currentChoice = Substitute.For<IMoveChoice>();
var move = Substitute.For<IExecutingMove>();
move.MoveChoice.Returns(currentChoice);
var hitData = Substitute.For<IHitData>();
move.GetHitData(target, 0).Returns(hitData);
return (script, move, currentChoice, target, hitData, battle);
}
private static void SetTurnChoices(IBattle battle, params ITurnChoice[] choices)
{
battle.PreviousTurnChoices.Returns(new List<IReadOnlyList<ITurnChoice>> { choices });
}
/// <summary>
/// Bulbapedia: "If the target has already used a move [...] in the same turn, Core Enforcer also
/// suppresses the target's Ability while it remains in battle."
/// </summary>
[Test]
public void OnSecondaryEffect_TargetMovedEarlierInTurn_SuppressesTargetAbility()
{
// Arrange
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
var targetChoice = Substitute.For<IMoveChoice>();
targetChoice.User.Returns(target);
SetTurnChoices(battle, targetChoice, currentChoice);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.Received(1).SuppressAbility();
hitData.DidNotReceive().Fail();
}
/// <summary>
/// Bulbapedia: the suppression also happens if the target "had a Bag item used on it by its Trainer in
/// the same turn".
/// </summary>
[Test]
public void OnSecondaryEffect_ItemUsedEarlierInTurn_SuppressesTargetAbility()
{
// Arrange
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
var itemChoice = Substitute.For<IItemChoice>();
itemChoice.User.Returns(target);
SetTurnChoices(battle, itemChoice, currentChoice);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.Received(1).SuppressAbility();
hitData.DidNotReceive().Fail();
}
/// <summary>
/// Bulbapedia: the Ability is only suppressed "If the target has already used a move [...] in the same
/// turn" — when Core Enforcer strikes before the target has acted, no suppression happens.
/// </summary>
[Test]
public void OnSecondaryEffect_TargetActsLaterInTurn_DoesNotSuppressAbility()
{
// Arrange
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
var targetChoice = Substitute.For<IMoveChoice>();
targetChoice.User.Returns(target);
SetTurnChoices(battle, currentChoice, targetChoice);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.DidNotReceive().SuppressAbility();
hitData.Received(1).Fail();
}
/// <summary>
/// Bulbapedia: suppression requires the target to have already acted — as the very first action of the
/// turn, Core Enforcer never suppresses.
/// </summary>
[Test]
public void OnSecondaryEffect_CoreEnforcerIsFirstActionOfTurn_DoesNotSuppressAbility()
{
// Arrange
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
SetTurnChoices(battle, currentChoice);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.DidNotReceive().SuppressAbility();
hitData.Received(1).Fail();
}
/// <summary>
/// Technical test: a target without battle data (not in battle) is left untouched.
/// </summary>
[Test]
public void OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
{
// Arrange
var (script, move, _, target, hitData, _) = CreateTestSetup();
target.BattleData.Returns((IPokemonBattleData?)null);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.DidNotReceive().SuppressAbility();
hitData.DidNotReceive().Fail();
}
/// <summary>
/// Bulbapedia: the condition is that "the target has already used a move" — an action by a different
/// Pokémon (e.g. the user's ally in a Double Battle) does not count as the target having acted.
/// </summary>
[Test]
public void OnSecondaryEffect_OnlyOtherPokemonActedEarlier_DoesNotSuppressAbility()
{
// Arrange
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
var allyChoice = Substitute.For<IMoveChoice>();
allyChoice.User.Returns(Substitute.For<IPokemon>());
SetTurnChoices(battle, allyChoice, currentChoice);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.DidNotReceive().SuppressAbility();
hitData.Received(1).Fail();
}
/// <summary>
/// Bulbapedia: "The move cannot suppress certain signature abilities including Multitype, Stance
/// Change, Schooling, Comatose, Shields Down, Disguise, RKS System, Battle Bond, Power Construct".
/// The script requests the suppression unconditionally; <see cref="IPokemon.SuppressAbility"/> refuses
/// it when <see cref="IAbility.CanBeChanged"/> is false, so these abilities must carry that flag in the
/// Gen7 data.
/// </summary>
[Test, Arguments("multitype"), Arguments("stance_change"), Arguments("schooling"), Arguments("comatose"),
Arguments("shields_down"), Arguments("disguise"), Arguments("rks_system"), Arguments("battle_bond"),
Arguments("power_construct")]
public async Task OnSecondaryEffect_UnsuppressableAbility_IsProtectedByAbilityData(string abilityName)
{
// Arrange
var library = LibraryHelpers.LoadLibrary();
// Assert
await Assert.That(library.StaticLibrary.Abilities.TryGet(new StringKey(abilityName), out var ability)).IsTrue();
await Assert.That(ability!.CanBeChanged).IsFalse();
}
}