136 lines
5.1 KiB
C#
136 lines
5.1 KiB
C#
using PkmnLib.Dynamic.Models;
|
||
using PkmnLib.Dynamic.ScriptHandling;
|
||
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||
using PkmnLib.Static;
|
||
|
||
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||
|
||
/// <summary>
|
||
/// Tests for the <see cref="KnockOff"/> move script.
|
||
/// Behavior is verified against the Bulbapedia page for Knock Off (Generation VII).
|
||
/// </summary>
|
||
public class KnockOffTests
|
||
{
|
||
/// <summary>
|
||
/// Creates a fully mocked test setup for Knock Off tests. When <paramref name="targetHasItem"/> is true,
|
||
/// <see cref="IBattlePokemon.TryStealHeldItem"/> succeeds and yields a mocked item.
|
||
/// </summary>
|
||
private static (KnockOff script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, IHitData hitData)
|
||
CreateTestSetup(bool targetHasItem)
|
||
{
|
||
var script = new KnockOff();
|
||
var move = Substitute.For<IExecutingMove>();
|
||
var target = Substitute.For<IBattlePokemon>();
|
||
var hitData = Substitute.For<IHitData>();
|
||
move.GetHitData(target, 0).Returns(hitData);
|
||
|
||
target.TryStealHeldItem(out Arg.Any<IItem?>()).Returns(callInfo =>
|
||
{
|
||
callInfo[0] = targetHasItem ? Substitute.For<IItem>() : null;
|
||
return targetHasItem;
|
||
});
|
||
|
||
var user = Substitute.For<IBattlePokemon>();
|
||
move.User.Returns(user);
|
||
|
||
return (script, move, target, user, hitData);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Bulbapedia: "Knock Off inflicts damage and knocks off the target's held item if it has one."
|
||
/// (Generation V onwards: "Knock Off now removes the held item rather than rendering it unusable".)
|
||
/// </summary>
|
||
[Test]
|
||
public async Task OnSecondaryEffect_TargetHoldsItem_ItemIsRemoved()
|
||
{
|
||
// Arrange
|
||
var (script, move, target, _, hitData) = CreateTestSetup(true);
|
||
|
||
// Act
|
||
script.OnSecondaryEffect(move, target, 0);
|
||
|
||
// Assert
|
||
target.Received(1).TryStealHeldItem(out Arg.Any<IItem?>());
|
||
hitData.DidNotReceive().Fail();
|
||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "TryStealHeldItem")).IsTrue();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Bulbapedia: "Knock Off inflicts damage and knocks off the target's held item if it has one."
|
||
/// Against a target without a held item the move simply deals its damage without any further effect; it
|
||
/// does not fail.
|
||
/// </summary>
|
||
[Test]
|
||
public async Task OnSecondaryEffect_TargetHoldsNoItem_HitIsNotMarkedAsFailed()
|
||
{
|
||
// Arrange
|
||
var (script, move, target, _, hitData) = CreateTestSetup(false);
|
||
|
||
// Act
|
||
script.OnSecondaryEffect(move, target, 0);
|
||
|
||
// Assert
|
||
hitData.DidNotReceive().Fail();
|
||
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsFalse();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Bulbapedia (Generation V onwards): "If the user faints due to the target's Ability (Rough Skin or
|
||
/// Iron Barbs) or held Rocky Helmet, it cannot remove the target's held item."
|
||
/// Those effects damage the user before the secondary effect runs, so a user that has fainted by then must
|
||
/// not remove the item.
|
||
/// </summary>
|
||
[Test]
|
||
public async Task OnSecondaryEffect_UserIsFainted_ItemIsNotRemoved()
|
||
{
|
||
// Arrange
|
||
var (script, move, target, user, _) = CreateTestSetup(true);
|
||
user.IsFainted.Returns(true);
|
||
|
||
// Act
|
||
script.OnSecondaryEffect(move, target, 0);
|
||
|
||
// Assert
|
||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "TryStealHeldItem")).IsFalse();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Bulbapedia (Generation VI onwards): "If Knock Off is used on a Pokémon that is holding an item that can
|
||
/// be knocked off, its base power will be boosted by 50%."
|
||
/// With Knock Off's base power of 65 the boosted power is 97 (65 × 1.5, fractions dropped).
|
||
/// </summary>
|
||
[Test]
|
||
public async Task ChangeBasePower_TargetHoldsRemovableItem_BasePowerBoostedByFiftyPercent()
|
||
{
|
||
// Arrange
|
||
var (script, move, target, _, _) = CreateTestSetup(true);
|
||
target.HeldItem.Returns(Substitute.For<IItem>());
|
||
ushort basePower = 65;
|
||
|
||
// Act
|
||
((IScriptChangeBasePower)script).ChangeBasePower(move, target, 0, ref basePower);
|
||
|
||
// Assert
|
||
await Assert.That(basePower).IsEqualTo((ushort)97);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Bulbapedia (Generation VI onwards): "If Knock Off is used on a Pokémon that is holding an item that can
|
||
/// be knocked off, its base power will be boosted by 50%."
|
||
/// A target without a held item does not grant the boost, so the base power stays unchanged.
|
||
/// </summary>
|
||
[Test]
|
||
public async Task ChangeBasePower_TargetHoldsNoItem_BasePowerUnchanged()
|
||
{
|
||
// Arrange
|
||
var (script, move, target, _, _) = CreateTestSetup(false);
|
||
target.HeldItem.Returns((IItem?)null);
|
||
ushort basePower = 65;
|
||
|
||
// Act
|
||
((IScriptChangeBasePower)script).ChangeBasePower(move, target, 0, ref basePower);
|
||
|
||
// Assert
|
||
await Assert.That(basePower).IsEqualTo((ushort)65);
|
||
}
|
||
} |