More unit tests, fixes
This commit is contained in:
208
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/EndureTests.cs
Normal file
208
Plugins/PkmnLib.Plugin.Gen7.Tests/Scripts/Moves/EndureTests.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.Models.Choices;
|
||||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the <see cref="Endure"/> move script and its <see cref="EndureEffect"/>.
|
||||
/// Gen VII Bulbapedia behavior: "For the rest of the turn, Endure allows the user to survive any attack
|
||||
/// that would cause it to faint, leaving the user with 1 HP instead." Like other protection moves, "if it
|
||||
/// or other protection moves are used consecutively, its success rate decreases."
|
||||
/// </summary>
|
||||
public class EndureTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a fully mocked setup for driving <see cref="Endure"/>'s inherited
|
||||
/// <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)
|
||||
CreateProtectSetup(bool userMovesLast, float randomRoll)
|
||||
{
|
||||
var script = new Endure();
|
||||
var move = Substitute.For<IExecutingMove>();
|
||||
var target = Substitute.For<IPokemon>();
|
||||
var hitData = Substitute.For<IHitData>();
|
||||
move.GetHitData(target, 0).Returns(hitData);
|
||||
|
||||
// A queue with a remaining choice means another Pokémon still has to move after the user.
|
||||
var queue = userMovesLast ? new BattleChoiceQueue([]) : new BattleChoiceQueue([Substitute.For<IMoveChoice>()]);
|
||||
|
||||
var random = Substitute.For<IBattleRandom>();
|
||||
random.GetFloat().Returns(randomRoll);
|
||||
|
||||
var battle = Substitute.For<IBattle>();
|
||||
battle.ChoiceQueue.Returns(queue);
|
||||
battle.Random.Returns(random);
|
||||
|
||||
var battleData = Substitute.For<IPokemonBattleData>();
|
||||
battleData.Battle.Returns(battle);
|
||||
target.BattleData.Returns(battleData);
|
||||
|
||||
target.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet volatileSet = new ScriptSet(target);
|
||||
target.Volatile.Returns(volatileSet);
|
||||
|
||||
return (script, move, target, hitData, volatileSet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "For the rest of the turn, Endure allows the user to survive any attack that would
|
||||
/// cause it to faint" — using the move attaches the <see cref="EndureEffect"/> to the user.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_FirstUse_AddsEndureEffect()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, hitData, volatileSet) = CreateProtectSetup(false, 0.5f);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(volatileSet.Contains(ScriptUtils.ResolveName<EndureEffect>())).IsTrue();
|
||||
hitData.DidNotReceive().Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: Endure "always fails if the user is the last to act in the turn" — with no remaining
|
||||
/// choices in the queue there is nothing left to protect against, and the move fails.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_UserMovesLast_FailsHit()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, hitData, volatileSet) = CreateProtectSetup(true, 0.0f);
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
hitData.Received(1).Fail();
|
||||
await Assert.That(volatileSet.Contains(ScriptUtils.ResolveName<EndureEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "If it or other protection moves are used consecutively, its success rate decreases."
|
||||
/// On the second consecutive use the success chance is 1/3, so a roll above that fails.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_SecondConsecutiveUseWithHighRoll_FailsHit()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, hitData, volatileSet) = CreateProtectSetup(false, 0.5f);
|
||||
volatileSet.Add(new ProtectionFailureScript { ProtectTurns = 1 });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
hitData.Received(1).Fail();
|
||||
await Assert.That(volatileSet.Contains(ScriptUtils.ResolveName<EndureEffect>())).IsFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "If it or other protection moves are used consecutively, its success rate decreases."
|
||||
/// On the second consecutive use the success chance is 1/3, so a roll below that still succeeds.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnSecondaryEffect_SecondConsecutiveUseWithLowRoll_AddsEndureEffect()
|
||||
{
|
||||
// Arrange
|
||||
var (script, move, target, hitData, volatileSet) = CreateProtectSetup(false, 0.2f);
|
||||
volatileSet.Add(new ProtectionFailureScript { ProtectTurns = 1 });
|
||||
|
||||
// Act
|
||||
script.OnSecondaryEffect(move, target, 0);
|
||||
|
||||
// Assert
|
||||
await Assert.That(volatileSet.Contains(ScriptUtils.ResolveName<EndureEffect>())).IsTrue();
|
||||
hitData.DidNotReceive().Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: "Endure allows the user to survive any attack that would cause it to faint, leaving
|
||||
/// the user with 1 HP instead." Damage exceeding the user's current HP is reduced to leave 1 HP.
|
||||
/// </summary>
|
||||
[Test, Arguments(100u, 150u, 99u), Arguments(50u, 51u, 49u), Arguments(2u, 9999u, 1u)]
|
||||
public async Task ChangeIncomingDamage_LethalDamage_LeavesUserWithOneHp(uint currentHealth, uint incomingDamage,
|
||||
uint expectedDamage)
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
pokemon.CurrentHealth.Returns(currentHealth);
|
||||
var damage = incomingDamage;
|
||||
|
||||
// Act
|
||||
effect.ChangeIncomingDamage(pokemon, DamageSource.MoveDamage, ref damage);
|
||||
|
||||
// Assert
|
||||
await Assert.That(damage).IsEqualTo(expectedDamage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: Endure lets the user "survive any attack that would cause it to faint" — a hit for
|
||||
/// exactly the user's current HP would faint it, so it too must be reduced to leave 1 HP.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeIncomingDamage_DamageEqualToCurrentHp_LeavesUserWithOneHp()
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
pokemon.CurrentHealth.Returns(100u);
|
||||
var damage = 100u;
|
||||
|
||||
// Act
|
||||
effect.ChangeIncomingDamage(pokemon, DamageSource.MoveDamage, ref damage);
|
||||
|
||||
// Assert
|
||||
await Assert.That(damage).IsEqualTo(99u);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: Endure only affects attacks "that would cause it to faint" — non-lethal damage passes
|
||||
/// through unchanged.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task ChangeIncomingDamage_NonLethalDamage_DamageUnchanged()
|
||||
{
|
||||
// Arrange
|
||||
var effect = new EndureEffect();
|
||||
var pokemon = Substitute.For<IPokemon>();
|
||||
pokemon.CurrentHealth.Returns(100u);
|
||||
var damage = 50u;
|
||||
|
||||
// Act
|
||||
effect.ChangeIncomingDamage(pokemon, DamageSource.MoveDamage, ref damage);
|
||||
|
||||
// Assert
|
||||
await Assert.That(damage).IsEqualTo(50u);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bulbapedia: the protection lasts "for the rest of the turn" — the effect removes itself at the end
|
||||
/// of the turn.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task OnEndTurn_EffectRemovesItself()
|
||||
{
|
||||
// Arrange
|
||||
var owner = Substitute.For<IPokemon>();
|
||||
owner.GetScripts().Returns(_ => new ScriptIterator(Array.Empty<IEnumerable<ScriptContainer>>()));
|
||||
IScriptSet ownerVolatile = new ScriptSet(owner);
|
||||
var effect = new EndureEffect();
|
||||
ownerVolatile.Add(effect);
|
||||
|
||||
// Act
|
||||
effect.OnEndTurn(owner, Substitute.For<IBattle>());
|
||||
|
||||
// Assert
|
||||
await Assert.That(ownerVolatile.Contains(ScriptUtils.ResolveName<EndureEffect>())).IsFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user