using PkmnLib.Dynamic.Models; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: "Flame Wheel will thaw out the user if it is frozen, and then inflict damage /// on the target. Flame Wheel also has a 10% chance of burning the target." /// public class FlameWheelTests { /// /// Creates a fully mocked test setup for Flame Wheel tests, initialized with the given burn chance. /// private static (FlameWheel script, IExecutingMove move, IBattlePokemon user, IBattlePokemon target, IBattleRandom random) CreateTestSetup(float burnChance = 10f) { var script = new FlameWheel(); script.OnInitialize(new Dictionary { { "burn_chance", burnChance } }); var move = Substitute.For(); var user = Substitute.For(); var target = Substitute.For(); var battle = Substitute.For(); var random = Substitute.For(); battle.Random.Returns(random); move.Battle.Returns(battle); move.User.Returns(user); return (script, move, user, target, random); } /// /// Helper that checks whether a Pokémon received a SetStatus call for the given status. /// private static bool ReceivedSetStatus(IBattlePokemon pokemon, string status) => pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetStatus" && (StringKey)c.GetArguments()[0]! == new StringKey(status)); /// /// Helper that checks whether a Pokémon received a ClearStatus call. /// private static bool ReceivedClearStatus(IBattlePokemon pokemon) => pokemon.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "ClearStatus"); /// /// Bulbapedia: "Flame Wheel also has a 10% chance of burning the target." /// When the effect chance roll succeeds, the target is burned by the user. /// [Test] public async Task OnSecondaryEffect_EffectChanceSucceeds_BurnsTarget() { // Arrange var (script, move, _, target, random) = CreateTestSetup(); random.EffectChance(10f, move, target, 0).Returns(true); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(ReceivedSetStatus(target, "burned")).IsTrue(); } /// /// Bulbapedia: "Flame Wheel also has a 10% chance of burning the target." /// When the effect chance roll fails, the target is not burned. /// [Test] public async Task OnSecondaryEffect_EffectChanceFails_DoesNotBurnTarget() { // Arrange var (script, move, _, target, random) = CreateTestSetup(); random.EffectChance(10f, move, target, 0).Returns(false); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(ReceivedSetStatus(target, "burned")).IsFalse(); } /// /// Bulbapedia: "Flame Wheel also has a 10% chance of burning the target." /// The configured burn chance is the one rolled against, and it is rolled through the battle's /// so that effect-chance-modifying effects apply. /// [Test] public async Task OnSecondaryEffect_ConfiguredBurnChance_IsPassedToEffectChanceRoll() { // Arrange var (script, move, _, target, random) = CreateTestSetup(30f); // Act script.OnSecondaryEffect(move, target, 0); // Assert random.Received(1).EffectChance(30f, move, target, 0); } /// /// Bulbapedia: "Flame Wheel will thaw out the user if it is frozen". /// [Test] public async Task OnSecondaryEffect_UserFrozen_UserIsThawed() { // Arrange var (script, move, user, target, _) = CreateTestSetup(); user.HasStatus("frozen").Returns(true); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(ReceivedClearStatus(user)).IsTrue(); } /// /// Bulbapedia: "Flame Wheel will thaw out the user if it is frozen". A user that is not frozen keeps /// whatever status it has; the script must not clear it. /// [Test] public async Task OnSecondaryEffect_UserNotFrozen_StatusIsNotCleared() { // Arrange var (script, move, user, target, _) = CreateTestSetup(); user.HasStatus("frozen").Returns(false); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(ReceivedClearStatus(user)).IsFalse(); } /// /// Technical test: initializing without parameters is invalid, as the script requires a burn chance. /// [Test] public async Task OnInitialize_NullParameters_Throws() { // Arrange var script = new FlameWheel(); // Act & Assert await Assert.That(() => script.OnInitialize(null)).ThrowsExactly(); } /// /// Technical test: initializing without a "burn_chance" parameter is invalid. /// [Test] public async Task OnInitialize_MissingBurnChance_Throws() { // Arrange var script = new FlameWheel(); var parameters = new Dictionary { { "unrelated", 10f } }; // Act & Assert await Assert.That(() => script.OnInitialize(parameters)).ThrowsExactly(); } /// /// Bulbapedia: "Flame Wheel also has a 10% chance of burning the target." /// Integration check: initializing the script with Flame Wheel's actual effect parameters from the Gen7 /// data results in a 10% burn chance being rolled. /// [Test] public async Task OnSecondaryEffect_InitializedWithFlameWheelData_UsesTenPercentBurnChance() { // Arrange var library = LibraryHelpers.LoadLibrary(); await Assert.That(library.StaticLibrary.Moves.TryGet("flame_wheel", out var flameWheel)).IsTrue(); var (script, move, _, target, random) = CreateTestSetup(); // Act script.OnInitialize(flameWheel!.SecondaryEffect!.Parameters); script.OnSecondaryEffect(move, target, 0); // Assert random.Received(1).EffectChance(10f, move, target, 0); } }