using PkmnLib.Dynamic.Models; using PkmnLib.Plugin.Gen7.Scripts.Moves; using PkmnLib.Static; using PkmnLib.Static.Utils; namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves; /// /// Tests for the move script. /// Gen VII Bulbapedia behavior: Camouflage changes the user's type based on the current battle /// environment, and the terrain in effect takes precedence (Electric Terrain → Electric, /// Misty Terrain → Fairy, Grassy Terrain → Grass, Psychic Terrain → Psychic). /// public class CamouflageTests { private static (Camouflage script, IExecutingMove move, IPokemon user, IBattle battle) CreateTestSetup( string? terrainName, string environmentName) { var script = new Camouflage(); var library = LibraryHelpers.LoadLibrary(); var battle = Substitute.For(); battle.Library.Returns(library); battle.TerrainName.Returns(terrainName == null ? null : new StringKey?(new StringKey(terrainName))); battle.EnvironmentName.Returns(new StringKey(environmentName)); var user = Substitute.For(); var move = Substitute.For(); move.User.Returns(user); move.Battle.Returns(battle); return (script, move, user, battle); } /// /// Helper that returns the single type the user was changed to, or null when /// was never called. /// private static TypeIdentifier? GetSetType(IPokemon user) { var call = user.ReceivedCalls().FirstOrDefault(c => c.GetMethodInfo().Name == "SetTypes"); return call != null ? ((IReadOnlyList)call.GetArguments()[0]!).Single() : null; } /// /// Bulbapedia (Generation VI onwards): terrain effects determine the type Camouflage grants — /// Electric Terrain makes the user Electric-type, Misty Terrain makes it Fairy-type, /// Grassy Terrain makes it Grass-type, and (Generation VII) Psychic Terrain makes it Psychic-type. /// [Test, Arguments("electric_terrain", "electric"), Arguments("misty_terrain", "fairy"), Arguments("grassy_terrain", "grass"), Arguments("psychic_terrain", "psychic")] public async Task OnSecondaryEffect_TerrainActive_UserBecomesTerrainType(string terrainName, string expectedType) { // Arrange var (script, move, user, battle) = CreateTestSetup(terrainName, "field"); battle.Library.StaticLibrary.Types.TryGetTypeIdentifier(expectedType, out var expected); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected); } /// /// Bulbapedia: without a terrain in effect, the battle environment decides the type — caves make /// the user Rock-type, mountains and beaches Ground-type, snow Ice-type, and water Water-type. /// [Test, Arguments("cave", "rock"), Arguments("mountain", "ground"), Arguments("beach", "ground"), Arguments("snow", "ice"), Arguments("sea", "water"), Arguments("lake", "water")] public async Task OnSecondaryEffect_NoTerrain_UserBecomesEnvironmentType(string environment, string expectedType) { // Arrange var (script, move, user, battle) = CreateTestSetup(null, environment); battle.Library.StaticLibrary.Types.TryGetTypeIdentifier(expectedType, out var expected); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected); } /// /// Bulbapedia: "On regular terrain" Camouflage changes the user's type to Normal. /// [Test, Arguments("field"), Arguments("forest"), Arguments("building")] public async Task OnSecondaryEffect_RegularEnvironment_UserBecomesNormalType(string environment) { // Arrange var (script, move, user, battle) = CreateTestSetup(null, environment); battle.Library.StaticLibrary.Types.TryGetTypeIdentifier("normal", out var expected); // Act script.OnSecondaryEffect(move, Substitute.For(), 0); // Assert await Assert.That(GetSetType(user)!.Value).IsEqualTo(expected); } /// /// Bulbapedia: Camouflage changes the type of the user, not the target — the target must be /// left untouched. /// [Test] public async Task OnSecondaryEffect_TargetTypes_AreNotChanged() { // Arrange var (script, move, _, _) = CreateTestSetup(null, "field"); var target = Substitute.For(); // Act script.OnSecondaryEffect(move, target, 0); // Assert await Assert.That(target.ReceivedCalls().Any(c => c.GetMethodInfo().Name == "SetTypes")).IsFalse(); } }