using PkmnLib.Dynamic.Events;
using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Scripts.Moves;
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
using PkmnLib.Static;
using PkmnLib.Static.Utils;
namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;
///
/// Tests for the move script.
/// Gen VII Bulbapedia behavior: Flatter raises the target's Special Attack stat by one stage and confuses it.
///
public class FlatterTests
{
private static (Flatter script, IExecutingMove move, IPokemon target, IScriptSet targetVolatile) CreateTestSetup()
{
var script = new Flatter();
var move = Substitute.For();
var user = Substitute.For();
move.User.Returns(user);
var target = Substitute.For();
var targetVolatile = Substitute.For();
target.Volatile.Returns(targetVolatile);
return (script, move, target, targetVolatile);
}
///
/// Helper to extract the arguments of the received ChangeStatBoost call, or null when no stat boost
/// was requested. Received-call inspection is used instead of NSubstitute argument matchers because
/// the trailing parameter cannot be bound by Arg.Any (its
/// parameterless constructor initializes a fresh id, so it never equals the matcher's default value).
///
private static object?[]? GetStatBoostArgs(IPokemon pokemon)
{
var call = pokemon.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "ChangeStatBoost");
return call?.GetArguments();
}
///
/// Bulbapedia: Flatter "raises the target's Special Attack stat by one stage".
/// The boost is caused by the opponent's move, so it is not self-inflicted.
///
[Test]
public async Task OnSecondaryEffect_Always_RaisesTargetSpecialAttackByOneStage()
{
// Arrange
var (script, move, target, _) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
var args = GetStatBoostArgs(target);
await Assert.That(args).IsNotNull();
await Assert.That((Statistic)args![0]!).IsEqualTo(Statistic.SpecialAttack);
await Assert.That((sbyte)args[1]!).IsEqualTo((sbyte)1);
await Assert.That((bool)args[2]!).IsFalse(); // not self-inflicted
await Assert.That((bool)args[3]!).IsFalse(); // not forced
}
///
/// Bulbapedia: Flatter raises the target's Special Attack "and confuses it". The confusion is applied
/// through the target's script set.
///
[Test]
public async Task OnSecondaryEffect_Always_ConfusesTarget()
{
// Arrange
var (script, move, target, targetVolatile) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
targetVolatile.Received(1).StackOrAdd(new StringKey("confusion"), Arg.Any>());
await Assert.That(targetVolatile.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "StackOrAdd")).IsTrue();
}
///
/// Bulbapedia: Flatter "confuses" the target. The instantiation function passed to the volatile script
/// set creates a script.
///
[Test]
public async Task OnSecondaryEffect_ConfusionInstantiation_CreatesConfusionScript()
{
// Arrange
var (script, move, target, targetVolatile) = CreateTestSetup();
// Act
script.OnSecondaryEffect(move, target, 0);
// Assert
var call = targetVolatile.ReceivedCalls().First(c => c.GetMethodInfo().Name == "StackOrAdd");
var instantiation = (Func