Skip to content

Commit

Permalink
Merge pull request #6 from gregsdennis/schema-update
Browse files Browse the repository at this point in the history
Updating JsonSchema.Net
  • Loading branch information
gregsdennis authored Jun 30, 2024
2 parents 3f8dcb6 + 24ae2ca commit e960425
Show file tree
Hide file tree
Showing 49 changed files with 607 additions and 275 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/dotnet-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
with:
dotnet-version: |
6.0.x
8.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
Expand All @@ -42,6 +43,9 @@ jobs:
needs: build
if: (success() || failure()) && github.event_name == 'pull_request'
name: Publish Unit Test Results
permissions:
checks: write
pull-requests: write
steps:
- name: Download Artifacts
uses: actions/download-artifact@v2
Expand Down
6 changes: 0 additions & 6 deletions Graeae.Models.Tests/DevTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,5 @@ public class DevTest
[Test]
public void Test()
{
var array = new[] { 0, 1, 2, 3, 4, 5, 6 };

var span = array.AsSpan();
var subSpan = span[7..];

Console.WriteLine(JsonSerializer.Serialize(subSpan.ToArray()));
}
}
7 changes: 5 additions & 2 deletions Graeae.Models.Tests/DocumentBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Graeae.Models.Tests;
// code is simple.
public class DocumentBuilderTests
{
[Test]
public void BuildDocument()
{
var doc = new OpenApiDocument("3.1.0", new("title", "1.0")
Expand All @@ -19,7 +20,7 @@ public void BuildDocument()
Email = "me@you.com",
Name = "me you",
Url = new Uri("https://you.com"),
ExtensionData = new() { ["key"] = new JsonArray { 1, 2, 3 } }
ExtensionData = new() { ["key"] = new JsonArray(1, 2, 3) }
},
Description = "this is an api",
License = new("generic license")
Expand Down Expand Up @@ -134,8 +135,10 @@ public void BuildDocument()
}
}
};
Console.WriteLine(YamlSerializer.Serialize(doc, TestEnvironment.TestOutputSerializerOptions));
}

[Test]
public void PetStoreExample()
{
var document = new OpenApiDocument("3.0.0",
Expand Down Expand Up @@ -299,6 +302,6 @@ public void PetStoreExample()
}
};

Console.WriteLine(YamlSerializer.Serialize(document));
Console.WriteLine(YamlSerializer.Serialize(document, TestEnvironment.TestOutputSerializerOptions));
}
}
4 changes: 3 additions & 1 deletion Graeae.Models.Tests/Graeae.Models.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<nowarn>NUnit2005</nowarn>
<JsonSerializerIsReflectionEnabledByDefault Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions Graeae.Models.Tests/RefResolutionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public void ResolvePathItem()
var file = "api-with-examples.yaml";
var fullFileName = GetFile(file);

var document = YamlSerializer.Deserialize<OpenApiDocument>(File.ReadAllText(fullFileName));
var document = YamlSerializer.Deserialize<OpenApiDocument>(File.ReadAllText(fullFileName), TestEnvironment.SerializerOptions);

var pathItem = document!.Find<PathItem>(JsonPointer.Parse("/paths/~1v2"));

Expand All @@ -28,7 +28,7 @@ public void ResolveExample()
var file = "api-with-examples.yaml";
var fullFileName = GetFile(file);

var document = YamlSerializer.Deserialize<OpenApiDocument>(File.ReadAllText(fullFileName));
var document = YamlSerializer.Deserialize<OpenApiDocument>(File.ReadAllText(fullFileName), TestEnvironment.SerializerOptions);

var example = document!.Find<Example>(JsonPointer.Parse("/paths/~1v2/get/responses/203/content/application~1json/examples/foo"));

Expand Down
28 changes: 19 additions & 9 deletions Graeae.Models.Tests/SpecificationExamples.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections;
using System.Text.Encodings.Web;
using System.Text.Json;
using Json.More;
Expand Down Expand Up @@ -25,15 +26,21 @@ public void RoundTripYaml(string fileName)

try
{
var document = YamlSerializer.Deserialize<OpenApiDocument>(yaml);
var document = YamlSerializer.Deserialize<OpenApiDocument>(yaml, TestEnvironment.SerializerOptions);

var returnToYaml = YamlSerializer.Serialize(document);
var returnToYaml = YamlSerializer.Serialize(document, TestEnvironment.SerializerOptions);

Console.WriteLine(returnToYaml);
}
catch (Exception e)
{
Console.WriteLine($"{JsonSerializer.Serialize(e.Data)}");
var data = new Dictionary<string, object?>();
foreach (DictionaryEntry entry in e.Data)
{
data[entry.Key.ToString()!] = entry.Value;
}

Console.WriteLine($"{JsonSerializer.Serialize(data, TestEnvironment.TestOutputSerializerOptions)}");
throw;
}
}
Expand Down Expand Up @@ -61,19 +68,22 @@ public void RoundTripJson(string fileName)
var yaml = yamlStream.Documents.First();
var json = yaml.ToJsonNode();
Console.WriteLine(json);
var document = json.Deserialize<OpenApiDocument>();
var document = json.Deserialize<OpenApiDocument>(TestEnvironment.SerializerOptions);

var returnToJson = JsonSerializer.SerializeToNode(document, new JsonSerializerOptions
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
})!;
var returnToJson = JsonSerializer.SerializeToNode(document, TestEnvironment.TestOutputSerializerOptions)!;

Console.WriteLine(returnToJson);
Assert.That(() => json.IsEquivalentTo(returnToJson));
}
catch (Exception e)
{
Console.WriteLine($"{JsonSerializer.Serialize(e.Data)}");
var data = new Dictionary<string, object?>();
foreach (DictionaryEntry entry in e.Data)
{
data[entry.Key.ToString()!] = entry.Value;
}

Console.WriteLine($"{JsonSerializer.Serialize(data, TestEnvironment.TestOutputSerializerOptions)}");
throw;
}
}
Expand Down
43 changes: 42 additions & 1 deletion Graeae.Models.Tests/TestEnvironment.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
using Graeae.Models.SchemaDraft4;
using Json.Schema;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

namespace Graeae.Models.Tests;

[SetUpFixture]
public class TestEnvironment
{
public static readonly JsonSerializerOptions SerializerOptions =
new()
{
TypeInfoResolverChain = { TestSerializerContext.Default },
};

public static readonly JsonSerializerOptions TestOutputSerializerOptions =
new()
{
TypeInfoResolverChain = { TestSerializerContext.Default },
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

[OneTimeSetUp]
public void Setup()
{
Draft4Support.Enable();
}
}
}

[JsonSerializable(typeof(OpenApiDocument))]
[JsonSerializable(typeof(Draft4ExclusiveMaximumKeyword))]
[JsonSerializable(typeof(Draft4ExclusiveMinimumKeyword))]
[JsonSerializable(typeof(Draft4IdKeyword))]
[JsonSerializable(typeof(Draft4TypeKeyword))]
[JsonSerializable(typeof(NullableKeyword))]
[JsonSerializable(typeof(ParameterStyle))]
[JsonSerializable(typeof(ParameterStyle?))]
[JsonSerializable(typeof(ParameterLocation))]
[JsonSerializable(typeof(ParameterLocation?))]
[JsonSerializable(typeof(SecuritySchemeLocation))]
[JsonSerializable(typeof(SecuritySchemeLocation?))]

[JsonSerializable(typeof(JsonSchema))]
[JsonSerializable(typeof(EvaluationResults))]

[JsonSerializable(typeof(JsonNode))]
[JsonSerializable(typeof(JsonObject))]
[JsonSerializable(typeof(Dictionary<string, object>))]
[JsonSerializable(typeof(Dictionary<string, JsonSchema>))]
internal partial class TestSerializerContext : JsonSerializerContext;
17 changes: 4 additions & 13 deletions Graeae.Models.Tests/ValidationTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using Json.Schema;
using Yaml2JsonNode;
Expand All @@ -21,19 +20,15 @@ public void ValidateOpenApiDoc_3_0(string fileName)
var yaml = File.ReadAllText(fullFileName);
var instance = YamlSerializer.Parse(yaml).First().ToJsonNode();
var schemaFileName = GetFile("openapi-schema-3.0.json");
var schema = JsonSchema.FromFile(schemaFileName);
var schema = JsonSchema.FromFile(schemaFileName, TestEnvironment.SerializerOptions);

var results = schema.Evaluate(instance, new EvaluationOptions
{
OutputFormat = OutputFormat.List,
EvaluateAs = SchemaDraft4.Draft4Support.Draft4Version
});

Console.WriteLine(JsonSerializer.Serialize(results, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
Console.WriteLine(JsonSerializer.Serialize(results, TestEnvironment.TestOutputSerializerOptions));

Assert.IsTrue(results.IsValid);
}
Expand All @@ -47,18 +42,14 @@ public void ValidateOpenApiDoc_3_1(string fileName)
var yaml = File.ReadAllText(fullFileName);
var instance = YamlSerializer.Parse(yaml).First().ToJsonNode();
var schemaFileName = GetFile("openapi-schema-3.1.json");
var schema = JsonSchema.FromFile(schemaFileName);
var schema = JsonSchema.FromFile(schemaFileName, TestEnvironment.SerializerOptions);

var results = schema.Evaluate(instance, new EvaluationOptions
{
OutputFormat = OutputFormat.List
});

Console.WriteLine(JsonSerializer.Serialize(results, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
Console.WriteLine(JsonSerializer.Serialize(results, TestEnvironment.TestOutputSerializerOptions));

Assert.IsTrue(results.IsValid);
}
Expand Down
16 changes: 8 additions & 8 deletions Graeae.Models/Callback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Callback : Dictionary<CallbackKeyExpression, PathItem>, IRefTargetC
/// </summary>
public ExtensionData? ExtensionData { get; set; }

internal static Callback FromNode(JsonNode? node)
internal static Callback FromNode(JsonNode? node, JsonSerializerOptions? options)
{
if (node is not JsonObject obj)
throw new JsonException("Expected an object");
Expand All @@ -35,19 +35,19 @@ internal static Callback FromNode(JsonNode? node)
else
{
callback = new Callback();
callback.Import(obj);
callback.Import(obj, options);
}
return callback;
}

private protected void Import(JsonObject obj)
private protected void Import(JsonObject obj, JsonSerializerOptions? options)
{
ExtensionData = ExtensionData.FromNode(obj);

foreach (var (key, value) in obj)
{
if (key.StartsWith("x-")) continue;
Add(CallbackKeyExpression.Parse(key), PathItem.FromNode(value));
Add(CallbackKeyExpression.Parse(key), PathItem.FromNode(value, options));
}
}

Expand Down Expand Up @@ -75,7 +75,7 @@ private protected void Import(JsonObject obj)
return obj;
}

object? IRefTargetContainer.Resolve(Span<string> keys)
object? IRefTargetContainer.Resolve(ReadOnlySpan<string> keys)
{
if (keys.Length == 0) return null;

Expand Down Expand Up @@ -145,13 +145,13 @@ public CallbackRef(string reference)
Ref = new Uri(reference ?? throw new ArgumentNullException(nameof(reference)), UriKind.RelativeOrAbsolute);
}

async Task IComponentRef.Resolve(OpenApiDocument root)
async Task IComponentRef.Resolve(OpenApiDocument root, JsonSerializerOptions? options)
{
bool import(JsonNode? node)
{
if (node is not JsonObject obj) return false;

Import(obj);
Import(obj, options);
return true;
}

Expand All @@ -175,7 +175,7 @@ public override Callback Read(ref Utf8JsonReader reader, Type typeToConvert, Jso
var obj = JsonSerializer.Deserialize<JsonObject>(ref reader, options) ??
throw new JsonException("Expected an object");

return Callback.FromNode(obj);
return Callback.FromNode(obj, options);
}

public override void Write(Utf8JsonWriter writer, Callback value, JsonSerializerOptions options)
Expand Down
24 changes: 12 additions & 12 deletions Graeae.Models/ComponentCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,23 @@ public class ComponentCollection : IRefTargetContainer
/// </summary>
public ExtensionData? ExtensionData { get; set; }

internal static ComponentCollection FromNode(JsonNode? node)
internal static ComponentCollection FromNode(JsonNode? node, JsonSerializerOptions? options)
{
if (node is not JsonObject obj)
throw new JsonException("Expected an object");

var components = new ComponentCollection
{
Schemas = obj.MaybeDeserialize<Dictionary<string, JsonSchema>>("schemas"),
Responses = obj.MaybeMap("responses", Response.FromNode),
Parameters = obj.MaybeMap("parameters", Parameter.FromNode),
Schemas = obj.MaybeDeserialize<Dictionary<string, JsonSchema>>("schemas", options),
Responses = obj.MaybeMap("responses", x => Response.FromNode(x, options)),
Parameters = obj.MaybeMap("parameters", x => Parameter.FromNode(x, options)),
Examples = obj.MaybeMap("examples", Example.FromNode),
RequestBodies = obj.MaybeMap("requestBodies", RequestBody.FromNode),
Headers = obj.MaybeMap("headers", Header.FromNode),
SecuritySchemes = obj.MaybeMap("securitySchemes", SecurityScheme.FromNode),
RequestBodies = obj.MaybeMap("requestBodies", x => RequestBody.FromNode(x, options)),
Headers = obj.MaybeMap("headers", x => Header.FromNode(x, options)),
SecuritySchemes = obj.MaybeMap("securitySchemes", x => SecurityScheme.FromNode(x, options)),
Links = obj.MaybeMap("links", Link.FromNode),
Callbacks = obj.MaybeMap("callbacks", Callback.FromNode),
PathItems = obj.MaybeMap("pathItems", PathItem.FromNode),
Callbacks = obj.MaybeMap("callbacks", x => Callback.FromNode(x, options)),
PathItems = obj.MaybeMap("pathItems", x => PathItem.FromNode(x, options)),
ExtensionData = ExtensionData.FromNode(obj)
};

Expand All @@ -107,7 +107,7 @@ internal static ComponentCollection FromNode(JsonNode? node)
obj.MaybeAddMap("examples", components.Examples, Example.ToNode);
obj.MaybeAddMap("requestBodies", components.RequestBodies, x => RequestBody.ToNode(x, options));
obj.MaybeAddMap("headers", components.Headers, x => Header.ToNode(x, options));
obj.MaybeAddMap("securitySchemes", components.SecuritySchemes, SecurityScheme.ToNode);
obj.MaybeAddMap("securitySchemes", components.SecuritySchemes, x => SecurityScheme.ToNode(x, options));
obj.MaybeAddMap("links", components.Links, Link.ToNode);
obj.MaybeAddMap("callbacks", components.Callbacks, x => Callback.ToNode(x, options));
obj.MaybeAddMap("pathItems", components.PathItems, x => PathItem.ToNode(x, options));
Expand All @@ -116,7 +116,7 @@ internal static ComponentCollection FromNode(JsonNode? node)
return obj;
}

object? IRefTargetContainer.Resolve(Span<string> keys)
object? IRefTargetContainer.Resolve(ReadOnlySpan<string> keys)
{
if (keys.Length == 0) return this;

Expand Down Expand Up @@ -206,7 +206,7 @@ public override ComponentCollection Read(ref Utf8JsonReader reader, Type typeToC
var obj = JsonSerializer.Deserialize<JsonObject>(ref reader, options) ??
throw new JsonException("Expected an object");

return ComponentCollection.FromNode(obj);
return ComponentCollection.FromNode(obj, options);
}

public override void Write(Utf8JsonWriter writer, ComponentCollection value, JsonSerializerOptions options)
Expand Down
Loading

0 comments on commit e960425

Please sign in to comment.