168 lines
7.0 KiB
C#
168 lines
7.0 KiB
C#
using PkmnLib.Dynamic.Libraries;
|
|
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Dynamic.Models.Choices;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Static.Libraries;
|
|
using PkmnLib.Static.Moves;
|
|
using PkmnLib.Static.Utils;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="Metronome"/> script, which implements Metronome.
|
|
/// Behavior is verified against the Bulbapedia page for Metronome (Generation VII).
|
|
/// </summary>
|
|
public class MetronomeTests
|
|
{
|
|
/// <summary>
|
|
/// Creates a fully mocked test setup for Metronome tests. The user's move library and battle random are
|
|
/// mocked so that tests control which move <see cref="Metronome.ChangeMove"/> "randomly" rolls.
|
|
/// </summary>
|
|
private static (Metronome metronome, IMoveChoice choice, IPokemon user, IReadOnlyMoveLibrary moveLibrary,
|
|
IBattleRandom random) CreateTestSetup()
|
|
{
|
|
var metronome = new Metronome();
|
|
var user = Substitute.For<IPokemon>();
|
|
var choice = Substitute.For<IMoveChoice>();
|
|
choice.User.Returns(user);
|
|
|
|
var battle = Substitute.For<IBattle>();
|
|
var random = Substitute.For<IBattleRandom>();
|
|
battle.Random.Returns(random);
|
|
var battleData = Substitute.For<IPokemonBattleData>();
|
|
battleData.Battle.Returns(battle);
|
|
user.BattleData.Returns(battleData);
|
|
|
|
var moveLibrary = Substitute.For<IReadOnlyMoveLibrary>();
|
|
var staticLibrary = Substitute.For<IStaticLibrary>();
|
|
staticLibrary.Moves.Returns(moveLibrary);
|
|
var dynamicLibrary = Substitute.For<IDynamicLibrary>();
|
|
dynamicLibrary.StaticLibrary.Returns(staticLibrary);
|
|
user.Library.Returns(dynamicLibrary);
|
|
|
|
return (metronome, choice, user, moveLibrary, random);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a mocked <see cref="IMoveData"/> with the given name.
|
|
/// </summary>
|
|
private static IMoveData CreateMoveData(string name)
|
|
{
|
|
var moveData = Substitute.For<IMoveData>();
|
|
moveData.Name.Returns(new StringKey(name));
|
|
return moveData;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The Metronome user executes a randomly selected move."
|
|
/// The move rolled from the move library replaces the used move name.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_SelectableMoveRolled_MoveNameChangesToRolledMove()
|
|
{
|
|
// Arrange
|
|
var (metronome, choice, _, moveLibrary, random) = CreateTestSetup();
|
|
var tackle = CreateMoveData("tackle");
|
|
moveLibrary.GetRandom(random).Returns(tackle);
|
|
var moveName = new StringKey("metronome");
|
|
|
|
// Act
|
|
metronome.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("tackle"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, the script cannot roll a random
|
|
/// move and must leave the move name unchanged.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_UserHasNoBattleData_MoveNameUnchanged()
|
|
{
|
|
// Arrange
|
|
var (metronome, choice, user, moveLibrary, random) = CreateTestSetup();
|
|
user.BattleData.Returns((IPokemonBattleData?)null);
|
|
var tackle = CreateMoveData("tackle");
|
|
moveLibrary.GetRandom(random).Returns(tackle);
|
|
var moveName = new StringKey("metronome");
|
|
|
|
// Act
|
|
metronome.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("metronome"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Metronome cannot select a Max Move, a Z-Move, or any of the moves" in its list of
|
|
/// unselectable moves. When an unselectable move is rolled, the script rerolls until it finds a
|
|
/// selectable one.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMove_UnselectableMoveRolledFirst_RerollsUntilSelectableMove()
|
|
{
|
|
// Arrange
|
|
var (metronome, choice, _, moveLibrary, random) = CreateTestSetup();
|
|
var protect = CreateMoveData("protect");
|
|
var tackle = CreateMoveData("tackle");
|
|
moveLibrary.GetRandom(random).Returns(protect, tackle);
|
|
var moveName = new StringKey("metronome");
|
|
|
|
// Act
|
|
metronome.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("tackle"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Metronome cannot select a Max Move, a Z-Move, or any of the moves" in its list of
|
|
/// unselectable moves. A sample of moves that are unselectable in Generation VII (including Metronome
|
|
/// itself) is rolled first; the script must skip them and use the next (selectable) roll instead.
|
|
/// </summary>
|
|
[Test, Arguments("metronome"), Arguments("protect"), Arguments("detect"), Arguments("endure"), Arguments("counter"),
|
|
Arguments("mirror_coat"), Arguments("mirror_move"), Arguments("mimic"), Arguments("sketch"),
|
|
Arguments("sleep_talk"), Arguments("struggle"), Arguments("transform"), Arguments("destiny_bond"),
|
|
Arguments("focus_punch"), Arguments("helping_hand"), Arguments("assist"), Arguments("copycat"),
|
|
Arguments("chatter"), Arguments("after_you"), Arguments("quash"), Arguments("wide_guard"),
|
|
Arguments("quick_guard"), Arguments("instruct"), Arguments("spectral_thief"), Arguments("crafty_shield"),
|
|
Arguments("snore")]
|
|
public async Task ChangeMove_Gen7UnselectableMoveRolled_IsNeverSelected(string unselectableMove)
|
|
{
|
|
// Arrange
|
|
var (metronome, choice, _, moveLibrary, random) = CreateTestSetup();
|
|
var rolled = CreateMoveData(unselectableMove);
|
|
var tackle = CreateMoveData("tackle");
|
|
moveLibrary.GetRandom(random).Returns(rolled, tackle);
|
|
var moveName = new StringKey("metronome");
|
|
|
|
// Act
|
|
metronome.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert - the unselectable move was skipped in favor of the next roll.
|
|
await Assert.That(moveName).IsEqualTo(new StringKey("tackle"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "The Metronome user executes a randomly selected move." Moves such as Dig, Fly, and Roar do
|
|
/// not appear in the Generation VII column of Bulbapedia's list of moves Metronome cannot select, so
|
|
/// Metronome must be able to call them (they are only excluded for other copying moves such as Assist).
|
|
/// </summary>
|
|
[Test, Arguments("dig"), Arguments("fly"), Arguments("roar")]
|
|
public async Task ChangeMove_MoveSelectableByMetronomeButBannedForAssistRolled_IsSelected(string selectableMove)
|
|
{
|
|
// Arrange
|
|
var (metronome, choice, _, moveLibrary, random) = CreateTestSetup();
|
|
var rolled = CreateMoveData(selectableMove);
|
|
var tackle = CreateMoveData("tackle");
|
|
moveLibrary.GetRandom(random).Returns(rolled, tackle);
|
|
var moveName = new StringKey("metronome");
|
|
|
|
// Act
|
|
metronome.ChangeMove(choice, ref moveName);
|
|
|
|
// Assert - the first roll is selectable by Metronome in Generation VII, so it must be used.
|
|
await Assert.That(moveName).IsEqualTo(new StringKey(selectableMove));
|
|
}
|
|
} |