Many more tests and fixes
All checks were successful
Build / Build (push) Successful in 3m12s

This commit is contained in:
2026-08-27 17:11:12 +02:00
parent 32b3ef9c4a
commit d2a82b5fe3
204 changed files with 20255 additions and 242 deletions

View 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);
}
}