From 6db5381d118c9bfd2286420868ca1ef638e25155 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sun, 18 May 2025 21:19:04 +0200 Subject: [PATCH] Add JSON validation test --- .woodpecker/build.yaml | 5 ++ .../QuestPaths.JsonValidator.csproj | 47 +++++++++++++++++ QuestPaths.JsonValidator/QuestWrapper.cs | 16 ++++++ QuestPaths.JsonValidator/TestQuestLoader.cs | 20 ++++++++ .../ValidJsonFilesTest.cs | 51 +++++++++++++++++++ QuestPaths/QuestPaths.csproj | 2 +- QuestPaths/packages.lock.json | 2 +- Questionable.sln | 14 +++-- 8 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 QuestPaths.JsonValidator/QuestPaths.JsonValidator.csproj create mode 100644 QuestPaths.JsonValidator/QuestWrapper.cs create mode 100644 QuestPaths.JsonValidator/TestQuestLoader.cs create mode 100644 QuestPaths.JsonValidator/ValidJsonFilesTest.cs diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml index d10c34e7..85910fbc 100644 --- a/.woodpecker/build.yaml +++ b/.woodpecker/build.yaml @@ -13,6 +13,11 @@ steps: commands: - dotnet restore /p:Configuration=Release --packages $CI_WORKSPACE/.nuget + - name: dotnet test + image: mcr.microsoft.com/dotnet/sdk:9.0-noble + commands: + - dotnet test QuestPaths.JsonValidator/QuestPaths.JsonValidator.csproj --source $CI_WORKSPACE/.nuget --no-restore + - name: dotnet build image: mcr.microsoft.com/dotnet/sdk:9.0-noble commands: diff --git a/QuestPaths.JsonValidator/QuestPaths.JsonValidator.csproj b/QuestPaths.JsonValidator/QuestPaths.JsonValidator.csproj new file mode 100644 index 00000000..a2ff13b1 --- /dev/null +++ b/QuestPaths.JsonValidator/QuestPaths.JsonValidator.csproj @@ -0,0 +1,47 @@ + + + + net9.0 + x64 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + $([System.String]::new('%(RelativeDir)').Substring(3).Replace('\','/'))%(FileName)%(Extension) + + + + diff --git a/QuestPaths.JsonValidator/QuestWrapper.cs b/QuestPaths.JsonValidator/QuestWrapper.cs new file mode 100644 index 00000000..3184455a --- /dev/null +++ b/QuestPaths.JsonValidator/QuestWrapper.cs @@ -0,0 +1,16 @@ +namespace QuestPaths.JsonValidator; + +public class QuestWrapper +{ + public QuestWrapper(string manifestName) + { + ManifestName = manifestName; + ShortName = ManifestName.Split('/').Last().Replace(".json", "", StringComparison.InvariantCulture); + } + + public string ManifestName { get; } + public string ShortName { get; } + public Stream AsStream() => typeof(QuestWrapper).Assembly.GetManifestResourceStream(ManifestName)!; + + public override string ToString() => ShortName; +} diff --git a/QuestPaths.JsonValidator/TestQuestLoader.cs b/QuestPaths.JsonValidator/TestQuestLoader.cs new file mode 100644 index 00000000..4d674ef8 --- /dev/null +++ b/QuestPaths.JsonValidator/TestQuestLoader.cs @@ -0,0 +1,20 @@ +using System.Collections; + +namespace QuestPaths.JsonValidator; + +public sealed class TestQuestLoader : IEnumerable +{ + private readonly List _data; + + public TestQuestLoader() + { + var assembly = typeof(TestQuestLoader).Assembly; + _data = assembly.GetManifestResourceNames() + .Where(x => x.StartsWith("QuestPaths/") && x.EndsWith(".json")) + .Select(x => new object[]{new QuestWrapper(x)}) + .ToList(); + } + public IEnumerator GetEnumerator() => _data.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/QuestPaths.JsonValidator/ValidJsonFilesTest.cs b/QuestPaths.JsonValidator/ValidJsonFilesTest.cs new file mode 100644 index 00000000..38ddfe83 --- /dev/null +++ b/QuestPaths.JsonValidator/ValidJsonFilesTest.cs @@ -0,0 +1,51 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Nodes; +using Json.Schema; +using Questionable.Model; +using Questionable.QuestPaths; +using Xunit; + +namespace QuestPaths.JsonValidator; + +public sealed class ValidJsonFilesTest +{ + private static readonly JsonSchema QuestSchema; + + static ValidJsonFilesTest() + { + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-aethernetshard.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonAethernetShard).AsTask().Result); + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-aetheryte.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonAetheryte).AsTask().Result); + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-classjob.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonClassJob).AsTask().Result); + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-completionflags.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonCompletionFlags).AsTask().Result); + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-vector3.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonVector3).AsTask().Result); + + QuestSchema = JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result; + } + + [Theory] + [ClassData(typeof(TestQuestLoader))] + public void QuestShouldValidateAsJson(QuestWrapper quest) + { + JsonNode questNode = JsonNode.Parse(quest.AsStream()) ?? throw new InvalidDataException("no quest stream"); + + EvaluationResults evaluationResult = QuestSchema.Evaluate(questNode, new EvaluationOptions + { + Culture = CultureInfo.InvariantCulture, + OutputFormat = OutputFormat.List + }); + + if (!evaluationResult.IsValid) + Assert.Fail($"Quest '{quest.ManifestName}' validation failed"); + } +} diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj index 845355b8..60526abc 100644 --- a/QuestPaths/QuestPaths.csproj +++ b/QuestPaths/QuestPaths.csproj @@ -1,6 +1,6 @@ - net9.0-windows + net9.0 12 enable Questionable.QuestPaths diff --git a/QuestPaths/packages.lock.json b/QuestPaths/packages.lock.json index 0d3376be..8b094b8a 100644 --- a/QuestPaths/packages.lock.json +++ b/QuestPaths/packages.lock.json @@ -1,7 +1,7 @@ { "version": 1, "dependencies": { - "net9.0-windows7.0": { + "net9.0": { "System.Text.Json": { "type": "Transitive", "resolved": "9.0.3", diff --git a/Questionable.sln b/Questionable.sln index cc77dd85..d96384bb 100644 --- a/Questionable.sln +++ b/Questionable.sln @@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pictomancy", "vendor\pictom EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Questionable.IpcTest", "Questionable.IpcTest\Questionable.IpcTest.csproj", "{8572A8B2-2F31-4D17-B207-6A7A2E0579EF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPaths.JsonValidator", "QuestPaths.JsonValidator\QuestPaths.JsonValidator.csproj", "{2521F2BA-9647-4851-92E1-F56280D1663C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -79,10 +81,14 @@ Global {D1AE2F8C-BDE7-457F-A369-973101044A25}.Debug|x64.Build.0 = Debug|x64 {D1AE2F8C-BDE7-457F-A369-973101044A25}.Release|x64.ActiveCfg = Release|x64 {D1AE2F8C-BDE7-457F-A369-973101044A25}.Release|x64.Build.0 = Release|x64 - {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.ActiveCfg = Debug|Any CPU - {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.Build.0 = Debug|Any CPU - {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.ActiveCfg = Release|Any CPU - {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.Build.0 = Release|Any CPU + {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.ActiveCfg = Debug|x64 + {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Debug|x64.Build.0 = Debug|x64 + {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.ActiveCfg = Release|x64 + {8572A8B2-2F31-4D17-B207-6A7A2E0579EF}.Release|x64.Build.0 = Release|x64 + {2521F2BA-9647-4851-92E1-F56280D1663C}.Debug|x64.ActiveCfg = Debug|x64 + {2521F2BA-9647-4851-92E1-F56280D1663C}.Debug|x64.Build.0 = Debug|x64 + {2521F2BA-9647-4851-92E1-F56280D1663C}.Release|x64.ActiveCfg = Release|x64 + {2521F2BA-9647-4851-92E1-F56280D1663C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE -- 2.20.1