using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Dynamic.ScriptHandling.Registry;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static.Utils;
using BattleGravity = PkmnLib.Plugin.Gen7.Scripts.Battle.Gravity;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
///
/// Tests for the move script.
/// Gen VII Bulbapedia behavior: "Gravity causes the field to undergo intense gravity lasting 5 turns",
/// and "Semi-invulnerable Pokémon using Fly or Bounce are immediately canceled."
///
public class GravityTests
{
///
/// Creates a fully mocked test setup for Gravity tests. The battle's volatile script set is a
/// substitute so the addition of the battle-wide gravity script can be inspected.
///
private static (Gravity script, IExecutingMove move, IBattlePokemon target, IBattle battle, IScriptSet
battleVolatile) CreateTestSetup(params IReadOnlyList[] sidePokemon)
{
var script = new Gravity();
var move = Substitute.For();
move.User.Returns(Substitute.For());
var battle = Substitute.For();
var battleVolatile = Substitute.For();
battle.Volatile.Returns(battleVolatile);
var sides = sidePokemon.Select(pokemon =>
{
var side = Substitute.For();
side.Pokemon.Returns(pokemon);
return side;
}).ToArray();
battle.Sides.Returns(sides);
var target = Substitute.For();
target.Battle.Returns(battle);
return (script, move, target, battle, battleVolatile);
}
///
/// Creates a mocked Pokémon with a real as its volatile set, so effects can
/// be attached and their removal inspected.
///
private static (IBattlePokemon pokemon, ScriptSet volatileSet) CreateFieldPokemon()
{
var pokemon = Substitute.For();
pokemon.GetScripts().Returns(_ => new ScriptIterator(new List>()));
var volatileSet = new ScriptSet(pokemon);
pokemon.Volatile.Returns(volatileSet);
return (pokemon, volatileSet);
}
///
/// Bulbapedia: "Gravity causes the field to undergo intense gravity lasting 5 turns." The battle-wide
/// gravity effect is added to the battle's volatile script set.
///
[Test]
public async Task OnSecondaryEffect_Always_AddsGravityToBattleVolatile()
{
// Arrange
var (script, move, target, _, battleVolatile) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
battleVolatile.Received(1).StackOrAdd(new StringKey("gravity"), Arg.Any>());
await Assert.That(battleVolatile.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "StackOrAdd")).IsTrue();
}
///
/// Bulbapedia: the field undergoes "intense gravity" — the instantiation function passed to the
/// battle's volatile script set creates the battle-wide script.
///
[Test]
public async Task OnSecondaryEffect_GravityInstantiation_CreatesBattleGravityScript()
{
// Arrange
var (script, move, target, battle, battleVolatile) = CreateTestSetup();
battle.Library.Returns(LibraryHelpers.LoadLibrary());
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
var call = battleVolatile.ReceivedCalls().First(c => c.GetMethodInfo().Name == "StackOrAdd");
var instantiation = (Func