Move all battle state from IPokemon to an ephemeral IBattlePokemon wrapper
This commit is contained in:
@@ -23,7 +23,7 @@ public class DamageCalculatorTests
|
||||
[Test]
|
||||
public async Task BulbapediaExampleDamageTest()
|
||||
{
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
// Imagine a level 75 Glaceon
|
||||
attacker.Level.Returns((byte)75);
|
||||
// with an effective Attack stat of 123
|
||||
@@ -31,7 +31,7 @@ public class DamageCalculatorTests
|
||||
// We use 10 as the Ice type
|
||||
attacker.Types.Returns([new TypeIdentifier(10, "ice")]);
|
||||
|
||||
var defender = Substitute.For<IPokemon>();
|
||||
var defender = Substitute.For<IBattlePokemon>();
|
||||
// a Garchomp with an effective Defense stat of 163
|
||||
defender.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 163, 1, 1, 1));
|
||||
defender.GetScripts().Returns(new ScriptIterator([]));
|
||||
|
||||
@@ -14,12 +14,12 @@ public class AftermathTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Aftermath tests.
|
||||
/// </summary>
|
||||
private static (Aftermath aftermath, IExecutingMove move, IPokemon target, IPokemon user, EventHook eventHook,
|
||||
IBattle battle) CreateFullTestSetup(bool isContact, uint userMaxHealth = 100)
|
||||
private static (Aftermath aftermath, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, EventHook
|
||||
eventHook, IBattle battle) CreateFullTestSetup(bool isContact, uint userMaxHealth = 100)
|
||||
{
|
||||
var aftermath = new Aftermath();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.IsContact.Returns(isContact);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
@@ -30,20 +30,14 @@ public class AftermathTests
|
||||
|
||||
// Setup empty sides by default (no Damp on field)
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.Pokemon.Returns(new List<IPokemon?>());
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?>());
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.IsUsable.Returns(true);
|
||||
user.Battle.Returns(battle);
|
||||
user.MaxHealth.Returns(userMaxHealth);
|
||||
|
||||
// Configure BattleData return value using NSubstitute's callback pattern
|
||||
// First return null to suppress auto-substitution, then configure actual value
|
||||
user.BattleData.Returns(battleData);
|
||||
|
||||
move.User.Returns(user);
|
||||
|
||||
return (aftermath, move, target, user, eventHook, battle);
|
||||
@@ -52,7 +46,7 @@ public class AftermathTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a substitute's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint GetDamageDealt(IPokemon user)
|
||||
private static uint GetDamageDealt(IBattlePokemon user)
|
||||
{
|
||||
var damageCall = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return damageCall != null ? (uint)damageCall.GetArguments()[0]! : 0;
|
||||
@@ -61,7 +55,7 @@ public class AftermathTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from a substitute's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon user)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon user)
|
||||
{
|
||||
var damageCall = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return damageCall != null ? (DamageSource)damageCall.GetArguments()[1]! : null;
|
||||
@@ -151,12 +145,12 @@ public class AftermathTests
|
||||
// Arrange
|
||||
var aftermath = new Aftermath();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.IsContact.Returns(true);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.IsUsable.Returns(false); // Attacker already fainted
|
||||
move.User.Returns(user);
|
||||
|
||||
@@ -168,34 +162,6 @@ public class AftermathTests
|
||||
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Damage")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "the attacking Pokémon takes damage".
|
||||
/// If the attacker has no battle data, no damage should be dealt.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnFaint_AttackerHasNoBattleData_DoesNotDealDamage()
|
||||
{
|
||||
// Arrange
|
||||
var aftermath = new Aftermath();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.IsContact.Returns(true);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.IsUsable.Returns(true);
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
|
||||
// Act
|
||||
aftermath.OnIncomingHit(move, target, 0);
|
||||
aftermath.OnFaint(target, DamageSource.MoveDamage);
|
||||
|
||||
// Assert - Damage should never be called because BattleData is null
|
||||
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Damage")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: Verifies OnFaint handles the case where no attack was received.
|
||||
/// </summary>
|
||||
@@ -204,7 +170,7 @@ public class AftermathTests
|
||||
{
|
||||
// Arrange
|
||||
var aftermath = new Aftermath();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act & Assert - Should not throw when _lastAttack is null
|
||||
aftermath.OnFaint(target, DamageSource.MoveDamage);
|
||||
@@ -220,19 +186,16 @@ public class AftermathTests
|
||||
{
|
||||
// Arrange
|
||||
var aftermath = new Aftermath();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var eventHook = new EventHook();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
|
||||
// Setup empty sides (no Damp on field)
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.Pokemon.Returns(new List<IPokemon?>());
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?>());
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
// First hit - non-contact
|
||||
var move1 = Substitute.For<IExecutingMove>();
|
||||
var hitData1 = Substitute.For<IHitData>();
|
||||
@@ -244,10 +207,10 @@ public class AftermathTests
|
||||
var hitData2 = Substitute.For<IHitData>();
|
||||
hitData2.IsContact.Returns(true);
|
||||
move2.GetHitData(target, 0).Returns(hitData2);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.IsUsable.Returns(true);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.MaxHealth.Returns(100u);
|
||||
user.Battle.Returns(battle);
|
||||
move2.User.Returns(user);
|
||||
|
||||
// Act
|
||||
@@ -268,7 +231,7 @@ public class AftermathTests
|
||||
{
|
||||
// Arrange
|
||||
var aftermath = new Aftermath();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// First hit - contact
|
||||
var move1 = Substitute.For<IExecutingMove>();
|
||||
@@ -346,14 +309,14 @@ public class AftermathTests
|
||||
var (aftermath, move, target, user, _, battle) = CreateFullTestSetup(true, 100);
|
||||
|
||||
// Create a Pokemon with Damp ability on the field
|
||||
var dampPokemon = Substitute.For<IPokemon>();
|
||||
var dampPokemon = Substitute.For<IBattlePokemon>();
|
||||
var dampAbility = Substitute.For<IAbility>();
|
||||
dampAbility.Name.Returns(new StringKey("damp"));
|
||||
dampPokemon.ActiveAbility.Returns(dampAbility);
|
||||
|
||||
// Update battle sides to include the Damp Pokemon
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.Pokemon.Returns(new List<IPokemon?> { dampPokemon });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { dampPokemon });
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
// Act
|
||||
|
||||
@@ -16,9 +16,9 @@ public class MegaLauncherTests
|
||||
{
|
||||
// Arrange
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var healPercent = 0.5f;
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
move.UseMove.Category.Returns(MoveCategory.Special);
|
||||
move.UseMove.HasFlag(MoveFlags.Pulse).Returns(true);
|
||||
|
||||
@@ -22,7 +22,7 @@ public class FireGrassPledgeMoveTests
|
||||
/// Creates a fully mocked test setup. The target's battle side gets a real <see cref="ScriptSet"/> as
|
||||
/// its volatile script set, so the sea of fire created by the combined move can be inspected and driven.
|
||||
/// </summary>
|
||||
private static (FireGrassPledgeMove script, IExecutingMove move, IPokemon target, IBattleSide side, IScriptSet
|
||||
private static (FireGrassPledgeMove script, IExecutingMove move, IBattlePokemon target, IBattleSide side, IScriptSet
|
||||
sideVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new FireGrassPledgeMove();
|
||||
@@ -33,11 +33,9 @@ public class FireGrassPledgeMoveTests
|
||||
var sideVolatile = new ScriptSet(side);
|
||||
side.VolatileScripts.Returns(sideVolatile);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.BattleSide.Returns(side);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.BattleSide.Returns(side);
|
||||
return (script, move, target, side, sideVolatile);
|
||||
}
|
||||
|
||||
@@ -45,9 +43,9 @@ public class FireGrassPledgeMoveTests
|
||||
/// Creates a Pokémon substitute of the given type with the given maximum HP, for placing on the side
|
||||
/// covered by the sea of fire.
|
||||
/// </summary>
|
||||
private static IPokemon CreateSidePokemon(string typeName, uint maxHealth)
|
||||
private static IBattlePokemon CreateSidePokemon(string typeName, uint maxHealth)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Types.Returns(new List<TypeIdentifier> { new(1, typeName) });
|
||||
pokemon.MaxHealth.Returns(maxHealth);
|
||||
return pokemon;
|
||||
@@ -56,7 +54,7 @@ public class FireGrassPledgeMoveTests
|
||||
/// <summary>
|
||||
/// Helper to count the Damage calls a Pokémon received.
|
||||
/// </summary>
|
||||
private static int CountDamageCalls(IPokemon pokemon) =>
|
||||
private static int CountDamageCalls(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Count(c => c.GetMethodInfo().Name == "Damage");
|
||||
|
||||
/// <summary>
|
||||
@@ -112,24 +110,6 @@ public class FireGrassPledgeMoveTests
|
||||
await Assert.That(sideVolatile.Get<SeaOfFireEffect>()).IsNotNull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: if the target has no <see cref="IPokemon.BattleData"/>, no sea of fire is created
|
||||
/// and the script does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, sideVolatile) = CreateTestSetup();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(sideVolatile.Count).IsEqualTo(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The sea of fire damages all non-Fire Pokémon on that side of the field for 1/8 of
|
||||
/// their maximum HP at the end of each turn."
|
||||
@@ -141,7 +121,7 @@ public class FireGrassPledgeMoveTests
|
||||
// Arrange
|
||||
var (script, move, target, side, sideVolatile) = CreateTestSetup();
|
||||
var waterPokemon = CreateSidePokemon("water", maxHealth);
|
||||
side.Pokemon.Returns(new List<IPokemon?> { waterPokemon });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { waterPokemon });
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var seaOfFire = sideVolatile.Get<SeaOfFireEffect>()!;
|
||||
|
||||
@@ -164,7 +144,7 @@ public class FireGrassPledgeMoveTests
|
||||
// Arrange
|
||||
var (script, move, target, side, sideVolatile) = CreateTestSetup();
|
||||
var firePokemon = CreateSidePokemon("fire", 100);
|
||||
side.Pokemon.Returns(new List<IPokemon?> { firePokemon });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { firePokemon });
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var seaOfFire = sideVolatile.Get<SeaOfFireEffect>()!;
|
||||
|
||||
@@ -185,7 +165,7 @@ public class FireGrassPledgeMoveTests
|
||||
// Arrange
|
||||
var (script, move, target, side, sideVolatile) = CreateTestSetup();
|
||||
var waterPokemon = CreateSidePokemon("water", 96);
|
||||
side.Pokemon.Returns(new List<IPokemon?> { waterPokemon });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { waterPokemon });
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var seaOfFire = sideVolatile.Get<SeaOfFireEffect>()!;
|
||||
var battle = Substitute.For<IBattle>();
|
||||
@@ -207,7 +187,7 @@ public class FireGrassPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, side, sideVolatile) = CreateTestSetup();
|
||||
side.Pokemon.Returns(new List<IPokemon?>());
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?>());
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var seaOfFire = sideVolatile.Get<SeaOfFireEffect>()!;
|
||||
var battle = Substitute.For<IBattle>();
|
||||
|
||||
@@ -20,7 +20,7 @@ public class FireWaterPledgeMoveTests
|
||||
/// Creates a fully mocked test setup. The user's battle side gets a real <see cref="ScriptSet"/> as its
|
||||
/// volatile script set, so the rainbow created by the combined move can be inspected and driven.
|
||||
/// </summary>
|
||||
private static (FireWaterPledgeMove script, IExecutingMove move, IPokemon user, IBattleSide side, IScriptSet
|
||||
private static (FireWaterPledgeMove script, IExecutingMove move, IBattlePokemon user, IBattleSide side, IScriptSet
|
||||
sideVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new FireWaterPledgeMove();
|
||||
@@ -31,11 +31,9 @@ public class FireWaterPledgeMoveTests
|
||||
var sideVolatile = new ScriptSet(side);
|
||||
side.VolatileScripts.Returns(sideVolatile);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.BattleSide.Returns(side);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.BattleSide.Returns(side);
|
||||
|
||||
return (script, move, user, side, sideVolatile);
|
||||
}
|
||||
@@ -67,7 +65,7 @@ public class FireWaterPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _, _) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 80;
|
||||
|
||||
// Act
|
||||
@@ -86,7 +84,7 @@ public class FireWaterPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _, sideVolatile) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -95,25 +93,6 @@ public class FireWaterPledgeMoveTests
|
||||
await Assert.That(sideVolatile.Get<RainbowEffect>()).IsNotNull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, no rainbow is created and the
|
||||
/// script does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_UserHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, _, sideVolatile) = CreateTestSetup();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(sideVolatile.Count).IsEqualTo(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The rainbow doubles the probability of additional effects taking place for moves used
|
||||
/// by that side of the field".
|
||||
@@ -123,7 +102,7 @@ public class FireWaterPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _, sideVolatile) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var rainbow = sideVolatile.Get<RainbowEffect>()!;
|
||||
|
||||
@@ -143,7 +122,7 @@ public class FireWaterPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, side, sideVolatile) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var rainbow = sideVolatile.Get<RainbowEffect>()!;
|
||||
var battle = Substitute.For<IBattle>();
|
||||
@@ -165,7 +144,7 @@ public class FireWaterPledgeMoveTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, side, sideVolatile) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
var rainbow = sideVolatile.Get<RainbowEffect>()!;
|
||||
var battle = Substitute.For<IBattle>();
|
||||
|
||||
@@ -11,9 +11,9 @@ public class AcrobaticsTests
|
||||
{
|
||||
// Arrange
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.HeldItem.Returns((IItem?)null);
|
||||
move.User.Returns(user);
|
||||
var acrobatics = new Acrobatics();
|
||||
@@ -30,9 +30,9 @@ public class AcrobaticsTests
|
||||
{
|
||||
// Arrange
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.HeldItem.Returns(Substitute.For<IItem>());
|
||||
move.User.Returns(user);
|
||||
var acrobatics = new Acrobatics();
|
||||
@@ -49,9 +49,9 @@ public class AcrobaticsTests
|
||||
{
|
||||
// Arrange
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = ushort.MaxValue - 100;
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.HeldItem.Returns((IItem?)null);
|
||||
var acrobatics = new Acrobatics();
|
||||
|
||||
@@ -13,24 +13,22 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class AcupressureTests
|
||||
{
|
||||
private static (Acupressure script, IExecutingMove move, IPokemon target, IBattleRandom random, IHitData hitData)
|
||||
CreateTestSetup()
|
||||
private static (Acupressure script, IExecutingMove move, IBattlePokemon target, IBattleRandom random, IHitData
|
||||
hitData) CreateTestSetup()
|
||||
{
|
||||
var script = new Acupressure();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Random.Returns(random);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
target.StatBoost.Returns(new StatBoostStatisticSet());
|
||||
|
||||
@@ -40,7 +38,7 @@ public class AcupressureTests
|
||||
/// <summary>
|
||||
/// Helper to extract the stat argument of a ChangeStatBoost call received by the target.
|
||||
/// </summary>
|
||||
private static object?[]? GetStatBoostCallArgs(IPokemon target)
|
||||
private static object?[]? GetStatBoostCallArgs(IBattlePokemon target)
|
||||
{
|
||||
var call = target.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
return call?.GetArguments();
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class AfterYouTests
|
||||
{
|
||||
private static IMoveChoice CreateChoice(IPokemon user, uint speed)
|
||||
private static IMoveChoice CreateChoice(IBattlePokemon user, uint speed)
|
||||
{
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -25,16 +25,14 @@ public class AfterYouTests
|
||||
var script = new AfterYou();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(Arg.Any<IPokemon>(), Arg.Any<byte>()).Returns(hitData);
|
||||
move.GetHitData(Arg.Any<IBattlePokemon>(), Arg.Any<byte>()).Returns(hitData);
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, hitData);
|
||||
}
|
||||
@@ -47,9 +45,9 @@ public class AfterYouTests
|
||||
public async Task OnSecondaryEffect_TargetLaterInQueue_TargetMovesNext()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var other = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var other = Substitute.For<IBattlePokemon>();
|
||||
// Sorted by speed: user (100), other (75), target (50)
|
||||
var queue = new BattleChoiceQueue([
|
||||
CreateChoice(user, 100), CreateChoice(other, 75), CreateChoice(target, 50),
|
||||
@@ -75,8 +73,8 @@ public class AfterYouTests
|
||||
public void OnSecondaryEffect_TargetAlreadyMoved_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
// Sorted by speed: target (100), user (50)
|
||||
var queue = new BattleChoiceQueue([
|
||||
CreateChoice(target, 100), CreateChoice(user, 50),
|
||||
@@ -103,8 +101,8 @@ public class AfterYouTests
|
||||
public void OnSecondaryEffect_TargetAlreadyNext_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
// Sorted by speed: user (100), target (50)
|
||||
var queue = new BattleChoiceQueue([
|
||||
CreateChoice(user, 100), CreateChoice(target, 50),
|
||||
@@ -132,7 +130,7 @@ public class AfterYouTests
|
||||
var (script, move, hitData) = CreateTestSetup(null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
hitData.DidNotReceive().Fail();
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class AssistTests
|
||||
{
|
||||
private static IPokemon CreatePokemonWithMoves(params string[] moveNames)
|
||||
private static IBattlePokemon CreatePokemonWithMoves(params string[] moveNames)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
var moves = moveNames.Select(name =>
|
||||
{
|
||||
var learned = Substitute.For<ILearnedMove>();
|
||||
@@ -30,27 +30,23 @@ public class AssistTests
|
||||
return pokemon;
|
||||
}
|
||||
|
||||
private static (Assist script, IMoveChoice choice, IPokemon user, IBattleRandom random) CreateTestSetup(
|
||||
params IPokemon?[] otherPartyMembers)
|
||||
private static (Assist script, IMoveChoice choice, IBattlePokemon user, IBattleRandom random) CreateTestSetup(
|
||||
params IBattlePokemon?[] otherPartyMembers)
|
||||
{
|
||||
var script = new Assist();
|
||||
var user = CreatePokemonWithMoves("tackle");
|
||||
|
||||
var members = new List<IPokemon?> { user };
|
||||
var members = new List<IBattlePokemon?> { user };
|
||||
members.AddRange(otherPartyMembers);
|
||||
|
||||
var party = Substitute.For<IPokemonParty>();
|
||||
party.GetEnumerator().Returns(_ => members.GetEnumerator());
|
||||
var battleParty = Substitute.For<IBattleParty>();
|
||||
battleParty.Party.Returns(party);
|
||||
battleParty.BattlePokemon.Returns(members);
|
||||
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Parties.Returns(new[] { battleParty });
|
||||
battle.Random.Returns(random);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -180,26 +176,4 @@ public class AssistTests
|
||||
await Assert.That(moveName).IsEqualTo(new StringKey("growl"));
|
||||
choice.DidNotReceive().Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) the script returns without failing the choice.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeMove_NoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var script = new Assist();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
StringKey moveName = "assist";
|
||||
|
||||
// Act
|
||||
script.ChangeMove(choice, ref moveName);
|
||||
|
||||
// Assert
|
||||
choice.DidNotReceive().Fail();
|
||||
await Assert.That(moveName).IsEqualTo(new StringKey("assist"));
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class AttractTests
|
||||
{
|
||||
private static (Attract script, IExecutingMove move, IPokemon target, IScriptSet targetVolatile, IHitData hitData)
|
||||
CreateTestSetup(Gender userGender, Gender targetGender)
|
||||
private static (Attract script, IExecutingMove move, IBattlePokemon target, IScriptSet targetVolatile, IHitData
|
||||
hitData) CreateTestSetup(Gender userGender, Gender targetGender)
|
||||
{
|
||||
var script = new Attract();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class AttractTests
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
target.Gender.Returns(targetGender);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Gender.Returns(userGender);
|
||||
move.User.Returns(user);
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ public class AuroraVeilTests
|
||||
}
|
||||
}
|
||||
|
||||
private static (AuroraVeil script, IExecutingMove move, IPokemon target, IPokemon user, IScriptSet sideScripts,
|
||||
IHitData hitData) CreateTestSetup(StringKey? weather)
|
||||
private static (AuroraVeil script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, IScriptSet
|
||||
sideScripts, IHitData hitData) CreateTestSetup(StringKey? weather)
|
||||
{
|
||||
var script = new AuroraVeil();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -51,13 +51,10 @@ public class AuroraVeilTests
|
||||
side.VolatileScripts.Returns(sideScripts);
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
user.SideIndex.Returns((byte)0);
|
||||
user.Battle.Returns(battle);
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, target, user, sideScripts, hitData);
|
||||
@@ -154,25 +151,4 @@ public class AuroraVeilTests
|
||||
var effect = (AuroraVeilEffect)((Func<Script?>)call.GetArguments()[1]!)()!;
|
||||
await Assert.That(effect.NumberOfTurns).IsEqualTo(8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) the script returns without throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var script = new AuroraVeil();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert - no hit data was touched
|
||||
await Assert.That(move.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "GetHitData")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class AutotomizeTests
|
||||
{
|
||||
private static (Autotomize script, IExecutingMove move, IPokemon user, IScriptSet userVolatile, EventHook eventHook)
|
||||
CreateTestSetup(float weightInKg, bool speedRaiseSucceeds, AutotomizeEffect? existingEffect = null)
|
||||
private static (Autotomize script, IExecutingMove move, IBattlePokemon user, IScriptSet userVolatile, EventHook
|
||||
eventHook) CreateTestSetup(float weightInKg, bool speedRaiseSucceeds, AutotomizeEffect? existingEffect = null)
|
||||
{
|
||||
var script = new Autotomize();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -26,15 +26,13 @@ public class AutotomizeTests
|
||||
var eventHook = new EventHook();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var userVolatile = Substitute.For<IScriptSet>();
|
||||
userVolatile.Get<AutotomizeEffect>().Returns(existingEffect);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.Battle.Returns(battle);
|
||||
user.WeightInKg.Returns(weightInKg);
|
||||
user.ChangeStatBoost(Arg.Any<Statistic>(), Arg.Any<sbyte>(), Arg.Any<bool>(), Arg.Any<bool>())
|
||||
.Returns(speedRaiseSucceeds);
|
||||
@@ -56,7 +54,7 @@ public class AutotomizeTests
|
||||
var (script, move, user, _, _) = CreateTestSetup(100f, true);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
user.Received(1).ChangeStatBoost(Statistic.Speed, 2, true, false);
|
||||
@@ -79,7 +77,7 @@ public class AutotomizeTests
|
||||
};
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ReceivedStackOrAdd(userVolatile)).IsTrue();
|
||||
@@ -100,7 +98,7 @@ public class AutotomizeTests
|
||||
eventHook.Handler += (_, _) => eventFired = true;
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ReceivedStackOrAdd(userVolatile)).IsFalse();
|
||||
@@ -119,7 +117,7 @@ public class AutotomizeTests
|
||||
var (script, move, _, userVolatile, _) = CreateTestSetup(50f, true);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ReceivedStackOrAdd(userVolatile)).IsTrue();
|
||||
@@ -140,7 +138,7 @@ public class AutotomizeTests
|
||||
var (script, move, _, userVolatile, _) = CreateTestSetup(50f, true, existingEffect);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert - the weight should still be reduced (to the minimum)
|
||||
await Assert.That(ReceivedStackOrAdd(userVolatile)).IsTrue();
|
||||
@@ -160,7 +158,7 @@ public class AutotomizeTests
|
||||
eventHook.Handler += (_, _) => eventFired = true;
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
user.Received(1).ChangeStatBoost(Statistic.Speed, 2, true, false);
|
||||
|
||||
@@ -19,12 +19,12 @@ public class BanefulBunkerTests
|
||||
/// <see cref="ProtectionScript.OnSecondaryEffect"/>. The <c>target</c> of the secondary effect is the
|
||||
/// Pokémon using Baneful Bunker itself, as the move is self-targeted.
|
||||
/// </summary>
|
||||
private static (BanefulBunker script, IExecutingMove move, IPokemon target, IHitData hitData, IScriptSet volatileSet
|
||||
) CreateProtectSetup(bool userMovesLast, float randomRoll)
|
||||
private static (BanefulBunker script, IExecutingMove move, IBattlePokemon target, IHitData hitData, IScriptSet
|
||||
volatileSet ) CreateProtectSetup(bool userMovesLast, float randomRoll)
|
||||
{
|
||||
var script = new BanefulBunker();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -38,9 +38,7 @@ public class BanefulBunkerTests
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
battle.Random.Returns(random);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
// Give the mock a real script iterator (used by the volatile add hook) and a real volatile script set.
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
@@ -54,12 +52,12 @@ public class BanefulBunkerTests
|
||||
/// Creates a fully mocked setup for driving <see cref="BanefulBunkerEffect.BlockIncomingHit"/>, the
|
||||
/// volatile script that <see cref="BanefulBunker"/> attaches to its user.
|
||||
/// </summary>
|
||||
private static (BanefulBunkerEffect effect, IExecutingMove move, IPokemon target, IPokemon attacker)
|
||||
private static (BanefulBunkerEffect effect, IExecutingMove move, IBattlePokemon target, IBattlePokemon attacker)
|
||||
CreateBlockSetup(bool isContact, bool hasProtectFlag, MoveCategory category = MoveCategory.Physical)
|
||||
{
|
||||
var effect = new BanefulBunkerEffect();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.IsContact.Returns(isContact);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
@@ -69,19 +67,17 @@ public class BanefulBunkerTests
|
||||
useMove.Category.Returns(category);
|
||||
move.UseMove.Returns(useMove);
|
||||
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
attacker.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
move.User.Returns(attacker);
|
||||
|
||||
target.BattleData.Returns(Substitute.For<IPokemonBattleData>());
|
||||
|
||||
return (effect, move, target, attacker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the status name from a Pokémon's received <see cref="IPokemon.SetStatus"/> calls.
|
||||
/// Helper to extract the status name from a Pokémon's received <see cref="IBattlePokemon.SetStatus"/> calls.
|
||||
/// </summary>
|
||||
private static string? GetStatusSet(IPokemon pokemon)
|
||||
private static string? GetStatusSet(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "SetStatus");
|
||||
return call != null ? ((StringKey)call.GetArguments()[0]!).ToString() : null;
|
||||
|
||||
@@ -21,9 +21,9 @@ public class BatonPassTests
|
||||
/// Creates a mocked Pokémon with a real volatile <see cref="ScriptSet"/> and a real
|
||||
/// <see cref="StatBoostStatisticSet"/>.
|
||||
/// </summary>
|
||||
private static IPokemon CreateMockPokemon(out IScriptSet volatileSet)
|
||||
private static IBattlePokemon CreateMockPokemon(out IScriptSet volatileSet)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
var set = new ScriptSet(pokemon);
|
||||
pokemon.Volatile.Returns(set);
|
||||
@@ -36,8 +36,8 @@ public class BatonPassTests
|
||||
/// Creates a fully mocked test setup for Baton Pass tests. The Pokémon to switch in is stored in the
|
||||
/// move choice's <see cref="IMoveChoice.AdditionalData"/> under the <c>to_switch</c> key.
|
||||
/// </summary>
|
||||
private static (BatonPass script, IExecutingMove move, IPokemon user, IPokemon toSwitch, IBattleSide side,
|
||||
IScriptSet userVolatile, IScriptSet switchInVolatile) CreateTestSetup()
|
||||
private static (BatonPass script, IExecutingMove move, IBattlePokemon user, IBattlePokemon toSwitch, IBattleSide
|
||||
side, IScriptSet userVolatile, IScriptSet switchInVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new BatonPass();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -52,11 +52,9 @@ public class BatonPassTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
battleData.Position.Returns((byte)1);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
user.SideIndex.Returns((byte)0);
|
||||
user.Position.Returns((byte)1);
|
||||
|
||||
move.User.Returns(user);
|
||||
return (script, move, user, toSwitch, side, userVolatile, switchInVolatile);
|
||||
@@ -213,7 +211,7 @@ public class BatonPassTests
|
||||
script.OnSecondaryEffect(move, user, 0);
|
||||
|
||||
// Assert
|
||||
side.DidNotReceive().SwapPokemon(Arg.Any<byte>(), Arg.Any<IPokemon?>());
|
||||
side.DidNotReceive().SwapPokemon(Arg.Any<byte>(), Arg.Any<IBattlePokemon?>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,26 +228,6 @@ public class BatonPassTests
|
||||
script.OnSecondaryEffect(move, user, 0);
|
||||
|
||||
// Assert
|
||||
side.DidNotReceive().SwapPokemon(Arg.Any<byte>(), Arg.Any<IPokemon?>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, the script returns without
|
||||
/// switching and without clearing the user's volatile scripts.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNotSwitch()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, _, side, userVolatile, _) = CreateTestSetup();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
userVolatile.Add(new AutotomizeEffect());
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, user, 0);
|
||||
|
||||
// Assert
|
||||
side.DidNotReceive().SwapPokemon(Arg.Any<byte>(), Arg.Any<IPokemon?>());
|
||||
await Assert.That(userVolatile.Get<AutotomizeEffect>()).IsNotNull();
|
||||
side.DidNotReceive().SwapPokemon(Arg.Any<byte>(), Arg.Any<IBattlePokemon?>());
|
||||
}
|
||||
}
|
||||
@@ -17,28 +17,19 @@ public class BeakBlastTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked setup for driving <see cref="BeakBlast.OnBeforeTurnStart"/>.
|
||||
/// </summary>
|
||||
private static (BeakBlast script, ITurnChoice choice, IPokemon user, IScriptSet volatileSet, EventHook eventHook)
|
||||
CreateChargeSetup(bool hasBattleData = true)
|
||||
private static (BeakBlast script, ITurnChoice choice, IBattlePokemon user, IScriptSet volatileSet, EventHook
|
||||
eventHook) CreateChargeSetup()
|
||||
{
|
||||
var script = new BeakBlast();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(user);
|
||||
user.Volatile.Returns(volatileSet);
|
||||
|
||||
var eventHook = new EventHook();
|
||||
if (hasBattleData)
|
||||
{
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
}
|
||||
else
|
||||
{
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
}
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var choice = Substitute.For<ITurnChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -85,24 +76,7 @@ public class BeakBlastTests
|
||||
// Assert
|
||||
await Assert.That(capturedEvent).IsNotNull();
|
||||
await Assert.That(capturedEvent!.Message).IsEqualTo("beak_blast_charge");
|
||||
await Assert.That((IPokemon)capturedEvent.Parameters!["user"]).IsEqualTo(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: a Pokémon without <see cref="IPokemon.BattleData"/> is not in battle, so no charging
|
||||
/// phase starts.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnBeforeTurnStart_NoBattleData_DoesNotAddChargeEffect()
|
||||
{
|
||||
// Arrange
|
||||
var (script, choice, _, volatileSet, _) = CreateChargeSetup(false);
|
||||
|
||||
// Act
|
||||
script.OnBeforeTurnStart(choice);
|
||||
|
||||
// Assert
|
||||
await Assert.That(volatileSet.Get<BeakBlastEffect>()).IsNull();
|
||||
await Assert.That((IBattlePokemon)capturedEvent.Parameters!["user"]).IsEqualTo(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -115,8 +89,8 @@ public class BeakBlastTests
|
||||
// Arrange
|
||||
var script = new BeakBlast();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(user);
|
||||
user.Volatile.Returns(volatileSet);
|
||||
@@ -133,26 +107,26 @@ public class BeakBlastTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked setup for driving <see cref="BeakBlastEffect.OnIncomingHit"/>.
|
||||
/// </summary>
|
||||
private static (BeakBlastEffect effect, IExecutingMove move, IPokemon target, IPokemon attacker)
|
||||
private static (BeakBlastEffect effect, IExecutingMove move, IBattlePokemon target, IBattlePokemon attacker)
|
||||
CreateIncomingHitSetup(bool isContact)
|
||||
{
|
||||
var effect = new BeakBlastEffect();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.IsContact.Returns(isContact);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(attacker);
|
||||
|
||||
return (effect, move, target, attacker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the status name from a Pokémon's received <see cref="IPokemon.SetStatus"/> calls.
|
||||
/// Helper to extract the status name from a Pokémon's received <see cref="IBattlePokemon.SetStatus"/> calls.
|
||||
/// </summary>
|
||||
private static string? GetStatusSet(IPokemon pokemon)
|
||||
private static string? GetStatusSet(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "SetStatus");
|
||||
return call != null ? ((StringKey)call.GetArguments()[0]!).ToString() : null;
|
||||
|
||||
@@ -19,11 +19,11 @@ public class BeatUpTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a mocked party member with the given base Attack stat, usability, and optional non-volatile
|
||||
/// status script in its <see cref="IPokemon.StatusScript"/>.
|
||||
/// status script in its <see cref="IBattlePokemon.StatusScript"/>.
|
||||
/// </summary>
|
||||
private static IPokemon CreatePartyMember(ushort baseAttack = 100, bool usable = true, Script? status = null)
|
||||
private static IBattlePokemon CreatePartyMember(ushort baseAttack = 100, bool usable = true, Script? status = null)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.IsUsable.Returns(usable);
|
||||
pokemon.StatusScript.Returns(status == null ? new ScriptContainer() : new ScriptContainer(status));
|
||||
var form = Substitute.For<IForm>();
|
||||
@@ -35,24 +35,20 @@ public class BeatUpTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the user and the given other Pokémon form a party in a battle.
|
||||
/// </summary>
|
||||
private static (BeatUp script, IMoveChoice choice, IExecutingMove move) CreateTestSetup(IPokemon user,
|
||||
params IPokemon?[] otherPartyMembers)
|
||||
private static (BeatUp script, IMoveChoice choice, IExecutingMove move) CreateTestSetup(IBattlePokemon user,
|
||||
params IBattlePokemon?[] otherPartyMembers)
|
||||
{
|
||||
var script = new BeatUp();
|
||||
|
||||
var members = new List<IPokemon?> { user };
|
||||
var members = new List<IBattlePokemon?> { user };
|
||||
members.AddRange(otherPartyMembers);
|
||||
|
||||
var party = Substitute.For<IPokemonParty>();
|
||||
party.GetEnumerator().Returns(_ => members.GetEnumerator());
|
||||
var battleParty = Substitute.For<IBattleParty>();
|
||||
battleParty.Party.Returns(party);
|
||||
battleParty.BattlePokemon.Returns(members);
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Parties.Returns(new[] { battleParty });
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -121,28 +117,6 @@ public class BeatUpTests
|
||||
await Assert.That(numberOfHits).IsEqualTo((byte)1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no <see cref="IPokemon.BattleData"/>) there are no relevant party
|
||||
/// members, and the number of hits falls back to a single strike.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeNumberOfHits_NoBattleData_SingleHit()
|
||||
{
|
||||
// Arrange
|
||||
var script = new BeatUp();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
byte numberOfHits = 3;
|
||||
|
||||
// Act
|
||||
script.ChangeNumberOfHits(choice, ref numberOfHits);
|
||||
|
||||
// Assert
|
||||
await Assert.That(numberOfHits).IsEqualTo((byte)1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "the base power per strike is no longer 10, but instead individually based on the Attack
|
||||
/// base stats of the party Pokémon: BasePower = BaseAttack(PartyMember)/10 + 5".
|
||||
@@ -155,7 +129,7 @@ public class BeatUpTests
|
||||
// Arrange
|
||||
var user = CreatePartyMember(baseAttack);
|
||||
var (script, _, move) = CreateTestSetup(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
|
||||
// Act
|
||||
@@ -175,7 +149,7 @@ public class BeatUpTests
|
||||
// Arrange
|
||||
var user = CreatePartyMember(100);
|
||||
var (script, _, move) = CreateTestSetup(user, CreatePartyMember(250));
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
|
||||
// Act
|
||||
@@ -197,7 +171,7 @@ public class BeatUpTests
|
||||
var user = CreatePartyMember(100);
|
||||
var (script, _, move) = CreateTestSetup(user, CreatePartyMember(250, status: new Burned()),
|
||||
CreatePartyMember(60));
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
|
||||
// Act
|
||||
@@ -217,7 +191,7 @@ public class BeatUpTests
|
||||
// Arrange
|
||||
var user = CreatePartyMember(100);
|
||||
var (script, _, move) = CreateTestSetup(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
ushort basePower = 10;
|
||||
|
||||
// Act
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
public class BelchTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the user's <see cref="IPokemonBattleData.ConsumedItems"/>
|
||||
/// Creates a fully mocked test setup where the user's <see cref="IBattlePokemon.ConsumedItems"/>
|
||||
/// contains one item per given <see cref="ItemCategory"/>.
|
||||
/// </summary>
|
||||
private static (Belch script, IMoveChoice choice) CreateTestSetup(params ItemCategory[] consumedItemCategories)
|
||||
{
|
||||
var script = new Belch();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var items = consumedItemCategories.Select(category =>
|
||||
{
|
||||
@@ -27,9 +27,7 @@ public class BelchTests
|
||||
item.Category.Returns(category);
|
||||
return item;
|
||||
}).ToArray();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.ConsumedItems.Returns(items);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.ConsumedItems.Returns(items);
|
||||
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -108,26 +106,4 @@ public class BelchTests
|
||||
// Assert
|
||||
await Assert.That(prevent).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no <see cref="IPokemon.BattleData"/>) the script does not prevent
|
||||
/// selection.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task PreventMoveSelection_NoBattleData_SelectionAllowed()
|
||||
{
|
||||
// Arrange
|
||||
var script = new Belch();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
var prevent = false;
|
||||
|
||||
// Act
|
||||
script.PreventMoveSelection(choice, ref prevent);
|
||||
|
||||
// Assert
|
||||
await Assert.That(prevent).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,11 @@ public class BellyDrumTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Belly Drum. The target of the secondary effect is the user itself.
|
||||
/// </summary>
|
||||
private static (BellyDrum script, IExecutingMove move, IPokemon user, IHitData hitData) CreateTestSetup(uint maxHp,
|
||||
uint currentHp, sbyte attackBoost = 0)
|
||||
private static (BellyDrum script, IExecutingMove move, IBattlePokemon user, IHitData hitData) CreateTestSetup(
|
||||
uint maxHp, uint currentHp, sbyte attackBoost = 0)
|
||||
{
|
||||
var script = new BellyDrum();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.BoostedStats.Returns(new StatisticSet<uint>(maxHp, 10, 10, 10, 10, 10));
|
||||
user.CurrentHealth.Returns(currentHp);
|
||||
user.StatBoost.Returns(new StatBoostStatisticSet(0, attackBoost, 0, 0, 0, 0));
|
||||
@@ -34,7 +34,7 @@ public class BellyDrumTests
|
||||
/// <summary>
|
||||
/// Helper to extract the received Damage call from the user, if any.
|
||||
/// </summary>
|
||||
private static (uint damage, DamageSource source, bool forceDamage)? GetDamageCall(IPokemon user)
|
||||
private static (uint damage, DamageSource source, bool forceDamage)? GetDamageCall(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
if (call == null)
|
||||
@@ -46,7 +46,7 @@ public class BellyDrumTests
|
||||
/// <summary>
|
||||
/// Helper to extract the received ChangeStatBoost call from the user, if any.
|
||||
/// </summary>
|
||||
private static (Statistic stat, sbyte change, bool selfInflicted)? GetStatBoostCall(IPokemon user)
|
||||
private static (Statistic stat, sbyte change, bool selfInflicted)? GetStatBoostCall(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
if (call == null)
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class BestowTests
|
||||
{
|
||||
private static (Bestow script, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData)
|
||||
private static (Bestow script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IHitData hitData)
|
||||
CreateTestSetup(IItem? userItem, IItem? targetItem)
|
||||
{
|
||||
var script = new Bestow();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
target.HeldItem.Returns(targetItem);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.HeldItem.Returns(userItem);
|
||||
user.RemoveHeldItemForBattle().Returns(userItem);
|
||||
move.User.Returns(user);
|
||||
@@ -68,7 +68,7 @@ public class BestowTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Items given away in Trainer battles return to the original Pokémon after the battle."
|
||||
/// The item is taken from the user through <see cref="IPokemon.RemoveHeldItemForBattle"/>, which only
|
||||
/// The item is taken from the user through <see cref="IBattlePokemon.RemoveHeldItemForBattle"/>, which only
|
||||
/// removes the item for the duration of the battle.
|
||||
/// </summary>
|
||||
[Test]
|
||||
|
||||
@@ -13,16 +13,16 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class BideTests
|
||||
{
|
||||
private static (Bide script, IExecutingMove move, IPokemon user, IPokemon target, IScriptSet userVolatile, IHitData
|
||||
hitData) CreateTestSetup()
|
||||
private static (Bide script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IScriptSet
|
||||
userVolatile, IHitData hitData) CreateTestSetup()
|
||||
{
|
||||
var script = new Bide();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
// A real script set so the volatile Bide effect can actually be added, retrieved and removed.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
@@ -32,12 +32,10 @@ public class BideTests
|
||||
return (script, move, user, target, userVolatile, hitData);
|
||||
}
|
||||
|
||||
private static IPokemon CreateAttacker(bool onBattlefield = true)
|
||||
private static IBattlePokemon CreateAttacker(bool onBattlefield = true)
|
||||
{
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.IsOnBattlefield.Returns(onBattlefield);
|
||||
attacker.BattleData.Returns(battleData);
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
attacker.IsOnBattlefield.Returns(onBattlefield);
|
||||
return attacker;
|
||||
}
|
||||
|
||||
@@ -45,8 +43,8 @@ public class BideTests
|
||||
/// Adds a <see cref="BideEffect"/> to the user's volatile scripts, as if Bide has already been storing
|
||||
/// energy for the given number of executed turns.
|
||||
/// </summary>
|
||||
private static BideEffect AddStoredBideEffect(IScriptSet userVolatile, IPokemon user, byte turns, uint damageTaken,
|
||||
params IPokemon[] hitBy)
|
||||
private static BideEffect AddStoredBideEffect(IScriptSet userVolatile, IBattlePokemon user, byte turns,
|
||||
uint damageTaken, params IBattlePokemon[] hitBy)
|
||||
{
|
||||
var effect = new BideEffect(user)
|
||||
{
|
||||
@@ -61,13 +59,13 @@ public class BideTests
|
||||
/// <summary>
|
||||
/// Helper to check whether a Pokémon received any Damage call.
|
||||
/// </summary>
|
||||
private static bool ReceivedDamage(IPokemon pokemon) =>
|
||||
private static bool ReceivedDamage(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Damage");
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a Pokémon's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon pokemon)
|
||||
private static uint? GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -76,7 +74,7 @@ public class BideTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from a Pokémon's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon pokemon)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (DamageSource)call.GetArguments()[1]! : null;
|
||||
@@ -245,7 +243,7 @@ public class BideTests
|
||||
public async Task BideEffect_OnDamage_AccumulatesDamageTaken()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var effect = new BideEffect(user);
|
||||
|
||||
// Act - the user drops from 100 to 60 HP, then from 60 to 50 HP
|
||||
@@ -265,10 +263,10 @@ public class BideTests
|
||||
public async Task BideEffect_OnIncomingHit_RecordsAttacker()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var effect = new BideEffect(user);
|
||||
var incomingMove = Substitute.For<IExecutingMove>();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
incomingMove.User.Returns(attacker);
|
||||
|
||||
// Act
|
||||
|
||||
@@ -44,16 +44,16 @@ public class BindTests
|
||||
}
|
||||
}
|
||||
|
||||
private static (Bind script, IExecutingMove move, IPokemon user, IPokemon target, IScriptSet targetVolatile)
|
||||
CreateTestSetup(params Script[] userScripts)
|
||||
private static (Bind script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IScriptSet
|
||||
targetVolatile) CreateTestSetup(params Script[] userScripts)
|
||||
{
|
||||
var script = new Bind();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = Substitute.For<IScriptSet>();
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// RunScriptHook iterates the user's scripts; give the mock a real iterator so the ModifyBind trigger
|
||||
// pass runs (empty unless the test attaches scripts such as the Grip Claw / Binding Band stand-in).
|
||||
var containers = userScripts.Select(IEnumerable<ScriptContainer> (s) => new ScriptContainer(s)).ToArray();
|
||||
@@ -73,7 +73,7 @@ public class BindTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from the target's first received Damage call.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon pokemon)
|
||||
private static uint? GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -82,7 +82,7 @@ public class BindTests
|
||||
/// <summary>
|
||||
/// Runs end-of-turn handling on the effect repeatedly and counts how many turns dealt damage to the target.
|
||||
/// </summary>
|
||||
private static int CountEndTurnDamageTicks(BindEffect effect, IPokemon target, int maxTurns = 10)
|
||||
private static int CountEndTurnDamageTicks(BindEffect effect, IBattlePokemon target, int maxTurns = 10)
|
||||
{
|
||||
var battle = Substitute.For<IBattle>();
|
||||
for (var i = 0; i < maxTurns; i++)
|
||||
@@ -204,7 +204,7 @@ public class BindTests
|
||||
public async Task BindEffect_WhileActive_PreventsSwitching()
|
||||
{
|
||||
// Arrange
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var effect = new BindEffect(target, 5, 1f / 8f);
|
||||
var prevent = false;
|
||||
|
||||
@@ -223,7 +223,7 @@ public class BindTests
|
||||
public async Task BindEffect_WhileActive_PreventsRunningAway()
|
||||
{
|
||||
// Arrange
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var effect = new BindEffect(target, 5, 1f / 8f);
|
||||
var prevent = false;
|
||||
|
||||
@@ -242,7 +242,7 @@ public class BindTests
|
||||
public async Task BindEffect_AfterDurationExpires_NoLongerPreventsSwitching()
|
||||
{
|
||||
// Arrange
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.MaxHealth.Returns(160u);
|
||||
var effect = new BindEffect(target, 1, 1f / 8f);
|
||||
|
||||
|
||||
@@ -14,14 +14,15 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class BlockTests
|
||||
{
|
||||
private static (Block script, IExecutingMove move, IPokemon target, ScriptSet targetVolatile) CreateTestSetup()
|
||||
private static (Block script, IExecutingMove move, IBattlePokemon target, ScriptSet targetVolatile)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new Block();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the volatile script added by Block can be inspected afterwards.
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
@@ -105,10 +106,8 @@ public class BlockTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
move.User.BattleData.Returns(battleData);
|
||||
target.BattleData.Returns(battleData);
|
||||
move.User.Battle.Returns(battle);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class BounceTests
|
||||
{
|
||||
private static (Bounce script, IExecutingMove move, IPokemon user, ScriptSet userVolatile, IMoveChoice moveChoice,
|
||||
IBattleRandom random) CreateTestSetup()
|
||||
private static (Bounce script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile, IMoveChoice
|
||||
moveChoice, IBattleRandom random) CreateTestSetup()
|
||||
{
|
||||
var script = new Bounce();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the charge volatile added by Bounce can be inspected afterwards.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
@@ -39,9 +39,7 @@ public class BounceTests
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
battle.Random.Returns(random);
|
||||
battle.EventHook.Returns(new EventHook());
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, user, userVolatile, moveChoice, random);
|
||||
}
|
||||
@@ -148,7 +146,7 @@ public class BounceTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, _, _, random) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
random.EffectChance(30, move, target, 0).Returns(true);
|
||||
|
||||
// Act
|
||||
@@ -168,7 +166,7 @@ public class BounceTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _, _, random) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
random.EffectChance(30, move, target, 0).Returns(false);
|
||||
|
||||
// Act
|
||||
@@ -187,7 +185,7 @@ public class BounceTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _, _, random) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -197,24 +195,6 @@ public class BounceTests
|
||||
await Assert.That(random.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "EffectChance")).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) the secondary effect does nothing and does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNotParalyzeTarget()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, _, _, _) = CreateTestSetup();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "While in Sky-High status, the user is invulnerable to most moves".
|
||||
/// The <see cref="ChargeBounceEffect"/> added by the charge turn blocks incoming hits from moves that
|
||||
|
||||
@@ -15,21 +15,19 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
public class BrickBreakTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a mocked Pokémon whose <see cref="IPokemonBattleData.BattleSide"/> is the given side.
|
||||
/// Creates a mocked Pokémon whose <see cref="IBattlePokemon.BattleSide"/> is the given side.
|
||||
/// </summary>
|
||||
private static IPokemon CreatePokemonOnSide(IBattleSide side)
|
||||
private static IBattlePokemon CreatePokemonOnSide(IBattleSide side)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.BattleSide.Returns(side);
|
||||
pokemon.BattleData.Returns(battleData);
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.BattleSide.Returns(side);
|
||||
return pokemon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the user targets a Pokémon on the opposing side.
|
||||
/// </summary>
|
||||
private static (BrickBreak script, IExecutingMove move, IPokemon user, IScriptSet userSideScripts, IScriptSet
|
||||
private static (BrickBreak script, IExecutingMove move, IBattlePokemon user, IScriptSet userSideScripts, IScriptSet
|
||||
targetSideScripts) CreateTestSetup()
|
||||
{
|
||||
var script = new BrickBreak();
|
||||
@@ -45,7 +43,7 @@ public class BrickBreakTests
|
||||
var user = CreatePokemonOnSide(userSide);
|
||||
move.User.Returns(user);
|
||||
var target = CreatePokemonOnSide(targetSide);
|
||||
move.Targets.Returns(new IPokemon?[] { target });
|
||||
move.Targets.Returns(new IBattlePokemon?[] { target });
|
||||
|
||||
return (script, move, user, userSideScripts, targetSideScripts);
|
||||
}
|
||||
@@ -115,8 +113,8 @@ public class BrickBreakTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, userSideScripts, _) = CreateTestSetup();
|
||||
var ally = CreatePokemonOnSide(user.BattleData!.BattleSide);
|
||||
move.Targets.Returns(new IPokemon?[] { ally });
|
||||
var ally = CreatePokemonOnSide(user.BattleSide);
|
||||
move.Targets.Returns(new IBattlePokemon?[] { ally });
|
||||
|
||||
// Act
|
||||
script.OnBeforeMove(move);
|
||||
@@ -146,7 +144,7 @@ public class BrickBreakTests
|
||||
var user = CreatePokemonOnSide(userSide);
|
||||
move.User.Returns(user);
|
||||
var target = CreatePokemonOnSide(targetSide);
|
||||
move.Targets.Returns(new IPokemon?[] { target });
|
||||
move.Targets.Returns(new IBattlePokemon?[] { target });
|
||||
|
||||
// Act
|
||||
script.OnBeforeMove(move);
|
||||
@@ -165,10 +163,9 @@ public class BrickBreakTests
|
||||
// Arrange
|
||||
var script = new BrickBreak();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
move.Targets.Returns(Array.Empty<IPokemon?>());
|
||||
move.Targets.Returns(Array.Empty<IBattlePokemon?>());
|
||||
|
||||
// Act & Assert
|
||||
await Assert.That(() => script.OnBeforeMove(move)).ThrowsNothing();
|
||||
|
||||
@@ -12,13 +12,13 @@ public class BrineTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Brine tests, with a target whose max HP
|
||||
/// (<see cref="IPokemon.BoostedStats"/>) and <see cref="IPokemon.CurrentHealth"/> are configured.
|
||||
/// (<see cref="IBattlePokemon.BoostedStats"/>) and <see cref="IBattlePokemon.CurrentHealth"/> are configured.
|
||||
/// </summary>
|
||||
private static (Brine brine, IExecutingMove move, IPokemon target) CreateTestSetup(uint maxHp, uint currentHp)
|
||||
private static (Brine brine, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint maxHp, uint currentHp)
|
||||
{
|
||||
var brine = new Brine();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(maxHp, 0, 0, 0, 0, 0));
|
||||
target.CurrentHealth.Returns(currentHp);
|
||||
return (brine, move, target);
|
||||
|
||||
@@ -41,8 +41,8 @@ public class BugBiteTests
|
||||
/// real resolver with a single registered item script constructor for <see cref="BerryEffectName"/>, so
|
||||
/// eating a Berry runs a <see cref="RecordingItemScript"/> that the test can inspect.
|
||||
/// </summary>
|
||||
private static (BugBite bugBite, IExecutingMove move, IPokemon target, IHitData hitData, List<RecordingItemScript>
|
||||
createdItemScripts) CreateTestSetup(IItem? targetHeldItem, bool canSteal = true)
|
||||
private static (BugBite bugBite, IExecutingMove move, IBattlePokemon target, IHitData hitData,
|
||||
List<RecordingItemScript> createdItemScripts) CreateTestSetup(IItem? targetHeldItem, bool canSteal = true)
|
||||
{
|
||||
var bugBite = new BugBite();
|
||||
|
||||
@@ -66,17 +66,14 @@ public class BugBiteTests
|
||||
dynamicLibrary.ScriptResolver.Returns(resolver);
|
||||
battle.Library.Returns(dynamicLibrary);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
|
||||
user.Battle.Returns(battle);
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
move.Battle.Returns(battle);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.HeldItem.Returns(targetHeldItem);
|
||||
if (targetHeldItem != null && canSteal)
|
||||
{
|
||||
@@ -111,7 +108,7 @@ public class BugBiteTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "If the target is holding a Berry, the user will eat the Berry and gain its effect."
|
||||
/// Eating the Berry removes it from the target via <see cref="IPokemon.ForceSetHeldItem"/>.
|
||||
/// Eating the Berry removes it from the target via <see cref="IBattlePokemon.ForceSetHeldItem"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHoldsBerry_BerryIsRemovedFromTarget()
|
||||
@@ -202,7 +199,7 @@ public class BugBiteTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Bug Bite will not consume the Berry of a target that has the Ability Sticky Hold."
|
||||
/// When the Berry cannot be stolen (<see cref="IPokemon.TryStealHeldItem"/> returns false, as with
|
||||
/// When the Berry cannot be stolen (<see cref="IBattlePokemon.TryStealHeldItem"/> returns false, as with
|
||||
/// Sticky Hold), the target keeps its Berry and the effect fails.
|
||||
/// </summary>
|
||||
[Test]
|
||||
@@ -219,25 +216,4 @@ public class BugBiteTests
|
||||
await Assert.That(createdItemScripts.Count).IsEqualTo(0);
|
||||
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the user has no <see cref="IPokemon.BattleData"/>, the script does nothing: no Berry is eaten
|
||||
/// and the hit is not failed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_UserHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (bugBite, move, target, hitData, _) = CreateTestSetup(CreateBerry());
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
|
||||
// Act
|
||||
bugBite.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ForceSetHeldItem")).IsFalse();
|
||||
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ public class BurnUpTests
|
||||
/// <see cref="TypeLibrary"/> with "fire" and "water" registered. The user is a Water-type, optionally
|
||||
/// also carrying the Fire type.
|
||||
/// </summary>
|
||||
private static (BurnUp burnUp, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData, TypeIdentifier
|
||||
fireType) CreateTestSetup(bool userIsFireType, bool userIsFrozen = false)
|
||||
private static (BurnUp burnUp, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IHitData hitData,
|
||||
TypeIdentifier fireType) CreateTestSetup(bool userIsFireType, bool userIsFrozen = false)
|
||||
{
|
||||
var burnUp = new BurnUp();
|
||||
|
||||
@@ -33,11 +33,9 @@ public class BurnUpTests
|
||||
dynamicLibrary.StaticLibrary.Returns(staticLibrary);
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(dynamicLibrary);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
user.Types.Returns(userIsFireType
|
||||
? new List<TypeIdentifier> { fireType, waterType }
|
||||
: new List<TypeIdentifier> { waterType });
|
||||
@@ -46,7 +44,7 @@ public class BurnUpTests
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -54,9 +52,9 @@ public class BurnUpTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper that checks whether <see cref="IPokemon.RemoveType"/> was called with the given type.
|
||||
/// Helper that checks whether <see cref="IBattlePokemon.RemoveType"/> was called with the given type.
|
||||
/// </summary>
|
||||
private static bool ReceivedRemoveType(IPokemon user, TypeIdentifier type) =>
|
||||
private static bool ReceivedRemoveType(IBattlePokemon user, TypeIdentifier type) =>
|
||||
user.ReceivedCalls().Any(c =>
|
||||
c.GetMethodInfo().Name == "RemoveType" && type.Equals((TypeIdentifier)c.GetArguments()[0]!));
|
||||
|
||||
@@ -177,23 +175,4 @@ public class BurnUpTests
|
||||
// Assert
|
||||
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ClearStatus")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the user has no <see cref="IPokemon.BattleData"/>, the script does nothing: no type is removed
|
||||
/// and the hit is not failed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_UserHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (burnUp, move, user, target, hitData, _) = CreateTestSetup(true);
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
burnUp.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "RemoveType")).IsFalse();
|
||||
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CamouflageTests
|
||||
{
|
||||
private static (Camouflage script, IExecutingMove move, IPokemon user, IBattle battle) CreateTestSetup(
|
||||
private static (Camouflage script, IExecutingMove move, IBattlePokemon user, IBattle battle) CreateTestSetup(
|
||||
string? terrainName, string environmentName)
|
||||
{
|
||||
var script = new Camouflage();
|
||||
@@ -24,7 +24,7 @@ public class CamouflageTests
|
||||
battle.TerrainName.Returns(terrainName == null ? null : new StringKey?(new StringKey(terrainName)));
|
||||
battle.EnvironmentName.Returns(new StringKey(environmentName));
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
move.Battle.Returns(battle);
|
||||
@@ -34,9 +34,9 @@ public class CamouflageTests
|
||||
|
||||
/// <summary>
|
||||
/// Helper that returns the single type the user was changed to, or null when
|
||||
/// <see cref="IPokemon.SetTypes"/> was never called.
|
||||
/// <see cref="IBattlePokemon.SetTypes"/> was never called.
|
||||
/// </summary>
|
||||
private static TypeIdentifier? GetSetType(IPokemon user)
|
||||
private static TypeIdentifier? GetSetType(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "SetTypes");
|
||||
return call != null ? ((IReadOnlyList<TypeIdentifier>)call.GetArguments()[0]!).Single() : null;
|
||||
@@ -56,7 +56,7 @@ public class CamouflageTests
|
||||
battle.Library.StaticLibrary.Types.TryGetTypeIdentifier(expectedType, out var expected);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected);
|
||||
@@ -75,7 +75,7 @@ public class CamouflageTests
|
||||
battle.Library.StaticLibrary.Types.TryGetTypeIdentifier(expectedType, out var expected);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected);
|
||||
@@ -92,7 +92,7 @@ public class CamouflageTests
|
||||
battle.Library.StaticLibrary.Types.TryGetTypeIdentifier("normal", out var expected);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected);
|
||||
@@ -107,7 +107,7 @@ public class CamouflageTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, _) = CreateTestSetup(null, "field");
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
@@ -14,16 +14,16 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CaptivateTests
|
||||
{
|
||||
private static (Captivate script, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData)
|
||||
private static (Captivate script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IHitData hitData)
|
||||
CreateTestSetup(Gender userGender, Gender targetGender)
|
||||
{
|
||||
var script = new Captivate();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Gender.Returns(userGender);
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Gender.Returns(targetGender);
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
@@ -34,7 +34,7 @@ public class CaptivateTests
|
||||
/// <summary>
|
||||
/// Helper that checks whether a stat boost change was applied to the given Pokémon.
|
||||
/// </summary>
|
||||
private static bool ReceivedStatBoost(IPokemon pokemon, Statistic stat, sbyte amount) =>
|
||||
private static bool ReceivedStatBoost(IBattlePokemon pokemon, Statistic stat, sbyte amount) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost" &&
|
||||
(Statistic)c.GetArguments()[0]! == stat &&
|
||||
(sbyte)c.GetArguments()[1]! == amount);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class ChangeTargetSpecialDefenseTests
|
||||
/// <summary>
|
||||
/// Helper to extract the arguments of the ChangeStatBoost call received by a substitute target.
|
||||
/// </summary>
|
||||
private static object?[]? GetStatBoostCallArgs(IPokemon target)
|
||||
private static object?[]? GetStatBoostCallArgs(IBattlePokemon target)
|
||||
{
|
||||
var call = target.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
return call?.GetArguments();
|
||||
@@ -41,9 +41,9 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -66,9 +66,9 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -90,9 +90,9 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -114,9 +114,9 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -137,7 +137,7 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
// Act - the user is hit by its own move (e.g. redirected)
|
||||
@@ -159,9 +159,9 @@ public class ChangeTargetSpecialDefenseTests
|
||||
// Arrange
|
||||
var script = CreateInitializedScript(amount);
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class ChargeTests
|
||||
{
|
||||
private static (Charge script, IExecutingMove move, IPokemon user, IScriptSet userVolatile) CreateTestSetup()
|
||||
private static (Charge script, IExecutingMove move, IBattlePokemon user, IScriptSet userVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new Charge();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the volatile script added by Charge can be inspected afterwards.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
@@ -32,16 +32,14 @@ public class ChargeTests
|
||||
/// Creates an executing move of the given type whose damage modifier can be changed by
|
||||
/// <see cref="ChargeEffect.ChangeDamageModifier"/>.
|
||||
/// </summary>
|
||||
private static (IExecutingMove move, IPokemon target) CreateExecutingMoveOfType(string typeName)
|
||||
private static (IExecutingMove move, IBattlePokemon target) CreateExecutingMoveOfType(string typeName)
|
||||
{
|
||||
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);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
library.StaticLibrary.Types.TryGetTypeIdentifier(typeName, out var typeIdentifier);
|
||||
var useMove = Substitute.For<IMoveData>();
|
||||
useMove.MoveType.Returns(typeIdentifier);
|
||||
@@ -61,7 +59,7 @@ public class ChargeTests
|
||||
var (script, move, user, _) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
var boost = user.ReceivedCalls().SingleOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
@@ -82,7 +80,7 @@ public class ChargeTests
|
||||
var (script, move, _, userVolatile) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<ChargeEffect>())).IsTrue();
|
||||
@@ -134,7 +132,7 @@ public class ChargeTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, userVolatile) = CreateTestSetup();
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
await Assert.That(userVolatile.TryGet<ChargeEffect>(out var effect)).IsTrue();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ public class ChipAwayTests
|
||||
var bypass = false;
|
||||
|
||||
// Act
|
||||
script.BypassDefensiveStatBoosts(Substitute.For<IExecutingMove>(), Substitute.For<IPokemon>(), 0, ref bypass);
|
||||
script.BypassDefensiveStatBoosts(Substitute.For<IExecutingMove>(), Substitute.For<IBattlePokemon>(), 0,
|
||||
ref bypass);
|
||||
|
||||
// Assert
|
||||
await Assert.That(bypass).IsTrue();
|
||||
@@ -40,7 +41,8 @@ public class ChipAwayTests
|
||||
var bypass = false;
|
||||
|
||||
// Act
|
||||
script.BypassEvasionStatBoosts(Substitute.For<IExecutingMove>(), Substitute.For<IPokemon>(), 0, ref bypass);
|
||||
script.BypassEvasionStatBoosts(Substitute.For<IExecutingMove>(), Substitute.For<IBattlePokemon>(), 0,
|
||||
ref bypass);
|
||||
|
||||
// Assert
|
||||
await Assert.That(bypass).IsTrue();
|
||||
|
||||
@@ -19,8 +19,8 @@ public class Conversion2Tests
|
||||
{
|
||||
private static readonly IDynamicLibrary Library = LibraryHelpers.LoadLibrary();
|
||||
|
||||
private static (Conversion2 script, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData)
|
||||
CreateTestSetup(TypeIdentifier? lastMoveType)
|
||||
private static (Conversion2 script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IHitData
|
||||
hitData) CreateTestSetup(TypeIdentifier? lastMoveType)
|
||||
{
|
||||
var script = new Conversion2();
|
||||
|
||||
@@ -30,15 +30,13 @@ public class Conversion2Tests
|
||||
battle.Library.Returns(Library);
|
||||
battle.Random.Returns(random);
|
||||
|
||||
var userBattleData = Substitute.For<IPokemonBattleData>();
|
||||
userBattleData.Battle.Returns(battle);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(userBattleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
if (lastMoveType == null)
|
||||
{
|
||||
targetBattleData.LastMoveChoice.Returns((IMoveChoice?)null);
|
||||
target.LastMoveChoice.Returns((IMoveChoice?)null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -48,12 +46,9 @@ public class Conversion2Tests
|
||||
learnedMove.MoveData.Returns(moveData);
|
||||
var lastChoice = Substitute.For<IMoveChoice>();
|
||||
lastChoice.ChosenMove.Returns(learnedMove);
|
||||
targetBattleData.LastMoveChoice.Returns(lastChoice);
|
||||
target.LastMoveChoice.Returns(lastChoice);
|
||||
}
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(targetBattleData);
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
@@ -70,9 +65,9 @@ public class Conversion2Tests
|
||||
|
||||
/// <summary>
|
||||
/// Helper that returns the single type the user was changed to, or null when
|
||||
/// <see cref="IPokemon.SetTypes"/> was never called.
|
||||
/// <see cref="IBattlePokemon.SetTypes"/> was never called.
|
||||
/// </summary>
|
||||
private static TypeIdentifier? GetSetType(IPokemon user)
|
||||
private static TypeIdentifier? GetSetType(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "SetTypes");
|
||||
return call != null ? ((IReadOnlyList<TypeIdentifier>)call.GetArguments()[0]!).Single() : null;
|
||||
|
||||
@@ -22,15 +22,15 @@ public class ConversionTests
|
||||
return learned;
|
||||
}
|
||||
|
||||
private static (Conversion script, IExecutingMove move, IPokemon user, IPokemon target, IHitData hitData)
|
||||
CreateTestSetup(params ILearnedMove?[] moves)
|
||||
private static (Conversion script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IHitData hitData
|
||||
) CreateTestSetup(params ILearnedMove?[] moves)
|
||||
{
|
||||
var script = new Conversion();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Moves.Returns(moves);
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
return (script, move, user, target, hitData);
|
||||
|
||||
@@ -17,11 +17,10 @@ public class CopycatTests
|
||||
private static (Copycat script, IMoveChoice choice) CreateTestSetup(string? lastMoveName)
|
||||
{
|
||||
var script = new Copycat();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
if (lastMoveName == null)
|
||||
{
|
||||
battleData.LastMoveChoice.Returns((IMoveChoice?)null);
|
||||
user.LastMoveChoice.Returns((IMoveChoice?)null);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -31,9 +30,8 @@ public class CopycatTests
|
||||
learnedMove.MoveData.Returns(moveData);
|
||||
var lastChoice = Substitute.For<IMoveChoice>();
|
||||
lastChoice.ChosenMove.Returns(learnedMove);
|
||||
battleData.LastMoveChoice.Returns(lastChoice);
|
||||
user.LastMoveChoice.Returns(lastChoice);
|
||||
}
|
||||
user.BattleData.Returns(battleData);
|
||||
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -94,25 +92,4 @@ public class CopycatTests
|
||||
choice.Received(1).Fail();
|
||||
await Assert.That(moveName).IsEqualTo(new StringKey("copycat"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) there is no last move, so Copycat fails.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ChangeMove_NoBattleData_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var script = new Copycat();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
StringKey moveName = "copycat";
|
||||
|
||||
// Act
|
||||
script.ChangeMove(choice, ref moveName);
|
||||
|
||||
// Assert
|
||||
choice.Received(1).Fail();
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,14 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CoreEnforcerTests
|
||||
{
|
||||
private static (CoreEnforcer script, IExecutingMove move, IMoveChoice currentChoice, IPokemon target, IHitData
|
||||
private static (CoreEnforcer script, IExecutingMove move, IMoveChoice currentChoice, IBattlePokemon target, IHitData
|
||||
hitData, IBattle battle) CreateTestSetup()
|
||||
{
|
||||
var script = new CoreEnforcer();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
var currentChoice = Substitute.For<IMoveChoice>();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.MoveChoice.Returns(currentChoice);
|
||||
@@ -120,24 +118,6 @@ public class CoreEnforcerTests
|
||||
hitData.Received(1).Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: a target without battle data (not in battle) is left untouched.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, target, hitData, _) = CreateTestSetup();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
target.DidNotReceive().SuppressAbility();
|
||||
hitData.DidNotReceive().Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the condition is that "the target has already used a move" — an action by a different
|
||||
/// Pokémon (e.g. the user's ally in a Double Battle) does not count as the target having acted.
|
||||
@@ -148,7 +128,7 @@ public class CoreEnforcerTests
|
||||
// Arrange
|
||||
var (script, move, currentChoice, target, hitData, battle) = CreateTestSetup();
|
||||
var allyChoice = Substitute.For<IMoveChoice>();
|
||||
allyChoice.User.Returns(Substitute.For<IPokemon>());
|
||||
allyChoice.User.Returns(Substitute.For<IBattlePokemon>());
|
||||
SetTurnChoices(battle, allyChoice, currentChoice);
|
||||
|
||||
// Act
|
||||
@@ -162,7 +142,7 @@ public class CoreEnforcerTests
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The move cannot suppress certain signature abilities including Multitype, Stance
|
||||
/// Change, Schooling, Comatose, Shields Down, Disguise, RKS System, Battle Bond, Power Construct".
|
||||
/// The script requests the suppression unconditionally; <see cref="IPokemon.SuppressAbility"/> refuses
|
||||
/// The script requests the suppression unconditionally; <see cref="IBattlePokemon.SuppressAbility"/> refuses
|
||||
/// it when <see cref="IAbility.CanBeChanged"/> is false, so these abilities must carry that flag in the
|
||||
/// Gen7 data.
|
||||
/// </summary>
|
||||
|
||||
@@ -21,9 +21,9 @@ public class CounterTests
|
||||
/// Creates a user whose volatile scripts contain a <see cref="CounterHelperEffect"/> that has recorded
|
||||
/// an incoming physical hit of the given damage by <paramref name="attacker"/>.
|
||||
/// </summary>
|
||||
private static IPokemon CreateUserHitBy(IPokemon? attacker, uint damage, bool physical = true)
|
||||
private static IBattlePokemon CreateUserHitBy(IBattlePokemon? attacker, uint damage, bool physical = true)
|
||||
{
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
@@ -55,7 +55,7 @@ public class CounterTests
|
||||
{
|
||||
// Arrange
|
||||
var script = new Counter();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
@@ -78,11 +78,11 @@ public class CounterTests
|
||||
{
|
||||
// Arrange
|
||||
var script = new Counter();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
var user = CreateUserHitBy(attacker, 40);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
IReadOnlyList<IPokemon?> targets = new IPokemon?[] { Substitute.For<IPokemon>() };
|
||||
IReadOnlyList<IBattlePokemon?> targets = new IBattlePokemon?[] { Substitute.For<IBattlePokemon>() };
|
||||
|
||||
// Act
|
||||
script.ChangeTargets(choice, ref targets);
|
||||
@@ -103,7 +103,7 @@ public class CounterTests
|
||||
var user = CreateUserHitBy(null, 0);
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(user);
|
||||
IReadOnlyList<IPokemon?> targets = new IPokemon?[] { Substitute.For<IPokemon>() };
|
||||
IReadOnlyList<IBattlePokemon?> targets = new IBattlePokemon?[] { Substitute.For<IBattlePokemon>() };
|
||||
|
||||
// Act
|
||||
script.ChangeTargets(choice, ref targets);
|
||||
@@ -122,7 +122,7 @@ public class CounterTests
|
||||
{
|
||||
// Arrange
|
||||
var script = new Counter();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
var user = CreateUserHitBy(attacker, damageTaken);
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
@@ -144,9 +144,9 @@ public class CounterTests
|
||||
{
|
||||
// Arrange
|
||||
var script = new Counter();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
var user = CreateUserHitBy(attacker, 40);
|
||||
var someoneElse = Substitute.For<IPokemon>();
|
||||
var someoneElse = Substitute.For<IBattlePokemon>();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
@@ -167,7 +167,7 @@ public class CounterTests
|
||||
public async Task CounterHelperEffect_PhysicalHit_RecordsAttackerAndDamage()
|
||||
{
|
||||
// Arrange
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
var user = CreateUserHitBy(attacker, 40);
|
||||
|
||||
// Assert
|
||||
@@ -184,7 +184,7 @@ public class CounterTests
|
||||
public async Task CounterHelperEffect_SpecialHit_IsNotRecorded()
|
||||
{
|
||||
// Arrange
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
var user = CreateUserHitBy(attacker, 40, false);
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CovetTests
|
||||
{
|
||||
private static (Covet script, IExecutingMove move, IPokemon user, IPokemon target) CreateTestSetup(
|
||||
private static (Covet script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target) CreateTestSetup(
|
||||
IItem? targetItem)
|
||||
{
|
||||
var script = new Covet();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Explicitly return null to suppress NSubstitute's auto-substitution; Covet must see an empty-handed user.
|
||||
user.HeldItem.Returns((IItem?)null);
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.HeldItem.Returns(targetItem);
|
||||
if (targetItem != null)
|
||||
{
|
||||
|
||||
@@ -26,13 +26,11 @@ public class CraftyShieldTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { side });
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
user.SideIndex.Returns((byte)0);
|
||||
user.Battle.Returns(battle);
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, sideVolatile);
|
||||
@@ -58,7 +56,7 @@ public class CraftyShieldTests
|
||||
var (script, move, sideVolatile) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(sideVolatile.Contains(ScriptUtils.ResolveName<CraftyShieldEffect>())).IsTrue();
|
||||
@@ -99,21 +97,4 @@ public class CraftyShieldTests
|
||||
// Assert
|
||||
await Assert.That(stop).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data) no shield can be raised and nothing happens.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, sideVolatile) = CreateTestSetup();
|
||||
move.User.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
|
||||
// Assert - no effect is added
|
||||
await Assert.That(sideVolatile.Contains(ScriptUtils.ResolveName<CraftyShieldEffect>())).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CrushGripTests
|
||||
{
|
||||
private static (CrushGrip script, IExecutingMove move, IPokemon target) CreateTestSetup(uint currentHealth,
|
||||
private static (CrushGrip script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint currentHealth,
|
||||
uint maxHealth)
|
||||
{
|
||||
var script = new CrushGrip();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.CurrentHealth.Returns(currentHealth);
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(maxHealth, 1, 1, 1, 1, 1));
|
||||
return (script, move, target);
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class CurseTests
|
||||
{
|
||||
private static (Curse script, IExecutingMove move, IPokemon user, IPokemon target, IScriptSet targetVolatile)
|
||||
CreateTestSetup(bool userIsGhost, uint userMaxHealth = 100, uint userCurrentHealth = 100)
|
||||
private static (Curse script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IScriptSet
|
||||
targetVolatile) CreateTestSetup(bool userIsGhost, uint userMaxHealth = 100, uint userCurrentHealth = 100)
|
||||
{
|
||||
var script = new Curse();
|
||||
var library = LibraryHelpers.LoadLibrary();
|
||||
@@ -26,18 +26,16 @@ public class CurseTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Types.Returns(new[] { userIsGhost ? ghostType : normalType });
|
||||
user.Battle.Returns(battle);
|
||||
user.MaxHealth.Returns(userMaxHealth);
|
||||
user.CurrentHealth.Returns(userCurrentHealth);
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the curse applied to the target can be inspected afterwards.
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
@@ -49,7 +47,7 @@ public class CurseTests
|
||||
/// <summary>
|
||||
/// Helper that checks whether a stat boost change was applied to the given Pokémon.
|
||||
/// </summary>
|
||||
private static bool ReceivedStatBoost(IPokemon pokemon, Statistic stat, sbyte amount) =>
|
||||
private static bool ReceivedStatBoost(IBattlePokemon pokemon, Statistic stat, sbyte amount) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost" &&
|
||||
(Statistic)c.GetArguments()[0]! == stat &&
|
||||
(sbyte)c.GetArguments()[1]! == amount);
|
||||
@@ -57,7 +55,7 @@ public class CurseTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a substitute's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon pokemon)
|
||||
private static uint? GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -178,7 +176,7 @@ public class CurseTests
|
||||
public async Task GhostCurseEffect_OnEndTurnAtFullHp_CursedPokemonLosesQuarterOfMaximumHp()
|
||||
{
|
||||
// Arrange
|
||||
var cursed = Substitute.For<IPokemon>();
|
||||
var cursed = Substitute.For<IBattlePokemon>();
|
||||
cursed.MaxHealth.Returns(100u);
|
||||
cursed.CurrentHealth.Returns(100u);
|
||||
var effect = new GhostCurseEffect(cursed);
|
||||
@@ -198,7 +196,7 @@ public class CurseTests
|
||||
public async Task GhostCurseEffect_OnEndTurnAtLowHp_CursedPokemonStillLosesQuarterOfMaximumHp()
|
||||
{
|
||||
// Arrange
|
||||
var cursed = Substitute.For<IPokemon>();
|
||||
var cursed = Substitute.For<IBattlePokemon>();
|
||||
cursed.MaxHealth.Returns(100u);
|
||||
cursed.CurrentHealth.Returns(40u);
|
||||
var effect = new GhostCurseEffect(cursed);
|
||||
|
||||
@@ -20,7 +20,7 @@ public class DarkestLariatTests
|
||||
// Arrange
|
||||
var script = new DarkestLariat();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var bypass = false;
|
||||
|
||||
// Act
|
||||
@@ -40,7 +40,7 @@ public class DarkestLariatTests
|
||||
// Arrange
|
||||
var script = new DarkestLariat();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var bypass = false;
|
||||
|
||||
// Act
|
||||
|
||||
@@ -19,7 +19,7 @@ public class DefogTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the target is on side 1 and the user on side 0.
|
||||
/// </summary>
|
||||
private static (Defog script, IExecutingMove move, IPokemon target, IScriptSet targetSideScripts, IScriptSet
|
||||
private static (Defog script, IExecutingMove move, IBattlePokemon target, IScriptSet targetSideScripts, IScriptSet
|
||||
userSideScripts) CreateTestSetup()
|
||||
{
|
||||
var script = new Defog();
|
||||
@@ -35,18 +35,14 @@ public class DefogTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { userSide, targetSide });
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var userBattleData = Substitute.For<IPokemonBattleData>();
|
||||
userBattleData.Battle.Returns(battle);
|
||||
userBattleData.SideIndex.Returns((byte)0);
|
||||
user.BattleData.Returns(userBattleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
user.SideIndex.Returns((byte)0);
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
||||
targetBattleData.Battle.Returns(battle);
|
||||
targetBattleData.SideIndex.Returns((byte)1);
|
||||
target.BattleData.Returns(targetBattleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
target.SideIndex.Returns((byte)1);
|
||||
|
||||
return (script, move, target, targetSideScripts, userSideScripts);
|
||||
}
|
||||
@@ -144,21 +140,4 @@ public class DefogTests
|
||||
c.GetMethodInfo().Name == "ChangeStatBoost" && (Statistic)c.GetArguments()[0]! == Statistic.Evasion &&
|
||||
(sbyte)c.GetArguments()[1]! == -1)).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data (outside of battle) the secondary effect does nothing and does
|
||||
/// not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var script = new Defog();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.That(() => script.OnSecondaryEffect(move, target, 0)).ThrowsNothing();
|
||||
}
|
||||
}
|
||||
@@ -17,14 +17,15 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
public class DestinyBondTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a mocked user whose <see cref="IPokemon.Volatile"/> is a real <see cref="ScriptSet"/> so
|
||||
/// Creates a mocked user whose <see cref="IBattlePokemon.Volatile"/> is a real <see cref="ScriptSet"/> so
|
||||
/// the volatile added by the move can be inspected.
|
||||
/// </summary>
|
||||
private static (DestinyBond script, IExecutingMove move, IPokemon user, ScriptSet userVolatile) CreateTestSetup()
|
||||
private static (DestinyBond script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new DestinyBond();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
@@ -36,7 +37,7 @@ public class DestinyBondTests
|
||||
/// Creates a fainting Pokémon whose battle's <see cref="BattleChoiceQueue.LastRanChoice"/> is a move
|
||||
/// choice made by the given attacker.
|
||||
/// </summary>
|
||||
private static IPokemon CreateFaintingPokemonAttackedBy(IPokemon attacker)
|
||||
private static IBattlePokemon CreateFaintingPokemonAttackedBy(IBattlePokemon attacker)
|
||||
{
|
||||
var moveChoice = Substitute.For<IMoveChoice>();
|
||||
moveChoice.User.Returns(attacker);
|
||||
@@ -45,10 +46,8 @@ public class DestinyBondTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
pokemon.BattleData.Returns(battleData);
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Battle.Returns(battle);
|
||||
return pokemon;
|
||||
}
|
||||
|
||||
@@ -61,7 +60,7 @@ public class DestinyBondTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _, userVolatile) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -119,7 +118,7 @@ public class DestinyBondTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new DestinyBondEffect();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
attacker.BoostedStats.Returns(new StatisticSet<uint>(100, 1, 1, 1, 1, 1));
|
||||
var pokemon = CreateFaintingPokemonAttackedBy(attacker);
|
||||
|
||||
@@ -141,7 +140,7 @@ public class DestinyBondTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new DestinyBondEffect();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
attacker.BoostedStats.Returns(new StatisticSet<uint>(100, 1, 1, 1, 1, 1));
|
||||
var pokemon = CreateFaintingPokemonAttackedBy(attacker);
|
||||
|
||||
@@ -162,7 +161,7 @@ public class DestinyBondTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new DestinyBondEffect();
|
||||
var attacker = Substitute.For<IPokemon>();
|
||||
var attacker = Substitute.For<IBattlePokemon>();
|
||||
attacker.BoostedStats.Returns(new StatisticSet<uint>(100, 1, 1, 1, 1, 1));
|
||||
var pokemon = CreateFaintingPokemonAttackedBy(attacker);
|
||||
|
||||
@@ -181,7 +180,7 @@ public class DestinyBondTests
|
||||
public async Task OnBeforeMove_UserMovesAgain_RemovesDestinyBondEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DestinyBondEffect();
|
||||
@@ -194,19 +193,4 @@ public class DestinyBondTests
|
||||
// Assert
|
||||
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<DestinyBondEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: fainting without battle data (outside of battle) does nothing and does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnFaint_NoBattleData_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var effect = new DestinyBondEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
pokemon.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.That(() => effect.OnFaint(pokemon, DamageSource.MoveDamage)).ThrowsNothing();
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class DigTests
|
||||
{
|
||||
private static (Dig script, IExecutingMove move, IPokemon user, ScriptSet userVolatile, IMoveChoice moveChoice)
|
||||
CreateTestSetup()
|
||||
private static (Dig script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile, IMoveChoice moveChoice
|
||||
) CreateTestSetup()
|
||||
{
|
||||
var script = new Dig();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the charge volatile added by Dig can be inspected afterwards.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
@@ -35,9 +35,7 @@ public class DigTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(new EventHook());
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, user, userVolatile, moveChoice);
|
||||
}
|
||||
@@ -250,7 +248,7 @@ public class DigTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsNotDigCharge_RemovesDigEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DigEffect(user);
|
||||
@@ -273,7 +271,7 @@ public class DigTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsDigCharge_KeepsDigEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DigEffect(user);
|
||||
|
||||
@@ -36,26 +36,22 @@ public class DisableTests
|
||||
/// Creates a fully mocked test setup where the target's volatile scripts are a real
|
||||
/// <see cref="ScriptSet"/> and its last used move is the given one (or none).
|
||||
/// </summary>
|
||||
private static (Disable script, IExecutingMove move, IPokemon target, ScriptSet targetVolatile, IHitData hitData)
|
||||
CreateTestSetup(string? lastUsedMove, bool lastMoveIsStruggle = false)
|
||||
private static (Disable script, IExecutingMove move, IBattlePokemon target, ScriptSet targetVolatile, IHitData
|
||||
hitData) CreateTestSetup(string? lastUsedMove, bool lastMoveIsStruggle = false)
|
||||
{
|
||||
var script = new Disable();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var userBattleData = Substitute.For<IPokemonBattleData>();
|
||||
user.BattleData.Returns(userBattleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
||||
// Create the choice before the Returns call; configuring substitutes inside Returns is not allowed.
|
||||
var lastMoveChoice = lastUsedMove == null ? null : CreateMoveChoice(lastUsedMove);
|
||||
targetBattleData.LastMoveChoice.Returns(lastMoveChoice);
|
||||
target.BattleData.Returns(targetBattleData);
|
||||
target.LastMoveChoice.Returns(lastMoveChoice);
|
||||
|
||||
// Struggle is recognized through the misc library's replacement choice check, not by name.
|
||||
var miscLibrary = Substitute.For<IMiscLibrary>();
|
||||
@@ -144,24 +140,6 @@ public class DisableTests
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<DisableEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the effect does nothing and
|
||||
/// does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_UserHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, targetVolatile, _) = CreateTestSetup("tackle");
|
||||
move.User.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<DisableEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Disable temporarily prevents the target from using a specific move." Selecting the
|
||||
/// disabled move is prevented by the <see cref="DisableEffect"/>.
|
||||
@@ -207,7 +185,7 @@ public class DisableTests
|
||||
public async Task OnEndTurn_ThreeTurnsPassed_EffectStillActive()
|
||||
{
|
||||
// Arrange
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DisableEffect(new StringKey("tackle"));
|
||||
@@ -230,7 +208,7 @@ public class DisableTests
|
||||
public async Task OnEndTurn_FourTurnsPassed_EffectRemovesItself()
|
||||
{
|
||||
// Arrange
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DisableEffect(new StringKey("tackle"));
|
||||
|
||||
@@ -18,12 +18,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class DiveTests
|
||||
{
|
||||
private static (Dive script, IExecutingMove move, IPokemon user, ScriptSet userVolatile, IMoveChoice moveChoice)
|
||||
CreateTestSetup()
|
||||
private static (Dive script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile, IMoveChoice
|
||||
moveChoice) CreateTestSetup()
|
||||
{
|
||||
var script = new Dive();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the charge volatile added by Dive can be inspected afterwards.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
@@ -35,9 +35,7 @@ public class DiveTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(new EventHook());
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, user, userVolatile, moveChoice);
|
||||
}
|
||||
@@ -126,7 +124,7 @@ public class DiveTests
|
||||
// Arrange
|
||||
var (script, move, user, userVolatile, _) = CreateTestSetup();
|
||||
userVolatile.Add(new DiveEffect(user));
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -248,7 +246,7 @@ public class DiveTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsNotDiveCharge_RemovesDiveEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DiveEffect(user);
|
||||
@@ -271,7 +269,7 @@ public class DiveTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsDiveCharge_KeepsDiveEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new DiveEffect(user);
|
||||
|
||||
@@ -18,8 +18,8 @@ public class DoomDesireTests
|
||||
/// Creates a fully mocked test setup where the target is at the given position on a side whose
|
||||
/// volatile scripts are a real <see cref="ScriptSet"/>.
|
||||
/// </summary>
|
||||
private static (DoomDesire script, IExecutingMove move, IPokemon target, IBattleSide side, ScriptSet sideScripts,
|
||||
IHitData hitData) CreateTestSetup(byte position = 0, uint damage = 100)
|
||||
private static (DoomDesire script, IExecutingMove move, IBattlePokemon target, IBattleSide side, ScriptSet
|
||||
sideScripts, IHitData hitData) CreateTestSetup(byte position = 0, uint damage = 100)
|
||||
{
|
||||
var script = new DoomDesire();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -31,13 +31,11 @@ public class DoomDesireTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
battleData.Position.Returns(position);
|
||||
target.BattleData.Returns(battleData);
|
||||
side.Pokemon.Returns(new IPokemon?[] { target });
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
target.SideIndex.Returns((byte)0);
|
||||
target.Position.Returns(position);
|
||||
side.Pokemon.Returns(new IBattlePokemon?[] { target });
|
||||
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.Damage.Returns(damage);
|
||||
@@ -175,25 +173,4 @@ public class DoomDesireTests
|
||||
// Assert
|
||||
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<DoomDesireEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the target (outside of battle) the script does nothing and
|
||||
/// does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task BlockOutgoingHit_TargetHasNoBattleData_DoesNotBlock()
|
||||
{
|
||||
// Arrange
|
||||
var script = new DoomDesire();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var block = false;
|
||||
|
||||
// Act
|
||||
script.BlockOutgoingHit(move, target, 0, ref block);
|
||||
|
||||
// Assert
|
||||
await Assert.That(block).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,8 @@ public class DoublePowerIfTargetDamagedInTurnTests
|
||||
/// Creates a fully mocked test setup where the target sits on side 0 whose volatile scripts are a
|
||||
/// real <see cref="ScriptSet"/>.
|
||||
/// </summary>
|
||||
private static (DoublePowerIfTargetDamagedInTurn script, IExecutingMove move, IPokemon target, ScriptSet sideScripts
|
||||
) CreateTestSetup()
|
||||
private static (DoublePowerIfTargetDamagedInTurn script, IExecutingMove move, IBattlePokemon target, ScriptSet
|
||||
sideScripts ) CreateTestSetup()
|
||||
{
|
||||
var script = new DoublePowerIfTargetDamagedInTurn();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -33,17 +33,13 @@ public class DoublePowerIfTargetDamagedInTurnTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var userBattleData = Substitute.For<IPokemonBattleData>();
|
||||
userBattleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(userBattleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
||||
targetBattleData.Battle.Returns(battle);
|
||||
targetBattleData.SideIndex.Returns((byte)0);
|
||||
target.BattleData.Returns(targetBattleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
target.SideIndex.Returns((byte)0);
|
||||
|
||||
return (script, move, target, sideScripts);
|
||||
}
|
||||
@@ -140,7 +136,7 @@ public class DoublePowerIfTargetDamagedInTurnTests
|
||||
var (script, move, target, sideScripts) = CreateTestSetup();
|
||||
var data = new DoublePowerIfTargetDamagedInTurnData();
|
||||
sideScripts.Add(data);
|
||||
data.OnDamage(Substitute.For<IPokemon>(), DamageSource.MoveDamage, 100, 80);
|
||||
data.OnDamage(Substitute.For<IBattlePokemon>(), DamageSource.MoveDamage, 100, 80);
|
||||
ushort basePower = 60;
|
||||
|
||||
// Act
|
||||
@@ -192,27 +188,4 @@ public class DoublePowerIfTargetDamagedInTurnTests
|
||||
await Assert.That(sideScripts.Contains(ScriptUtils.ResolveName<DoublePowerIfTargetDamagedInTurnData>()))
|
||||
.IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the base power is unchanged
|
||||
/// and nothing throws.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeBasePower_UserHasNoBattleData_BasePowerUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var script = new DoublePowerIfTargetDamagedInTurn();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
ushort basePower = 60;
|
||||
|
||||
// Act
|
||||
script.ChangeBasePower(move, target, 0, ref basePower);
|
||||
|
||||
// Assert
|
||||
await Assert.That(basePower).IsEqualTo((ushort)60);
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,11 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class DragonAscentTests
|
||||
{
|
||||
private static (DragonAscent script, IExecutingMove move, IPokemon user) CreateTestSetup()
|
||||
private static (DragonAscent script, IExecutingMove move, IBattlePokemon user) CreateTestSetup()
|
||||
{
|
||||
var script = new DragonAscent();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
return (script, move, user);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class DragonAscentTests
|
||||
/// Helper checking whether the given Pokémon received a ChangeStatBoost call for the given stat with
|
||||
/// a one-stage self-inflicted, non-forced drop.
|
||||
/// </summary>
|
||||
private static bool ReceivedSelfInflictedDrop(IPokemon pokemon, Statistic stat) =>
|
||||
private static bool ReceivedSelfInflictedDrop(IBattlePokemon pokemon, Statistic stat) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost" &&
|
||||
(Statistic)c.GetArguments()[0]! == stat && (sbyte)c.GetArguments()[1]! == -1 &&
|
||||
(bool)c.GetArguments()[2]! && !(bool)c.GetArguments()[3]!);
|
||||
@@ -39,7 +39,7 @@ public class DragonAscentTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -57,7 +57,7 @@ public class DragonAscentTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -75,7 +75,7 @@ public class DragonAscentTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, _) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -93,7 +93,7 @@ public class DragonAscentTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user) = CreateTestSetup();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
@@ -15,12 +15,12 @@ public class DrainTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Drain tests.
|
||||
/// </summary>
|
||||
private static (Drain drain, IExecutingMove move, IPokemon target, IPokemon user) CreateTestSetup(uint damage,
|
||||
bool holdsBigRoot = false, Script[]? targetScripts = null)
|
||||
private static (Drain drain, IExecutingMove move, IBattlePokemon target, IBattlePokemon user) CreateTestSetup(
|
||||
uint damage, bool holdsBigRoot = false, Script[]? targetScripts = null)
|
||||
{
|
||||
var drain = new Drain();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.Damage.Returns(damage);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
@@ -31,7 +31,7 @@ public class DrainTests
|
||||
.ToArray();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(containers));
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
if (holdsBigRoot)
|
||||
user.HasHeldItem("big_root").Returns(true);
|
||||
move.User.Returns(user);
|
||||
@@ -42,7 +42,7 @@ public class DrainTests
|
||||
/// <summary>
|
||||
/// Helper to extract the heal amount from the user's received Heal calls.
|
||||
/// </summary>
|
||||
private static uint? GetHealAmount(IPokemon user)
|
||||
private static uint? GetHealAmount(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Heal");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -51,7 +51,7 @@ public class DrainTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from the user's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon user)
|
||||
private static uint? GetDamageAmount(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -60,7 +60,7 @@ public class DrainTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from the user's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon user)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (DamageSource)call.GetArguments()[1]! : null;
|
||||
|
||||
@@ -17,12 +17,12 @@ public class DreamEaterTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Dream Eater tests.
|
||||
/// </summary>
|
||||
private static (DreamEater script, IExecutingMove move, IPokemon target, IPokemon user) CreateTestSetup(uint damage,
|
||||
bool holdsBigRoot = false, Script[]? targetScripts = null)
|
||||
private static (DreamEater script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user) CreateTestSetup(
|
||||
uint damage, bool holdsBigRoot = false, Script[]? targetScripts = null)
|
||||
{
|
||||
var script = new DreamEater();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.Damage.Returns(damage);
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
@@ -33,7 +33,7 @@ public class DreamEaterTests
|
||||
.ToArray();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(containers));
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
if (holdsBigRoot)
|
||||
user.HasHeldItem("big_root").Returns(true);
|
||||
move.User.Returns(user);
|
||||
@@ -44,7 +44,7 @@ public class DreamEaterTests
|
||||
/// <summary>
|
||||
/// Helper to extract the heal amount from the user's received Heal calls.
|
||||
/// </summary>
|
||||
private static uint? GetHealAmount(IPokemon user)
|
||||
private static uint? GetHealAmount(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Heal");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
|
||||
@@ -35,11 +35,12 @@ public class EchoedVoiceTests
|
||||
/// Creates a fully mocked test setup where the user's side has a real <see cref="ScriptSet"/> as its
|
||||
/// volatile scripts.
|
||||
/// </summary>
|
||||
private static (EchoedVoice script, IExecutingMove move, IPokemon target, IScriptSet sideScripts) CreateTestSetup()
|
||||
private static (EchoedVoice script, IExecutingMove move, IBattlePokemon target, IScriptSet sideScripts)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new EchoedVoice();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
@@ -49,13 +50,10 @@ public class EchoedVoiceTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.SideIndex.Returns((byte)0);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, target, sideScripts);
|
||||
}
|
||||
@@ -155,25 +153,6 @@ public class EchoedVoiceTests
|
||||
await Assert.That(sideScripts.Get<EchoedVoiceData>()!.Stacks).IsEqualTo(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the base power hook does
|
||||
/// nothing and does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeBasePower_UserHasNoBattleData_BasePowerUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _) = CreateTestSetup();
|
||||
move.User.BattleData.Returns((IPokemonBattleData?)null);
|
||||
ushort basePower = 40;
|
||||
|
||||
// Act
|
||||
script.ChangeBasePower(move, target, 0, ref basePower);
|
||||
|
||||
// Assert
|
||||
await Assert.That(basePower).IsEqualTo((ushort)40);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the boost only applies on "consecutive" turns — when a Pokémon on the side chooses a
|
||||
/// move other than Echoed Voice, the <see cref="EchoedVoiceData"/> marker removes itself, resetting
|
||||
|
||||
@@ -18,12 +18,10 @@ public class ElectricTerrainTests
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, battle);
|
||||
}
|
||||
@@ -40,27 +38,9 @@ public class ElectricTerrainTests
|
||||
var (script, move, battle) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
battle.Received(1).SetTerrain(ScriptUtils.ResolveName<ElectricTerrainScript>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the effect does nothing and
|
||||
/// does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OnSecondaryEffect_UserHasNoBattleData_DoesNotSetTerrain()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, battle) = CreateTestSetup();
|
||||
move.User.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
battle.DidNotReceiveWithAnyArgs().SetTerrain(default);
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ public class ElectrifyTests
|
||||
/// <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)
|
||||
private static (Electrify script, IExecutingMove move, IBattlePokemon 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 target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -40,9 +40,7 @@ public class ElectrifyTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.ChoiceQueue.Returns(hasQueue ? queue : null);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
return (script, move, target, choiceVolatile, hitData);
|
||||
}
|
||||
@@ -111,10 +109,8 @@ public class ElectrifyTests
|
||||
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);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
await Assert.That(library.StaticLibrary.Types.TryGetTypeIdentifier("normal", out var normal)).IsTrue();
|
||||
await Assert.That(library.StaticLibrary.Types.TryGetTypeIdentifier("electric", out var electric)).IsTrue();
|
||||
@@ -127,24 +123,4 @@ public class ElectrifyTests
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -14,15 +14,15 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class ElectroBallTests
|
||||
{
|
||||
private static (ElectroBall script, IExecutingMove move, IPokemon target) CreateTestSetup(uint userSpeed,
|
||||
private static (ElectroBall script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint userSpeed,
|
||||
uint targetSpeed)
|
||||
{
|
||||
var script = new ElectroBall();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 1, 1, 1, userSpeed));
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 1, 1, 1, targetSpeed));
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ public class EmbargoTests
|
||||
/// <summary>
|
||||
/// Creates a target Pokémon whose volatile scripts are a real <see cref="ScriptSet"/>.
|
||||
/// </summary>
|
||||
private static (IPokemon target, IScriptSet targetVolatile) CreateTarget()
|
||||
private static (IBattlePokemon target, IScriptSet targetVolatile) CreateTarget()
|
||||
{
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
@@ -57,7 +57,7 @@ public class EmbargoTests
|
||||
var prevented = false;
|
||||
|
||||
// Act
|
||||
effect.PreventHeldItemConsume(Substitute.For<IPokemon>(), Substitute.For<IItem>(), ref prevented);
|
||||
effect.PreventHeldItemConsume(Substitute.For<IBattlePokemon>(), Substitute.For<IItem>(), ref prevented);
|
||||
|
||||
// Assert
|
||||
await Assert.That(prevented).IsTrue();
|
||||
|
||||
@@ -39,8 +39,9 @@ public class EncoreTests
|
||||
/// Creates a fully mocked test setup where the target's volatile scripts are a real
|
||||
/// <see cref="ScriptSet"/> and its last used move is the given one (or none).
|
||||
/// </summary>
|
||||
private static (Encore script, IExecutingMove move, IPokemon target, IScriptSet targetVolatile, IHitData hitData)
|
||||
CreateTestSetup(string? lastUsedMove, bool lastMoveIsReplacement = false, bool lastMoveCantRepeat = false)
|
||||
private static (Encore script, IExecutingMove move, IBattlePokemon target, IScriptSet targetVolatile, IHitData
|
||||
hitData) CreateTestSetup(string? lastUsedMove, bool lastMoveIsReplacement = false,
|
||||
bool lastMoveCantRepeat = false)
|
||||
{
|
||||
var script = new Encore();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -52,16 +53,14 @@ public class EncoreTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
var targetBattleData = Substitute.For<IPokemonBattleData>();
|
||||
// Create the choice before the Returns call; configuring substitutes inside Returns is not allowed.
|
||||
var lastMoveChoice = lastUsedMove == null ? null : CreateMoveChoice(lastUsedMove, lastMoveCantRepeat);
|
||||
targetBattleData.LastMoveChoice.Returns(lastMoveChoice);
|
||||
targetBattleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(targetBattleData);
|
||||
target.LastMoveChoice.Returns(lastMoveChoice);
|
||||
target.Battle.Returns(battle);
|
||||
if (lastMoveChoice != null)
|
||||
miscLibrary.IsReplacementChoice(lastMoveChoice).Returns(lastMoveIsReplacement);
|
||||
|
||||
@@ -165,25 +164,6 @@ public class EncoreTests
|
||||
await Assert.That(moveData!.HasFlag(MoveFlags.CantRepeat)).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the target (outside of battle) the effect does nothing and
|
||||
/// does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, targetVolatile, hitData) = CreateTestSetup("tackle");
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
hitData.DidNotReceive().Fail();
|
||||
await Assert.That(targetVolatile.Contains(ScriptUtils.ResolveName<EncoreEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Duration standardized to exactly 3 turns" (Generation V onward). After two
|
||||
/// end-of-turn ticks the effect is still active.
|
||||
@@ -192,7 +172,7 @@ public class EncoreTests
|
||||
public async Task OnEndTurn_TwoTurnsPassed_EffectStillActive()
|
||||
{
|
||||
// Arrange
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
var owner = Substitute.For<IBattlePokemon>();
|
||||
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet ownerVolatile = new ScriptSet(owner);
|
||||
var effect = new EncoreEffect(owner, new StringKey("tackle"), 3);
|
||||
@@ -214,7 +194,7 @@ public class EncoreTests
|
||||
public async Task OnEndTurn_ThreeTurnsPassed_EffectRemovesItself()
|
||||
{
|
||||
// Arrange
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
var owner = Substitute.For<IBattlePokemon>();
|
||||
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet ownerVolatile = new ScriptSet(owner);
|
||||
var effect = new EncoreEffect(owner, new StringKey("tackle"), 3);
|
||||
|
||||
@@ -11,15 +11,15 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class EndeavorTests
|
||||
{
|
||||
private static (Endeavor script, IExecutingMove move, IPokemon target) CreateTestSetup(uint userHealth,
|
||||
private static (Endeavor script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint userHealth,
|
||||
uint targetHealth)
|
||||
{
|
||||
var script = new Endeavor();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.CurrentHealth.Returns(userHealth);
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.CurrentHealth.Returns(targetHealth);
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ public class EndureTests
|
||||
/// <see cref="ProtectionScript.OnSecondaryEffect"/>. The <c>target</c> of the secondary effect is the
|
||||
/// Pokémon using Endure itself, as the move is self-targeted.
|
||||
/// </summary>
|
||||
private static (Endure script, IExecutingMove move, IPokemon target, IHitData hitData, IScriptSet volatileSet)
|
||||
private static (Endure script, IExecutingMove move, IBattlePokemon target, IHitData hitData, IScriptSet volatileSet)
|
||||
CreateProtectSetup(bool userMovesLast, float randomRoll)
|
||||
{
|
||||
var script = new Endure();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -39,9 +39,7 @@ public class EndureTests
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
battle.Random.Returns(random);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(target);
|
||||
@@ -134,7 +132,7 @@ public class EndureTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.CurrentHealth.Returns(currentHealth);
|
||||
var damage = incomingDamage;
|
||||
|
||||
@@ -154,7 +152,7 @@ public class EndureTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.CurrentHealth.Returns(100u);
|
||||
var damage = 100u;
|
||||
|
||||
@@ -174,7 +172,7 @@ public class EndureTests
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.CurrentHealth.Returns(100u);
|
||||
var damage = 50u;
|
||||
|
||||
@@ -193,7 +191,7 @@ public class EndureTests
|
||||
public async Task OnEndTurn_EffectRemovesItself()
|
||||
{
|
||||
// Arrange
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
var owner = Substitute.For<IBattlePokemon>();
|
||||
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet ownerVolatile = new ScriptSet(owner);
|
||||
var effect = new EndureEffect();
|
||||
|
||||
@@ -25,16 +25,16 @@ public class EntrainmentTests
|
||||
return ability;
|
||||
}
|
||||
|
||||
private static (Entrainment script, IExecutingMove move, IPokemon target, IHitData hitData) CreateTestSetup(
|
||||
private static (Entrainment script, IExecutingMove move, IBattlePokemon target, IHitData hitData) CreateTestSetup(
|
||||
IAbility? userAbility, IAbility? targetAbility)
|
||||
{
|
||||
var script = new Entrainment();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.ActiveAbility.Returns(userAbility);
|
||||
move.User.Returns(user);
|
||||
target.ActiveAbility.Returns(targetAbility);
|
||||
|
||||
@@ -12,16 +12,16 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class EruptionTests
|
||||
{
|
||||
private static (Eruption script, IExecutingMove move, IPokemon target) CreateTestSetup(uint currentHealth,
|
||||
private static (Eruption script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint currentHealth,
|
||||
uint maxHealth)
|
||||
{
|
||||
var script = new Eruption();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.CurrentHealth.Returns(currentHealth);
|
||||
user.BoostedStats.Returns(new StatisticSet<uint>(maxHealth, 1, 1, 1, 1, 1));
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class ExplosionTests
|
||||
{
|
||||
private static (Explosion script, IExecutingMove move, IPokemon user) CreateTestSetup(uint currentHealth)
|
||||
private static (Explosion script, IExecutingMove move, IBattlePokemon user) CreateTestSetup(uint currentHealth)
|
||||
{
|
||||
var script = new Explosion();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.CurrentHealth.Returns(currentHealth);
|
||||
move.User.Returns(user);
|
||||
return (script, move, user);
|
||||
@@ -23,7 +23,7 @@ public class ExplosionTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from the user's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon user)
|
||||
private static uint? GetDamageAmount(IBattlePokemon user)
|
||||
{
|
||||
var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -40,7 +40,7 @@ public class ExplosionTests
|
||||
var (script, move, user) = CreateTestSetup(100);
|
||||
|
||||
// Act
|
||||
script.OnAfterHits(move, Substitute.For<IPokemon>());
|
||||
script.OnAfterHits(move, Substitute.For<IBattlePokemon>());
|
||||
|
||||
// Assert
|
||||
var damage = GetDamageAmount(user);
|
||||
@@ -60,7 +60,7 @@ public class ExplosionTests
|
||||
var (script, move, user) = CreateTestSetup(100);
|
||||
|
||||
// Act
|
||||
script.OnAfterHits(move, Substitute.For<IPokemon>());
|
||||
script.OnAfterHits(move, Substitute.For<IBattlePokemon>());
|
||||
|
||||
// Assert
|
||||
var call = user.ReceivedCalls().First(c => c.GetMethodInfo().Name == "Damage");
|
||||
|
||||
@@ -16,15 +16,15 @@ public class FacadeTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the user has the given (or no) non-volatile status in its
|
||||
/// <see cref="IPokemon.StatusScript"/>, and is using a move of the given category.
|
||||
/// <see cref="IBattlePokemon.StatusScript"/>, and is using a move of the given category.
|
||||
/// </summary>
|
||||
private static (Facade facade, IExecutingMove move, IPokemon target) CreateTestSetup(Script? status,
|
||||
private static (Facade facade, IExecutingMove move, IBattlePokemon target) CreateTestSetup(Script? status,
|
||||
MoveCategory category = MoveCategory.Physical)
|
||||
{
|
||||
var facade = new Facade();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.StatusScript.Returns(status == null ? new ScriptContainer() : new ScriptContainer(status));
|
||||
move.User.Returns(user);
|
||||
var useMove = Substitute.For<IMoveData>();
|
||||
|
||||
@@ -20,31 +20,29 @@ public class FairyLockTests
|
||||
/// Creates a fully mocked test setup where the battle has a real <see cref="ScriptSet"/> as its volatile
|
||||
/// script set.
|
||||
/// </summary>
|
||||
private static (FairyLock script, IExecutingMove move, IPokemon target, IBattle battle, IScriptSet battleVolatile)
|
||||
CreateTestSetup()
|
||||
private static (FairyLock script, IExecutingMove move, IBattlePokemon target, IBattle battle, IScriptSet
|
||||
battleVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new FairyLock();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet battleVolatile = new ScriptSet(battle);
|
||||
battle.Volatile.Returns(battleVolatile);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
return (script, move, target, battle, battleVolatile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a mocked Pokémon with the given type names as its <see cref="IPokemon.Types"/>.
|
||||
/// Creates a mocked Pokémon with the given type names as its <see cref="IBattlePokemon.Types"/>.
|
||||
/// </summary>
|
||||
private static IPokemon CreatePokemonWithTypes(params string[] types)
|
||||
private static IBattlePokemon CreatePokemonWithTypes(params string[] types)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Types.Returns(types.Select((name, index) => new TypeIdentifier((byte)(index + 1), new StringKey(name)))
|
||||
.ToList());
|
||||
return pokemon;
|
||||
@@ -68,23 +66,6 @@ public class FairyLockTests
|
||||
await Assert.That(battleVolatile.Contains(ScriptUtils.ResolveName<FairyLockEffect>())).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the target (outside of battle) the secondary effect does
|
||||
/// nothing and does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OnSecondaryEffect_TargetHasNoBattleData_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FairyLock();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act & Assert - should not throw
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Fairy Lock prevents all Pokémon (except Ghost types) on the field from switching out".
|
||||
/// A non-Ghost Pokémon is prevented from switching.
|
||||
|
||||
@@ -25,13 +25,11 @@ public class FakeOutTests
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.CurrentTurnNumber.Returns(currentTurn);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SwitchInTurn.Returns(switchInTurn);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.SwitchInTurn.Returns(switchInTurn);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move);
|
||||
}
|
||||
@@ -74,28 +72,6 @@ public class FakeOutTests
|
||||
await Assert.That(stop).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the first-turn check does nothing
|
||||
/// and the move is not stopped.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task StopBeforeMove_UserHasNoBattleData_MoveNotStopped()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FakeOut();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
var stop = false;
|
||||
|
||||
// Act
|
||||
script.StopBeforeMove(move, ref stop);
|
||||
|
||||
// Assert
|
||||
await Assert.That(stop).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Fake Out inflicts damage and always makes the target flinch" — the secondary effect puts
|
||||
/// a <see cref="FlinchEffect"/> on the target.
|
||||
@@ -106,7 +82,7 @@ public class FakeOutTests
|
||||
// Arrange
|
||||
var script = new FakeOut();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(target);
|
||||
target.Volatile.Returns(volatileSet);
|
||||
|
||||
@@ -14,11 +14,11 @@ public class FalseSwipeTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup where the target has the given current health.
|
||||
/// </summary>
|
||||
private static (FalseSwipe script, IExecutingMove move, IPokemon target) CreateTestSetup(uint currentHealth)
|
||||
private static (FalseSwipe script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint currentHealth)
|
||||
{
|
||||
var script = new FalseSwipe();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.CurrentHealth.Returns(currentHealth);
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ public class FeintTests
|
||||
/// Creates a fully mocked test setup where the target has a real <see cref="ScriptSet"/> as its volatile
|
||||
/// script set.
|
||||
/// </summary>
|
||||
private static (Feint script, IExecutingMove move, IPokemon target, IScriptSet volatileSet) CreateTestSetup()
|
||||
private static (Feint script, IExecutingMove move, IBattlePokemon target, IScriptSet volatileSet) CreateTestSetup()
|
||||
{
|
||||
var script = new Feint();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(target);
|
||||
target.Volatile.Returns(volatileSet);
|
||||
@@ -36,16 +36,14 @@ public class FeintTests
|
||||
/// Extends the test setup with a battle side that has a real <see cref="ScriptSet"/> as its volatile
|
||||
/// scripts, so side-wide protections such as <see cref="CraftyShieldEffect"/> can be attached.
|
||||
/// </summary>
|
||||
private static IScriptSet AttachSide(IPokemon target)
|
||||
private static IScriptSet AttachSide(IBattlePokemon target)
|
||||
{
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet sideScripts = new ScriptSet(side);
|
||||
side.VolatileScripts.Returns(sideScripts);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.BattleSide.Returns(side);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.BattleSide.Returns(side);
|
||||
|
||||
return sideScripts;
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@ public class FellStingerTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Fell Stinger tests.
|
||||
/// </summary>
|
||||
private static (FellStinger script, IExecutingMove move, IPokemon user, IPokemon target) CreateTestSetup(
|
||||
bool targetFainted)
|
||||
private static (FellStinger script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target)
|
||||
CreateTestSetup(bool targetFainted)
|
||||
{
|
||||
var script = new FellStinger();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.IsFainted.Returns(targetFainted);
|
||||
return (script, move, user, target);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public class FellStingerTests
|
||||
/// <summary>
|
||||
/// Helper to find the first ChangeStatBoost call received by a Pokémon substitute.
|
||||
/// </summary>
|
||||
private static object[]? GetStatBoostArguments(IPokemon pokemon)
|
||||
private static object[]? GetStatBoostArguments(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
return call?.GetArguments()!;
|
||||
|
||||
@@ -13,22 +13,22 @@ public class FinalGambitTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Final Gambit tests.
|
||||
/// </summary>
|
||||
private static (FinalGambit script, IExecutingMove move, IPokemon user, IPokemon target) CreateTestSetup(
|
||||
uint userCurrentHealth)
|
||||
private static (FinalGambit script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target)
|
||||
CreateTestSetup(uint userCurrentHealth)
|
||||
{
|
||||
var script = new FinalGambit();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.CurrentHealth.Returns(userCurrentHealth);
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
return (script, move, user, target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from the user's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon pokemon)
|
||||
private static uint? GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -37,7 +37,7 @@ public class FinalGambitTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from the user's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon pokemon)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (DamageSource)call.GetArguments()[1]! : null;
|
||||
|
||||
@@ -20,24 +20,22 @@ public class FireFangTests
|
||||
/// Creates a fully mocked test setup for Fire Fang tests. The target has not yet moved this turn when
|
||||
/// <paramref name="queue"/> contains a choice for it.
|
||||
/// </summary>
|
||||
private static (FireFang script, IExecutingMove move, IPokemon user, IPokemon target, IBattleRandom random,
|
||||
IScriptSet targetVolatile) CreateTestSetup(BattleChoiceQueue? queue)
|
||||
private static (FireFang script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IBattleRandom
|
||||
random, IScriptSet targetVolatile) CreateTestSetup(BattleChoiceQueue? queue)
|
||||
{
|
||||
var script = new FireFang();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Random.Returns(random);
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = Substitute.For<IScriptSet>();
|
||||
target.Battle.Returns(battle);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
|
||||
return (script, move, user, target, random, targetVolatile);
|
||||
@@ -46,7 +44,7 @@ public class FireFangTests
|
||||
/// <summary>
|
||||
/// Creates a choice queue containing a single yet-to-execute move choice for the given Pokémon.
|
||||
/// </summary>
|
||||
private static BattleChoiceQueue CreateQueueWithChoiceFor(IPokemon pokemon)
|
||||
private static BattleChoiceQueue CreateQueueWithChoiceFor(IBattlePokemon pokemon)
|
||||
{
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.User.Returns(pokemon);
|
||||
@@ -58,7 +56,7 @@ public class FireFangTests
|
||||
/// matchers cannot be used for <see cref="EventBatchId"/> parameters: its parameterless constructor
|
||||
/// generates a random Guid, which breaks NSubstitute's argument specification binding.)
|
||||
/// </summary>
|
||||
private static bool ReceivedSetStatus(IPokemon pokemon) =>
|
||||
private static bool ReceivedSetStatus(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus");
|
||||
|
||||
/// <summary>
|
||||
@@ -126,7 +124,7 @@ public class FireFangTests
|
||||
// Arrange
|
||||
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
|
||||
var queue = CreateQueueWithChoiceFor(target);
|
||||
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
|
||||
target.Battle.ChoiceQueue.Returns(queue);
|
||||
random.EffectChance(10, move, target, 0).Returns(true, true);
|
||||
|
||||
// Act
|
||||
@@ -147,7 +145,7 @@ public class FireFangTests
|
||||
// Arrange
|
||||
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
|
||||
var queue = CreateQueueWithChoiceFor(target);
|
||||
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
|
||||
target.Battle.ChoiceQueue.Returns(queue);
|
||||
// First roll (burn) fails, second roll (flinch) succeeds.
|
||||
random.EffectChance(10, move, target, 0).Returns(false, true);
|
||||
|
||||
@@ -170,8 +168,8 @@ public class FireFangTests
|
||||
// Arrange
|
||||
var (script, move, _, target, random, targetVolatile) = CreateTestSetup(null);
|
||||
// The queue only holds a choice for some other Pokémon; the target's choice already executed.
|
||||
var queue = CreateQueueWithChoiceFor(Substitute.For<IPokemon>());
|
||||
target.BattleData!.Battle.ChoiceQueue.Returns(queue);
|
||||
var queue = CreateQueueWithChoiceFor(Substitute.For<IBattlePokemon>());
|
||||
target.Battle.ChoiceQueue.Returns(queue);
|
||||
random.EffectChance(10, move, target, 0).Returns(true, true);
|
||||
|
||||
// Act
|
||||
@@ -199,26 +197,4 @@ public class FireFangTests
|
||||
target.Received(1).SetStatus("burned", user);
|
||||
targetVolatile.DidNotReceive().Add(Arg.Any<Script>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: if the target has no <see cref="IPokemon.BattleData"/>, the script does nothing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FireFang();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var targetVolatile = Substitute.For<IScriptSet>();
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ReceivedSetStatus(target)).IsFalse();
|
||||
targetVolatile.DidNotReceive().Add(Arg.Any<Script>());
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,8 @@ public class FirePledgeTests
|
||||
var choice = Substitute.For<IMoveChoice>();
|
||||
choice.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.SideIndex.Returns(sideIndex);
|
||||
pokemon.BattleData.Returns(battleData);
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.SideIndex.Returns(sideIndex);
|
||||
choice.User.Returns(pokemon);
|
||||
|
||||
var moveData = Substitute.For<IMoveData>();
|
||||
@@ -56,10 +54,8 @@ public class FirePledgeTests
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
move.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var userBattleData = Substitute.For<IPokemonBattleData>();
|
||||
userBattleData.SideIndex.Returns((byte)0);
|
||||
user.BattleData.Returns(userBattleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.SideIndex.Returns((byte)0);
|
||||
move.User.Returns(user);
|
||||
|
||||
var ownChoice = CreateQueuedChoice("fire_pledge", 0);
|
||||
|
||||
@@ -22,11 +22,12 @@ public class FireSpinTests
|
||||
/// <see cref="ScriptSet"/> as its volatile set, so the applied effect can be inspected.
|
||||
/// The battle random is stubbed to return 5, the maximum of Fire Spin's four-to-five turn duration.
|
||||
/// </summary>
|
||||
private static (FireSpin script, IExecutingMove move, IPokemon target, IScriptSet targetVolatile) CreateTestSetup()
|
||||
private static (FireSpin script, IExecutingMove move, IBattlePokemon target, IScriptSet targetVolatile)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new FireSpin();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var targetVolatile = new ScriptSet(target);
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
@@ -35,9 +36,7 @@ public class FireSpinTests
|
||||
random.GetInt(Arg.Any<int>(), Arg.Any<int>()).Returns(5);
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Random.Returns(random);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
return (script, move, target, targetVolatile);
|
||||
}
|
||||
@@ -84,19 +83,20 @@ public class FireSpinTests
|
||||
/// Creates a trapped Pokémon substitute with the given maximum HP, together with the
|
||||
/// <see cref="FireSpinEffect"/> that traps it.
|
||||
/// </summary>
|
||||
private static (FireSpinEffect effect, IPokemon owner) CreateTrappedPokemon(uint maxHealth, IPokemon? user = null)
|
||||
private static (FireSpinEffect effect, IBattlePokemon owner) CreateTrappedPokemon(uint maxHealth,
|
||||
IBattlePokemon? user = null)
|
||||
{
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
var owner = Substitute.For<IBattlePokemon>();
|
||||
owner.BoostedStats.Returns(new StatisticSet<uint>(maxHealth, 1, 1, 1, 1, 1));
|
||||
owner.MaxHealth.Returns(maxHealth);
|
||||
owner.Types.Returns(new List<TypeIdentifier> { new(10, "fire") });
|
||||
return (new FireSpinEffect(owner, 5, user ?? Substitute.For<IPokemon>()), owner);
|
||||
return (new FireSpinEffect(owner, 5, user ?? Substitute.For<IBattlePokemon>()), owner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a Pokémon's received Damage calls.
|
||||
/// </summary>
|
||||
private static uint? GetDamageAmount(IPokemon pokemon)
|
||||
private static uint? GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -206,7 +206,7 @@ public class FireSpinTests
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, targetVolatile) = CreateTestSetup();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.HasHeldItem("binding_band").Returns(true);
|
||||
move.User.Returns(user);
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(120, 1, 1, 1, 1, 1));
|
||||
|
||||
@@ -15,19 +15,17 @@ public class FirstImpressionTests
|
||||
/// Creates a fully mocked test setup for First Impression tests, with the user having switched in on
|
||||
/// <paramref name="switchInTurn"/> while the battle is on <paramref name="currentTurn"/>.
|
||||
/// </summary>
|
||||
private static (FirstImpression script, IExecutingMove move, IPokemon user) CreateTestSetup(uint switchInTurn,
|
||||
private static (FirstImpression script, IExecutingMove move, IBattlePokemon user) CreateTestSetup(uint switchInTurn,
|
||||
uint currentTurn)
|
||||
{
|
||||
var script = new FirstImpression();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.CurrentTurnNumber.Returns(currentTurn);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SwitchInTurn.Returns(switchInTurn);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
user.SwitchInTurn.Returns(switchInTurn);
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, user);
|
||||
@@ -88,26 +86,4 @@ public class FirstImpressionTests
|
||||
// Assert
|
||||
await Assert.That(stop).IsEqualTo(expectedStop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, the script cannot determine the
|
||||
/// switch-in turn and leaves the move untouched.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task StopBeforeMove_NoBattleData_MoveIsNotStopped()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FirstImpression();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
var stop = false;
|
||||
|
||||
// Act
|
||||
script.StopBeforeMove(move, ref stop);
|
||||
|
||||
// Assert
|
||||
await Assert.That(stop).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,13 @@ public class FlailTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Flail tests with the user at the given current and maximum HP.
|
||||
/// </summary>
|
||||
private static (Flail script, IExecutingMove move, IPokemon target) CreateTestSetup(uint currentHp, uint maxHp)
|
||||
private static (Flail script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint currentHp,
|
||||
uint maxHp)
|
||||
{
|
||||
var script = new Flail();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.CurrentHealth.Returns(currentHp);
|
||||
user.BoostedStats.Returns(new StatisticSet<uint>(maxHp, 0, 0, 0, 0, 0));
|
||||
move.User.Returns(user);
|
||||
|
||||
@@ -15,14 +15,12 @@ public class FlameBurstTests
|
||||
/// <summary>
|
||||
/// Creates a mocked battle Pokémon that lives in <paramref name="battle"/> on the given side and position.
|
||||
/// </summary>
|
||||
private static IPokemon CreateBattlePokemon(IBattle battle, byte sideIndex, byte position, uint maxHp = 100)
|
||||
private static IBattlePokemon CreateBattlePokemon(IBattle battle, byte sideIndex, byte position, uint maxHp = 100)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns(sideIndex);
|
||||
battleData.Position.Returns(position);
|
||||
pokemon.BattleData.Returns(battleData);
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Battle.Returns(battle);
|
||||
pokemon.SideIndex.Returns(sideIndex);
|
||||
pokemon.Position.Returns(position);
|
||||
pokemon.BoostedStats.Returns(new StatisticSet<uint>(maxHp, 0, 0, 0, 0, 0));
|
||||
pokemon.MaxHealth.Returns(maxHp);
|
||||
return pokemon;
|
||||
@@ -31,7 +29,7 @@ public class FlameBurstTests
|
||||
/// <summary>
|
||||
/// Configures the two sides of <paramref name="battle"/> with the given Pokémon lists.
|
||||
/// </summary>
|
||||
private static void SetSides(IBattle battle, List<IPokemon?> side0Pokemon, List<IPokemon?> side1Pokemon)
|
||||
private static void SetSides(IBattle battle, List<IBattlePokemon?> side0Pokemon, List<IBattlePokemon?> side1Pokemon)
|
||||
{
|
||||
var side0 = Substitute.For<IBattleSide>();
|
||||
side0.Pokemon.Returns(side0Pokemon);
|
||||
@@ -44,8 +42,8 @@ public class FlameBurstTests
|
||||
/// Creates a fully mocked double battle: the user and its ally on side 0, the target and its ally on
|
||||
/// side 1. Flame Burst is used by the user against the target.
|
||||
/// </summary>
|
||||
private static (FlameBurst script, IExecutingMove move, IPokemon user, IPokemon userAlly, IPokemon target, IPokemon
|
||||
targetAlly) CreateDoubleBattleSetup(uint targetAllyMaxHp = 160)
|
||||
private static (FlameBurst script, IExecutingMove move, IBattlePokemon user, IBattlePokemon userAlly, IBattlePokemon
|
||||
target, IBattlePokemon targetAlly) CreateDoubleBattleSetup(uint targetAllyMaxHp = 160)
|
||||
{
|
||||
var script = new FlameBurst();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
@@ -66,7 +64,7 @@ public class FlameBurstTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a Pokémon's received Damage calls, or 0 if none was received.
|
||||
/// </summary>
|
||||
private static uint GetDamageAmount(IPokemon pokemon)
|
||||
private static uint GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : 0;
|
||||
@@ -75,7 +73,7 @@ public class FlameBurstTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from a Pokémon's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon pokemon)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (DamageSource)call.GetArguments()[1]! : null;
|
||||
@@ -84,7 +82,7 @@ public class FlameBurstTests
|
||||
/// <summary>
|
||||
/// Helper that checks whether a Pokémon received any Damage call.
|
||||
/// </summary>
|
||||
private static bool WasDamaged(IPokemon pokemon) =>
|
||||
private static bool WasDamaged(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Damage");
|
||||
|
||||
/// <summary>
|
||||
@@ -266,23 +264,4 @@ public class FlameBurstTests
|
||||
// Act & Assert
|
||||
await Assert.That(() => script.OnSecondaryEffect(move, target, 0)).ThrowsNothing();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when no battle data is available the script does nothing instead of throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NoBattleData_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FlameBurst();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.That(() => script.OnSecondaryEffect(move, target, 0)).ThrowsNothing();
|
||||
}
|
||||
}
|
||||
@@ -14,15 +14,15 @@ public class FlameWheelTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Flame Wheel tests, initialized with the given burn chance.
|
||||
/// </summary>
|
||||
private static (FlameWheel script, IExecutingMove move, IPokemon user, IPokemon target, IBattleRandom random)
|
||||
CreateTestSetup(float burnChance = 10f)
|
||||
private static (FlameWheel script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IBattleRandom
|
||||
random) CreateTestSetup(float burnChance = 10f)
|
||||
{
|
||||
var script = new FlameWheel();
|
||||
script.OnInitialize(new Dictionary<StringKey, object?> { { "burn_chance", burnChance } });
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
@@ -36,14 +36,14 @@ public class FlameWheelTests
|
||||
/// <summary>
|
||||
/// Helper that checks whether a Pokémon received a SetStatus call for the given status.
|
||||
/// </summary>
|
||||
private static bool ReceivedSetStatus(IPokemon pokemon, string status) =>
|
||||
private static bool ReceivedSetStatus(IBattlePokemon pokemon, string status) =>
|
||||
pokemon.ReceivedCalls().Any(c =>
|
||||
c.GetMethodInfo().Name == "SetStatus" && (StringKey)c.GetArguments()[0]! == new StringKey(status));
|
||||
|
||||
/// <summary>
|
||||
/// Helper that checks whether a Pokémon received a ClearStatus call.
|
||||
/// </summary>
|
||||
private static bool ReceivedClearStatus(IPokemon pokemon) =>
|
||||
private static bool ReceivedClearStatus(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ClearStatus");
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -17,13 +17,13 @@ public class FlareBlitzTests
|
||||
/// Creates a fully mocked test setup for Flare Blitz tests, where the hit dealt
|
||||
/// <paramref name="damage"/> damage to the target.
|
||||
/// </summary>
|
||||
private static (FlareBlitz script, IExecutingMove move, IPokemon user, IPokemon target, IBattleRandom random)
|
||||
CreateTestSetup(uint damage, Script[]? moveScripts = null)
|
||||
private static (FlareBlitz script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IBattleRandom
|
||||
random) CreateTestSetup(uint damage, Script[]? moveScripts = null)
|
||||
{
|
||||
var script = new FlareBlitz();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.Damage.Returns(damage);
|
||||
@@ -32,9 +32,7 @@ public class FlareBlitzTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
battle.Random.Returns(random);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
// RunScriptHook iterates the move's scripts; give the mock a real iterator so the hook pass runs
|
||||
// (empty unless the test attaches scripts such as Rock Head).
|
||||
@@ -50,7 +48,7 @@ public class FlareBlitzTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage amount from a Pokémon's received Damage calls, or 0 if none was received.
|
||||
/// </summary>
|
||||
private static uint GetDamageAmount(IPokemon pokemon)
|
||||
private static uint GetDamageAmount(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : 0;
|
||||
@@ -59,7 +57,7 @@ public class FlareBlitzTests
|
||||
/// <summary>
|
||||
/// Helper to extract the damage source from a Pokémon's received Damage calls.
|
||||
/// </summary>
|
||||
private static DamageSource? GetDamageSource(IPokemon pokemon)
|
||||
private static DamageSource? GetDamageSource(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Damage");
|
||||
return call != null ? (DamageSource)call.GetArguments()[1]! : null;
|
||||
@@ -68,7 +66,7 @@ public class FlareBlitzTests
|
||||
/// <summary>
|
||||
/// Helper that checks whether a Pokémon received a SetStatus call for the given status.
|
||||
/// </summary>
|
||||
private static bool ReceivedSetStatus(IPokemon pokemon, string status) =>
|
||||
private static bool ReceivedSetStatus(IBattlePokemon pokemon, string status) =>
|
||||
pokemon.ReceivedCalls().Any(c =>
|
||||
c.GetMethodInfo().Name == "SetStatus" && (StringKey)c.GetArguments()[0]! == new StringKey(status));
|
||||
|
||||
@@ -212,23 +210,4 @@ public class FlareBlitzTests
|
||||
// Assert
|
||||
await Assert.That(ReceivedSetStatus(target, "burned")).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when the target has no <see cref="IPokemon.BattleData"/>, the script does nothing;
|
||||
/// no recoil is taken and no burn is rolled.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_NoRecoilOrBurn()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, target, _) = CreateTestSetup(90);
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(user.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Damage")).IsFalse();
|
||||
await Assert.That(ReceivedSetStatus(target, "burned")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,15 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class FlatterTests
|
||||
{
|
||||
private static (Flatter script, IExecutingMove move, IPokemon target, IScriptSet targetVolatile) CreateTestSetup()
|
||||
private static (Flatter script, IExecutingMove move, IBattlePokemon target, IScriptSet targetVolatile)
|
||||
CreateTestSetup()
|
||||
{
|
||||
var script = new Flatter();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var targetVolatile = Substitute.For<IScriptSet>();
|
||||
target.Volatile.Returns(targetVolatile);
|
||||
|
||||
@@ -34,7 +35,7 @@ public class FlatterTests
|
||||
/// the trailing <see cref="EventBatchId"/> parameter cannot be bound by <c>Arg.Any</c> (its
|
||||
/// parameterless constructor initializes a fresh id, so it never equals the matcher's default value).
|
||||
/// </summary>
|
||||
private static object?[]? GetStatBoostArgs(IPokemon pokemon)
|
||||
private static object?[]? GetStatBoostArgs(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
return call?.GetArguments();
|
||||
@@ -64,7 +65,7 @@ public class FlatterTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: Flatter raises the target's Special Attack "and confuses it". The confusion is applied
|
||||
/// through the target's <see cref="IPokemon.Volatile"/> script set.
|
||||
/// through the target's <see cref="IBattlePokemon.Volatile"/> script set.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_Always_ConfusesTarget()
|
||||
@@ -101,7 +102,7 @@ public class FlatterTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Even if the target's Special Attack is already at +6 stages, it will still become
|
||||
/// confused." A substitute's <see cref="IPokemon.ChangeStatBoost"/> returns false by default (the
|
||||
/// confused." A substitute's <see cref="IBattlePokemon.ChangeStatBoost"/> returns false by default (the
|
||||
/// boost failed), yet the confusion is still applied.
|
||||
/// </summary>
|
||||
[Test]
|
||||
|
||||
@@ -12,16 +12,16 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class FlingTests
|
||||
{
|
||||
private static (Fling script, IExecutingMove move, IPokemon target, IPokemon user, IHitData hitData)
|
||||
private static (Fling script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, IHitData hitData)
|
||||
CreateTestSetup(IItem? heldItem)
|
||||
{
|
||||
var script = new Fling();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.HeldItem.Returns(heldItem);
|
||||
move.User.Returns(user);
|
||||
|
||||
@@ -123,7 +123,7 @@ public class FlingTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "After using Fling, the item is consumed". The user's held item is removed for the
|
||||
/// remainder of the battle via <see cref="IPokemon.RemoveHeldItemForBattle"/>.
|
||||
/// remainder of the battle via <see cref="IBattlePokemon.RemoveHeldItemForBattle"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_Always_RemovesHeldItemForBattle()
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class FloralHealingTests
|
||||
{
|
||||
private static (FloralHealing script, IExecutingMove move, IPokemon target) CreateTestSetup(uint maxHp,
|
||||
string? terrainName = null, bool isFainted = false, bool hasBattleData = true)
|
||||
private static (FloralHealing script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(uint maxHp,
|
||||
string? terrainName = null, bool isFainted = false)
|
||||
{
|
||||
var script = new FloralHealing();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -21,19 +21,10 @@ public class FloralHealingTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.TerrainName.Returns(terrainName == null ? null : new StringKey?(new StringKey(terrainName)));
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.IsFainted.Returns(isFainted);
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(maxHp, 0, 0, 0, 0, 0));
|
||||
if (hasBattleData)
|
||||
{
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
}
|
||||
else
|
||||
{
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
}
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
return (script, move, target);
|
||||
}
|
||||
@@ -41,7 +32,7 @@ public class FloralHealingTests
|
||||
/// <summary>
|
||||
/// Helper to extract the heal amount from the target's received Heal calls.
|
||||
/// </summary>
|
||||
private static uint? GetHealAmount(IPokemon target)
|
||||
private static uint? GetHealAmount(IBattlePokemon target)
|
||||
{
|
||||
var call = target.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Heal");
|
||||
return call != null ? (uint)call.GetArguments()[0]! : null;
|
||||
@@ -116,7 +107,7 @@ public class FloralHealingTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: Floral Healing "restores" HP of the target; a fainted Pokémon can no longer be healed,
|
||||
/// so no heal is applied when the target <see cref="IPokemon.IsFainted"/>.
|
||||
/// so no heal is applied when the target <see cref="IBattlePokemon.IsFainted"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetFainted_DoesNotHeal()
|
||||
@@ -130,21 +121,4 @@ public class FloralHealingTests
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Heal")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when the target has no <see cref="IPokemon.BattleData"/> (it is not in a battle),
|
||||
/// the script does nothing instead of throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_DoesNotHeal()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target) = CreateTestSetup(100, hasBattleData: false);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Heal")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -24,12 +24,12 @@ public class FlowerShieldTests
|
||||
library.StaticLibrary.Types.TryGetTypeIdentifier("water", out WaterType);
|
||||
}
|
||||
|
||||
private static (FlowerShield script, IExecutingMove move, IPokemon target, IBattle battle) CreateTestSetup(
|
||||
params IReadOnlyList<IPokemon?>[] sidePokemon)
|
||||
private static (FlowerShield script, IExecutingMove move, IBattlePokemon target, IBattle battle) CreateTestSetup(
|
||||
params IReadOnlyList<IBattlePokemon?>[] sidePokemon)
|
||||
{
|
||||
var script = new FlowerShield();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
var library = LibraryHelpers.LoadLibrary();
|
||||
@@ -43,23 +43,21 @@ public class FlowerShieldTests
|
||||
}).ToArray();
|
||||
battle.Sides.Returns(sides);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
return (script, move, target, battle);
|
||||
}
|
||||
|
||||
private static IPokemon CreatePokemon(TypeIdentifier type, bool isFainted = false)
|
||||
private static IBattlePokemon CreatePokemon(TypeIdentifier type, bool isFainted = false)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Types.Returns(new[] { type });
|
||||
pokemon.IsFainted.Returns(isFainted);
|
||||
return pokemon;
|
||||
}
|
||||
|
||||
private static bool ReceivedStatBoost(IPokemon pokemon) =>
|
||||
private static bool ReceivedStatBoost(IBattlePokemon pokemon) =>
|
||||
pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +66,7 @@ public class FlowerShieldTests
|
||||
/// the trailing <see cref="EventBatchId"/> parameter cannot be bound by <c>Arg.Any</c> (its
|
||||
/// parameterless constructor initializes a fresh id, so it never equals the matcher's default value).
|
||||
/// </summary>
|
||||
private static object?[]? GetStatBoostArgs(IPokemon pokemon)
|
||||
private static object?[]? GetStatBoostArgs(IBattlePokemon pokemon)
|
||||
{
|
||||
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
|
||||
return call?.GetArguments();
|
||||
@@ -83,7 +81,7 @@ public class FlowerShieldTests
|
||||
{
|
||||
// Arrange
|
||||
var grassPokemon = CreatePokemon(GrassType);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { grassPokemon });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { grassPokemon });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -107,8 +105,8 @@ public class FlowerShieldTests
|
||||
// Arrange
|
||||
var allyGrass = CreatePokemon(GrassType);
|
||||
var opposingGrass = CreatePokemon(GrassType);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { allyGrass },
|
||||
new List<IPokemon?> { opposingGrass });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { allyGrass },
|
||||
new List<IBattlePokemon?> { opposingGrass });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -127,7 +125,7 @@ public class FlowerShieldTests
|
||||
{
|
||||
// Arrange
|
||||
var waterPokemon = CreatePokemon(WaterType);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { waterPokemon });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { waterPokemon });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -145,7 +143,7 @@ public class FlowerShieldTests
|
||||
{
|
||||
// Arrange
|
||||
var faintedGrass = CreatePokemon(GrassType, true);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { faintedGrass });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { faintedGrass });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -167,7 +165,7 @@ public class FlowerShieldTests
|
||||
user.Types.Returns(new[] { GrassType });
|
||||
user.IsFainted.Returns(false);
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.Pokemon.Returns(new List<IPokemon?> { user });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { user });
|
||||
battle.Sides.Returns(new[] { side });
|
||||
|
||||
// Act
|
||||
@@ -195,7 +193,7 @@ public class FlowerShieldTests
|
||||
var flyingGrassVolatile = new ScriptSet(flyingGrass);
|
||||
flyingGrassVolatile.Add(new ChargeFlyEffect(flyingGrass));
|
||||
flyingGrass.Volatile.Returns(flyingGrassVolatile);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { flyingGrass });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { flyingGrass });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -213,7 +211,7 @@ public class FlowerShieldTests
|
||||
{
|
||||
// Arrange
|
||||
var waterPokemon = CreatePokemon(WaterType);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { waterPokemon });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { waterPokemon });
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -232,7 +230,7 @@ public class FlowerShieldTests
|
||||
{
|
||||
// Arrange
|
||||
var grassPokemon = CreatePokemon(GrassType);
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IPokemon?> { null, grassPokemon });
|
||||
var (script, move, target, _) = CreateTestSetup(new List<IBattlePokemon?> { null, grassPokemon });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -240,24 +238,4 @@ public class FlowerShieldTests
|
||||
// Assert
|
||||
await Assert.That(ReceivedStatBoost(grassPokemon)).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when the target has no <see cref="IPokemon.BattleData"/> (it is not in a battle),
|
||||
/// the script does nothing instead of throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var grassPokemon = CreatePokemon(GrassType);
|
||||
var (script, move, _, _) = CreateTestSetup(new List<IPokemon?> { grassPokemon });
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ReceivedStatBoost(grassPokemon)).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,12 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// </summary>
|
||||
public class FlyTests
|
||||
{
|
||||
private static (Fly script, IExecutingMove move, IPokemon user, ScriptSet userVolatile, IMoveChoice moveChoice,
|
||||
EventHook eventHook) CreateTestSetup()
|
||||
private static (Fly script, IExecutingMove move, IBattlePokemon user, ScriptSet userVolatile, IMoveChoice moveChoice
|
||||
, EventHook eventHook) CreateTestSetup()
|
||||
{
|
||||
var script = new Fly();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
// Use a real script set so the charge volatile added by Fly can be inspected afterwards.
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
@@ -38,9 +38,7 @@ public class FlyTests
|
||||
var eventHook = new EventHook();
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, user, userVolatile, moveChoice, eventHook);
|
||||
}
|
||||
@@ -146,33 +144,6 @@ public class FlyTests
|
||||
await Assert.That(prevent).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: a user that is not in a battle (no <see cref="IPokemon.BattleData"/>) still starts
|
||||
/// the charge turn without throwing; only the dialog event is skipped.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task PreventMove_NoBattleData_StillPreventsMove()
|
||||
{
|
||||
// Arrange
|
||||
var script = new Fly();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
move.User.Returns(user);
|
||||
move.MoveChoice.Returns(Substitute.For<IMoveChoice>());
|
||||
var prevent = false;
|
||||
|
||||
// Act
|
||||
script.PreventMove(move, ref prevent);
|
||||
|
||||
// Assert
|
||||
await Assert.That(prevent).IsTrue();
|
||||
await Assert.That(userVolatile.Contains(ScriptUtils.ResolveName<ChargeFlyEffect>())).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the attack executes on the second turn, ending the semi-invulnerable state. Once the
|
||||
/// attack executes, the <see cref="ChargeFlyEffect"/> is removed from the user.
|
||||
@@ -309,7 +280,7 @@ public class FlyTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsNotFlyCharge_RemovesChargeFlyEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new ChargeFlyEffect(user);
|
||||
@@ -332,7 +303,7 @@ public class FlyTests
|
||||
public async Task OnAfterMoveChoice_ChoiceIsFlyCharge_KeepsChargeFlyEffect()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(new List<IEnumerable<ScriptContainer>>()));
|
||||
var effect = new ChargeFlyEffect(user);
|
||||
|
||||
@@ -15,7 +15,7 @@ public class FlyingPressTests
|
||||
/// Creates a fully mocked test setup for Flying Press tests, with a type library containing both the
|
||||
/// Fighting and Flying types.
|
||||
/// </summary>
|
||||
private static (FlyingPress flyingPress, IExecutingMove move, IPokemon target, TypeIdentifier fighting,
|
||||
private static (FlyingPress flyingPress, IExecutingMove move, IBattlePokemon target, TypeIdentifier fighting,
|
||||
TypeIdentifier flying) CreateTestSetup()
|
||||
{
|
||||
var flyingPress = new FlyingPress();
|
||||
@@ -25,7 +25,7 @@ public class FlyingPressTests
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Library.StaticLibrary.Types.Returns(typeLibrary);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
return (flyingPress, move, target, fighting, flying);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class FlyingPressTests
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Library.StaticLibrary.Types.Returns(typeLibrary);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
IList<TypeIdentifier> types = new List<TypeIdentifier> { fighting };
|
||||
|
||||
// Act
|
||||
|
||||
@@ -18,12 +18,12 @@ public class FocusEnergyTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Focus Energy tests.
|
||||
/// </summary>
|
||||
private static (FocusEnergy focusEnergy, IExecutingMove move, IPokemon target, IScriptSet volatileSet, IHitData
|
||||
hitData) CreateTestSetup()
|
||||
private static (FocusEnergy focusEnergy, IExecutingMove move, IBattlePokemon target, IScriptSet volatileSet,
|
||||
IHitData hitData) CreateTestSetup()
|
||||
{
|
||||
var focusEnergy = new FocusEnergy();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
|
||||
@@ -16,27 +16,18 @@ public class FocusPunchTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for the turn start (charging) phase of Focus Punch.
|
||||
/// </summary>
|
||||
private static (FocusPunch focusPunch, ITurnChoice choice, IPokemon user, IScriptSet volatileSet, EventHook
|
||||
eventHook) CreateChargeSetup(bool hasBattleData = true)
|
||||
private static (FocusPunch focusPunch, ITurnChoice choice, IBattlePokemon user, IScriptSet volatileSet, EventHook
|
||||
eventHook) CreateChargeSetup()
|
||||
{
|
||||
var focusPunch = new FocusPunch();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var volatileSet = Substitute.For<IScriptSet>();
|
||||
user.Volatile.Returns(volatileSet);
|
||||
|
||||
var eventHook = new EventHook();
|
||||
if (hasBattleData)
|
||||
{
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
user.BattleData.Returns(battleData);
|
||||
}
|
||||
else
|
||||
{
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
}
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var choice = Substitute.For<ITurnChoice>();
|
||||
choice.User.Returns(user);
|
||||
@@ -50,7 +41,7 @@ public class FocusPunchTests
|
||||
{
|
||||
var focusPunch = new FocusPunch();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var volatileSet = Substitute.For<IScriptSet>();
|
||||
user.Volatile.Returns(volatileSet);
|
||||
move.User.Returns(user);
|
||||
@@ -64,8 +55,8 @@ public class FocusPunchTests
|
||||
private static FocusPunchEffect CreateHitEffect()
|
||||
{
|
||||
var effect = new FocusPunchEffect();
|
||||
var hitReceiver = Substitute.For<IPokemon>();
|
||||
hitReceiver.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var hitReceiver = Substitute.For<IBattlePokemon>();
|
||||
hitReceiver.Battle.EventHook.Returns(new EventHook());
|
||||
effect.OnIncomingHit(Substitute.For<IExecutingMove>(), hitReceiver, 0);
|
||||
return effect;
|
||||
}
|
||||
@@ -118,26 +109,6 @@ public class FocusPunchTests
|
||||
await Assert.That(ReferenceEquals(capturedEvent.Parameters["pokemon"], user)).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The user of Focus Punch will start focusing at the beginning of the turn the move is used".
|
||||
/// Technical test: if the user has no <see cref="IPokemon.BattleData"/>, no dialog can be shown, but the
|
||||
/// charging effect is still applied without throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnBeforeTurnStart_UserWithoutBattleData_StillAddsFocusPunchEffect()
|
||||
{
|
||||
// Arrange
|
||||
var (focusPunch, choice, _, volatileSet, _) = CreateChargeSetup(false);
|
||||
|
||||
// Act
|
||||
focusPunch.OnBeforeTurnStart(choice);
|
||||
|
||||
// Assert
|
||||
var addCall = volatileSet.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "Add");
|
||||
await Assert.That(addCall).IsNotNull();
|
||||
await Assert.That(addCall!.GetArguments()[0] is FocusPunchEffect).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "then execute the move Focus Punch at a decreased priority, unless it was hit by another
|
||||
/// Pokémon's damaging move before executing Focus Punch".
|
||||
@@ -217,8 +188,7 @@ public class FocusPunchTests
|
||||
var effect = new FocusPunchEffect();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.UseMove.Returns(fissure!);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
effect.OnIncomingHit(move, target, 0);
|
||||
|
||||
@@ -40,23 +40,22 @@ public class FollowMeTests
|
||||
/// <summary>
|
||||
/// Creates a mocked Pokémon standing on the given side of the given <see cref="Arena"/>.
|
||||
/// </summary>
|
||||
private static IPokemon CreatePokemon(Arena arena, byte sideIndex)
|
||||
private static IBattlePokemon CreatePokemon(Arena arena, byte sideIndex)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
pokemon.Volatile.Returns(Substitute.For<IScriptSet>());
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.SideIndex.Returns(sideIndex);
|
||||
battleData.BattleSide.Returns(arena.Sides[sideIndex]);
|
||||
battleData.Battle.Returns(arena.Battle);
|
||||
pokemon.BattleData.Returns(battleData);
|
||||
pokemon.SideIndex.Returns(sideIndex);
|
||||
pokemon.BattleSide.Returns(arena.Sides[sideIndex]);
|
||||
pokemon.Battle.Returns(arena.Battle);
|
||||
return pokemon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a mocked move choice made by the given Pokémon, using the named move.
|
||||
/// </summary>
|
||||
private static IMoveChoice CreateMoveChoice(IPokemon user, string moveName = "tackle", bool noRedirection = false)
|
||||
private static IMoveChoice CreateMoveChoice(IBattlePokemon user, string moveName = "tackle",
|
||||
bool noRedirection = false)
|
||||
{
|
||||
var moveData = Substitute.For<IMoveData>();
|
||||
moveData.Name.Returns(new StringKey(moveName));
|
||||
@@ -94,7 +93,7 @@ public class FollowMeTests
|
||||
/// Executes <see cref="FollowMe"/> for the given user and returns the center-of-attention effect it
|
||||
/// registered, regardless of which script set it chose to register it on.
|
||||
/// </summary>
|
||||
private static Script? MakeCenterOfAttention(IPokemon user)
|
||||
private static Script? MakeCenterOfAttention(IBattlePokemon user)
|
||||
{
|
||||
var followMe = new FollowMe();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -102,14 +101,14 @@ public class FollowMeTests
|
||||
|
||||
followMe.OnSecondaryEffect(move, user, 0);
|
||||
|
||||
return RegisteredScript(user.Volatile) ?? RegisteredScript(user.BattleData!.BattleSide.VolatileScripts);
|
||||
return RegisteredScript(user.Volatile) ?? RegisteredScript(user.BattleSide.VolatileScripts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drives the registered effect through whichever target-redirection hook it implements, mirroring the two
|
||||
/// hooks the engine runs while resolving a move's targets.
|
||||
/// </summary>
|
||||
private static void Redirect(Script effect, IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
private static void Redirect(Script effect, IMoveChoice moveChoice, ref IReadOnlyList<IBattlePokemon?> targets)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
@@ -146,7 +145,7 @@ public class FollowMeTests
|
||||
/// The engine resolves a move's targets by running <see cref="IScriptChangeTargets"/> over the attacker's
|
||||
/// own script scope, and <see cref="IScriptChangeIncomingTargets"/> over each intended target's scope —
|
||||
/// which covers that target's own scripts and its <see cref="IBattleSide.VolatileScripts"/>. A redirection
|
||||
/// effect stored on the center of attention's <see cref="IPokemon.Volatile"/> therefore sits in neither
|
||||
/// effect stored on the center of attention's <see cref="IBattlePokemon.Volatile"/> therefore sits in neither
|
||||
/// scope when an opponent attacks the center's ally. It must live on the center's side, the way
|
||||
/// <see cref="PkmnLib.Plugin.Gen7.Scripts.Side.RagePowderEffect"/> does.
|
||||
/// </summary>
|
||||
@@ -200,7 +199,7 @@ public class FollowMeTests
|
||||
var opponent = CreatePokemon(arena, OpposingSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(opponent);
|
||||
IReadOnlyList<IPokemon?> targets = [ally];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [ally];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
@@ -223,7 +222,7 @@ public class FollowMeTests
|
||||
var opponent = CreatePokemon(arena, OpposingSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(opponent);
|
||||
IReadOnlyList<IPokemon?> targets = [center, ally];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [center, ally];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
@@ -248,7 +247,7 @@ public class FollowMeTests
|
||||
var targetedAlly = CreatePokemon(arena, CenterSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(attackingAlly);
|
||||
IReadOnlyList<IPokemon?> targets = [targetedAlly];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [targetedAlly];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
@@ -271,7 +270,7 @@ public class FollowMeTests
|
||||
var opponent = CreatePokemon(arena, OpposingSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(opponent);
|
||||
IReadOnlyList<IPokemon?> targets = [center];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [center];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
@@ -287,7 +286,7 @@ public class FollowMeTests
|
||||
/// </summary>
|
||||
private static IScriptSet CreateHostedSet(Script effect)
|
||||
{
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
var owner = Substitute.For<IBattlePokemon>();
|
||||
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet set = new ScriptSet(owner);
|
||||
set.Add(effect);
|
||||
@@ -369,7 +368,7 @@ public class FollowMeTests
|
||||
var opponent = CreatePokemon(arena, OpposingSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(opponent, moveName, true);
|
||||
IReadOnlyList<IPokemon?> targets = [ally];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [ally];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
@@ -391,7 +390,7 @@ public class FollowMeTests
|
||||
var opponent = CreatePokemon(arena, OpposingSide);
|
||||
var effect = MakeCenterOfAttention(center)!;
|
||||
var moveChoice = CreateMoveChoice(opponent);
|
||||
IReadOnlyList<IPokemon?> targets = [];
|
||||
IReadOnlyList<IBattlePokemon?> targets = [];
|
||||
|
||||
// Act
|
||||
Redirect(effect, moveChoice, ref targets);
|
||||
|
||||
@@ -22,12 +22,12 @@ public class ForesightTests
|
||||
/// Creates a fully mocked test setup for Foresight tests. The target is in battle, with a mocked
|
||||
/// battle library chain and the given evasion stat stage.
|
||||
/// </summary>
|
||||
private static (Foresight script, IExecutingMove move, IPokemon target, IScriptSet volatileSet, IHitData hitData)
|
||||
CreateTestSetup(sbyte evasionStage = 0)
|
||||
private static (Foresight script, IExecutingMove move, IBattlePokemon target, IScriptSet volatileSet, IHitData
|
||||
hitData) CreateTestSetup(sbyte evasionStage = 0)
|
||||
{
|
||||
var script = new Foresight();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -38,9 +38,7 @@ public class ForesightTests
|
||||
library.StaticLibrary.Returns(staticLibrary);
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
var volatileSet = Substitute.For<IScriptSet>();
|
||||
target.Volatile.Returns(volatileSet);
|
||||
@@ -54,9 +52,9 @@ public class ForesightTests
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract all stat boost changes requested on the target through
|
||||
/// <see cref="IPokemon.ChangeStatBoost"/>.
|
||||
/// <see cref="IBattlePokemon.ChangeStatBoost"/>.
|
||||
/// </summary>
|
||||
private static IReadOnlyList<(Statistic stat, sbyte amount)> GetStatBoostChanges(IPokemon target) =>
|
||||
private static IReadOnlyList<(Statistic stat, sbyte amount)> GetStatBoostChanges(IBattlePokemon target) =>
|
||||
target.ReceivedCalls().Where(c => c.GetMethodInfo().Name == "ChangeStatBoost")
|
||||
.Select(c => ((Statistic)c.GetArguments()[0]!, (sbyte)c.GetArguments()[1]!)).ToList();
|
||||
|
||||
@@ -143,25 +141,6 @@ public class ForesightTests
|
||||
await Assert.That(changes.Any(c => c.amount != 0)).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the target has no <see cref="IPokemon.BattleData"/>, the script cannot resolve the type library,
|
||||
/// so nothing may happen: no volatile script is added and no stat stage is changed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_NoEffect()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, volatileSet, _) = CreateTestSetup(2);
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(volatileSet.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Add")).IsFalse();
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia (Generations V to VII): "Foresight will once again fail if used against a Pokémon already
|
||||
/// under its effect."
|
||||
|
||||
@@ -22,12 +22,12 @@ public class ForestsCurseTests
|
||||
/// Creates a fully mocked test setup for Forest's Curse tests. The target is in battle, with a mocked
|
||||
/// battle library chain that can resolve the Grass type identifier.
|
||||
/// </summary>
|
||||
private static (ForestsCurse script, IExecutingMove move, IPokemon target, IHitData hitData) CreateTestSetup(
|
||||
private static (ForestsCurse script, IExecutingMove move, IBattlePokemon target, IHitData hitData) CreateTestSetup(
|
||||
bool grassTypeInLibrary = true, TypeIdentifier[]? targetTypes = null)
|
||||
{
|
||||
var script = new ForestsCurse();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
@@ -47,18 +47,16 @@ public class ForestsCurseTests
|
||||
library.StaticLibrary.Returns(staticLibrary);
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
target.Types.Returns(targetTypes ?? [NormalType]);
|
||||
|
||||
return (script, move, target, hitData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to extract the type passed to the target's <see cref="IPokemon.AddType"/> call.
|
||||
/// Helper to extract the type passed to the target's <see cref="IBattlePokemon.AddType"/> call.
|
||||
/// </summary>
|
||||
private static TypeIdentifier? GetAddedType(IPokemon target)
|
||||
private static TypeIdentifier? GetAddedType(IBattlePokemon target)
|
||||
{
|
||||
var call = target.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "AddType");
|
||||
return call != null ? (TypeIdentifier)call.GetArguments()[0]! : null;
|
||||
@@ -85,7 +83,7 @@ public class ForestsCurseTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the Grass type is added "in addition to the Pokémon's original type(s)".
|
||||
/// The target's original types may not be replaced, so <see cref="IPokemon.SetTypes"/> must not be used.
|
||||
/// The target's original types may not be replaced, so <see cref="IBattlePokemon.SetTypes"/> must not be used.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetInBattle_OriginalTypesNotReplaced()
|
||||
@@ -117,24 +115,6 @@ public class ForestsCurseTests
|
||||
await Assert.That(hitData.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "Fail")).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the target has no <see cref="IPokemon.BattleData"/>, the script cannot resolve the type library,
|
||||
/// so no type may be added.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_DoesNotAddType()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _) = CreateTestSetup();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "AddType")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when the type library cannot resolve the Grass type identifier, the script must
|
||||
/// bail out without adding a type.
|
||||
@@ -158,8 +138,8 @@ public class ForestsCurseTests
|
||||
/// A target whose Ghost type was added by <see cref="TrickOrTreat"/> must end up with the Grass type and
|
||||
/// without the Ghost type, while keeping its original type. The mocked target uses a real
|
||||
/// <see cref="ScriptSet"/> for its volatile scripts, so the <c>HasHadTypeAddedEffect</c> marker set by
|
||||
/// Trick-or-Treat is visible to Forest's Curse, and reacts to <see cref="IPokemon.AddType"/> and
|
||||
/// <see cref="IPokemon.RemoveType"/> with a backing type list, mirroring the real Pokemon implementation,
|
||||
/// Trick-or-Treat is visible to Forest's Curse, and reacts to <see cref="IBattlePokemon.AddType"/> and
|
||||
/// <see cref="IBattlePokemon.RemoveType"/> with a backing type list, mirroring the real Pokemon implementation,
|
||||
/// so the resulting type list is observable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
@@ -169,7 +149,7 @@ public class ForestsCurseTests
|
||||
var forestsCurse = new ForestsCurse();
|
||||
var trickOrTreat = new TrickOrTreat();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
var typeLibrary = Substitute.For<IReadOnlyTypeLibrary>();
|
||||
typeLibrary.TryGetTypeIdentifier(new StringKey("grass"), out Arg.Any<TypeIdentifier>()).Returns(x =>
|
||||
@@ -189,9 +169,7 @@ public class ForestsCurseTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Library.Returns(library);
|
||||
move.Battle.Returns(battle);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
// Real script set so the HasHadTypeAddedEffect marker added by Trick-or-Treat is visible
|
||||
// to Forest's Curse.
|
||||
|
||||
@@ -15,7 +15,7 @@ public class FoulPlayTests
|
||||
/// Creates a fully mocked test setup for Foul Play tests, with a target whose (boosted) offensive
|
||||
/// stats are set to the given values.
|
||||
/// </summary>
|
||||
private static (FoulPlay script, IExecutingMove move, IPokemon target) CreateTestSetup(MoveCategory category,
|
||||
private static (FoulPlay script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(MoveCategory category,
|
||||
uint targetAttack, uint targetSpecialAttack)
|
||||
{
|
||||
var script = new FoulPlay();
|
||||
@@ -24,10 +24,10 @@ public class FoulPlayTests
|
||||
useMove.Category.Returns(category);
|
||||
move.UseMove.Returns(useMove);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.BoostedStats.Returns(new StatisticSet<uint>(100, targetAttack, 80, targetSpecialAttack, 80, 80));
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, target);
|
||||
@@ -54,8 +54,8 @@ public class FoulPlayTests
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "The target's Attack stat stage-modifiers are applied (rather than the user's)".
|
||||
/// The stat used must be the target's boosted Attack (<see cref="IPokemon.BoostedStats"/>, which includes
|
||||
/// stat stages), not its flat Attack (<see cref="IPokemon.FlatStats"/>).
|
||||
/// The stat used must be the target's boosted Attack (<see cref="IBattlePokemon.BoostedStats"/>, which includes
|
||||
/// stat stages), not its flat Attack (<see cref="IBattlePokemon.FlatStats"/>).
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeOffensiveStatValue_PhysicalMove_TargetStatStagesApplied()
|
||||
|
||||
@@ -17,7 +17,7 @@ public class FreezeDryTests
|
||||
/// <summary>
|
||||
/// Creates a test setup with the real Gen7 type library, and a target in battle with the given types.
|
||||
/// </summary>
|
||||
private static (FreezeDry script, IExecutingMove move, IPokemon target, IDynamicLibrary library)
|
||||
private static (FreezeDry script, IExecutingMove move, IBattlePokemon target, IDynamicLibrary library)
|
||||
CreateEffectivenessSetup(params string[] targetTypes)
|
||||
{
|
||||
var script = new FreezeDry();
|
||||
@@ -25,18 +25,16 @@ public class FreezeDryTests
|
||||
|
||||
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);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Types.Returns(targetTypes.Select(name => GetTypeId(library, name)).ToList());
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
hitData.Type.Returns(GetTypeId(library, "ice"));
|
||||
move.GetHitData(Arg.Any<IPokemon>(), Arg.Any<byte>()).Returns(hitData);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
move.GetHitData(Arg.Any<IBattlePokemon>(), Arg.Any<byte>()).Returns(hitData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, target, library);
|
||||
@@ -46,24 +44,21 @@ public class FreezeDryTests
|
||||
/// Creates a fully mocked test setup for the secondary (freeze) effect tests, with a battle random
|
||||
/// that reports the given result for effect chance rolls.
|
||||
/// </summary>
|
||||
private static (FreezeDry script, IExecutingMove move, IPokemon target, IPokemon user, IBattleRandom random)
|
||||
CreateSecondaryEffectSetup(bool effectChanceResult)
|
||||
private static (FreezeDry script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, IBattleRandom
|
||||
random) CreateSecondaryEffectSetup(bool effectChanceResult)
|
||||
{
|
||||
var script = new FreezeDry();
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
random.EffectChance(Arg.Any<float>(), Arg.Any<IExecutingMove>(), Arg.Any<IPokemon>(), Arg.Any<byte>())
|
||||
random.EffectChance(Arg.Any<float>(), Arg.Any<IExecutingMove>(), Arg.Any<IBattlePokemon>(), Arg.Any<byte>())
|
||||
.Returns(effectChanceResult);
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.Random.Returns(random);
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, target, user, random);
|
||||
@@ -139,25 +134,6 @@ public class FreezeDryTests
|
||||
await Assert.That(effectiveness).IsEqualTo(2f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the target has no <see cref="IPokemon.BattleData"/>, the script cannot resolve the type library,
|
||||
/// so the effectiveness must be left untouched.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeEffectiveness_NullBattleData_EffectivenessUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _) = CreateEffectivenessSetup("water");
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var effectiveness = 0.5f;
|
||||
|
||||
// Act
|
||||
script.ChangeEffectiveness(move, target, 0, ref effectiveness);
|
||||
|
||||
// Assert
|
||||
await Assert.That(effectiveness).IsEqualTo(0.5f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia (Generation VI to VIII): "Freeze-Dry has a 10% chance of freezing the target."
|
||||
/// When the effect chance roll succeeds, the target is frozen, with the user as the origin.
|
||||
@@ -213,22 +189,4 @@ public class FreezeDryTests
|
||||
await Assert.That(call).IsNotNull();
|
||||
await Assert.That((float)call!.GetArguments()[0]!).IsEqualTo(10f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the target has no <see cref="IPokemon.BattleData"/>, no effect chance can be rolled, so the
|
||||
/// target may not be frozen.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_TargetNotFrozen()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, _) = CreateSecondaryEffectSetup(true);
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -17,23 +17,21 @@ public class FreezeShockTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup for Freeze Shock secondary effect tests.
|
||||
/// </summary>
|
||||
private static (FreezeShock script, IExecutingMove move, IPokemon target, IPokemon user, IBattleRandom random)
|
||||
CreateTestSetup()
|
||||
private static (FreezeShock script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, IBattleRandom
|
||||
random) CreateTestSetup()
|
||||
{
|
||||
var script = new FreezeShock();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.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);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
return (script, move, target, user, random);
|
||||
}
|
||||
|
||||
@@ -92,24 +90,6 @@ public class FreezeShockTests
|
||||
await Assert.That(random.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "EffectChance")).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data on the target) the secondary effect does nothing
|
||||
/// and does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_TargetHasNoBattleData_DoesNotParalyzeTarget()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, _, _) = CreateTestSetup();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus")).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the user is "cloaked in a freezing light" on the charge turn and attacks on the following
|
||||
/// turn. The concrete script provides the <see cref="RequireChargeEffect"/> volatile that forces the user
|
||||
@@ -120,7 +100,7 @@ public class FreezeShockTests
|
||||
{
|
||||
// Arrange
|
||||
var script = new FreezeShock();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
var chargeEffect = script.CreateVolatile(user);
|
||||
|
||||
@@ -15,12 +15,12 @@ public class FrustrationTests
|
||||
/// <summary>
|
||||
/// Creates a fully mocked test setup with a user that has the given friendship value.
|
||||
/// </summary>
|
||||
private static (Frustration script, IExecutingMove move, IPokemon target) CreateTestSetup(byte friendship)
|
||||
private static (Frustration script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(byte friendship)
|
||||
{
|
||||
var script = new Frustration();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Happiness.Returns(friendship);
|
||||
move.User.Returns(user);
|
||||
return (script, move, target);
|
||||
|
||||
@@ -20,13 +20,13 @@ public class FuryCutterTests
|
||||
/// 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()
|
||||
private static (FuryCutter script, IExecutingMove move, IBattlePokemon target, IBattlePokemon user, ScriptSet
|
||||
userVolatile) CreateTestSetup()
|
||||
{
|
||||
var script = new FuryCutter();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var userVolatile = new ScriptSet(user);
|
||||
user.Volatile.Returns(userVolatile);
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
@@ -38,7 +38,8 @@ public class FuryCutterTests
|
||||
/// 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)
|
||||
private static ushort SimulateConsecutiveUses(FuryCutter script, IExecutingMove move, IBattlePokemon target,
|
||||
int uses)
|
||||
{
|
||||
ushort basePower = 40;
|
||||
for (var i = 0; i < uses; i++)
|
||||
@@ -127,7 +128,7 @@ public class FuryCutterTests
|
||||
public async Task OnBeforeMove_DifferentMoveUsed_EffectRemovesItself()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
var userVolatile = new ScriptSet(user);
|
||||
var effect = new FuryCutterEffect();
|
||||
@@ -153,7 +154,7 @@ public class FuryCutterTests
|
||||
public async Task OnBeforeMove_FuryCutterUsedAgain_EffectPersists()
|
||||
{
|
||||
// Arrange
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
var userVolatile = new ScriptSet(user);
|
||||
var effect = new FuryCutterEffect();
|
||||
|
||||
@@ -25,7 +25,7 @@ public class FusionBoltTests
|
||||
moveData.SecondaryEffect.Returns((ISecondaryEffect?)null);
|
||||
var learnedMove = Substitute.For<ILearnedMove>();
|
||||
learnedMove.MoveData.Returns(moveData);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var choice = new MoveChoice(user, learnedMove, 0, 0);
|
||||
if (failed)
|
||||
choice.Fail();
|
||||
@@ -36,7 +36,7 @@ public class FusionBoltTests
|
||||
/// Creates a fully mocked test setup where the current turn consists of the given choices, executed in
|
||||
/// order, and the script is evaluating the given executing choice.
|
||||
/// </summary>
|
||||
private static (FusionBolt script, IExecutingMove move, IPokemon target) CreateTestSetup(
|
||||
private static (FusionBolt script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(
|
||||
IMoveChoice executingChoice, params ITurnChoice[] currentTurnChoices)
|
||||
{
|
||||
var script = new FusionBolt();
|
||||
@@ -46,11 +46,9 @@ public class FusionBoltTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.PreviousTurnChoices.Returns(new List<IReadOnlyList<ITurnChoice>> { currentTurnChoices });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
@@ -135,10 +133,8 @@ public class FusionBoltTests
|
||||
new ITurnChoice[] { boltChoice },
|
||||
});
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
var modifier = 1f;
|
||||
|
||||
// Act
|
||||
@@ -229,25 +225,4 @@ public class FusionBoltTests
|
||||
// Assert
|
||||
await Assert.That(modifier).IsEqualTo(1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data on the target) the modifier is left unchanged and
|
||||
/// the hook does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeDamageModifier_TargetHasNoBattleData_ModifierUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FusionBolt();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var modifier = 1f;
|
||||
|
||||
// Act
|
||||
script.ChangeDamageModifier(move, target, 0, ref modifier);
|
||||
|
||||
// Assert
|
||||
await Assert.That(modifier).IsEqualTo(1f);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public class FusionFlareTests
|
||||
moveData.SecondaryEffect.Returns((ISecondaryEffect?)null);
|
||||
var learnedMove = Substitute.For<ILearnedMove>();
|
||||
learnedMove.MoveData.Returns(moveData);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
var choice = new MoveChoice(user, learnedMove, 0, 0);
|
||||
if (failed)
|
||||
choice.Fail();
|
||||
@@ -36,7 +36,7 @@ public class FusionFlareTests
|
||||
/// Creates a fully mocked test setup where the current turn consists of the given choices, executed in
|
||||
/// order, and the script is evaluating the given executing choice.
|
||||
/// </summary>
|
||||
private static (FusionFlare script, IExecutingMove move, IPokemon target) CreateTestSetup(
|
||||
private static (FusionFlare script, IExecutingMove move, IBattlePokemon target) CreateTestSetup(
|
||||
IMoveChoice executingChoice, params ITurnChoice[] currentTurnChoices)
|
||||
{
|
||||
var script = new FusionFlare();
|
||||
@@ -46,11 +46,9 @@ public class FusionFlareTests
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.PreviousTurnChoices.Returns(new List<IReadOnlyList<ITurnChoice>> { currentTurnChoices });
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
target.Battle.Returns(battle);
|
||||
return (script, move, target);
|
||||
}
|
||||
|
||||
@@ -135,10 +133,8 @@ public class FusionFlareTests
|
||||
new ITurnChoice[] { flareChoice },
|
||||
});
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns(battleData);
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.Battle.Returns(battle);
|
||||
var modifier = 1f;
|
||||
|
||||
// Act
|
||||
@@ -229,25 +225,4 @@ public class FusionFlareTests
|
||||
// Assert
|
||||
await Assert.That(modifier).IsEqualTo(1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data on the target) the modifier is left unchanged and
|
||||
/// the hook does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeDamageModifier_TargetHasNoBattleData_ModifierUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var script = new FusionFlare();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
target.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var modifier = 1f;
|
||||
|
||||
// Act
|
||||
script.ChangeDamageModifier(move, target, 0, ref modifier);
|
||||
|
||||
// Assert
|
||||
await Assert.That(modifier).IsEqualTo(1f);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class FutureSightTests
|
||||
/// Creates a fully mocked test setup for the <see cref="FutureSight"/> script where the battle's
|
||||
/// volatile scripts are a real <see cref="ScriptSet"/>.
|
||||
/// </summary>
|
||||
private static (FutureSight script, IExecutingMove move, IPokemon user, IScriptSet battleVolatile)
|
||||
private static (FutureSight script, IExecutingMove move, IBattlePokemon user, IScriptSet battleVolatile)
|
||||
CreateScriptSetup()
|
||||
{
|
||||
var script = new FutureSight();
|
||||
@@ -34,11 +34,9 @@ public class FutureSightTests
|
||||
IScriptSet battleVolatile = new ScriptSet(battle);
|
||||
battle.Volatile.Returns(battleVolatile);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var moveChoice = Substitute.For<IMoveChoice>();
|
||||
move.MoveChoice.Returns(moveChoice);
|
||||
@@ -50,8 +48,8 @@ public class FutureSightTests
|
||||
/// Creates a fully mocked test setup for the <see cref="FutureSightEffect"/>, with a target at side 1,
|
||||
/// position 0 and a damage calculator that computes the given damage when the delayed strike lands.
|
||||
/// </summary>
|
||||
private static (FutureSightEffect effect, IBattle battle, IPokemon target, EventHook eventHook) CreateEffectSetup(
|
||||
uint damage = 100, bool targetUsable = true)
|
||||
private static (FutureSightEffect effect, IBattle battle, IBattlePokemon target, EventHook eventHook)
|
||||
CreateEffectSetup(uint damage = 100, bool targetUsable = true)
|
||||
{
|
||||
var moveData = Substitute.For<IMoveData>();
|
||||
var learnedMove = Substitute.For<ILearnedMove>();
|
||||
@@ -65,12 +63,13 @@ public class FutureSightTests
|
||||
var eventHook = new EventHook();
|
||||
battle.EventHook.Returns(eventHook);
|
||||
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
target.IsUsable.Returns(targetUsable);
|
||||
battle.GetPokemon(1, 0).Returns(target);
|
||||
|
||||
battle.Library.DamageCalculator.GetDamage(Arg.Any<IExecutingMove?>(), Arg.Any<MoveCategory>(),
|
||||
Arg.Any<IPokemon>(), Arg.Any<IPokemon>(), Arg.Any<int>(), Arg.Any<byte>(), Arg.Any<IHitData>())
|
||||
Arg.Any<IBattlePokemon>(), Arg.Any<IBattlePokemon>(), Arg.Any<int>(), Arg.Any<byte>(),
|
||||
Arg.Any<IHitData>())
|
||||
.Returns(damage);
|
||||
|
||||
var effect = new FutureSightEffect(moveChoice);
|
||||
@@ -113,25 +112,6 @@ public class FutureSightTests
|
||||
await Assert.That(battleVolatile.Contains(ScriptUtils.ResolveName<FutureSightEffect>())).IsTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: outside of battle (no battle data on the user) the hook does nothing and does not
|
||||
/// stop the move.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task StopBeforeMove_UserHasNoBattleData_DoesNotStopMove()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, user, _) = CreateScriptSetup();
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
var stop = false;
|
||||
|
||||
// Act
|
||||
script.StopBeforeMove(move, ref stop);
|
||||
|
||||
// Assert
|
||||
await Assert.That(stop).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Two turns later, Future Sight will do damage against the target." One end-of-turn tick
|
||||
/// after selection (the selection turn itself) plus one more is not enough for the strike to land.
|
||||
@@ -244,10 +224,8 @@ public class FutureSightTests
|
||||
moveChoice.TargetSide.Returns(targetSide);
|
||||
moveChoice.TargetPosition.Returns(targetPosition);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
move.User.Returns(user);
|
||||
@@ -325,15 +303,16 @@ public class FutureSightTests
|
||||
var (battle, battleVolatile) = CreateBattleWithRealVolatile();
|
||||
battle.EventHook.Returns(new EventHook());
|
||||
|
||||
var targetA = Substitute.For<IPokemon>();
|
||||
var targetA = Substitute.For<IBattlePokemon>();
|
||||
targetA.IsUsable.Returns(true);
|
||||
battle.GetPokemon(1, 0).Returns(targetA);
|
||||
var targetB = Substitute.For<IPokemon>();
|
||||
var targetB = Substitute.For<IBattlePokemon>();
|
||||
targetB.IsUsable.Returns(true);
|
||||
battle.GetPokemon(1, 1).Returns(targetB);
|
||||
|
||||
battle.Library.DamageCalculator.GetDamage(Arg.Any<IExecutingMove?>(), Arg.Any<MoveCategory>(),
|
||||
Arg.Any<IPokemon>(), Arg.Any<IPokemon>(), Arg.Any<int>(), Arg.Any<byte>(), Arg.Any<IHitData>())
|
||||
Arg.Any<IBattlePokemon>(), Arg.Any<IBattlePokemon>(), Arg.Any<int>(), Arg.Any<byte>(),
|
||||
Arg.Any<IHitData>())
|
||||
.Returns(100u);
|
||||
|
||||
var useA = CreateFutureSightUse(battle, 1, 0);
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
/// <remarks>
|
||||
/// Bulbapedia also lists Abilities the move fails against (Multitype, Stance Change, ...); that check is
|
||||
/// implemented engine-side through <see cref="PkmnLib.Static.Species.IAbility.CanBeChanged"/> inside
|
||||
/// <see cref="IPokemon.SuppressAbility"/>, so it is not the responsibility of this script.
|
||||
/// <see cref="IBattlePokemon.SuppressAbility"/>, so it is not the responsibility of this script.
|
||||
/// </remarks>
|
||||
public class GastroAcidTests
|
||||
{
|
||||
@@ -24,7 +24,7 @@ public class GastroAcidTests
|
||||
// Arrange
|
||||
var script = new GastroAcid();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
@@ -44,9 +44,9 @@ public class GastroAcidTests
|
||||
// Arrange
|
||||
var script = new GastroAcid();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var target = Substitute.For<IBattlePokemon>();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
@@ -17,8 +17,8 @@ public class GearUpTests
|
||||
/// Creates a fully mocked test setup for Gear Up tests. The user is on side 0; the given side lists
|
||||
/// are installed as the battle's sides.
|
||||
/// </summary>
|
||||
private static (GearUp script, IExecutingMove move, IPokemon user) CreateTestSetup(
|
||||
params IReadOnlyList<IPokemon?>[] sidePokemon)
|
||||
private static (GearUp script, IExecutingMove move, IBattlePokemon user) CreateTestSetup(
|
||||
params IReadOnlyList<IBattlePokemon?>[] sidePokemon)
|
||||
{
|
||||
var script = new GearUp();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
@@ -32,23 +32,21 @@ public class GearUpTests
|
||||
}).ToArray();
|
||||
battle.Sides.Returns(sides);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
battleData.SideIndex.Returns((byte)0);
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
user.Battle.Returns(battle);
|
||||
user.SideIndex.Returns((byte)0);
|
||||
move.User.Returns(user);
|
||||
|
||||
return (script, move, user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a mocked Pokémon whose <see cref="IPokemon.ActiveAbility"/> has the given name, or no
|
||||
/// Creates a mocked Pokémon whose <see cref="IBattlePokemon.ActiveAbility"/> has the given name, or no
|
||||
/// ability at all when <paramref name="abilityName"/> is null.
|
||||
/// </summary>
|
||||
private static IPokemon CreatePokemon(string? abilityName)
|
||||
private static IBattlePokemon CreatePokemon(string? abilityName)
|
||||
{
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
var pokemon = Substitute.For<IBattlePokemon>();
|
||||
if (abilityName != null)
|
||||
{
|
||||
var ability = Substitute.For<IAbility>();
|
||||
@@ -68,7 +66,7 @@ public class GearUpTests
|
||||
/// null when that stat was not boosted. Received-call inspection is used instead of NSubstitute
|
||||
/// argument matchers because the trailing EventBatchId parameter cannot be bound by <c>Arg.Any</c>.
|
||||
/// </summary>
|
||||
private static object?[]? GetStatBoostArgs(IPokemon pokemon, Statistic stat) =>
|
||||
private static object?[]? GetStatBoostArgs(IBattlePokemon pokemon, Statistic stat) =>
|
||||
pokemon.ReceivedCalls().Where(c => c.GetMethodInfo().Name == "ChangeStatBoost").Select(c => c.GetArguments())
|
||||
.FirstOrDefault(args => (Statistic)args[0]! == stat);
|
||||
|
||||
@@ -81,10 +79,10 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon("plus");
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?> { ally });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?> { ally });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
var attackArgs = GetStatBoostArgs(ally, Statistic.Attack);
|
||||
@@ -104,10 +102,10 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon("minus");
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?> { ally });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?> { ally });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(GetStatBoostArgs(ally, Statistic.Attack)).IsNotNull();
|
||||
@@ -127,11 +125,11 @@ public class GearUpTests
|
||||
ability.Name.Returns(new StringKey("plus"));
|
||||
user.ActiveAbility.Returns(ability);
|
||||
var side = Substitute.For<IBattleSide>();
|
||||
side.Pokemon.Returns(new List<IPokemon?> { user });
|
||||
user.BattleData!.Battle.Sides.Returns(new[] { side });
|
||||
side.Pokemon.Returns(new List<IBattlePokemon?> { user });
|
||||
user.Battle.Sides.Returns(new[] { side });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
var attackArgs = GetStatBoostArgs(user, Statistic.Attack);
|
||||
@@ -148,10 +146,10 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon("levitate");
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?> { ally });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?> { ally });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ally.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse();
|
||||
@@ -165,10 +163,10 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var opponent = CreatePokemon("plus");
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?>(), new List<IPokemon?> { opponent });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?>(), new List<IBattlePokemon?> { opponent });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(opponent.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse();
|
||||
@@ -182,10 +180,10 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon(null);
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?> { ally });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?> { ally });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ally.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse();
|
||||
@@ -199,31 +197,12 @@ public class GearUpTests
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon("plus");
|
||||
var (script, move, _) = CreateTestSetup(new List<IPokemon?> { null, ally });
|
||||
var (script, move, _) = CreateTestSetup(new List<IBattlePokemon?> { null, ally });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(GetStatBoostArgs(ally, Statistic.Attack)).IsNotNull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: when the user has no <see cref="IPokemon.BattleData"/> (it is not in a battle),
|
||||
/// the script does nothing instead of throwing.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_NullBattleData_DoesNothing()
|
||||
{
|
||||
// Arrange
|
||||
var ally = CreatePokemon("plus");
|
||||
var (script, move, user) = CreateTestSetup(new List<IPokemon?> { ally });
|
||||
user.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(ally.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ChangeStatBoost")).IsFalse();
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,10 @@ public class GenesisSupernovaTests
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
|
||||
var user = Substitute.For<IPokemon>();
|
||||
user.BattleData.Returns(battleData);
|
||||
var user = Substitute.For<IBattlePokemon>();
|
||||
move.User.Returns(user);
|
||||
user.Battle.Returns(battle);
|
||||
|
||||
return (script, move, battle);
|
||||
}
|
||||
@@ -39,27 +37,9 @@ public class GenesisSupernovaTests
|
||||
var (script, move, battle) = CreateTestSetup();
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
script.OnSecondaryEffect(move, Substitute.For<IBattlePokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
battle.Received(1).SetTerrain(ScriptUtils.ResolveName<PsychicTerrainScript>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Technical test: without battle data on the user (outside of battle) the effect does nothing and
|
||||
/// does not throw.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OnSecondaryEffect_UserHasNoBattleData_DoesNotSetTerrain()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, battle) = CreateTestSetup();
|
||||
move.User.BattleData.Returns((IPokemonBattleData?)null);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, Substitute.For<IPokemon>(), 0);
|
||||
|
||||
// Assert
|
||||
battle.DidNotReceiveWithAnyArgs().SetTerrain(default);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user