This commit is contained in:
136
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/KnockOffTests.cs
Normal file
136
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/KnockOffTests.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
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="IPokemon.TryStealHeldItem"/> succeeds and yields a mocked item.
|
||||
/// </summary>
|
||||
private static (KnockOff script, IExecutingMove move, IPokemon target, IPokemon user, IHitData hitData)
|
||||
CreateTestSetup(bool targetHasItem)
|
||||
{
|
||||
var script = new KnockOff();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
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<IPokemon>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user