Support for integration tests, fixes
This commit is contained in:
parent
e7dc885afd
commit
2a0aaed4c3
|
@ -516,7 +516,7 @@ ij_javascript_wrap_comments = false
|
|||
|
||||
[{*.har,*.jsb2,*.jsb3,*.json,*.jsonc,*.postman_collection,*.postman_collection.json,*.postman_environment,*.postman_environment.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,.ws-context,jest.config}]
|
||||
indent_size = 2
|
||||
ij_json_array_wrapping = split_into_lines
|
||||
ij_json_array_wrapping = normal
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
|
|
|
@ -26,7 +26,7 @@ public static class TypeDataLoader
|
|||
if (!types.Any())
|
||||
throw new InvalidDataException("No types found in type data.");
|
||||
|
||||
foreach (var type in types)
|
||||
foreach (var type in types.Skip(1))
|
||||
library.RegisterType(type);
|
||||
|
||||
while (!reader.EndOfStream)
|
||||
|
|
|
@ -223,7 +223,7 @@ public class BattleImpl : ScriptSource, IBattle
|
|||
/// <inheritdoc />
|
||||
public bool CanUse(ITurnChoice choice)
|
||||
{
|
||||
if (choice.User.IsUsable)
|
||||
if (!choice.User.IsUsable)
|
||||
return false;
|
||||
if (choice is IMoveChoice moveChoice)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using PkmnLib.Dynamic.ScriptHandling;
|
||||
|
||||
namespace PkmnLib.Dynamic.Models.Choices;
|
||||
|
||||
/// <summary>
|
||||
|
@ -7,3 +9,24 @@ public interface IPassChoice : ITurnChoice
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
public class PassChoice : TurnChoice, IPassChoice
|
||||
{
|
||||
public PassChoice(IPokemon user) : base(user)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int ScriptCount => User.ScriptCount;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts)
|
||||
{
|
||||
User.CollectScripts(scripts);
|
||||
}
|
||||
}
|
|
@ -271,7 +271,7 @@ public interface IPokemon : IScriptSource
|
|||
/// <summary>
|
||||
/// Learn a move by name.
|
||||
/// </summary>
|
||||
void LearnMove(string moveName, MoveLearnMethod method, byte index);
|
||||
void LearnMove(StringKey moveName, MoveLearnMethod method, byte index);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the current non-volatile status from the Pokemon.
|
||||
|
@ -658,7 +658,7 @@ public class PokemonImpl : ScriptSource, IPokemon
|
|||
/// <remarks>
|
||||
/// If the index is 255, it will try to find the first empty move slot.
|
||||
/// </remarks>
|
||||
public void LearnMove(string moveName, MoveLearnMethod method, byte index)
|
||||
public void LearnMove(StringKey moveName, MoveLearnMethod method, byte index)
|
||||
{
|
||||
if (index == 255)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,10 @@ namespace PkmnLib.Dynamic.ScriptHandling.Registry;
|
|||
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
|
||||
public abstract class Plugin
|
||||
{
|
||||
protected Plugin(PluginConfiguration configuration)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of the plugin. Mostly used for debugging purposes.
|
||||
/// </summary>
|
||||
|
@ -24,3 +28,7 @@ public abstract class Plugin
|
|||
/// </summary>
|
||||
public abstract void Register(ScriptRegistry registry);
|
||||
}
|
||||
|
||||
public abstract class PluginConfiguration
|
||||
{
|
||||
}
|
|
@ -10,5 +10,13 @@ public class TypeDataloaderTests
|
|||
using var file = File.Open("Data/Types.csv", FileMode.Open);
|
||||
var library = TypeDataLoader.LoadTypeLibrary(file);
|
||||
Assert.That(library, Is.Not.Null);
|
||||
|
||||
var fire = library.TryGetTypeIdentifier("Fire", out var fireId);
|
||||
Assert.That(fire, Is.True);
|
||||
var grass = library.TryGetTypeIdentifier("Grass", out var grassId);
|
||||
Assert.That(grass, Is.True);
|
||||
|
||||
var fireEffectiveness = library.GetSingleEffectiveness(fireId, grassId);
|
||||
Assert.That(fireEffectiveness, Is.EqualTo(2.0f));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
using System.Collections;
|
||||
using System.Text.Json;
|
||||
using PkmnLib.Dataloader;
|
||||
using PkmnLib.Dynamic.Libraries;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Plugin.Gen7;
|
||||
using PkmnLib.Static.Libraries;
|
||||
using PkmnLib.Static.Species;
|
||||
using PkmnLib.Tests.Integration.Models;
|
||||
|
||||
namespace PkmnLib.Tests.Integration;
|
||||
|
||||
public class IntegrationTestRunner
|
||||
{
|
||||
private static IEnumerable TestCases
|
||||
{
|
||||
get
|
||||
{
|
||||
var files = Directory.GetFiles("Integration/Tests", "*.json");
|
||||
var serializerOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
};
|
||||
foreach (var file in files)
|
||||
{
|
||||
var json = File.ReadAllText(file);
|
||||
var test = JsonSerializer.Deserialize<IntegrationTestModel>(json, serializerOptions)!;
|
||||
yield return new TestCaseData(test).SetName(test.Name).SetDescription(test.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IDynamicLibrary LoadLibrary()
|
||||
{
|
||||
using var typesFile = File.Open("Data/Types.csv", FileMode.Open);
|
||||
var types = TypeDataLoader.LoadTypeLibrary(typesFile);
|
||||
using var naturesFile = File.Open("Data/Natures.csv", FileMode.Open);
|
||||
var natures = NatureDataLoader.LoadNatureLibrary(naturesFile);
|
||||
using var movesFile = File.Open("Data/Moves.json", FileMode.Open);
|
||||
var moves = MoveDataLoader.LoadMoves(movesFile, types);
|
||||
using var itemsFile = File.Open("Data/Items.json", FileMode.Open);
|
||||
var items = ItemDataLoader.LoadItems(itemsFile);
|
||||
using var abilitiesFile = File.Open("Data/Abilities.json", FileMode.Open);
|
||||
var abilities = AbilityDataLoader.LoadAbilities(abilitiesFile);
|
||||
using var growthRatesFile = File.Open("Data/GrowthRates.json", FileMode.Open);
|
||||
var growthRates = GrowthRateDataLoader.LoadGrowthRates(growthRatesFile);
|
||||
using var speciesFile = File.Open("Data/Pokemon.json", FileMode.Open);
|
||||
var species = SpeciesDataLoader.LoadSpecies(speciesFile, types);
|
||||
|
||||
var staticLibrary = new StaticLibraryImpl(new LibrarySettings()
|
||||
{
|
||||
MaxLevel = 100,
|
||||
ShinyRate = 4096,
|
||||
}, species, moves, abilities, types, natures, growthRates, items);
|
||||
|
||||
var dynamicLibrary = DynamicLibraryImpl.Create(staticLibrary, [
|
||||
new Gen7Plugin(new Gen7PluginConfiguration()
|
||||
{
|
||||
DamageCalculatorHasRandomness = false,
|
||||
}),
|
||||
]);
|
||||
return dynamicLibrary;
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(TestCases))]
|
||||
public void RunIntegrationTest(IntegrationTestModel test)
|
||||
{
|
||||
var library = LoadLibrary();
|
||||
|
||||
var parties = test.BattleSetup.Parties.Select(IBattleParty (x) =>
|
||||
{
|
||||
var party = new PokemonParty(6);
|
||||
for (var index = 0; index < x.Pokemon.Length; index++)
|
||||
{
|
||||
var pokemon = x.Pokemon[index];
|
||||
Assert.That(library.StaticLibrary.Species.TryGet(pokemon.Species, out var species), Is.True);
|
||||
var mon = new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex
|
||||
{
|
||||
IsHidden = false,
|
||||
Index = 0,
|
||||
},
|
||||
pokemon.Level, 0, Gender.Genderless, 0, "hardy");
|
||||
foreach (var move in pokemon.Moves)
|
||||
{
|
||||
mon.LearnMove(move, MoveLearnMethod.Unknown, 255);
|
||||
}
|
||||
|
||||
party.SwapInto(mon, index);
|
||||
}
|
||||
|
||||
return new BattlePartyImpl(party, x.Indices.Select(y => new ResponsibleIndex(y[0], y[1])).ToArray());
|
||||
}).ToArray();
|
||||
var battle = new BattleImpl(library, parties, test.BattleSetup.CanFlee, test.BattleSetup.NumberOfSides,
|
||||
test.BattleSetup.PositionsPerSide);
|
||||
|
||||
foreach (var action in test.Actions)
|
||||
{
|
||||
action.Execute(battle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using CSPath;
|
||||
using PkmnLib.Dynamic.Models;
|
||||
using PkmnLib.Dynamic.Models.Choices;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace PkmnLib.Tests.Integration.Models;
|
||||
|
||||
|
||||
[JsonDerivedType(typeof(SetPokemonAction), "setPokemon")]
|
||||
[JsonDerivedType(typeof(SetMoveChoiceAction), "setMoveChoice")]
|
||||
[JsonDerivedType(typeof(SetPassChoiceAction), "setPassChoice")]
|
||||
[JsonDerivedType(typeof(AssertAction), "assert")]
|
||||
public abstract class IntegrationTestAction
|
||||
{
|
||||
public abstract void Execute(IBattle battle);
|
||||
}
|
||||
|
||||
public class SetPokemonAction : IntegrationTestAction
|
||||
{
|
||||
public List<byte> Place { get; set; } = null!;
|
||||
public List<byte> FromParty { get; set; } = null!;
|
||||
|
||||
public override void Execute(IBattle battle)
|
||||
{
|
||||
var mon = battle.Parties[FromParty[0]].Party[FromParty[1]];
|
||||
battle.Sides[Place[0]].SwapPokemon(Place[1], mon);
|
||||
}
|
||||
}
|
||||
|
||||
public class SetMoveChoiceAction : IntegrationTestAction
|
||||
{
|
||||
public List<byte> Place { get; set; } = null!;
|
||||
public string Move { get; set; } = null!;
|
||||
public List<byte> Target { get; set; } = null!;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Execute(IBattle battle)
|
||||
{
|
||||
var user = battle.Sides[Place[0]].Pokemon[Place[1]];
|
||||
Assert.That(user, Is.Not.Null);
|
||||
var move = user.Moves.First(m => m?.MoveData.Name == Move);
|
||||
Assert.That(move, Is.Not.Null);
|
||||
var res = battle.TrySetChoice(new MoveChoice(user, move, Target[0], Target[1]));
|
||||
Assert.That(res, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
public class SetPassChoiceAction : IntegrationTestAction
|
||||
{
|
||||
public List<byte> Place { get; set; } = null!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Execute(IBattle battle)
|
||||
{
|
||||
var user = battle.Sides[Place[0]].Pokemon[Place[1]];
|
||||
Assert.That(user, Is.Not.Null);
|
||||
var res = battle.TrySetChoice(new PassChoice(user));
|
||||
Assert.That(res, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
public class AssertAction : IntegrationTestAction
|
||||
{
|
||||
public string Value { get; set; } = null!;
|
||||
public JsonNode Expected { get; set; } = null!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Execute(IBattle battle)
|
||||
{
|
||||
var list = battle.Path(Value).ToList();
|
||||
var value = list.Count == 1 ? list[0] : list;
|
||||
|
||||
var serialized = JsonSerializer.Serialize(value);
|
||||
Assert.That(serialized, Is.EqualTo(Expected.ToJsonString()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
namespace PkmnLib.Tests.Integration.Models;
|
||||
|
||||
public class IntegrationTestModel
|
||||
{
|
||||
public string Name { get; set; } = null!;
|
||||
public string Description { get; set; } = null!;
|
||||
public IntegrationTestBattleSetup BattleSetup { get; set; } = null!;
|
||||
public IntegrationTestAction[] Actions { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class IntegrationTestBattleSetup
|
||||
{
|
||||
public int Seed { get; set; }
|
||||
public bool CanFlee { get; set; }
|
||||
public byte NumberOfSides { get; set; }
|
||||
public byte PositionsPerSide { get; set; }
|
||||
public IntegrationTestParty[] Parties { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class IntegrationTestParty
|
||||
{
|
||||
public List<List<byte>> Indices { get; set; } = null!;
|
||||
public IntegrationTestPokemon[] Pokemon { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class IntegrationTestPokemon
|
||||
{
|
||||
public string Species { get; set; } = null!;
|
||||
public LevelInt Level { get; set; }
|
||||
public string[] Moves { get; set; } = null!;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "BasicSingleTurn",
|
||||
"description": "An extremely basic test that checks if a single turn of a battle works correctly. This test has two Pokemon, a Charizard and a Venusaur, and the Charizard uses Ember on the Venusaur.",
|
||||
"battleSetup": {
|
||||
"seed": 10,
|
||||
"canFlee": false,
|
||||
"numberOfSides": 2,
|
||||
"positionsPerSide": 1,
|
||||
"parties": [
|
||||
{
|
||||
"indices": [[0, 0]],
|
||||
"pokemon": [
|
||||
{
|
||||
"species": "charizard",
|
||||
"level": 50,
|
||||
"moves": ["ember"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"indices": [[1, 0]],
|
||||
"pokemon": [
|
||||
{
|
||||
"species": "venusaur",
|
||||
"level": 50,
|
||||
"moves": ["vine_whip"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"actions": [
|
||||
{
|
||||
"$type": "setPokemon",
|
||||
"place": [0, 0],
|
||||
"fromParty": [0, 0]
|
||||
},
|
||||
{
|
||||
"$type": "setPokemon",
|
||||
"place": [1, 0],
|
||||
"fromParty": [1, 0]
|
||||
},
|
||||
{
|
||||
"$type": "assert",
|
||||
"value": ".Sides[1].Pokemon[0].CurrentHealth",
|
||||
"expected": 140
|
||||
},
|
||||
{
|
||||
"$type": "setMoveChoice",
|
||||
"place": [0, 0],
|
||||
"move": "ember",
|
||||
"target": [1, 0]
|
||||
},
|
||||
{
|
||||
"$type": "setPassChoice",
|
||||
"place": [1, 0]
|
||||
},
|
||||
{
|
||||
"$type": "assert",
|
||||
"value": ".Sides[1].Pokemon[0].CurrentHealth",
|
||||
"expected": 78
|
||||
}
|
||||
]
|
||||
}
|
|
@ -10,7 +10,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="CSPath" Version="0.0.4" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||
|
@ -19,19 +20,23 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\PkmnLib.Dataloader\PkmnLib.Dataloader.csproj" />
|
||||
<ProjectReference Include="..\PkmnLib.Dynamic\PkmnLib.Dynamic.csproj" />
|
||||
<ProjectReference Include="..\PkmnLib.Static\PkmnLib.Static.csproj" />
|
||||
<ProjectReference Include="..\PkmnLib.Dataloader\PkmnLib.Dataloader.csproj"/>
|
||||
<ProjectReference Include="..\PkmnLib.Dynamic\PkmnLib.Dynamic.csproj"/>
|
||||
<ProjectReference Include="..\PkmnLib.Static\PkmnLib.Static.csproj"/>
|
||||
<ProjectReference Include="..\Plugins\PkmnLib.Plugin.Gen7\PkmnLib.Plugin.Gen7.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\" />
|
||||
<Folder Include="Data\"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Data\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Data\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Integration\Tests\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -3,8 +3,21 @@ using PkmnLib.Plugin.Gen7.Libraries;
|
|||
|
||||
namespace PkmnLib.Plugin.Gen7;
|
||||
|
||||
public class Gen7PluginConfiguration : PluginConfiguration
|
||||
{
|
||||
public bool DamageCalculatorHasRandomness { get; set; }
|
||||
}
|
||||
|
||||
public class Gen7Plugin : Dynamic.ScriptHandling.Registry.Plugin
|
||||
{
|
||||
private readonly Gen7PluginConfiguration _configuration;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Gen7Plugin(PluginConfiguration configuration) : base(configuration)
|
||||
{
|
||||
_configuration = (Gen7PluginConfiguration)configuration;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Gen7";
|
||||
|
||||
|
@ -16,7 +29,7 @@ public class Gen7Plugin : Dynamic.ScriptHandling.Registry.Plugin
|
|||
{
|
||||
registry.RegisterAssemblyScripts(typeof(Gen7Plugin).Assembly);
|
||||
registry.RegisterBattleStatCalculator(new Gen7BattleStatCalculator());
|
||||
registry.RegisterDamageCalculator(new Gen7DamageCalculator(true));
|
||||
registry.RegisterDamageCalculator(new Gen7DamageCalculator(_configuration.DamageCalculatorHasRandomness));
|
||||
registry.RegisterMiscLibrary(new Gen7MiscLibrary());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue