Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/EntrainmentTests.cs
2026-07-05 19:45:40 +02:00

154 lines
5.2 KiB
C#

using PkmnLib.Dynamic.Models;
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="Entrainment"/> move script.
/// Gen VII Bulbapedia behavior: "Entrainment changes the target's Ability to match the user's." It fails
/// if both Pokémon already share the same Ability, if the target's Ability cannot be changed (e.g.
/// Truant, Multitype, Stance Change, Comatose, Disguise), or if the user's Ability cannot be copied
/// (e.g. Trace, Illusion, Imposter, Power Construct).
/// </summary>
public class EntrainmentTests
{
/// <summary>
/// Creates a mocked ability that reports the given flags as set.
/// </summary>
private static IAbility CreateAbility(params string[] flags)
{
var ability = Substitute.For<IAbility>();
foreach (var flag in flags)
ability.HasFlag(new StringKey(flag)).Returns(true);
return ability;
}
private static (Entrainment script, IExecutingMove move, IPokemon target, IHitData hitData) CreateTestSetup(
IAbility? userAbility, IAbility? targetAbility)
{
var script = new Entrainment();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IPokemon>();
var hitData = Substitute.For<IHitData>();
move.GetHitData(target, 0).Returns(hitData);
var user = Substitute.For<IPokemon>();
user.ActiveAbility.Returns(userAbility);
move.User.Returns(user);
target.ActiveAbility.Returns(targetAbility);
return (script, move, target, hitData);
}
/// <summary>
/// Bulbapedia: "Entrainment changes the target's Ability to match the user's."
/// </summary>
[Test]
public void OnSecondaryEffect_DifferentAbilities_ChangesTargetAbilityToUsers()
{
// Arrange
var userAbility = CreateAbility();
var (script, move, target, hitData) = CreateTestSetup(userAbility, CreateAbility());
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
target.Received(1).ChangeAbility(userAbility);
hitData.DidNotReceive().Fail();
}
/// <summary>
/// Bulbapedia: "The move fails if both Pokémon already share the same Ability."
/// </summary>
[Test]
public void OnSecondaryEffect_SameAbility_FailsHit()
{
// Arrange
var sharedAbility = CreateAbility();
var (script, move, target, hitData) = CreateTestSetup(sharedAbility, sharedAbility);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
hitData.Received(1).Fail();
target.DidNotReceiveWithAnyArgs().ChangeAbility(default!);
}
/// <summary>
/// Bulbapedia: "The move fails if the user has: Trace, Forecast, Flower Gift, Zen Mode, Illusion,
/// Imposter, [...]" — abilities that cannot be copied prevent Entrainment from working.
/// </summary>
[Test]
public void OnSecondaryEffect_UserAbilityCantBeCopied_FailsHit()
{
// Arrange
var userAbility = CreateAbility("cant_be_copied");
var (script, move, target, hitData) = CreateTestSetup(userAbility, CreateAbility());
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
hitData.Received(1).Fail();
target.DidNotReceiveWithAnyArgs().ChangeAbility(default!);
}
/// <summary>
/// Bulbapedia: "The move cannot affect Pokémon with these Abilities: Truant, Multitype, Stance
/// Change, [...]" — a target whose ability cannot be changed prevents Entrainment from working.
/// </summary>
[Test]
public void OnSecondaryEffect_TargetAbilityCantBeChanged_FailsHit()
{
// Arrange
var targetAbility = CreateAbility("cant_be_changed");
var (script, move, target, hitData) = CreateTestSetup(CreateAbility(), targetAbility);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
hitData.Received(1).Fail();
target.DidNotReceiveWithAnyArgs().ChangeAbility(default!);
}
/// <summary>
/// Bulbapedia: "Entrainment changes the target's Ability to match the user's" — without a user
/// ability there is nothing to copy, so the move fails.
/// </summary>
[Test]
public void OnSecondaryEffect_UserHasNoAbility_FailsHit()
{
// Arrange
var (script, move, target, hitData) = CreateTestSetup(null, CreateAbility());
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
hitData.Received(1).Fail();
target.DidNotReceiveWithAnyArgs().ChangeAbility(default!);
}
/// <summary>
/// Technical test: a target without an active ability cannot have it validated for replacement, so
/// the move fails rather than throwing.
/// </summary>
[Test]
public void OnSecondaryEffect_TargetHasNoAbility_FailsHit()
{
// Arrange
var (script, move, target, hitData) = CreateTestSetup(CreateAbility(), null);
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
hitData.Received(1).Fail();
target.DidNotReceiveWithAnyArgs().ChangeAbility(default!);
}
}