Files
PkmnLib.NET/Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/FuryCutterTests.cs
Deukhoofd d2a82b5fe3
All checks were successful
Build / Build (push) Successful in 3m12s
Many more tests and fixes
2026-08-27 17:11:12 +02:00

173 lines
6.7 KiB
C#

using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Dynamic.ScriptHandling.Registry;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
/// <summary>
/// Tests for the <see cref="FuryCutter"/> move script and its <see cref="FuryCutterEffect"/> volatile.
/// Gen VII Bulbapedia behavior: "Every time Fury Cutter hits the power will double", and (Generation VI
/// onwards) "Fury Cutter's base power increased even further from 20 to 40, meaning that it takes three
/// consecutive turns to reach the maximum power of 160."
/// </summary>
public class FuryCutterTests
{
/// <summary>
/// Creates a fully mocked test setup where the user's volatile scripts are a real
/// <see cref="ScriptSet"/>, so the <see cref="FuryCutterEffect"/> added by the move can be inspected.
/// </summary>
private static (FuryCutter script, IExecutingMove move, IPokemon target, IPokemon user, ScriptSet userVolatile)
CreateTestSetup()
{
var script = new FuryCutter();
var move = Substitute.For<IExecutingMove>();
var target = Substitute.For<IPokemon>();
var user = Substitute.For<IPokemon>();
var userVolatile = new ScriptSet(user);
user.Volatile.Returns(userVolatile);
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
move.User.Returns(user);
return (script, move, target, user, userVolatile);
}
/// <summary>
/// Simulates the given number of consecutive uses of Fury Cutter, feeding the Gen VII base power of 40
/// into each use, and returns the base power of the final use.
/// </summary>
private static ushort SimulateConsecutiveUses(FuryCutter script, IExecutingMove move, IPokemon target, int uses)
{
ushort basePower = 40;
for (var i = 0; i < uses; i++)
{
basePower = 40;
script.ChangeBasePower(move, target, 0, ref basePower);
}
return basePower;
}
/// <summary>
/// Bulbapedia (Generation VI onwards): "Fury Cutter's base power increased even further from 20 to 40" —
/// on the first use there is no previous hit, so the base power is not modified.
/// </summary>
[Test]
public async Task ChangeBasePower_FirstUse_BasePowerUnchanged()
{
// Arrange
var (script, move, target, _, _) = CreateTestSetup();
// Act
var basePower = SimulateConsecutiveUses(script, move, target, 1);
// Assert
await Assert.That(basePower).IsEqualTo((ushort)40);
}
/// <summary>
/// Bulbapedia: the power doubles on consecutive hits — the first use attaches the
/// <see cref="FuryCutterEffect"/> volatile to the user so the next use is recognized as consecutive.
/// </summary>
[Test]
public async Task ChangeBasePower_FirstUse_AddsFuryCutterEffectToUser()
{
// Arrange
var (script, move, target, _, userVolatile) = CreateTestSetup();
// Act
SimulateConsecutiveUses(script, move, target, 1);
// Assert
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<FuryCutterEffect>())).IsTrue();
}
/// <summary>
/// Bulbapedia: "Every time Fury Cutter hits the power will double" — the second consecutive use has
/// power 80 and the third consecutive use reaches the maximum of 160.
/// </summary>
[Test, Arguments(2, (ushort)80), Arguments(3, (ushort)160)]
public async Task ChangeBasePower_ConsecutiveUses_PowerDoublesEachTurn(int uses, ushort expectedPower)
{
// Arrange
var (script, move, target, _, _) = CreateTestSetup();
// Act
var basePower = SimulateConsecutiveUses(script, move, target, uses);
// Assert
await Assert.That(basePower).IsEqualTo(expectedPower);
}
/// <summary>
/// Bulbapedia (Generation VI onwards): "it takes three consecutive turns to reach the maximum power of
/// 160" — uses beyond the third consecutive turn stay capped at 160 and do not keep doubling.
/// </summary>
[Test, Arguments(4), Arguments(5), Arguments(6)]
public async Task ChangeBasePower_BeyondThirdConsecutiveUse_PowerCappedAt160(int uses)
{
// Arrange
var (script, move, target, _, _) = CreateTestSetup();
// Act
var basePower = SimulateConsecutiveUses(script, move, target, uses);
// Assert
await Assert.That(basePower).IsEqualTo((ushort)160);
}
/// <summary>
/// Bulbapedia (Generation V onwards): "If another move is selected, its power resets to normal." — when
/// the user executes a different move, the <see cref="FuryCutterEffect"/> removes itself, resetting the
/// doubling progression.
/// </summary>
[Test]
public async Task OnBeforeMove_DifferentMoveUsed_EffectRemovesItself()
{
// Arrange
var user = Substitute.For<IPokemon>();
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
var userVolatile = new ScriptSet(user);
var effect = new FuryCutterEffect();
userVolatile.Add(effect);
var otherMove = Substitute.For<IExecutingMove>();
var otherMoveData = Substitute.For<IMoveData>();
otherMoveData.Name.Returns(new StringKey("tackle"));
otherMove.UseMove.Returns(otherMoveData);
// Act
effect.OnBeforeMove(otherMove);
// Assert
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<FuryCutterEffect>())).IsFalse();
}
/// <summary>
/// Bulbapedia: the doubling continues on "consecutive turns" — when Fury Cutter is used again, the
/// <see cref="FuryCutterEffect"/> stays on the user so the progression continues.
/// </summary>
[Test]
public async Task OnBeforeMove_FuryCutterUsedAgain_EffectPersists()
{
// Arrange
var user = Substitute.For<IPokemon>();
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
var userVolatile = new ScriptSet(user);
var effect = new FuryCutterEffect();
userVolatile.Add(effect);
var furyCutterMove = Substitute.For<IExecutingMove>();
var furyCutterMoveData = Substitute.For<IMoveData>();
furyCutterMoveData.Name.Returns(new StringKey("fury_cutter"));
furyCutterMove.UseMove.Returns(furyCutterMoveData);
// Act
effect.OnBeforeMove(furyCutterMove);
// Assert
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<FuryCutterEffect>())).IsTrue();
}
}