From c17c582a4580cf41bee55b28ce15dd19ad29806b Mon Sep 17 00:00:00 2001 From: glopesdev Date: Thu, 18 Jan 2024 06:00:06 +0000 Subject: [PATCH 1/3] Refactor discriminator assertion tests --- .../DiscriminatorGenerationTests.cs | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs index ee30f10..c13755a 100644 --- a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs +++ b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs @@ -7,6 +7,22 @@ namespace Bonsai.Sgen.Tests [TestClass] public class DiscriminatorGenerationTests { + static void AssertDiscriminatorAttribute(string code, SerializerLibraries serializerLibraries, string discriminatorName) + { + if (serializerLibraries.HasFlag(SerializerLibraries.NewtonsoftJson)) + { + Assert.IsTrue( + code.Contains($"[Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), \"{discriminatorName}\")]"), + message: "Missing JSON discriminator attribute."); + } + if (serializerLibraries.HasFlag(SerializerLibraries.YamlDotNet)) + { + Assert.IsTrue( + code.Contains($"[YamlDiscriminator(\"{discriminatorName}\")]"), + message: "Missing YAML discriminator attribute."); + } + } + [TestMethod] [DataRow(SerializerLibraries.YamlDotNet)] [DataRow(SerializerLibraries.NewtonsoftJson)] @@ -80,18 +96,7 @@ public async Task GenerateFromAnyOfDiscriminatorSchema_SerializerAnnotationsDecl var generator = TestHelper.CreateGenerator(schema, serializerLibraries); var code = generator.GenerateFile(); Assert.IsTrue(code.Contains("[JsonInheritanceAttribute(\"DogType\", typeof(Dog))]")); - if (serializerLibraries.HasFlag(SerializerLibraries.NewtonsoftJson)) - { - Assert.IsTrue( - code.Contains("[Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), \"discriminator\")]"), - message: "Missing JSON discriminator attribute."); - } - if (serializerLibraries.HasFlag(SerializerLibraries.YamlDotNet)) - { - Assert.IsTrue( - code.Contains("[YamlDiscriminator(\"discriminator\")]"), - message: "Missing YAML discriminator attribute."); - } + AssertDiscriminatorAttribute(code, serializerLibraries, "discriminator"); CompilerTestHelper.CompileFromSource(code); } @@ -194,18 +199,7 @@ public async Task GenerateFromOneOfDiscriminatorSchema_SerializerAnnotationsDecl Assert.IsTrue(!code.Contains("public enum DogKind"), "Discriminator property is repeated in derived types."); Assert.IsTrue(code.Contains("List Animals"), "Container array element type does not match base type."); Assert.IsTrue(code.Contains("[JsonInheritanceAttribute(\"Dog\", typeof(Dog))]")); - if (serializerLibraries.HasFlag(SerializerLibraries.NewtonsoftJson)) - { - Assert.IsTrue( - code.Contains("[Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), \"kind\")]"), - message: "Missing JSON discriminator attribute."); - } - if (serializerLibraries.HasFlag(SerializerLibraries.YamlDotNet)) - { - Assert.IsTrue( - code.Contains("[YamlDiscriminator(\"kind\")]"), - message: "Missing YAML discriminator attribute."); - } + AssertDiscriminatorAttribute(code, serializerLibraries, "kind"); CompilerTestHelper.CompileFromSource(code); } } From 68494ac57406b06c602943f7ddf822427d69dd10 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Thu, 18 Jan 2024 14:17:17 +0000 Subject: [PATCH 2/3] Add regression testing for inline discriminators --- .../DiscriminatorGenerationTests.cs | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs index c13755a..3ffe493 100644 --- a/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs +++ b/Bonsai.Sgen.Tests/DiscriminatorGenerationTests.cs @@ -202,5 +202,83 @@ public async Task GenerateFromOneOfDiscriminatorSchema_SerializerAnnotationsDecl AssertDiscriminatorAttribute(code, serializerLibraries, "kind"); CompilerTestHelper.CompileFromSource(code); } + + [TestMethod] + [DataRow(SerializerLibraries.YamlDotNet)] + [DataRow(SerializerLibraries.NewtonsoftJson)] + [DataRow(SerializerLibraries.NewtonsoftJson | SerializerLibraries.YamlDotNet)] + public async Task GenerateFromOneOfDiscriminatorSchemaProperty_SerializerAnnotationsDeclareKnownTypes(SerializerLibraries serializerLibraries) + { + var schema = await JsonSchema.FromJsonAsync(@" +{ + ""$schema"": ""http://json-schema.org/draft-04/schema#"", + ""type"": ""object"", + ""title"": ""Container"", + ""properties"": { + ""Animal"": { + ""x-abstract"": true, + ""discriminator"": { + ""propertyName"": ""kind"", + ""mapping"": { + ""Dog"": ""#/definitions/Dog"", + ""Cat"": ""#/definitions/Cat"" + } + }, + ""oneOf"": [ + { + ""$ref"": ""#/definitions/Dog"" + }, + { + ""$ref"": ""#/definitions/Cat"" + }, + { + ""type"": ""null"" + } + ] + } + }, + ""definitions"": { + ""Dog"": { + ""type"": ""object"", + ""properties"": { + ""kind"": { + ""enum"": [ ""Dog"" ] + }, + ""Bar"": { + ""type"": [ + ""null"", + ""string"" + ] + } + }, + ""required"": [ ""kind"", ""Bar"" ] + }, + ""Cat"": { + ""type"": ""object"", + ""properties"": { + ""kind"": { + ""enum"": [ ""Cat"" ] + }, + ""Baz"": { + ""type"": [ + ""null"", + ""string"" + ] + } + }, + ""required"": [ ""kind"", ""Baz"" ] + } + } +} +"); + var generator = TestHelper.CreateGenerator(schema, serializerLibraries); + var code = generator.GenerateFile(); + Assert.IsTrue(code.Contains("class Dog : Animal"), "Derived types do not inherit from base type."); + Assert.IsTrue(!code.Contains("public enum DogKind"), "Discriminator property is repeated in derived types."); + Assert.IsTrue(code.Contains("Animal Animal"), "Container element type does not match base type."); + Assert.IsTrue(code.Contains("[JsonInheritanceAttribute(\"Dog\", typeof(Dog))]")); + AssertDiscriminatorAttribute(code, serializerLibraries, "kind"); + CompilerTestHelper.CompileFromSource(code); + } } } From 5fa58d24870896e04780616a4fdeda425bc6393a Mon Sep 17 00:00:00 2001 From: glopesdev Date: Thu, 18 Jan 2024 14:20:08 +0000 Subject: [PATCH 3/3] Support inline oneOf discriminated properties --- Bonsai.Sgen/JsonSchemaExtensions.cs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Bonsai.Sgen/JsonSchemaExtensions.cs b/Bonsai.Sgen/JsonSchemaExtensions.cs index 526014e..2bcf3d8 100644 --- a/Bonsai.Sgen/JsonSchemaExtensions.cs +++ b/Bonsai.Sgen/JsonSchemaExtensions.cs @@ -15,17 +15,41 @@ public static JsonSchema WithUniqueDiscriminatorProperties(this JsonSchema schem class DiscriminatorSchemaVisitor : JsonSchemaVisitorBase { - public DiscriminatorSchemaVisitor(object rootObject) + public DiscriminatorSchemaVisitor(JsonSchema rootObject) { RootObject = rootObject; } - public object RootObject { get; } + public JsonSchema RootObject { get; } protected override JsonSchema VisitSchema(JsonSchema schema, string path, string typeNameHint) { if (schema.DiscriminatorObject != null) { + if (schema is JsonSchemaProperty schemaProperty) + { + if (!RootObject.Definitions.ContainsKey(typeNameHint)) + { + var discriminatorSchema = new JsonSchema(); + discriminatorSchema.DiscriminatorObject = schemaProperty.DiscriminatorObject; + discriminatorSchema.IsAbstract = schemaProperty.IsAbstract; + foreach (var derivedSchema in schemaProperty.OneOf) + { + if (derivedSchema.IsNullable(SchemaType.JsonSchema)) + { + continue; + } + + derivedSchema.ActualSchema.AllOf.Add(new JsonSchema { Reference = discriminatorSchema }); + } + RootObject.Definitions.Add(typeNameHint, discriminatorSchema); + } + + schemaProperty.DiscriminatorObject = null; + schemaProperty.IsAbstract = false; + return schema; + } + foreach (var derivedSchema in schema.GetDerivedSchemas(RootObject).Keys) { foreach (var property in derivedSchema.Properties.Keys.ToList())