150 lines
5.7 KiB
C#
150 lines
5.7 KiB
C#
using PkmnLib.Dynamic.Models;
|
|
using PkmnLib.Dynamic.Models.Choices;
|
|
using PkmnLib.Dynamic.ScriptHandling;
|
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
|
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|
using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
|
using PkmnLib.Static;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
|
|
|
/// <summary>
|
|
/// Tests for the <see cref="Electrify"/> move script and its <see cref="ElectrifyEffect"/> move volatile.
|
|
/// Gen VII Bulbapedia behavior: "If the target has not yet used a move, Electrify makes the target's move
|
|
/// Electric-type for that turn, even if it is a status move."
|
|
/// </summary>
|
|
public class ElectrifyTests
|
|
{
|
|
/// <summary>
|
|
/// Creates a fully mocked test setup where the battle's choice queue is a real
|
|
/// <see cref="BattleChoiceQueue"/>. When <paramref name="targetStillHasChoice"/> is false, the queue
|
|
/// only contains another Pokémon's choice, simulating a target that already moved this turn.
|
|
/// </summary>
|
|
private static (Electrify script, IExecutingMove move, IPokemon target, IScriptSet choiceVolatile, IHitData hitData)
|
|
CreateTestSetup(bool targetStillHasChoice = true, bool hasQueue = true)
|
|
{
|
|
var script = new Electrify();
|
|
var move = Substitute.For<IExecutingMove>();
|
|
var target = Substitute.For<IPokemon>();
|
|
var hitData = Substitute.For<IHitData>();
|
|
move.GetHitData(target, 0).Returns(hitData);
|
|
|
|
var targetChoice = Substitute.For<IMoveChoice>();
|
|
targetChoice.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
|
IScriptSet choiceVolatile = new ScriptSet(targetChoice);
|
|
targetChoice.Volatile.Returns(choiceVolatile);
|
|
targetChoice.User.Returns(target);
|
|
|
|
var queue = new BattleChoiceQueue(targetStillHasChoice ? [targetChoice] : [Substitute.For<IMoveChoice>()]);
|
|
|
|
var battle = Substitute.For<IBattle>();
|
|
battle.ChoiceQueue.Returns(hasQueue ? queue : null);
|
|
|
|
var battleData = Substitute.For<IPokemonBattleData>();
|
|
battleData.Battle.Returns(battle);
|
|
target.BattleData.Returns(battleData);
|
|
|
|
return (script, move, target, choiceVolatile, hitData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "If the target has not yet used a move, Electrify makes the target's move Electric-type
|
|
/// for that turn" — the <see cref="ElectrifyEffect"/> is attached to the target's pending move choice.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task OnSecondaryEffect_TargetHasNotMovedYet_AddsElectrifyEffectToTargetChoice()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, choiceVolatile, hitData) = CreateTestSetup();
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
await Assert.That(choiceVolatile.Contains(ScriptUtils.ResolveName<ElectrifyEffect>())).IsTrue();
|
|
hitData.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: the effect only applies "if the target has not yet used a move" — when the target has
|
|
/// no remaining choice in the queue this turn, the move fails.
|
|
/// </summary>
|
|
[Test]
|
|
public void OnSecondaryEffect_TargetAlreadyMoved_FailsHit()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _, hitData) = CreateTestSetup(false);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
hitData.Received(1).Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: when the battle has no active choice queue, the script returns without throwing and
|
|
/// without failing the hit.
|
|
/// </summary>
|
|
[Test]
|
|
public void OnSecondaryEffect_NoChoiceQueue_DoesNothing()
|
|
{
|
|
// Arrange
|
|
var (script, move, target, _, hitData) = CreateTestSetup(hasQueue: false);
|
|
|
|
// Act
|
|
script.OnSecondaryEffect(move, target, 0);
|
|
|
|
// Assert
|
|
hitData.DidNotReceive().Fail();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Bulbapedia: "Electrify makes the target's move Electric-type for that turn, even if it is a status
|
|
/// move" — the <see cref="ElectrifyEffect"/> changes the executed move's type to Electric.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMoveType_ChangesMoveTypeToElectric()
|
|
{
|
|
// Arrange
|
|
var effect = new ElectrifyEffect();
|
|
var library = LibraryHelpers.LoadLibrary();
|
|
var battle = Substitute.For<IBattle>();
|
|
battle.Library.Returns(library);
|
|
var battleData = Substitute.For<IPokemonBattleData>();
|
|
battleData.Battle.Returns(battle);
|
|
var target = Substitute.For<IPokemon>();
|
|
target.BattleData.Returns(battleData);
|
|
|
|
await Assert.That(library.StaticLibrary.Types.TryGetTypeIdentifier("normal", out var normal)).IsTrue();
|
|
await Assert.That(library.StaticLibrary.Types.TryGetTypeIdentifier("electric", out var electric)).IsTrue();
|
|
TypeIdentifier? moveType = normal;
|
|
|
|
// Act
|
|
effect.ChangeMoveType(Substitute.For<IExecutingMove>(), target, 0, ref moveType);
|
|
|
|
// Assert
|
|
await Assert.That(moveType).IsNotNull();
|
|
await Assert.That(moveType!.Value).IsEqualTo(electric);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Technical test: without battle data on the target the move type cannot be resolved and remains
|
|
/// unchanged.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ChangeMoveType_TargetHasNoBattleData_TypeUnchanged()
|
|
{
|
|
// Arrange
|
|
var effect = new ElectrifyEffect();
|
|
var target = Substitute.For<IPokemon>();
|
|
target.BattleData.Returns((IPokemonBattleData?)null);
|
|
TypeIdentifier? moveType = null;
|
|
|
|
// Act
|
|
effect.ChangeMoveType(Substitute.For<IExecutingMove>(), target, 0, ref moveType);
|
|
|
|
// Assert
|
|
await Assert.That(moveType).IsNull();
|
|
}
|
|
} |