194 lines
7.9 KiB
C#
194 lines
7.9 KiB
C#
using System.Buffers;
|
|
using System.Text.Json;
|
|
using PkmnLib.Dynamic.Libraries;
|
|
using PkmnLib.Dynamic.Libraries.DataLoaders.Models;
|
|
using PkmnLib.Dynamic.ScriptHandling;
|
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
|
using PkmnLib.Static.Moves;
|
|
using TUnit.Core.Logging;
|
|
|
|
namespace PkmnLib.Plugin.Gen7.Tests.DataTests;
|
|
|
|
public class MoveDataTests
|
|
{
|
|
public record TestCaseData(IDynamicLibrary Library, IMoveData Move)
|
|
{
|
|
/// <inheritdoc />
|
|
public override string ToString() => Move.Name + " has valid scripts";
|
|
}
|
|
|
|
public static IEnumerable<Func<TestCaseData>> AllMovesHaveValidScriptsData()
|
|
{
|
|
var library = LibraryHelpers.LoadLibrary();
|
|
var moveLibrary = library.StaticLibrary.Moves;
|
|
foreach (var move in moveLibrary)
|
|
{
|
|
if (move.SecondaryEffect == null)
|
|
continue;
|
|
yield return () => new TestCaseData(library, move);
|
|
}
|
|
}
|
|
|
|
[Test, MethodDataSource(nameof(AllMovesHaveValidScriptsData))]
|
|
public async Task AllMoveEffectsHaveValidScripts(TestCaseData test)
|
|
{
|
|
if (test.Move.SecondaryEffect == null)
|
|
return;
|
|
var scriptName = test.Move.SecondaryEffect.Name;
|
|
|
|
try
|
|
{
|
|
await Assert.That(test.Library.ScriptResolver.TryResolve(ScriptCategory.Move, scriptName,
|
|
test.Move.SecondaryEffect.Parameters, out _)).IsTrue();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
// Helper method to find the line number of the effect in the JSON file
|
|
var file = Path.GetFullPath("../../../../Plugins/PkmnLib.Plugin.Gen7/Data/Moves.jsonc");
|
|
var json = await File.ReadAllLinesAsync(file);
|
|
var moveLineNumber = json.Select((line, index) => new { line, index })
|
|
.FirstOrDefault(x => x.line.Contains($"\"name\": \"{test.Move.Name}\""))?.index + 1;
|
|
var effectLineNumber = moveLineNumber + json.Skip(moveLineNumber ?? 0)
|
|
.Select((line, index) => new { line, index }).FirstOrDefault(x => x.line.Contains("effect"))
|
|
?.index +
|
|
1 ?? 0;
|
|
|
|
await TestContext.Current!.OutputWriter.WriteLineAsync("File: " + $"file://{file}:{effectLineNumber}");
|
|
throw new AggregateException($"Failed to resolve script for move {test.Move.Name} with effect {scriptName}",
|
|
e);
|
|
}
|
|
}
|
|
|
|
public record SetStatusTestCaseData(IDynamicLibrary Library, IMoveData Move)
|
|
{
|
|
/// <inheritdoc />
|
|
public override string ToString() => Move.Name + " has valid status: " +
|
|
Move.SecondaryEffect?.Parameters.GetValueOrDefault("status");
|
|
}
|
|
|
|
public static IEnumerable<Func<SetStatusTestCaseData>> SetStatusMovesHaveValidStatusData()
|
|
{
|
|
var library = LibraryHelpers.LoadLibrary();
|
|
var moveLibrary = library.StaticLibrary.Moves;
|
|
foreach (var move in moveLibrary)
|
|
{
|
|
if (move.SecondaryEffect?.Name != "set_status")
|
|
continue;
|
|
yield return () => new SetStatusTestCaseData(library, move);
|
|
}
|
|
}
|
|
|
|
[Test, MethodDataSource(nameof(SetStatusMovesHaveValidStatusData))]
|
|
public async Task SetStatusMovesHaveValidStatus(SetStatusTestCaseData test)
|
|
{
|
|
if (test.Move.SecondaryEffect == null)
|
|
return;
|
|
var status = test.Move.SecondaryEffect.Parameters["status"]?.ToString();
|
|
if (status == null)
|
|
throw new Exception("Missing required parameter 'status'");
|
|
|
|
await Assert.That(test.Library.ScriptResolver.TryResolve(ScriptCategory.Status, status, null, out _)).IsTrue();
|
|
}
|
|
|
|
public record HasEitherEffectOrComment(string MoveName, bool HasEffect, bool HasComment)
|
|
{
|
|
/// <inheritdoc />
|
|
public override string ToString() => MoveName + " has effect: " + HasEffect + ", comment: " + HasComment;
|
|
}
|
|
|
|
public static IEnumerable<Func<HasEitherEffectOrComment>> EveryMoveHasEitherEffectOrCommentData()
|
|
{
|
|
IResourceProvider plugin = new Gen7Plugin();
|
|
using var movesJson = plugin.GetResource(ResourceFileType.Moves)!.Open();
|
|
var json = new BinaryReader(movesJson);
|
|
var moves = json.ReadBytes((int)movesJson.Length);
|
|
var reader = new Utf8JsonReader(new ReadOnlySequence<byte>(moves), new JsonReaderOptions
|
|
{
|
|
CommentHandling = JsonCommentHandling.Allow,
|
|
AllowTrailingCommas = true,
|
|
});
|
|
Console.WriteLine("Reading moves.json");
|
|
|
|
// The JSON is an object { "data": [] }.
|
|
// Each move is an object in the "data" array.
|
|
// Each object needs to have either an "effect" or a "comment" property.
|
|
|
|
// Read the first object
|
|
reader.Read();
|
|
// Read the properties, until we find the "data" property
|
|
while (reader.TokenType != JsonTokenType.PropertyName || reader.GetString() != "data")
|
|
{
|
|
reader.Read();
|
|
}
|
|
// Read the "data" property
|
|
reader.Read();
|
|
// Read the start of the array
|
|
reader.Read();
|
|
|
|
var results = new List<HasEitherEffectOrComment>();
|
|
// Read each move object
|
|
while (reader.TokenType != JsonTokenType.EndArray)
|
|
{
|
|
// Read the start of the object
|
|
if (!reader.Read())
|
|
break;
|
|
// Read each property
|
|
var name = "";
|
|
var hasEffect = false;
|
|
var hasComment = false;
|
|
while (reader.TokenType != JsonTokenType.EndObject)
|
|
{
|
|
if (reader.TokenType == JsonTokenType.PropertyName)
|
|
{
|
|
var propertyName = reader.GetString();
|
|
if (propertyName == "name")
|
|
{
|
|
reader.Read();
|
|
name = reader.GetString()!;
|
|
}
|
|
else if (propertyName == "effect")
|
|
{
|
|
hasEffect = true;
|
|
reader.Read();
|
|
// Read the effect object
|
|
while (reader.TokenType != JsonTokenType.EndObject)
|
|
{
|
|
reader.Read();
|
|
if (reader.TokenType != JsonTokenType.StartObject)
|
|
continue;
|
|
while (reader.TokenType != JsonTokenType.EndObject)
|
|
{
|
|
reader.Read();
|
|
}
|
|
reader.Read();
|
|
}
|
|
}
|
|
}
|
|
else if (reader.TokenType == JsonTokenType.Comment)
|
|
{
|
|
// Read the comment
|
|
var comment = reader.GetComment();
|
|
hasComment = comment.Trim() == "No secondary effect";
|
|
}
|
|
|
|
reader.Read();
|
|
}
|
|
results.Add(new HasEitherEffectOrComment(name, hasEffect, hasComment));
|
|
}
|
|
return results.Where(x => !string.IsNullOrWhiteSpace(x.MoveName))
|
|
.Select<HasEitherEffectOrComment, Func<HasEitherEffectOrComment>>(x => () => x).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// To ensure that all moves have been properly implemented, we require that each move has either an "effect" property,
|
|
/// or a comment with the exact text "No secondary effect". This ensures that we have not missed any moves.
|
|
///
|
|
/// The implementation of this test is a bit tricky, as we need to read the JSON file and parse it ourselves,
|
|
/// as System.Text.Json does not support reading comments in JSON files beyond the low-level API.
|
|
/// </summary>
|
|
/// <param name="test"></param>
|
|
[Test, MethodDataSource(nameof(EveryMoveHasEitherEffectOrCommentData))]
|
|
public async Task AllMovesHaveEitherEffectOrComment(HasEitherEffectOrComment test) =>
|
|
// Check that each move has either an "effect" or a "comment" property
|
|
await Assert.That(test.HasEffect || test.HasComment).IsTrue();
|
|
} |