From da64594dfc73bdd2aae86670861e5863f1ab2510 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 12 Aug 2024 16:53:05 +0300 Subject: [PATCH 01/44] Replace JsonSchema with OpenApiSchema --- .../Formatters/PowerShellFormatter.cs | 276 +++++------------- .../StatsVisitor.cs | 5 +- .../Extensions/OpenApiTypeMapper.cs | 152 +++++----- .../Models/OpenApiComponents.cs | 34 +-- .../Models/OpenApiDocument.cs | 117 ++++---- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 11 +- .../Models/OpenApiMediaType.cs | 9 +- .../Models/OpenApiParameter.cs | 23 +- .../Models/OpenApiResponse.cs | 4 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 17 +- .../Services/OpenApiVisitorBase.cs | 18 +- .../Services/OpenApiWalker.cs | 102 +++---- .../Validations/OpenApiValidator.cs | 5 +- 13 files changed, 263 insertions(+), 510 deletions(-) diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index d8b19f916..fbfb1b716 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -4,12 +4,10 @@ using System.Text; using System.Text.RegularExpressions; using Humanizer; -using Json.Schema; -using Json.Schema.OpenApi; +using Humanizer.Inflections; using Microsoft.OpenApi.Hidi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; -using Microsoft.OpenApi.Extensions; namespace Microsoft.OpenApi.Hidi.Formatters { @@ -17,7 +15,7 @@ internal class PowerShellFormatter : OpenApiVisitorBase { private const string DefaultPutPrefix = ".Update"; private const string PowerShellPutPrefix = ".Set"; - private readonly Stack _schemaLoop = new(); + private readonly Stack _schemaLoop = new(); private static readonly Regex s_oDataCastRegex = new("(.*(?<=[a-z]))\\.(As(?=[A-Z]).*)", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); private static readonly Regex s_hashSuffixRegex = new(@"^[^-]+", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); private static readonly Regex s_oDataRefRegex = new("(?<=[a-z])Ref(?=[A-Z])", RegexOptions.Compiled, TimeSpan.FromSeconds(5)); @@ -26,11 +24,11 @@ static PowerShellFormatter() { // Add singularization exclusions. // Enhancement: Read exclusions from a user provided file. - Humanizer.Inflections.Vocabularies.Default.AddSingular("(drive)s$", "$1"); // drives does not properly singularize to drive. - Humanizer.Inflections.Vocabularies.Default.AddSingular("(data)$", "$1"); // exclude the following from singularization. - Humanizer.Inflections.Vocabularies.Default.AddSingular("(delta)$", "$1"); - Humanizer.Inflections.Vocabularies.Default.AddSingular("(quota)$", "$1"); - Humanizer.Inflections.Vocabularies.Default.AddSingular("(statistics)$", "$1"); + Vocabularies.Default.AddSingular("(drive)s$", "$1"); // drives does not properly singularize to drive. + Vocabularies.Default.AddSingular("(data)$", "$1"); // exclude the following from singularization. + Vocabularies.Default.AddSingular("(delta)$", "$1"); + Vocabularies.Default.AddSingular("(quota)$", "$1"); + Vocabularies.Default.AddSingular("(statistics)$", "$1"); } //FHL task for PS @@ -43,13 +41,13 @@ static PowerShellFormatter() // 5. Fix anyOf and oneOf schema. // 6. Add AdditionalProperties to object schemas. - public override void Visit(ref JsonSchema schema) - { - AddAdditionalPropertiesToSchema(ref schema); - schema = ResolveAnyOfSchema(ref schema); - schema = ResolveOneOfSchema(ref schema); + public override void Visit(OpenApiSchema schema) + { + AddAdditionalPropertiesToSchema(schema); + ResolveAnyOfSchema(schema); + ResolveOneOfSchema(schema); - base.Visit(ref schema); + base.Visit(schema); } public override void Visit(OpenApiPathItem pathItem) @@ -165,237 +163,97 @@ private static IList ResolveFunctionParameters(IList public static class OpenApiTypeMapper { - private static readonly Dictionary> _simpleTypeToJsonSchema = new() + private static readonly Dictionary> _simpleTypeToOpenApiSchema = new() { - [typeof(bool)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Boolean).Build(), - [typeof(byte)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("byte").Build(), - [typeof(int)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build(), - [typeof(uint)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build(), - [typeof(long)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build(), - [typeof(ulong)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build(), - [typeof(float)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float").Build(), - [typeof(double)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), - [typeof(decimal)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), - [typeof(DateTime)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build(), - [typeof(DateTimeOffset)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build(), - [typeof(Guid)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("uuid").Build(), - [typeof(char)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("string").Build(), + [typeof(bool)] = () => new() { Type = "boolean" }, + [typeof(byte)] = () => new() { Type = "string", Format = "byte" }, + [typeof(int)] = () => new() { Type = "integer", Format = "int32" }, + [typeof(uint)] = () => new() { Type = "integer", Format = "int32" }, + [typeof(long)] = () => new() { Type = "integer", Format = "int64" }, + [typeof(ulong)] = () => new() { Type = "integer", Format = "int64" }, + [typeof(float)] = () => new() { Type = "number", Format = "float" }, + [typeof(double)] = () => new() { Type = "number", Format = "double" }, + [typeof(decimal)] = () => new() { Type = "number", Format = "double" }, + [typeof(DateTime)] = () => new() { Type = "string", Format = "date-time" }, + [typeof(DateTimeOffset)] = () => new() { Type = "string", Format = "date-time" }, + [typeof(Guid)] = () => new() { Type = "string", Format = "uuid" }, + [typeof(char)] = () => new() { Type = "string" }, // Nullable types - [typeof(bool?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Boolean).Build(), - [typeof(byte?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.String).Format("byte").Build(), - [typeof(int?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("int32").Build(), - [typeof(uint?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("int32").Build(), - [typeof(long?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("int64").Build(), - [typeof(ulong?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("int64").Build(), - [typeof(float?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("float").Build(), - [typeof(double?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Number).Format("double").Build(), - [typeof(decimal?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.Integer).Format("double").Build(), - [typeof(DateTime?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.String).Format("date-time").Build(), - [typeof(DateTimeOffset?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.String).Format("date-time").Build(), - [typeof(Guid?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.String).Format("string").Build(), - [typeof(char?)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Null | SchemaValueType.String).Format("string").Build(), - - [typeof(Uri)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Format("uri").Build(), // Uri is treated as simple string - [typeof(string)] = () => new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), - [typeof(object)] = () => new JsonSchemaBuilder().Type(SchemaValueType.Object).Build(), + [typeof(bool?)] = () => new() { Type = "boolean", Nullable = true }, + [typeof(byte?)] = () => new() { Type = "string", Format = "byte", Nullable = true }, + [typeof(int?)] = () => new() { Type = "integer", Format = "int32", Nullable = true }, + [typeof(uint?)] = () => new() { Type = "integer", Format = "int32", Nullable = true }, + [typeof(long?)] = () => new() { Type = "integer", Format = "int64", Nullable = true }, + [typeof(ulong?)] = () => new() { Type = "integer", Format = "int64", Nullable = true }, + [typeof(float?)] = () => new() { Type = "number", Format = "float", Nullable = true }, + [typeof(double?)] = () => new() { Type = "number", Format = "double", Nullable = true }, + [typeof(decimal?)] = () => new() { Type = "number", Format = "double", Nullable = true }, + [typeof(DateTime?)] = () => new() { Type = "string", Format = "date-time", Nullable = true }, + [typeof(DateTimeOffset?)] = () => new() { Type = "string", Format = "date-time", Nullable = true }, + [typeof(Guid?)] = () => new() { Type = "string", Format = "uuid", Nullable = true }, + [typeof(char?)] = () => new() { Type = "string", Nullable = true }, + [typeof(Uri)] = () => new() { Type = "string", Format = "uri" }, // Uri is treated as simple string + [typeof(string)] = () => new() { Type = "string" }, + [typeof(object)] = () => new() { Type = "object" } }; /// @@ -71,16 +70,16 @@ public static class OpenApiTypeMapper /// password string password Used to hint UIs the input needs to be obscured. /// If the type is not recognized as "simple", System.String will be returned. /// - public static JsonSchema MapTypeToJsonPrimitiveType(this Type type) + public static OpenApiSchema MapTypeToOpenApiPrimitiveType(this Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } - return _simpleTypeToJsonSchema.TryGetValue(type, out var result) + return _simpleTypeToOpenApiSchema.TryGetValue(type, out var result) ? result() - : new JsonSchemaBuilder().Type(SchemaValueType.String).Build(); + : new() { Type = "string" }; } /// @@ -89,66 +88,47 @@ public static JsonSchema MapTypeToJsonPrimitiveType(this Type type) /// The OpenApi data type /// The simple type /// - public static Type MapJsonSchemaValueTypeToSimpleType(this JsonSchema schema) + public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema) { if (schema == null) { throw new ArgumentNullException(nameof(schema)); } - var type = schema.GetJsonType(); - var format = schema.GetFormat().Key; - var result = (type, format) switch + var type = (schema.Type?.ToString().ToLowerInvariant(), schema.Format?.ToLowerInvariant(), schema.Nullable) switch { - (SchemaValueType.Boolean, null) => typeof(bool), - (SchemaValueType.Integer, "int32") => typeof(int), - (SchemaValueType.Integer, "int64") => typeof(long), - (SchemaValueType.Number, "float") => typeof(float), - (SchemaValueType.Number, "double") => typeof(double), - (SchemaValueType.Number, "decimal") => typeof(decimal), - (SchemaValueType.String, "byte") => typeof(byte), - (SchemaValueType.String, "date-time") => typeof(DateTimeOffset), - (SchemaValueType.String, "uuid") => typeof(Guid), - (SchemaValueType.String, "duration") => typeof(TimeSpan), - (SchemaValueType.String, "char") => typeof(char), - (SchemaValueType.String, null) => typeof(string), - (SchemaValueType.Object, null) => typeof(object), - (SchemaValueType.String, "uri") => typeof(Uri), - (SchemaValueType.Integer or null, "int32") => typeof(int?), - (SchemaValueType.Integer or null, "int64") => typeof(long?), - (SchemaValueType.Number or null, "float") => typeof(float?), - (SchemaValueType.Number or null, "double") => typeof(double?), - (SchemaValueType.Number or null, "decimal") => typeof(decimal?), - (SchemaValueType.String or null, "byte") => typeof(byte?), - (SchemaValueType.String or null, "date-time") => typeof(DateTimeOffset?), - (SchemaValueType.String or null, "uuid") => typeof(Guid?), - (SchemaValueType.String or null, "char") => typeof(char?), - (SchemaValueType.Boolean or null, null) => typeof(bool?), + ("boolean", null, false) => typeof(bool), + ("integer", "int32", false) => typeof(int), + ("integer", "int64", false) => typeof(long), + ("integer", null, false) => typeof(int), + ("number", "float", false) => typeof(float), + ("number", "double", false) => typeof(double), + ("number", "decimal", false) => typeof(decimal), + ("number", null, false) => typeof(double), + ("string", "byte", false) => typeof(byte), + ("string", "date-time", false) => typeof(DateTimeOffset), + ("string", "uuid", false) => typeof(Guid), + ("string", "duration", false) => typeof(TimeSpan), + ("string", "char", false) => typeof(char), + ("string", null, false) => typeof(string), + ("object", null, false) => typeof(object), + ("string", "uri", false) => typeof(Uri), + ("integer", "int32", true) => typeof(int?), + ("integer", "int64", true) => typeof(long?), + ("integer", null, true) => typeof(int?), + ("number", "float", true) => typeof(float?), + ("number", "double", true) => typeof(double?), + ("number", null, true) => typeof(double?), + ("number", "decimal", true) => typeof(decimal?), + ("string", "byte", true) => typeof(byte?), + ("string", "date-time", true) => typeof(DateTimeOffset?), + ("string", "uuid", true) => typeof(Guid?), + ("string", "char", true) => typeof(char?), + ("boolean", null, true) => typeof(bool?), _ => typeof(string), }; - return result; - } - - /// - /// Converts the Schema value type to its string equivalent - /// - /// - /// - /// - internal static string ConvertSchemaValueTypeToString(SchemaValueType value) - { - return value switch - { - SchemaValueType.String => "string", - SchemaValueType.Number => "number", - SchemaValueType.Integer => "integer", - SchemaValueType.Boolean => "boolean", - SchemaValueType.Array => "array", - SchemaValueType.Object => "object", - SchemaValueType.Null => "null", - _ => throw new NotSupportedException(), - }; + return type; } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 4af4248ab..8d2f36883 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -17,9 +16,9 @@ namespace Microsoft.OpenApi.Models public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible { /// - /// An object to hold reusable Objects. + /// An object to hold reusable Objects. /// - public IDictionary Schemas { get; set; } = new Dictionary(); + public IDictionary Schemas { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. @@ -84,7 +83,7 @@ public OpenApiComponents() { } /// public OpenApiComponents(OpenApiComponents components) { - Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; + Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; Parameters = components?.Parameters != null ? new Dictionary(components.Parameters) : null; Examples = components?.Examples != null ? new Dictionary(components.Examples) : null; @@ -109,7 +108,7 @@ public void SerializeAsV31(IOpenApiWriter writer) // however if they have cycles, then we will need a component rendered if (writer.GetSettings().InlineLocalReferences) { - RenderComponents(writer, OpenApiSpecVersion.OpenApi3_1); + RenderComponents(writer, (writer, element) => element.SerializeAsV31(writer)); return; } @@ -149,7 +148,7 @@ public void SerializeAsV3(IOpenApiWriter writer) // however if they have cycles, then we will need a component rendered if (writer.GetSettings().InlineLocalReferences) { - RenderComponents(writer, OpenApiSpecVersion.OpenApi3_0); + RenderComponents(writer, (writer, element) => element.SerializeAsV3(writer)); return; } @@ -171,17 +170,16 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteOptionalMap( OpenApiConstants.Schemas, Schemas, - (w, key, s) => + (w, key, component) => { - var reference = s.GetRef(); - if (reference != null && - reference.OriginalString.Split('/').Last().Equals(key)) + if (component.Reference is { Type: ReferenceType.Schema } && + component.Reference.Id == key) { - w.WriteJsonSchemaWithoutReference(w, s, version); + component.SerializeAsV3WithoutReference(w); } else { - w.WriteJsonSchema(s, version); + component.SerializeAsV3(w); } }); @@ -335,16 +333,16 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteEndObject(); } - private void RenderComponents(IOpenApiWriter writer, OpenApiSpecVersion version) + private void RenderComponents(IOpenApiWriter writer, Action callback) { var loops = writer.GetSettings().LoopDetector.Loops; writer.WriteStartObject(); - if (loops.TryGetValue(typeof(JsonSchema), out List schemas)) + if (loops.TryGetValue(typeof(OpenApiSchema), out List schemas)) { - writer.WriteOptionalMap( - OpenApiConstants.Schemas, - Schemas, - (w, key, s) => { w.WriteJsonSchema(s, version); }); + var openApiSchemas = schemas.Cast().Distinct().ToList() + .ToDictionary(k => k.Reference.Id); + + writer.WriteOptionalMap(OpenApiConstants.Schemas, Schemas, callback); } writer.WriteEndObject(); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 64dc1d2d4..aa060baf9 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -9,7 +9,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Reader; @@ -21,7 +20,7 @@ namespace Microsoft.OpenApi.Models /// /// Describes an OpenAPI object (OpenAPI document). See: https://swagger.io/specification /// - public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible, IBaseDocument + public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible { /// /// Related workspace containing OpenApiDocuments that are referenced in this document @@ -240,10 +239,10 @@ public void SerializeAsV2(IOpenApiWriter writer) { var loops = writer.GetSettings().LoopDetector.Loops; - if (loops.TryGetValue(typeof(JsonSchema), out List schemas)) + if (loops.TryGetValue(typeof(OpenApiSchema), out List schemas)) { - var openApiSchemas = schemas.Cast().Distinct() - .ToDictionary(k => k.GetRef().ToString()); + var openApiSchemas = schemas.Cast().Distinct().ToList() + .ToDictionary(k => k.Reference.Id); foreach (var schema in openApiSchemas.Values.ToList()) { @@ -253,7 +252,7 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteOptionalMap( OpenApiConstants.Definitions, openApiSchemas, - (w, key, s) => w.WriteJsonSchema(s, OpenApiSpecVersion.OpenApi2_0)); + (w, _, component) => component.SerializeAsV2WithoutReference(w)); } } else @@ -261,25 +260,21 @@ public void SerializeAsV2(IOpenApiWriter writer) // Serialize each referenceable object as full object without reference if the reference in the object points to itself. // If the reference exists but points to other objects, the object is serialized to just that reference. // definitions - if (Components?.Schemas != null) - { - writer.WriteOptionalMap( - OpenApiConstants.Definitions, - Components?.Schemas, - (w, key, s) => + writer.WriteOptionalMap( + OpenApiConstants.Definitions, + Components?.Schemas, + (w, key, component) => + { + if (component.Reference is { Type: ReferenceType.Schema } && + component.Reference.Id == key) { - var reference = s.GetRef(); - if (reference != null && - reference.OriginalString.Split('/').Last().Equals(key)) - { - w.WriteJsonSchemaWithoutReference(w, s, OpenApiSpecVersion.OpenApi2_0); - } - else - { - w.WriteJsonSchema(s, OpenApiSpecVersion.OpenApi2_0); - } - }); - } + component.SerializeAsV2WithoutReference(w); + } + else + { + component.SerializeAsV2(w); + } + }); // parameters var parameters = Components?.Parameters != null @@ -477,33 +472,6 @@ public IOpenApiReferenceable ResolveReference(OpenApiReference reference) return ResolveReference(reference, false); } - /// - /// Resolves JsonSchema refs - /// - /// - /// A JsonSchema ref. - public JsonSchema ResolveJsonSchemaReference(Uri referenceUri) - { - const char pound = '#'; - string uriLocation; - int poundIndex = referenceUri.OriginalString.IndexOf(pound); - - if (poundIndex > 0) - { - // External reference, ex: ./TodoReference.yaml#/components/schemas/todo - string externalUri = referenceUri.OriginalString.Split(pound).First(); - Uri externalDocId = Workspace.GetDocumentId(externalUri); - string relativePath = referenceUri.OriginalString.Split(pound).Last(); - uriLocation = externalDocId + relativePath; - } - else - { - uriLocation = BaseUri + referenceUri.ToString().TrimStart(pound); - } - - return (JsonSchema)Workspace.ResolveReference(uriLocation); - } - /// /// Takes in an OpenApi document instance and generates its hash value /// @@ -666,31 +634,48 @@ public static ReadResult Parse(string input, { return OpenApiModelFactory.Parse(input, format, settings); } - - /// - /// - /// - /// - /// - /// - /// - public JsonSchema FindSubschema(Json.Pointer.JsonPointer pointer, EvaluationOptions options) - { - var locationUri = string.Concat(BaseUri, pointer); - return (JsonSchema)Workspace.ResolveReference(locationUri); - } } internal class FindSchemaReferences : OpenApiVisitorBase { - private Dictionary Schemas; + private Dictionary Schemas; - public static void ResolveSchemas(OpenApiComponents components, Dictionary schemas) + public static void ResolveSchemas(OpenApiComponents components, Dictionary schemas) { var visitor = new FindSchemaReferences(); visitor.Schemas = schemas; var walker = new OpenApiWalker(visitor); walker.Walk(components); } + + public override void Visit(IOpenApiReferenceable referenceable) + { + switch (referenceable) + { + case OpenApiSchema schema: + if (!Schemas.ContainsKey(schema.Reference.Id)) + { + Schemas.Add(schema.Reference.Id, schema); + } + break; + + default: + break; + } + base.Visit(referenceable); + } + + public override void Visit(OpenApiSchema schema) + { + // This is needed to handle schemas used in Responses in components + if (schema.Reference != null) + { + if (!Schemas.ContainsKey(schema.Reference.Id)) + { + Schemas.Add(schema.Reference.Id, schema); + } + } + base.Visit(schema); + } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index d2bb6267c..799d4314a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; @@ -18,7 +17,7 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiHeader : IOpenApiReferenceable, IOpenApiExtensible { - private JsonSchema _schema; + private OpenApiSchema _schema; /// /// Indicates if object is populated with data or is just a reference to the data @@ -69,7 +68,7 @@ public class OpenApiHeader : IOpenApiReferenceable, IOpenApiExtensible /// /// The schema defining the type used for the request body. /// - public virtual JsonSchema Schema + public virtual OpenApiSchema Schema { get => _schema; set => _schema = value; @@ -114,7 +113,7 @@ public OpenApiHeader(OpenApiHeader header) Style = header?.Style ?? Style; Explode = header?.Explode ?? Explode; AllowReserved = header?.AllowReserved ?? AllowReserved; - Schema = header?.Schema != null ? JsonNodeCloneHelper.CloneJsonSchema(header.Schema) : null; + Schema = header?.Schema != null ? new(header.Schema) : null; Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; @@ -193,7 +192,7 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); // schema - writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, (w, s) => writer.WriteJsonSchema(s, version)); + writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, callback); // example writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, s) => w.WriteAny(s)); @@ -250,7 +249,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); // schema - SchemaSerializerHelper.WriteAsItemsProperties(Schema, writer, Extensions, OpenApiSpecVersion.OpenApi2_0); + Schema.WriteAsItemsProperties(writer); // example writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, s) => w.WriteAny(s)); diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index cb97f3185..8c0ecd4ec 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; @@ -16,12 +15,12 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible { - private JsonSchema _schema; + private OpenApiSchema _schema; /// /// The schema defining the type used for the request body. /// - public virtual JsonSchema Schema + public virtual OpenApiSchema Schema { get => _schema; set => _schema = value; @@ -62,7 +61,7 @@ public OpenApiMediaType() { } /// public OpenApiMediaType(OpenApiMediaType mediaType) { - Schema = mediaType?.Schema != null ? JsonNodeCloneHelper.CloneJsonSchema(mediaType.Schema) : null; + Schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; Encoding = mediaType?.Encoding != null ? new Dictionary(mediaType.Encoding) : null; @@ -96,7 +95,7 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version writer.WriteStartObject(); // schema - writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, (w, s) => writer.WriteJsonSchema(s, version)); + writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, callback); // example writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, e) => w.WriteAny(e)); diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index a7ad97b2d..a169f786c 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using System.Linq; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; @@ -20,7 +19,7 @@ public class OpenApiParameter : IOpenApiReferenceable, IOpenApiExtensible { private bool? _explode; private ParameterStyle? _style; - private JsonSchema _schema; + private OpenApiSchema _schema; /// /// Indicates if object is populated with data or is just a reference to the data @@ -108,7 +107,7 @@ public virtual bool Explode /// /// The schema defining the type used for the parameter. /// - public virtual JsonSchema Schema + public virtual OpenApiSchema Schema { get => _schema; set => _schema = value; @@ -168,7 +167,7 @@ public OpenApiParameter(OpenApiParameter parameter) Style = parameter?.Style ?? Style; Explode = parameter?.Explode ?? Explode; AllowReserved = parameter?.AllowReserved ?? AllowReserved; - Schema = parameter?.Schema != null ? JsonNodeCloneHelper.CloneJsonSchema(parameter.Schema) : null; + Schema = parameter?.Schema != null ? new(parameter.Schema) : null; Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null; Example = parameter?.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; Content = parameter?.Content != null ? new Dictionary(parameter.Content) : null; @@ -258,11 +257,7 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false); // schema - if (Schema != null) - { - writer.WritePropertyName(OpenApiConstants.Schema); - writer.WriteJsonSchema(Schema, version); - } + writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, callback); // example writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, s) => w.WriteAny(s)); @@ -328,11 +323,11 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) // schema if (this is OpenApiBodyParameter) { - writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, (w, s) => writer.WriteJsonSchema(s, OpenApiSpecVersion.OpenApi2_0)); + writer.WriteOptionalObject(OpenApiConstants.Schema, Schema, (w, s) => s.SerializeAsV2(w)); } // In V2 parameter's type can't be a reference to a custom object schema or can't be of type object // So in that case map the type as string. - else if (Schema?.GetJsonType() == SchemaValueType.Object) + else if (Schema?.UnresolvedReference == true || "object".Equals(Schema?.Type.ToString(), StringComparison.OrdinalIgnoreCase)) { writer.WriteProperty(OpenApiConstants.Type, "string"); } @@ -357,8 +352,8 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) // multipleOf if (Schema != null) { - SchemaSerializerHelper.WriteAsItemsProperties(Schema, writer, Extensions, OpenApiSpecVersion.OpenApi2_0); - var extensions = Schema.GetExtensions(); + Schema.WriteAsItemsProperties(writer); + var extensions = Schema.Extensions; if (extensions != null) { foreach (var key in extensions.Keys) @@ -373,7 +368,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) // allowEmptyValue writer.WriteProperty(OpenApiConstants.AllowEmptyValue, AllowEmptyValue, false); - if (this.In == ParameterLocation.Query && SchemaValueType.Array.Equals(Schema?.GetJsonType())) + if (this.In == ParameterLocation.Query && "array".Equals(Schema?.Type.ToString(), StringComparison.OrdinalIgnoreCase)) { if (this.Style == ParameterStyle.Form && this.Explode == true) { diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index e0785fe67..83f3e19e3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -168,7 +168,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) if (mediatype.Value != null) { // schema - writer.WriteOptionalObject(OpenApiConstants.Schema, mediatype.Value.Schema, (w, s) => writer.WriteJsonSchema(s, OpenApiSpecVersion.OpenApi2_0)); + writer.WriteOptionalObject(OpenApiConstants.Schema, mediatype.Value.Schema, (w, s) => s.SerializeAsV2(w)); // examples if (Content.Values.Any(m => m.Example != null)) diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index fbcbf6a0a..a402ce9ca 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -189,7 +188,7 @@ private static void MakeServers(IList servers, ParsingContext con private static string BuildUrl(string scheme, string host, string basePath) { - if (String.IsNullOrEmpty(scheme) && !String.IsNullOrEmpty(host)) + if (string.IsNullOrEmpty(scheme) && !string.IsNullOrEmpty(host)) { host = "//" + host; // The double slash prefix creates a relative url where the scheme is defined by the BaseUrl } @@ -301,20 +300,6 @@ private static bool IsHostValid(string host) var hostPart = host.Split(':').First(); return Uri.CheckHostName(hostPart) != UriHostNameType.Unknown; } - - private static void RegisterComponentsSchemasInGlobalRegistry(IDictionary schemas) - { - if (schemas == null) - { - return; - } - - foreach (var schema in schemas) - { - var refUri = new Uri(OpenApiConstants.V2ReferenceUri + schema.Key); - SchemaRegistry.Global.Register(refUri, schema.Value); - } - } } internal class RequestBodyReferenceFixer : OpenApiVisitorBase diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index 3e04e5eb8..c731d4d8b 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -229,22 +228,9 @@ public virtual void Visit(OpenApiExternalDocs externalDocs) } /// - /// Visits + /// Visits /// - public virtual void Visit(ref JsonSchema schema) - { - } - - /// - /// Visits - /// - /// - public virtual void Visit(IBaseDocument document) { } - - /// - /// Visits - /// - public virtual void Visit(IReadOnlyCollection schema) + public virtual void Visit(OpenApiSchema schema) { } diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index b934074f9..c422007a7 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -3,8 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -20,8 +18,8 @@ public class OpenApiWalker { private OpenApiDocument _hostDocument; private readonly OpenApiVisitorBase _visitor; - private readonly Stack _schemaLoop = new Stack(); - private readonly Stack _pathItemLoop = new Stack(); + private readonly Stack _schemaLoop = new(); + private readonly Stack _pathItemLoop = new(); /// /// Initializes the class. @@ -130,7 +128,7 @@ internal void Walk(OpenApiComponents components) { foreach (var item in components.Schemas) { - Walk(item.Key, () => components.Schemas[item.Key] = Walk(item.Value, isComponent: true)); + Walk(item.Key, () => Walk(item.Value, isComponent: true)); } } }); @@ -790,7 +788,7 @@ internal void Walk(OpenApiMediaType mediaType) _visitor.Visit(mediaType); Walk(OpenApiConstants.Example, () => Walk(mediaType.Examples)); - Walk(OpenApiConstants.Schema, () => mediaType.Schema = Walk(mediaType.Schema)); + Walk(OpenApiConstants.Schema, () => Walk(mediaType.Schema)); Walk(OpenApiConstants.Encoding, () => Walk(mediaType.Encoding)); Walk(mediaType as IOpenApiExtensible); } @@ -838,104 +836,74 @@ internal void Walk(OpenApiEncoding encoding) } /// - /// Visits and child objects + /// Visits and child objects /// - internal JsonSchema Walk(JsonSchema schema, bool isComponent = false) + internal void Walk(OpenApiSchema schema, bool isComponent = false) { - if (schema == null - || ProcessSchemaAsReference(schema, isComponent)) + if (schema == null || ProcessAsReference(schema, isComponent)) { - return schema; + return; } if (_schemaLoop.Contains(schema)) { - return schema; // Loop detected, this schema has already been walked. + return; // Loop detected, this schema has already been walked. } else { _schemaLoop.Push(schema); } - _visitor.Visit(ref schema); + _visitor.Visit(schema); - if (schema.GetItems() != null) + if (schema.Items != null) { - Walk("items", () => Walk(schema.GetItems())); + Walk("items", () => Walk(schema.Items)); } - if (schema.GetNot() != null) + if (schema.Not != null) { - Walk("not", () => Walk(schema.GetNot())); + Walk("not", () => Walk(schema.Not)); } - if (schema.GetAllOf() != null) + if (schema.AllOf != null) { - Walk("allOf", () => Walk(schema.GetAllOf())); + Walk("allOf", () => Walk(schema.AllOf)); } - if (schema.GetAnyOf() != null) + if (schema.AnyOf != null) { - Walk("anyOf", () => Walk(schema.GetAnyOf())); + Walk("anyOf", () => Walk(schema.AnyOf)); } - if (schema.GetOneOf() != null) + if (schema.OneOf != null) { - Walk("oneOf", () => Walk(schema.GetOneOf())); + Walk("oneOf", () => Walk(schema.OneOf)); } - if (schema.GetProperties() != null) + if (schema.Properties != null) { Walk("properties", () => { - var props = new Dictionary(); - var builder = new JsonSchemaBuilder(); - foreach(var keyword in schema.Keywords) - { - builder.Add(keyword); - } - - foreach (var item in schema.GetProperties()) + foreach (var item in schema.Properties) { - var key = item.Key; - JsonSchema newSchema = null; - Walk(key, () => newSchema = Walk(item.Value)); - props.Add(key, newSchema); - schema = builder.Properties(props); - if (_hostDocument != null) - { - schema.BaseUri = _hostDocument.BaseUri; - } + Walk(item.Key, () => Walk(item.Value)); } }); } - if (schema.GetAdditionalProperties() != null) + if (schema.AdditionalProperties != null) { - Walk("additionalProperties", () => Walk(schema.GetAdditionalProperties())); + Walk("additionalProperties", () => Walk(schema.AdditionalProperties)); } - Walk(OpenApiConstants.ExternalDocs, () => Walk(schema.GetExternalDocs())); + Walk(OpenApiConstants.ExternalDocs, () => Walk(schema.ExternalDocs)); Walk(schema as IOpenApiExtensible); _schemaLoop.Pop(); - return schema; } - internal void Walk(IReadOnlyCollection schemaCollection, bool isComponent = false) - { - if (schemaCollection is null) - { - return; - } - - _visitor.Visit(schemaCollection); - foreach (var schema in schemaCollection) - { - Walk(schema); - } - } /// /// Visits dictionary of @@ -1016,9 +984,9 @@ internal void Walk(IList examples) } /// - /// Visits a list of and child objects + /// Visits a list of and child objects /// - internal void Walk(IList schemas) + internal void Walk(IList schemas) { if (schemas == null) { @@ -1211,7 +1179,7 @@ internal void Walk(IOpenApiElement element) case OpenApiPaths e: Walk(e); break; case OpenApiRequestBody e: Walk(e); break; case OpenApiResponse e: Walk(e); break; - case JsonSchema e: Walk(e); break; + case OpenApiSchema e: Walk(e); break; case OpenApiSecurityRequirement e: Walk(e); break; case OpenApiSecurityScheme e: Walk(e); break; case OpenApiServer e: Walk(e); break; @@ -1235,15 +1203,17 @@ private void Walk(string context, Action walk) _visitor.Exit(); } - private bool ProcessSchemaAsReference(IBaseDocument baseDocument, bool isComponent = false) + /// + /// Identify if an element is just a reference to a component, or an actual component + /// + private bool ProcessAsReference(IOpenApiReferenceable referenceable, bool isComponent = false) { - var schema = baseDocument as JsonSchema; - var isReference = schema?.GetRef() != null && !isComponent; + var isReference = referenceable.Reference != null && + (!isComponent || referenceable.UnresolvedReference); if (isReference) { - _visitor.Visit(baseDocument); + Walk(referenceable); } - return isReference; } } diff --git a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs index 73c473d61..6908e58bf 100644 --- a/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs +++ b/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -147,10 +146,10 @@ public void AddWarning(OpenApiValidatorWarning warning) public override void Visit(OpenApiParameter item) => Validate(item); /// - /// Execute validation rules against an + /// Execute validation rules against an /// /// The object to be validated - public override void Visit(ref JsonSchema item) => Validate(item); + public override void Visit(OpenApiSchema item) => Validate(item); /// /// Execute validation rules against an From 6cd1db69931010040cebba91bfa0487d63719484 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 12 Aug 2024 16:54:56 +0300 Subject: [PATCH 02/44] Uninstall JSON schema library --- .../Microsoft.OpenApi.Readers.csproj | 2 -- src/Microsoft.OpenApi/Microsoft.OpenApi.csproj | 4 ---- .../Microsoft.OpenApi.Readers.Tests.csproj | 2 -- 3 files changed, 8 deletions(-) diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj index 4497af0ba..b9c5dff10 100644 --- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj +++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj @@ -24,8 +24,6 @@ - - diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj index 5e732d80a..a4cc8e4b3 100644 --- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj +++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj @@ -21,10 +21,6 @@ true - - - - diff --git a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj index 9b2cdfc19..b169ea016 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj +++ b/test/Microsoft.OpenApi.Readers.Tests/Microsoft.OpenApi.Readers.Tests.csproj @@ -15,8 +15,6 @@ - - From 66a033c5ee67cf574b4a4708ccfcadc9e2db9aa4 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 12 Aug 2024 16:56:01 +0300 Subject: [PATCH 03/44] Code cleanup --- .../Helpers/SchemaSerializerHelper.cs | 112 --------- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 66 ++++++ .../Services/OpenApiWorkspace.cs | 25 +- .../Writers/IOpenApiWriter.cs | 30 +-- .../Writers/OpenApiWriterBase.cs | 215 ------------------ .../Writers/OpenApiWriterExtensions.cs | 20 -- 6 files changed, 70 insertions(+), 398 deletions(-) delete mode 100644 src/Microsoft.OpenApi/Helpers/SchemaSerializerHelper.cs diff --git a/src/Microsoft.OpenApi/Helpers/SchemaSerializerHelper.cs b/src/Microsoft.OpenApi/Helpers/SchemaSerializerHelper.cs deleted file mode 100644 index 62a677432..000000000 --- a/src/Microsoft.OpenApi/Helpers/SchemaSerializerHelper.cs +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Linq; -using Json.Schema; -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Writers; - -namespace Microsoft.OpenApi.Helpers -{ - internal static class SchemaSerializerHelper - { - internal static void WriteAsItemsProperties(JsonSchema schema, - IOpenApiWriter writer, - IDictionary extensions, - OpenApiSpecVersion version) - { - Utils.CheckArgumentNull(writer); - // type - if (schema.GetJsonType() != null) - { - writer.WritePropertyName(OpenApiConstants.Type); - var type = schema.GetJsonType().Value; - writer.WriteValue(OpenApiTypeMapper.ConvertSchemaValueTypeToString(type)); - } - - // format - var format = schema.GetFormat()?.Key; - if (string.IsNullOrEmpty(format)) - { - format = RetrieveFormatFromNestedSchema(schema.GetAllOf()) ?? RetrieveFormatFromNestedSchema(schema.GetOneOf()) - ?? RetrieveFormatFromNestedSchema(schema.GetAnyOf()); - } - writer.WriteProperty(OpenApiConstants.Format, format); - - // items - writer.WriteOptionalObject(OpenApiConstants.Items, schema.GetItems(), - (w, s) => w.WriteJsonSchema(s, version)); - - // collectionFormat - // We need information from style in parameter to populate this. - // The best effort we can make is to pull this information from the first parameter - // that leverages this schema. However, that in itself may not be as simple - // as the schema directly under parameter might be referencing one in the Components, - // so we will need to do a full scan of the object before we can write the value for - // this property. This is not supported yet, so we will skip this property at the moment. - - // default - if (schema.GetDefault() != null) - { - writer.WritePropertyName(OpenApiConstants.Default); - writer.WriteValue(schema.GetDefault()); - } - - // maximum - writer.WriteProperty(OpenApiConstants.Maximum, schema.GetMaximum()); - - // exclusiveMaximum - writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, schema.GetExclusiveMaximum()); - - // minimum - writer.WriteProperty(OpenApiConstants.Minimum, schema.GetMinimum()); - - // exclusiveMinimum - writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, schema.GetExclusiveMinimum()); - - // maxLength - writer.WriteProperty(OpenApiConstants.MaxLength, schema.GetMaxLength()); - - // minLength - writer.WriteProperty(OpenApiConstants.MinLength, schema.GetMinLength()); - - // pattern - writer.WriteProperty(OpenApiConstants.Pattern, schema.GetPattern()?.ToString()); - - // maxItems - writer.WriteProperty(OpenApiConstants.MaxItems, schema.GetMaxItems()); - - // minItems - writer.WriteProperty(OpenApiConstants.MinItems, schema.GetMinItems()); - - // enum - if (schema.GetEnum() != null) - { - writer.WritePropertyName(OpenApiConstants.Enum); - writer.WriteValue(schema.GetEnum()); - } - - // multipleOf - writer.WriteProperty(OpenApiConstants.MultipleOf, schema.GetMultipleOf()); - - // extensions - writer.WriteExtensions(extensions, OpenApiSpecVersion.OpenApi2_0); - } - - private static string RetrieveFormatFromNestedSchema(IReadOnlyCollection schema) - { - if (schema != null) - { - return schema - .Where(item => !string.IsNullOrEmpty(item.GetFormat()?.Key)) - .Select(item => item.GetFormat().Key) - .FirstOrDefault(); - } - - return null; - } - } -} diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index af9b5e037..c194a297b 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -624,6 +624,72 @@ internal void SerializeAsV2WithoutReference( writer.WriteEndObject(); } + internal void WriteAsItemsProperties(IOpenApiWriter writer) + { + // type + writer.WriteProperty(OpenApiConstants.Type, (string)Type); + + // format + if (string.IsNullOrEmpty(Format)) + { + Format = AllOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? + AnyOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format ?? + OneOf?.FirstOrDefault(static x => !string.IsNullOrEmpty(x.Format))?.Format; + } + + writer.WriteProperty(OpenApiConstants.Format, Format); + + // items + writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w)); + + // collectionFormat + // We need information from style in parameter to populate this. + // The best effort we can make is to pull this information from the first parameter + // that leverages this schema. However, that in itself may not be as simple + // as the schema directly under parameter might be referencing one in the Components, + // so we will need to do a full scan of the object before we can write the value for + // this property. This is not supported yet, so we will skip this property at the moment. + + // default + writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d)); + + // maximum + writer.WriteProperty(OpenApiConstants.Maximum, Maximum); + + // exclusiveMaximum + writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, ExclusiveMaximum); + + // minimum + writer.WriteProperty(OpenApiConstants.Minimum, Minimum); + + // exclusiveMinimum + writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, ExclusiveMinimum); + + // maxLength + writer.WriteProperty(OpenApiConstants.MaxLength, MaxLength); + + // minLength + writer.WriteProperty(OpenApiConstants.MinLength, MinLength); + + // pattern + writer.WriteProperty(OpenApiConstants.Pattern, Pattern); + + // maxItems + writer.WriteProperty(OpenApiConstants.MaxItems, MaxItems); + + // minItems + writer.WriteProperty(OpenApiConstants.MinItems, MinItems); + + // enum + writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s))); + + // multipleOf + writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf); + + // extensions + writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi2_0); + } + internal void WriteAsSchemaProperties( IOpenApiWriter writer, ISet parentRequiredProperties, diff --git a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs index f8ca95a13..319a5d63f 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -17,7 +16,6 @@ public class OpenApiWorkspace { private readonly Dictionary _documentsIdRegistry = new(); private readonly Dictionary _artifactsRegistry = new(); - private readonly Dictionary _jsonSchemaRegistry = new(); private readonly Dictionary _IOpenApiReferenceableRegistry = new(); /// @@ -53,7 +51,7 @@ public OpenApiWorkspace(OpenApiWorkspace workspace) { } /// public int ComponentsCount() { - return _IOpenApiReferenceableRegistry.Count + _jsonSchemaRegistry.Count + _artifactsRegistry.Count; + return _IOpenApiReferenceableRegistry.Count + _artifactsRegistry.Count; } /// @@ -65,15 +63,7 @@ public int ComponentsCount() public bool RegisterComponent(string location, T component) { var uri = ToLocationUrl(location); - if (component is JsonSchema schema) - { - if (!_jsonSchemaRegistry.ContainsKey(uri)) - { - _jsonSchemaRegistry[uri] = schema; - return true; - } - } - else if (component is IOpenApiReferenceable referenceable) + if (component is IOpenApiReferenceable referenceable) { if (!_IOpenApiReferenceableRegistry.ContainsKey(uri)) { @@ -128,7 +118,7 @@ public Uri GetDocumentId(string key) public bool Contains(string location) { var key = ToLocationUrl(location); - return _IOpenApiReferenceableRegistry.ContainsKey(key) || _jsonSchemaRegistry.ContainsKey(key) || _artifactsRegistry.ContainsKey(key); + return _IOpenApiReferenceableRegistry.ContainsKey(key) || _artifactsRegistry.ContainsKey(key); } /// @@ -146,10 +136,6 @@ public T ResolveReference(string location) { return (T)referenceableValue; } - else if (_jsonSchemaRegistry.TryGetValue(uri, out var schemaValue)) - { - return (T)schemaValue; - } else if (_artifactsRegistry.TryGetValue(uri, out var artifact)) { return (T)(object)artifact; @@ -162,10 +148,5 @@ private Uri ToLocationUrl(string location) { return new(BaseUrl, location); } - - internal Dictionary GetSchemaRegistry() - { - return _jsonSchemaRegistry; - } } } diff --git a/src/Microsoft.OpenApi/Writers/IOpenApiWriter.cs b/src/Microsoft.OpenApi/Writers/IOpenApiWriter.cs index 9da2b64e0..9ea04b400 100644 --- a/src/Microsoft.OpenApi/Writers/IOpenApiWriter.cs +++ b/src/Microsoft.OpenApi/Writers/IOpenApiWriter.cs @@ -1,11 +1,6 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using System; -using System.Collections.Generic; -using Json.Schema; -using Microsoft.OpenApi.Models; - namespace Microsoft.OpenApi.Writers { /// @@ -73,32 +68,9 @@ public interface IOpenApiWriter /// void WriteValue(object value); - /// - /// Write the JsonSchema object - /// - /// - /// - void WriteJsonSchema(JsonSchema schema, OpenApiSpecVersion version); - - /// - /// Write the JsonSchema object - /// - /// The IOpenApiWriter object - /// The JsonSchema object - /// - void WriteJsonSchemaWithoutReference(IOpenApiWriter writer, JsonSchema schema, OpenApiSpecVersion version); - /// /// Flush the writer. /// void Flush(); - - /// - /// Writes a reference to a JsonSchema object. - /// - /// - /// - /// - void WriteJsonSchemaReference(IOpenApiWriter writer, Uri reference, OpenApiSpecVersion version); } } diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs index 542dc5cd4..99b148652 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs @@ -6,9 +6,6 @@ using System.IO; using System.Linq; using System.Text.Json; -using System.Text.RegularExpressions; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; @@ -420,201 +417,6 @@ protected void VerifyCanWritePropertyName(string name) } } - /// - /// Writes out a JsonSchema object - /// - /// - /// - public void WriteJsonSchema(JsonSchema schema, OpenApiSpecVersion version) - { - if (schema == null) - { - return; - } - - var reference = schema.GetRef(); - if (reference != null) - { - if (!Settings.ShouldInlineReference()) - { - WriteJsonSchemaReference(this, reference, version); - return; - } - else - { - if (Settings.InlineExternalReferences) - { - FindJsonSchemaRefs.ResolveJsonSchema(schema); - } - if (!Settings.LoopDetector.PushLoop(schema)) - { - Settings.LoopDetector.SaveLoop(schema); - WriteJsonSchemaReference(this, reference, version); - return; - } - } - } - - WriteJsonSchemaWithoutReference(this, schema, version); - - if (reference != null) - { - Settings.LoopDetector.PopLoop(); - } - } - - /// - public void WriteJsonSchemaWithoutReference(IOpenApiWriter writer, JsonSchema schema, OpenApiSpecVersion version) - { - writer.WriteStartObject(); - - // title - writer.WriteProperty(OpenApiConstants.Title, schema.GetTitle()); - - // multipleOf - writer.WriteProperty(OpenApiConstants.MultipleOf, schema.GetMultipleOf()); - - // maximum - writer.WriteProperty(OpenApiConstants.Maximum, schema.GetMaximum()); - - // exclusiveMaximum - writer.WriteProperty(OpenApiConstants.ExclusiveMaximum, schema.GetOpenApiExclusiveMaximum()); - - // minimum - writer.WriteProperty(OpenApiConstants.Minimum, schema.GetMinimum()); - - // exclusiveMinimum - writer.WriteProperty(OpenApiConstants.ExclusiveMinimum, schema.GetOpenApiExclusiveMinimum()); - - // maxLength - writer.WriteProperty(OpenApiConstants.MaxLength, schema.GetMaxLength()); - - // minLength - writer.WriteProperty(OpenApiConstants.MinLength, schema.GetMinLength()); - - // pattern - writer.WriteProperty(OpenApiConstants.Pattern, schema.GetPattern()?.ToString()); - - // maxItems - writer.WriteProperty(OpenApiConstants.MaxItems, schema.GetMaxItems()); - - // minItems - writer.WriteProperty(OpenApiConstants.MinItems, schema.GetMinItems()); - - // uniqueItems - writer.WriteProperty(OpenApiConstants.UniqueItems, schema.GetUniqueItems()); - - // maxProperties - writer.WriteProperty(OpenApiConstants.MaxProperties, schema.GetMaxProperties()); - - // minProperties - writer.WriteProperty(OpenApiConstants.MinProperties, schema.GetMinProperties()); - - // required - writer.WriteOptionalCollection(OpenApiConstants.Required, schema.GetRequired(), (w, s) => w.WriteValue(s)); - - // enum - writer.WriteOptionalCollection(OpenApiConstants.Enum, schema.GetEnum(), (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); - - // type - writer.WriteProperty(OpenApiConstants.Type, schema.GetJsonType()?.ToString().ToLowerInvariant()); - - // allOf - writer.WriteOptionalCollection(OpenApiConstants.AllOf, schema.GetAllOf(), (w, s) => w.WriteJsonSchema(s, version)); - - // anyOf - writer.WriteOptionalCollection(OpenApiConstants.AnyOf, schema.GetAnyOf(), (w, s) => w.WriteJsonSchema(s, version)); - - // oneOf - writer.WriteOptionalCollection(OpenApiConstants.OneOf, schema.GetOneOf(), (w, s) => w.WriteJsonSchema(s, version)); - - // not - writer.WriteOptionalObject(OpenApiConstants.Not, schema.GetNot(), (w, s) => w.WriteJsonSchema(s, version)); - - // items - writer.WriteOptionalObject(OpenApiConstants.Items, schema.GetItems(), (w, s) => w.WriteJsonSchema(s, version)); - - // properties - writer.WriteOptionalMap(OpenApiConstants.Properties, (IDictionary)schema.GetProperties(), - (w, key, s) => w.WriteJsonSchema(s, version)); - - // pattern properties - var patternProperties = schema?.GetPatternProperties(); - var stringPatternProperties = patternProperties?.ToDictionary( - kvp => kvp.Key.ToString(), // Convert Regex key to string - kvp => kvp.Value - ); - - writer.WriteOptionalMap(OpenApiConstants.PatternProperties, stringPatternProperties, - (w, key, s) => w.WriteJsonSchema(s, version)); - - // additionalProperties - if (schema.GetAdditionalPropertiesAllowed() ?? false) - { - writer.WriteOptionalObject( - OpenApiConstants.AdditionalProperties, - schema.GetAdditionalProperties(), - (w, s) => w.WriteJsonSchema(s, version)); - } - else - { - writer.WriteProperty(OpenApiConstants.AdditionalProperties, schema.GetAdditionalPropertiesAllowed()); - } - - // description - writer.WriteProperty(OpenApiConstants.Description, schema.GetDescription()); - - // format - writer.WriteProperty(OpenApiConstants.Format, schema.GetFormat()?.Key); - - // default - writer.WriteOptionalObject(OpenApiConstants.Default, schema.GetDefault(), (w, d) => w.WriteAny(new OpenApiAny(d))); - - // nullable - writer.WriteProperty(OpenApiConstants.Nullable, schema.GetNullable(), false); - - // discriminator - writer.WriteOptionalObject(OpenApiConstants.Discriminator, schema.GetOpenApiDiscriminator(), (w, d) => d.SerializeAsV3(w)); - - // readOnly - writer.WriteProperty(OpenApiConstants.ReadOnly, schema.GetReadOnly(), false); - - // writeOnly - writer.WriteProperty(OpenApiConstants.WriteOnly, schema.GetWriteOnly(), false); - - // xml - writer.WriteOptionalObject(OpenApiConstants.Xml, schema.GetXml(), (w, s) => JsonSerializer.Serialize(s)); - - // externalDocs - writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, schema.GetExternalDocs(), (w, s) => JsonSerializer.Serialize(s)); - - // example - writer.WriteOptionalObject(OpenApiConstants.Example, schema.GetExample(), (w, s) => w.WriteAny(new OpenApiAny(s))); - - // examples - writer.WriteOptionalCollection(OpenApiConstants.Examples, schema.GetExamples(), (n, e) => n.WriteAny(new OpenApiAny(e))); - - // deprecated - writer.WriteProperty(OpenApiConstants.Deprecated, schema.GetDeprecated(), false); - - // extensions - writer.WriteExtensions(schema.GetExtensions(), OpenApiSpecVersion.OpenApi3_0); - - writer.WriteEndObject(); - } - - /// - public void WriteJsonSchemaReference(IOpenApiWriter writer, Uri reference, OpenApiSpecVersion version) - { - var referenceItem = version.Equals(OpenApiSpecVersion.OpenApi2_0) - ? reference.OriginalString.Replace("components/schemas", "definitions") - : reference.OriginalString; - - WriteStartObject(); - this.WriteProperty(OpenApiConstants.DollarRef, referenceItem); - WriteEndObject(); - } - /// public void WriteV2Examples(IOpenApiWriter writer, OpenApiExample example, OpenApiSpecVersion version) { @@ -638,21 +440,4 @@ public void WriteV2Examples(IOpenApiWriter writer, OpenApiExample example, OpenA writer.WriteEndObject(); } } - - internal class FindJsonSchemaRefs : OpenApiVisitorBase - { - public static void ResolveJsonSchema(JsonSchema schema) - { - var visitor = new FindJsonSchemaRefs(); - var walker = new OpenApiWalker(visitor); - walker.Walk(schema); - } - - public static JsonSchema FetchSchemaFromRegistry(JsonSchema schema, Uri reference) - { - var referencePath = string.Concat("https://registry", reference.OriginalString.Split('#').Last()); - var resolvedSchema = (JsonSchema)SchemaRegistry.Global.Get(new Uri(referencePath)); - return resolvedSchema ?? schema; - } - } } diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs index 0ab285c93..bbf00fef0 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs @@ -5,7 +5,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Interfaces; namespace Microsoft.OpenApi.Writers @@ -252,25 +251,6 @@ public static void WriteRequiredMap( writer.WriteMapInternal(name, elements, action); } - /// - /// Write the optional Open API element map. - /// - /// The Open API writer. - /// The property name. - /// The map values. - /// The map element writer action with writer and value as input. - public static void WriteOptionalMap( - this IOpenApiWriter writer, - string name, - IDictionary elements, - Action action) - { - if (elements != null && elements.Any()) - { - writer.WriteMapInternal(name, elements, action); - } - } - /// /// Write the optional Open API element map (string to string mapping). /// From f0233f8e83271a5ab3bc027f2ff4e4088a869a47 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 11:48:52 +0300 Subject: [PATCH 04/44] Delete JSON schema extension classes --- .../Extensions/JsonSchemaBuilderExtensions.cs | 399 ------------------ .../Extensions/JsonSchemaExtensions.cs | 89 ---- 2 files changed, 488 deletions(-) delete mode 100644 src/Microsoft.OpenApi/Extensions/JsonSchemaBuilderExtensions.cs delete mode 100644 src/Microsoft.OpenApi/Extensions/JsonSchemaExtensions.cs diff --git a/src/Microsoft.OpenApi/Extensions/JsonSchemaBuilderExtensions.cs b/src/Microsoft.OpenApi/Extensions/JsonSchemaBuilderExtensions.cs deleted file mode 100644 index c37e23d8f..000000000 --- a/src/Microsoft.OpenApi/Extensions/JsonSchemaBuilderExtensions.cs +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using Json.Schema; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; - -namespace Microsoft.OpenApi.Extensions -{ - /// - /// Provides extension methods for JSON schema generation - /// - public static class JsonSchemaBuilderExtensions - { - /// - /// Custom extensions in the schema - /// - /// - /// - /// - public static JsonSchemaBuilder Extensions(this JsonSchemaBuilder builder, IDictionary extensions) - { - builder.Add(new ExtensionsKeyword(extensions)); - return builder; - } - - /// - /// The Schema summary - /// - /// - /// - /// - public static JsonSchemaBuilder Summary(this JsonSchemaBuilder builder, string summary) - { - builder.Add(new SummaryKeyword(summary)); - return builder; - } - - /// - /// Indicates if the schema can contain properties other than those defined by the properties map - /// - /// - /// - /// - public static JsonSchemaBuilder AdditionalPropertiesAllowed(this JsonSchemaBuilder builder, bool additionalPropertiesAllowed) - { - builder.Add(new AdditionalPropertiesAllowedKeyword(additionalPropertiesAllowed)); - return builder; - } - - /// - /// Allows sending a null value for the defined schema. Default value is false. - /// - /// - /// - /// - public static JsonSchemaBuilder Nullable(this JsonSchemaBuilder builder, bool value) - { - builder.Add(new NullableKeyword(value)); - return builder; - } - - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - /// - /// - /// - public static JsonSchemaBuilder ExclusiveMaximum(this JsonSchemaBuilder builder, bool value) - { - builder.Add(new Draft4ExclusiveMaximumKeyword(value)); - return builder; - } - - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// - /// - /// - /// - public static JsonSchemaBuilder ExclusiveMinimum(this JsonSchemaBuilder builder, bool value) - { - builder.Add(new Draft4ExclusiveMinimumKeyword(value)); - return builder; - } - - /// - /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate - /// between other schemas which may satisfy the payload description. - /// - /// - /// - /// - public static JsonSchemaBuilder Discriminator(this JsonSchemaBuilder builder, OpenApiDiscriminator discriminator) - { - builder.Add(new DiscriminatorKeyword(discriminator)); - return builder; - } - - /// - /// ExternalDocs object. - /// - /// - /// - /// - public static JsonSchemaBuilder OpenApiExternalDocs(this JsonSchemaBuilder builder, OpenApiExternalDocs externalDocs) - { - builder.Add(new ExternalDocsKeyword(externalDocs)); - return builder; - } - - /// - /// Removes a keyword - /// - /// - /// - public static JsonSchemaBuilder Remove(this JsonSchemaBuilder builder, string keyword) - { - var keywords = builder.Build().Keywords; - keywords = keywords.Where(x => !x.Keyword().Equals(keyword)).ToList(); - var schemaBuilder = new JsonSchemaBuilder(); - if (keywords.Count == 0) - { - return schemaBuilder; - } - else - { - foreach (var item in keywords) - { - schemaBuilder.Add(item); - } - } - - return schemaBuilder; - } - } - - /// - /// The Exclusive minimum keyword as defined in JSON schema Draft4 - /// - [SchemaKeyword(Name)] - public class Draft4ExclusiveMinimumKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "exclusiveMinimum"; - - /// - /// The ID. - /// - public bool MinValue { get; } - - internal Draft4ExclusiveMinimumKeyword(bool value) - { - MinValue = value; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The Exclusive maximum keyword as defined in JSON schema Draft4 - /// - [SchemaKeyword(Name)] - public class Draft4ExclusiveMaximumKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "exclusiveMaximum"; - - /// - /// The ID. - /// - public bool MaxValue { get; } - - internal Draft4ExclusiveMaximumKeyword(bool value) - { - MaxValue = value; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The nullable keyword - /// - [SchemaKeyword(Name)] - [SchemaSpecVersion(SpecVersion.Draft202012)] - public class NullableKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "nullable"; - - /// - /// The ID. - /// - public bool Value { get; } - - /// - /// Creates a new . - /// - /// Whether the `minimum` value should be considered exclusive. - public NullableKeyword(bool value) - { - Value = value; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The nullable keyword - /// - [SchemaKeyword(Name)] - public class ExternalDocsKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "externalDocs"; - - /// - /// The ID. - /// - public OpenApiExternalDocs Value { get; } - - /// - /// Creates a new . - /// - /// Whether the `minimum` value should be considered exclusive. - public ExternalDocsKeyword(OpenApiExternalDocs value) - { - Value = value; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The extensions keyword - /// - [SchemaKeyword(Name)] - [SchemaSpecVersion(SpecVersion.Draft202012)] - public class ExtensionsKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "extensions"; - - internal IDictionary Extensions { get; } - - internal ExtensionsKeyword(IDictionary extensions) - { - Extensions = extensions; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The summary keyword - /// - [SchemaKeyword(Name)] - public class SummaryKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "summary"; - - internal string Summary { get; } - - internal SummaryKeyword(string summary) - { - Summary = summary; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The AdditionalPropertiesAllowed Keyword - /// - [SchemaKeyword(Name)] - public class AdditionalPropertiesAllowedKeyword : IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "additionalPropertiesAllowed"; - - internal bool AdditionalPropertiesAllowed { get; } - - internal AdditionalPropertiesAllowedKeyword(bool additionalPropertiesAllowed) - { - AdditionalPropertiesAllowed = additionalPropertiesAllowed; - } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - - /// - /// The Discriminator Keyword - /// - [SchemaKeyword(Name)] - [SchemaSpecVersion(SpecVersion.Draft202012)] - public class DiscriminatorKeyword : OpenApiDiscriminator, IJsonSchemaKeyword - { - /// - /// The schema keyword name - /// - public const string Name = "discriminator"; - - /// - /// Parameter-less constructor - /// - public DiscriminatorKeyword() : base() { } - - /// - /// Initializes a copy of an instance - /// - internal DiscriminatorKeyword(OpenApiDiscriminator discriminator) : base(discriminator) { } - - /// - /// Implementation of IJsonSchemaKeyword interface - /// - /// - /// - public void Evaluate(EvaluationContext context) - { - throw new NotImplementedException(); - } - } - -} diff --git a/src/Microsoft.OpenApi/Extensions/JsonSchemaExtensions.cs b/src/Microsoft.OpenApi/Extensions/JsonSchemaExtensions.cs deleted file mode 100644 index 6c0545fc3..000000000 --- a/src/Microsoft.OpenApi/Extensions/JsonSchemaExtensions.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using Json.Schema; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; - -namespace Microsoft.OpenApi.Extensions -{ - /// - /// Specifies Extension methods to be applied on a JSON schema instance - /// - public static class JsonSchemaExtensions - { - /// - /// Gets the `discriminator` keyword if it exists. - /// - public static DiscriminatorKeyword GetOpenApiDiscriminator(this JsonSchema schema) - { - return schema.TryGetKeyword(DiscriminatorKeyword.Name, out var k) ? k! : null; - } - - /// - /// Gets the 'externalDocs' keyword if it exists. - /// - /// - /// - public static OpenApiExternalDocs GetOpenApiExternalDocs(this JsonSchema schema) - { - return schema.TryGetKeyword(ExternalDocsKeyword.Name, out var k) ? k.Value! : null; - } - - /// - /// Gets the `summary` keyword if it exists. - /// - public static string GetSummary(this JsonSchema schema) - { - return schema.TryGetKeyword(SummaryKeyword.Name, out var k) ? k.Summary! : null; - } - - /// - /// Gets the nullable value if it exists - /// - /// - /// - public static bool? GetNullable(this JsonSchema schema) - { - return schema.TryGetKeyword(NullableKeyword.Name, out var k) ? k.Value! : null; - } - - /// - /// Gets the additional properties value if it exists - /// - /// - /// - public static bool? GetAdditionalPropertiesAllowed(this JsonSchema schema) - { - return schema.TryGetKeyword(AdditionalPropertiesAllowedKeyword.Name, out var k) ? k.AdditionalPropertiesAllowed! : null; - } - - /// - /// Gets the exclusive maximum value if it exists - /// - /// - /// - public static bool? GetOpenApiExclusiveMaximum(this JsonSchema schema) - { - return schema.TryGetKeyword(Draft4ExclusiveMaximumKeyword.Name, out var k) ? k.MaxValue! : null; - } - - /// - /// Gets the exclusive minimum value if it exists - /// - /// - /// - public static bool? GetOpenApiExclusiveMinimum(this JsonSchema schema) - { - return schema.TryGetKeyword(Draft4ExclusiveMinimumKeyword.Name, out var k) ? k.MinValue! : null; - } - - /// - /// Gets the custom extensions if it exists - /// - /// - /// - public static IDictionary GetExtensions(this JsonSchema schema) - { - return schema.TryGetKeyword(ExtensionsKeyword.Name, out var k) ? k.Extensions! : null; - } - } -} From 8b0fb29ed8d3a3881a3d132866ccf2035c7e4796 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 15:48:32 +0300 Subject: [PATCH 05/44] Add support for examples --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 9 +++++++++ .../Reader/V31/OpenApiSchemaDeserializer.cs | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index c194a297b..ae1e63196 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -262,6 +262,13 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// public OpenApiAny Example { get; set; } + /// + /// A free-form property to include examples of an instance for this schema. + /// To represent examples that cannot be naturally represented in JSON or YAML, + /// a list of values can be used to contain the examples with escaping where necessary. + /// + public IList Examples { get; set; } + /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// @@ -362,6 +369,7 @@ public OpenApiSchema(OpenApiSchema schema) AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; Example = schema?.Example != null ? new(schema?.Example.Node) : null; + Examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; Nullable = schema?.Nullable ?? Nullable; ExternalDocs = schema?.ExternalDocs != null ? new(schema?.ExternalDocs) : null; @@ -587,6 +595,7 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum); writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); + writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); } /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 9cb2ffa77..1df2d6014 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Extensions; @@ -203,6 +203,10 @@ internal static partial class OpenApiV31Deserializer "example", (o, n, _) => o.Example = n.CreateAny() }, + { + "examples", + (o, n, _) => o.Examples = n.CreateListOfAny() + }, { "deprecated", (o, n, _) => o.Deprecated = bool.Parse(n.GetScalarValue()) From 6d32cc1a366a2e4565756a94446b59d63f1baa29 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 17:47:20 +0300 Subject: [PATCH 06/44] Add support for pattern properties --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 13 ++++++++++++- .../Reader/V31/OpenApiSchemaDeserializer.cs | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index ae1e63196..ecd0ef37e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -227,6 +227,15 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// public IDictionary Properties { get; set; } = new Dictionary(); + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// PatternProperty definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced) + /// Each property name of this object SHOULD be a valid regular expression according to the ECMA 262 r + /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST + /// be a valid Schema Object not a standard JSON Schema. + /// + public IDictionary PatternProperties { get; set; } = new Dictionary(); + /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// @@ -363,11 +372,12 @@ public OpenApiSchema(OpenApiSchema schema) MinItems = schema?.MinItems ?? MinItems; UniqueItems = schema?.UniqueItems ?? UniqueItems; Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; + PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; MaxProperties = schema?.MaxProperties ?? MaxProperties; MinProperties = schema?.MinProperties ?? MinProperties; AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; - Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; + Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; Example = schema?.Example != null ? new(schema?.Example.Node) : null; Examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; @@ -596,6 +606,7 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 1df2d6014..9e2e7a879 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Extensions; @@ -150,6 +150,10 @@ internal static partial class OpenApiV31Deserializer "properties", (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) }, + { + "patternProperties", + (o, n, t) => o.PatternProperties = n.CreateMap(LoadOpenApiSchema, t) + }, { "additionalProperties", (o, n, _) => { From 8f62e5497beea460b3c90adea392b611575e0c54 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 17:53:18 +0300 Subject: [PATCH 07/44] Revert "Add support for pattern properties" This reverts commit 6d32cc1a366a2e4565756a94446b59d63f1baa29. --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 13 +------------ .../Reader/V31/OpenApiSchemaDeserializer.cs | 6 +----- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index ecd0ef37e..ae1e63196 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -227,15 +227,6 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// public IDictionary Properties { get; set; } = new Dictionary(); - /// - /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 - /// PatternProperty definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced) - /// Each property name of this object SHOULD be a valid regular expression according to the ECMA 262 r - /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST - /// be a valid Schema Object not a standard JSON Schema. - /// - public IDictionary PatternProperties { get; set; } = new Dictionary(); - /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// @@ -372,12 +363,11 @@ public OpenApiSchema(OpenApiSchema schema) MinItems = schema?.MinItems ?? MinItems; UniqueItems = schema?.UniqueItems ?? UniqueItems; Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; - PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; MaxProperties = schema?.MaxProperties ?? MaxProperties; MinProperties = schema?.MinProperties ?? MinProperties; AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; - Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; + Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; Example = schema?.Example != null ? new(schema?.Example.Node) : null; Examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; @@ -606,7 +596,6 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); - writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 9e2e7a879..1df2d6014 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Extensions; @@ -150,10 +150,6 @@ internal static partial class OpenApiV31Deserializer "properties", (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) }, - { - "patternProperties", - (o, n, t) => o.PatternProperties = n.CreateMap(LoadOpenApiSchema, t) - }, { "additionalProperties", (o, n, _) => { From 7f754b7c5b2edddd20bc85f1d3879f3219d0a885 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 18:38:36 +0300 Subject: [PATCH 08/44] Code refactoring; replace JsonSchema with OpenApiSchema --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 3 +- src/Microsoft.OpenApi.Workbench/MainModel.cs | 1 - .../Helpers/JsonNodeCloneHelper.cs | 13 - .../Models/OpenApiRequestBody.cs | 22 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 14 +- .../References/OpenApiHeaderReference.cs | 3 +- .../References/OpenApiParameterReference.cs | 3 +- .../Reader/ParseNodes/AnyFieldMapParameter.cs | 6 +- .../ParseNodes/AnyListFieldMapParameter.cs | 8 +- .../ParseNodes/AnyMapFieldMapParameter.cs | 8 +- .../Reader/ParseNodes/MapNode.cs | 35 -- .../Reader/ParseNodes/ParseNode.cs | 13 +- .../Reader/SchemaTypeConverter.cs | 26 -- .../Reader/V2/JsonSchemaDeserializer.cs | 269 --------------- .../Reader/V2/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 108 ++---- .../Reader/V2/OpenApiOperationDeserializer.cs | 25 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 80 ++--- .../Reader/V2/OpenApiResponseDeserializer.cs | 5 +- .../Reader/V2/OpenApiSchemaDeserializer.cs | 10 +- .../Reader/V2/OpenApiV2VersionService.cs | 3 +- .../Reader/V3/JsonSchemaDeserializer.cs | 309 ----------------- .../V3/OpenApiComponentsDeserializer.cs | 3 +- .../Reader/V3/OpenApiSchemaDeserializer.cs | 16 +- .../Reader/V3/OpenApiV3VersionService.cs | 3 +- .../Reader/V31/JsonSchemaDeserializer.cs | 312 ------------------ .../V31/OpenApiComponentsDeserializer.cs | 1 - .../Reader/V31/OpenApiSchemaDeserializer.cs | 22 +- .../Reader/V31/OpenApiV31VersionService.cs | 4 +- .../Services/CopyReferences.cs | 21 +- .../Services/JsonSchemaReferenceResolver.cs | 199 ----------- .../OpenApiComponentsRegistryExtensions.cs | 5 +- ...onSchemaRules.cs => OpenApiSchemaRules.cs} | 83 ++--- .../Validations/Rules/RuleHelpers.cs | 265 +++++++++++++-- 34 files changed, 413 insertions(+), 1487 deletions(-) delete mode 100644 src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs rename src/Microsoft.OpenApi/Validations/Rules/{JsonSchemaRules.cs => OpenApiSchemaRules.cs} (55%) diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index bc68746d9..b6af07778 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -20,7 +19,7 @@ public override void Visit(OpenApiParameter parameter) public int SchemaCount { get; set; } - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { SchemaCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/MainModel.cs b/src/Microsoft.OpenApi.Workbench/MainModel.cs index e46b83b67..d9b2a0fa1 100644 --- a/src/Microsoft.OpenApi.Workbench/MainModel.cs +++ b/src/Microsoft.OpenApi.Workbench/MainModel.cs @@ -11,7 +11,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations; diff --git a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs index 32025d198..9f89ddc11 100644 --- a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs +++ b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs @@ -4,7 +4,6 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; -using Json.Schema; using Microsoft.OpenApi.Any; namespace Microsoft.OpenApi.Helpers @@ -28,18 +27,6 @@ internal static OpenApiAny Clone(OpenApiAny value) return new OpenApiAny(result); } - internal static JsonSchema CloneJsonSchema(JsonSchema schema) - { - var jsonString = Serialize(schema); - if (string.IsNullOrEmpty(jsonString)) - { - return null; - } - - var result = JsonSerializer.Deserialize(jsonString, options); - return result; - } - private static string Serialize(object obj) { if (obj == null) diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 00d50a7be..11b1af6be 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -1,10 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -165,7 +164,7 @@ internal OpenApiBodyParameter ConvertToBodyParameter() // V2 spec actually allows the body to have custom name. // To allow round-tripping we use an extension to hold the name Name = "body", - Schema = Content.Values.FirstOrDefault()?.Schema ?? new JsonSchemaBuilder(), + Schema = Content.Values.FirstOrDefault()?.Schema ?? new OpenApiSchema(), Examples = Content.Values.FirstOrDefault()?.Examples, Required = Required, Extensions = Extensions.ToDictionary(static k => k.Key, static v => v.Value) // Clone extensions so we can remove the x-bodyName extensions from the output V2 model. @@ -184,24 +183,23 @@ internal IEnumerable ConvertToFormDataParameters() if (Content == null || !Content.Any()) yield break; - foreach (var property in Content.First().Value.Schema.GetProperties()) + foreach (var property in Content.First().Value.Schema.Properties) { var paramSchema = property.Value; - if (paramSchema.GetType().Equals(SchemaValueType.String) - && ("binary".Equals(paramSchema.GetFormat().Key, StringComparison.OrdinalIgnoreCase) - || "base64".Equals(paramSchema.GetFormat().Key, StringComparison.OrdinalIgnoreCase))) + if ("string".Equals(paramSchema.Type.ToString(), StringComparison.OrdinalIgnoreCase) + && ("binary".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase) + || "base64".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase))) { - // JsonSchema is immutable so these can't be set - //paramSchema.Type("file"); - //paramSchema.Format(null); + paramSchema.Type = "file"; + paramSchema.Format = null; } yield return new() { - Description = property.Value.GetDescription(), + Description = property.Value.Description, Name = property.Key, Schema = property.Value, Examples = Content.Values.FirstOrDefault()?.Examples, - Required = Content.First().Value.Schema.GetRequired().Contains(property.Key) + Required = Content.First().Value.Schema.Required?.Contains(property.Key) ?? false }; } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 16b50383a..c6f6f25ee 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -715,6 +715,12 @@ internal void WriteAsSchemaProperties( ISet parentRequiredProperties, string propertyName) { + // type + writer.WriteProperty(OpenApiConstants.Type, (string)Type); + + // description + writer.WriteProperty(OpenApiConstants.Description, Description); + // format if (string.IsNullOrEmpty(Format)) { @@ -728,9 +734,6 @@ internal void WriteAsSchemaProperties( // title writer.WriteProperty(OpenApiConstants.Title, Title); - // description - writer.WriteProperty(OpenApiConstants.Description, Description); - // default writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d)); @@ -779,9 +782,6 @@ internal void WriteAsSchemaProperties( // enum writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s))); - // type - writer.WriteProperty(OpenApiConstants.Type, (string)Type); - // items writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w)); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index b878898bf..64111c477 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -86,7 +85,7 @@ public override string Description public override bool AllowEmptyValue { get => Target.AllowEmptyValue; set => Target.AllowEmptyValue = value; } /// - public override JsonSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } /// public override ParameterStyle? Style { get => Target.Style; set => Target.Style = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 6722bf1bd..488e054a4 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -94,7 +93,7 @@ public override string Description public override bool AllowReserved { get => Target.AllowReserved; set => Target.AllowReserved = value; } /// - public override JsonSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } /// public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs index 9b674c408..933040da6 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs @@ -2,8 +2,8 @@ // Licensed under the MIT license. using System; -using Json.Schema; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -15,7 +15,7 @@ internal class AnyFieldMapParameter public AnyFieldMapParameter( Func propertyGetter, Action propertySetter, - Func SchemaGetter = null) + Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -35,6 +35,6 @@ public AnyFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs index 32342d594..fc87a548e 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Json.Schema; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -16,7 +16,7 @@ internal class AnyListFieldMapParameter public AnyListFieldMapParameter( Func> propertyGetter, Action> propertySetter, - Func SchemaGetter = null) + Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -36,6 +36,6 @@ public AnyListFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs index 43468acfc..b0c38247c 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -17,7 +17,7 @@ public AnyMapFieldMapParameter( Func> propertyMapGetter, Func propertyGetter, Action propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyMapGetter = propertyMapGetter; this.PropertyGetter = propertyGetter; @@ -43,6 +43,6 @@ public AnyMapFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs index 0cc8539cf..c251bce3c 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; @@ -79,40 +78,6 @@ public override Dictionary CreateMap(Func k.key, v => v.value); } - public override Dictionary CreateJsonSchemaMap( - ReferenceType referenceType, - Func map, - OpenApiSpecVersion version, - OpenApiDocument hostDocument = null) - { - var jsonMap = _node ?? throw new OpenApiReaderException($"Expected map while parsing {typeof(JsonSchema).Name}", Context); - - var nodes = jsonMap.Select( - n => - { - var key = n.Key; - (string key, JsonSchema value) entry; - try - { - Context.StartObject(key); - entry = (key, - value: map(new MapNode(Context, (JsonObject)n.Value), hostDocument) - ); - if (entry.value == null) - { - return default; // Body Parameters shouldn't be converted to Parameters - } - } - finally - { - Context.EndObject(); - } - return entry; - } - ); - return nodes.Where(n => n != default).ToDictionary(k => k.key, v => v.value); - } - public override Dictionary CreateSimpleMap(Func map) { var jsonMap = _node ?? throw new OpenApiReaderException($"Expected map while parsing {typeof(T).Name}", Context); diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs index a72f1bed9..250581fbd 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; -using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes @@ -59,15 +57,6 @@ public virtual Dictionary CreateMap(Func CreateJsonSchemaMap( - ReferenceType referenceType, - Func map, - OpenApiSpecVersion version, - OpenApiDocument hostDocument = null) - { - throw new OpenApiReaderException("Cannot create map from this reference.", Context); - } - public virtual List CreateSimpleList(Func map) { throw new OpenApiReaderException("Cannot create simple list from this type of node.", Context); @@ -96,6 +85,6 @@ public virtual string GetScalarValue() public virtual List CreateListOfAny() { throw new OpenApiReaderException("Cannot create a list from this type of node.", Context); - } + } } } diff --git a/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs b/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs deleted file mode 100644 index f446fa78b..000000000 --- a/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System; -using Json.Schema; - -namespace Microsoft.OpenApi.Reader -{ - internal static class SchemaTypeConverter - { - internal static SchemaValueType ConvertToSchemaValueType(string value) - { - return value.ToLowerInvariant() switch - { - "string" => SchemaValueType.String, - "number" or "double" => SchemaValueType.Number, - "integer" => SchemaValueType.Integer, - "boolean" => SchemaValueType.Boolean, - "array" => SchemaValueType.Array, - "object" => SchemaValueType.Object, - "null" => SchemaValueType.Null, - _ => throw new NotSupportedException(), - }; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs deleted file mode 100644 index 176593c94..000000000 --- a/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Reader.ParseNodes; - -namespace Microsoft.OpenApi.Reader.V2 -{ - /// - /// Class containing logic to deserialize Open API V2 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV2Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(bool.Parse(n.GetScalarValue())); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalProperties(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "discriminator", (o, n, _) => - { - var discriminator = new OpenApiDiscriminator - { - PropertyName = n.GetScalarValue() - }; - o.Discriminator(discriminator.PropertyName, (IReadOnlyDictionary)discriminator.Mapping, - (IReadOnlyDictionary)discriminator.Extensions); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n, t); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - o.Example(n.CreateAny().Node); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var schemaBuilder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - var jsonSchema = schemaBuilder.Ref(pointer).Build(); - if (hostDocument != null) - { - jsonSchema.BaseUri = hostDocument.BaseUri; - } - - return jsonSchema; - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(schemaBuilder, _schemaFixedFields, _schemaPatternFields); - } - - var schema = schemaBuilder.Build(); - - if (hostDocument != null) - { - schema.BaseUri = hostDocument.BaseUri; - } - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index a402ce9ca..b0e2a29ae 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -59,7 +59,7 @@ internal static partial class OpenApiV2Deserializer (o, n, _) => { o.Components ??= new(); - o.Components.Schemas = n.CreateJsonSchemaMap(ReferenceType.Schema, LoadSchema, OpenApiSpecVersion.OpenApi2_0, o); + o.Components.Schemas = n.CreateMap(LoadSchema, o); } }, { diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index 4c2431721..500f10353 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -3,7 +3,6 @@ using System; using System.Globalization; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Exceptions; @@ -17,7 +16,6 @@ namespace Microsoft.OpenApi.Reader.V2 /// internal static partial class OpenApiV2Deserializer { - private static JsonSchemaBuilder _headerJsonSchemaBuilder; private static readonly FixedFieldMap _headerFixedFields = new() { { @@ -25,105 +23,73 @@ internal static partial class OpenApiV2Deserializer (o, n, _) => o.Description = n.GetScalarValue() }, { - "type", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } + "type", + (o, n, _) => GetOrCreateSchema(o).Type = n.GetScalarValue() }, { - "format", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Format(n.GetScalarValue()); - } + "format", + (o, n, _) => GetOrCreateSchema(o).Format = n.GetScalarValue() }, { - "items", (o, n, t) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Items(LoadSchema(n, t)); - } + "items", + (o, n, _) => GetOrCreateSchema(o).Items = LoadSchema(n) }, { "collectionFormat", (o, n, _) => LoadStyle(o, n.GetScalarValue()) }, { - "default", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Default(n.CreateAny().Node); - } + "default", + (o, n, _) => GetOrCreateSchema(o).Default = n.CreateAny() }, { - "maximum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Maximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maximum", + (o, n, _) => GetOrCreateSchema(o).Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue) }, { - "exclusiveMaximum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().ExclusiveMaximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "exclusiveMaximum", + (o, n, _) => GetOrCreateSchema(o).ExclusiveMaximum = bool.Parse(n.GetScalarValue()) }, { - "minimum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Minimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minimum", + (o, n, _) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue) }, { - "exclusiveMinimum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().ExclusiveMinimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "exclusiveMinimum", + (o, n, _) => GetOrCreateSchema(o).ExclusiveMinimum = bool.Parse(n.GetScalarValue()) }, { - "maxLength", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxLength", + (o, n, _) => GetOrCreateSchema(o).MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minLength", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minLength", + (o, n, _) => GetOrCreateSchema(o).MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "pattern", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Pattern(n.GetScalarValue()); - } + "pattern", + (o, n, _) => GetOrCreateSchema(o).Pattern = n.GetScalarValue() }, { - "maxItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxItems", + (o, n, _) => GetOrCreateSchema(o).MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minItems", + (o, n, _) => GetOrCreateSchema(o).MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "uniqueItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().UniqueItems(bool.Parse(n.GetScalarValue())); - } + "uniqueItems", + (o, n, _) => GetOrCreateSchema(o).UniqueItems = bool.Parse(n.GetScalarValue()) }, { - "multipleOf", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MultipleOf(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "multipleOf", + (o, n, _) => GetOrCreateSchema(o).MultipleOf = decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "enum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Enum(n.CreateListOfAny()).Build(); - } - } + "enum", + (o, n, _) => GetOrCreateSchema(o).Enum = n.CreateListOfAny() + } }; private static readonly PatternFieldMap _headerPatternFields = new() @@ -131,24 +97,22 @@ internal static partial class OpenApiV2Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - private static JsonSchemaBuilder GetOrCreateHeaderSchemaBuilder() + private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) { - _headerJsonSchemaBuilder ??= new JsonSchemaBuilder(); - return _headerJsonSchemaBuilder; + return p.Schema ??= new(); } public static OpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode("header"); var header = new OpenApiHeader(); - _headerJsonSchemaBuilder = null; foreach (var property in mapNode) { property.ParseField(header, _headerFixedFields, _headerPatternFields); } - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { header.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 5dfc3b9a1..a2faa5810 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -148,25 +147,19 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List k.Name, v => { - var schemaBuilder = new JsonSchemaBuilder(); var schema = v.Schema; - - foreach (var keyword in schema.Keywords) - { - schemaBuilder.Add(keyword); - } - - schemaBuilder.Description(v.Description); - if (v.Extensions.Any()) - { - schemaBuilder.Extensions(v.Extensions); - } - return schemaBuilder.Build(); - })).Required(new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name))).Build() + schema.Description = v.Description; + schema.Extensions = v.Extensions; + return schema; + }), + Required = new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name)) + } }; var consumes = context.GetFromTempStorage>(TempStorageKeys.OperationConsumes) ?? diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 54c584df2..2823974de 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -4,9 +4,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using Json.Schema; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -20,7 +17,6 @@ namespace Microsoft.OpenApi.Reader.V2 /// internal static partial class OpenApiV2Deserializer { - private static JsonSchemaBuilder _parameterJsonSchemaBuilder; private static readonly FixedFieldMap _parameterFixedFields = new() { @@ -49,74 +45,52 @@ internal static partial class OpenApiV2Deserializer (o, n, t) => o.AllowEmptyValue = bool.Parse(n.GetScalarValue()) }, { - "type", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } + "type", + (o, n, t) => GetOrCreateSchema(o).Type = n.GetScalarValue() }, { - "items", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Items(LoadSchema(n, t)); - } + "items", + (o, n, t) => GetOrCreateSchema(o).Items = LoadSchema(n) }, { "collectionFormat", (o, n, t) => LoadStyle(o, n.GetScalarValue()) }, { - "format", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Format(n.GetScalarValue()); - } + "format", + (o, n, t) => GetOrCreateSchema(o).Format = n.GetScalarValue() }, { - "minimum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Minimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minimum", + (o, n, t) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue) }, { - "maximum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Maximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maximum", + (o, n, t) => GetOrCreateSchema(o).Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue) }, { - "maxLength", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxLength", + (o, n, t) => GetOrCreateSchema(o).MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minLength", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minLength", + (o, n, t) => GetOrCreateSchema(o).MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "readOnly", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().ReadOnly(bool.Parse(n.GetScalarValue())); - } + "readOnly", + (o, n, t) => GetOrCreateSchema(o).ReadOnly = bool.Parse(n.GetScalarValue()) }, { - "default", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Default(n.CreateAny().Node); - } + "default", + (o, n, t) => GetOrCreateSchema(o).Default = n.CreateAny() }, { - "pattern", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Pattern(n.GetScalarValue()); - } + "pattern", + (o, n, t) => GetOrCreateSchema(o).Pattern = n.GetScalarValue() }, { - "enum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Enum(n.CreateListOfAny()).Build(); - } + "enum", + (o, n, t) => GetOrCreateSchema(o).Enum = n.CreateListOfAny() }, { "schema", @@ -169,11 +143,10 @@ private static void LoadParameterExamplesExtension(OpenApiParameter parameter, P var examples = LoadExamplesExtension(node); node.Context.SetTempStorage(TempStorageKeys.Examples, examples, parameter); } - - private static JsonSchemaBuilder GetOrCreateParameterSchemaBuilder() + + private static OpenApiSchema GetOrCreateSchema(OpenApiParameter p) { - _parameterJsonSchemaBuilder ??= new JsonSchemaBuilder(); - return _parameterJsonSchemaBuilder; + return p.Schema ??= new(); } private static void ProcessIn(OpenApiParameter o, ParseNode n, OpenApiDocument hostDocument = null) @@ -228,11 +201,10 @@ public static OpenApiParameter LoadParameter(ParseNode node, bool loadRequestBod } var parameter = new OpenApiParameter(); - _parameterJsonSchemaBuilder = null; ParseMap(mapNode, parameter, _parameterFixedFields, _parameterPatternFields, doc: hostDocument); - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { parameter.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index 05b89cfff..8436a09cd 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -74,7 +73,7 @@ private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, P ?? context.GetFromTempStorage>(TempStorageKeys.GlobalProduces) ?? context.DefaultContentType ?? new List { "application/octet-stream" }; - var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); + var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); var examples = context.GetFromTempStorage>(TempStorageKeys.Examples, response) ?? new Dictionary(); @@ -171,7 +170,7 @@ private static void LoadExample(OpenApiResponse response, string mediaType, Pars { mediaTypeObject = new() { - Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) + Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) }; response.Content.Add(mediaType, mediaTypeObject); } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 868ea2d32..96ed771f1 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -88,15 +88,15 @@ internal static partial class OpenApiV2Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -107,7 +107,7 @@ internal static partial class OpenApiV2Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -155,7 +155,7 @@ internal static partial class OpenApiV2Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode("schema"); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs index ea5e66f0a..c9e58b519 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; @@ -44,7 +43,7 @@ public OpenApiV2VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiPaths)] = OpenApiV2Deserializer.LoadPaths, [typeof(OpenApiResponse)] = OpenApiV2Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV2Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV2Deserializer.LoadSchema, + [typeof(OpenApiSchema)] = OpenApiV2Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV2Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV2Deserializer.LoadSecurityScheme, [typeof(OpenApiTag)] = OpenApiV2Deserializer.LoadTag, diff --git a/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs deleted file mode 100644 index 0f6be069a..000000000 --- a/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using JsonSchema = Json.Schema.JsonSchema; -using Microsoft.OpenApi.Reader.ParseNodes; - -namespace Microsoft.OpenApi.Reader.V3 -{ - /// - /// Class containing logic to deserialize Open API V3 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV3Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(bool.Parse(n.GetScalarValue())); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "oneOf", (o, n, t) => - { - o.OneOf(n.CreateList(LoadSchema, t)); - } - }, - { - "anyOf", (o, n, t) => - { - o.AnyOf(n.CreateList(LoadSchema, t)); - } - }, - { - "not", (o, n, t) => - { - o.Not(LoadSchema(n, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalPropertiesAllowed(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "nullable", (o, n, _) => - { - o.Nullable(bool.Parse(n.GetScalarValue())); - } - }, - { - "discriminator", (o, n, t) => - { - var discriminator = LoadDiscriminator(n, t); - o.Discriminator(discriminator); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "writeOnly", (o, n, _) => - { - o.WriteOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n, t); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - if(n is ListNode) - { - o.Examples(n.CreateSimpleList((s, p) => (JsonNode)s.GetScalarValue())); - } - else - { - o.Example(n.CreateAny().Node); - } - } - }, - { - "deprecated", (o, n, _) => - { - o.Deprecated(bool.Parse(n.GetScalarValue())); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var builder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - var jsonSchema = builder.Ref(pointer).Build(); - if (hostDocument != null) - { - jsonSchema.BaseUri = hostDocument.BaseUri; - } - - return jsonSchema; - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(builder, _schemaFixedFields, _schemaPatternFields, hostDocument); - } - - var schema = builder.Build(); - - if (hostDocument != null) - { - schema.BaseUri = hostDocument.BaseUri; - } - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs index 3e1d2539b..cc51187d2 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -16,7 +15,7 @@ internal static partial class OpenApiV3Deserializer { private static readonly FixedFieldMap _componentsFixedFields = new() { - {"schemas", (o, n, t) => o.Schemas = n.CreateJsonSchemaMap(ReferenceType.Schema, LoadSchema, OpenApiSpecVersion.OpenApi3_0, t)}, + {"schemas", (o, n, t) => o.Schemas = n.CreateMap(LoadSchema, t)}, {"responses", (o, n, t) => o.Responses = n.CreateMap(LoadResponse, t)}, {"parameters", (o, n, t) => o.Parameters = n.CreateMap(LoadParameter, t)}, {"examples", (o, n, t) => o.Examples = n.CreateMap(LoadExample, t)}, diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index 51b427321..bacd72e4c 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -87,27 +87,27 @@ internal static partial class OpenApiV3Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "oneOf", - (o, n, _) => o.OneOf = n.CreateList(LoadOpenApiSchema) + (o, n, _) => o.OneOf = n.CreateList(LoadSchema) }, { "anyOf", - (o, n, t) => o.AnyOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AnyOf = n.CreateList(LoadSchema, t) }, { "not", - (o, n, _) => o.Not = LoadOpenApiSchema(n) + (o, n, _) => o.Not = LoadSchema(n) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -118,7 +118,7 @@ internal static partial class OpenApiV3Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -173,7 +173,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index 4479332bd..7ffc907fc 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; @@ -57,7 +56,7 @@ public OpenApiV3VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiRequestBody)] = OpenApiV3Deserializer.LoadRequestBody, [typeof(OpenApiResponse)] = OpenApiV3Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV3Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV3Deserializer.LoadSchema, + [typeof(OpenApiSchema)] = OpenApiV3Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV3Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV3Deserializer.LoadSecurityScheme, [typeof(OpenApiServer)] = OpenApiV3Deserializer.LoadServer, diff --git a/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs deleted file mode 100644 index 02bf282a6..000000000 --- a/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Reader.ParseNodes; -using JsonSchema = Json.Schema.JsonSchema; - -namespace Microsoft.OpenApi.Reader.V31 -{ - /// - /// Class containing logic to deserialize Open API V31 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV31Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "oneOf", (o, n, t) => - { - o.OneOf(n.CreateList(LoadSchema, t)); - } - }, - { - "anyOf", (o, n, t) => - { - o.AnyOf(n.CreateList(LoadSchema, t)); - } - }, - { - "not", (o, n, t) => - { - o.Not(LoadSchema(n, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "patternProperties", (o, n, t) => - { - o.PatternProperties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalPropertiesAllowed(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "discriminator", (o, n, t) => - { - var discriminator = LoadDiscriminator(n, t); - o.Discriminator(discriminator); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "writeOnly", (o, n, _) => - { - o.WriteOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - o.Example(n.CreateAny().Node); - } - }, - { - "examples", (o, n, _) => - { - o.Examples(n.CreateSimpleList((s, p) =>(JsonNode) s.GetScalarValue())); - } - }, - { - "deprecated", (o, n, _) => - { - o.Deprecated(bool.Parse(n.GetScalarValue())); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var builder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - builder = builder.Ref(pointer); - - // Check for summary and description and append to builder - var summary = mapNode.GetSummaryValue(); - var description = mapNode.GetDescriptionValue(); - if (!string.IsNullOrEmpty(summary)) - { - builder.Summary(summary); - } - if (!string.IsNullOrEmpty(description)) - { - builder.Description(description); - } - - return builder.Build(); - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(builder, _schemaFixedFields, _schemaPatternFields); - } - - var schema = builder.Build(); - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } - -} diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs index a9c543813..e70087d4b 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 116674238..9d27d811d 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Extensions; @@ -51,7 +51,7 @@ internal static partial class OpenApiV31Deserializer }, { "$defs", - (o, n, t) => o.Definitions = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Definitions = n.CreateMap(LoadSchema, t) }, { "multipleOf", @@ -128,31 +128,31 @@ internal static partial class OpenApiV31Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "oneOf", - (o, n, t) => o.OneOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.OneOf = n.CreateList(LoadSchema, t) }, { "anyOf", - (o, n, t) => o.AnyOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AnyOf = n.CreateList(LoadSchema, t) }, { "not", - (o, n, _) => o.Not = LoadOpenApiSchema(n) + (o, n, _) => o.Not = LoadSchema(n) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "patternProperties", - (o, n, t) => o.PatternProperties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.PatternProperties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -163,7 +163,7 @@ internal static partial class OpenApiV31Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -222,7 +222,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs index 5e47f03b6..333ec53bb 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; @@ -56,8 +55,7 @@ public OpenApiV31VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiRequestBody)] = OpenApiV31Deserializer.LoadRequestBody, [typeof(OpenApiResponse)] = OpenApiV31Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV31Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV31Deserializer.LoadSchema, - [typeof(OpenApiSchema)] = OpenApiV31Deserializer.LoadOpenApiSchema, + [typeof(OpenApiSchema)] = OpenApiV31Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV31Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV31Deserializer.LoadSecurityScheme, [typeof(OpenApiServer)] = OpenApiV31Deserializer.LoadServer, diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index f6b53c3f1..757471466 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -26,12 +25,12 @@ public override void Visit(IOpenApiReferenceable referenceable) { switch (referenceable) { - case JsonSchema schema: + case OpenApiSchema schema: EnsureComponentsExists(); EnsureSchemasExists(); - if (!Components.Schemas.ContainsKey(schema.GetRef().OriginalString)) + if (!Components.Schemas.ContainsKey(schema.Reference.Id)) { - Components.Schemas.Add(schema.GetRef().OriginalString, schema); + Components.Schemas.Add(schema.Reference.Id, schema); } break; @@ -70,22 +69,22 @@ public override void Visit(IOpenApiReferenceable referenceable) } /// - /// Visits + /// Visits /// /// The OpenApiSchema to be visited. - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { // This is needed to handle schemas used in Responses in components - if (schema.GetRef() != null) + if (schema.Reference != null) { EnsureComponentsExists(); EnsureSchemasExists(); - if (!Components.Schemas.ContainsKey(schema.GetRef().OriginalString)) + if (!Components.Schemas.ContainsKey(schema.Reference.Id)) { - Components.Schemas.Add(schema.GetRef().OriginalString, schema); + Components.Schemas.Add(schema.Reference.Id, schema); } } - base.Visit(ref schema); + base.Visit(schema); } private void EnsureComponentsExists() @@ -100,7 +99,7 @@ private void EnsureSchemasExists() { if (_target.Components.Schemas == null) { - _target.Components.Schemas = new Dictionary(); + _target.Components.Schemas = new Dictionary(); } } diff --git a/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs b/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs deleted file mode 100644 index 87e493b3c..000000000 --- a/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using Json.Schema; -using Microsoft.OpenApi.Exceptions; -using System.Linq; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; - -namespace Microsoft.OpenApi.Services -{ - /// - /// This class is used to walk an OpenApiDocument and resolves JsonSchema references. - /// - internal class JsonSchemaReferenceResolver : OpenApiVisitorBase - { - private readonly OpenApiDocument _currentDocument; - private readonly List _errors = new(); - - public JsonSchemaReferenceResolver(OpenApiDocument currentDocument) - { - _currentDocument = currentDocument; - } - - /// - /// List of errors related to the OpenApiDocument - /// - public IEnumerable Errors => _errors; - - /// - /// Resolves schemas in components - /// - /// - public override void Visit(OpenApiComponents components) - { - components.Schemas = ResolveJsonSchemas(components.Schemas); - } - - /// - /// Resolve all JsonSchema references used in mediaType object - /// - /// - public override void Visit(OpenApiMediaType mediaType) - { - ResolveJsonSchema(mediaType.Schema, r => mediaType.Schema = r ?? mediaType.Schema); - } - - /// - /// Resolve all JsonSchema references used in a parameter - /// - public override void Visit(OpenApiParameter parameter) - { - ResolveJsonSchema(parameter.Schema, r => parameter.Schema = r); - } - - /// - /// Resolve all references used in a JsonSchema - /// - /// - public override void Visit(ref JsonSchema schema) - { - var reference = schema.GetRef(); - var description = schema.GetDescription(); - var summary = schema.GetSummary(); - - if (schema.Keywords.Count.Equals(1) && reference != null) - { - schema = ResolveJsonSchemaReference(reference, description, summary); - } - - var builder = new JsonSchemaBuilder(); - if (schema?.Keywords is { } keywords) - { - foreach (var keyword in keywords) - { - builder.Add(keyword); - } - } - - ResolveJsonSchema(schema.GetItems(), r => builder.Items(r)); - ResolveJsonSchemaList((IList)schema.GetOneOf(), r => builder.OneOf(r)); - ResolveJsonSchemaList((IList)schema.GetAllOf(), r => builder.AllOf(r)); - ResolveJsonSchemaList((IList)schema.GetAnyOf(), r => builder.AnyOf(r)); - ResolveJsonSchemaMap((IDictionary)schema.GetProperties(), r => builder.Properties((IReadOnlyDictionary)r)); - ResolveJsonSchema(schema.GetAdditionalProperties(), r => builder.AdditionalProperties(r)); - - schema = builder.Build(); - } - - /// - /// Visits an IBaseDocument instance - /// - /// - public override void Visit(IBaseDocument document) { } - - private Dictionary ResolveJsonSchemas(IDictionary schemas) - { - var resolvedSchemas = new Dictionary(); - foreach (var schema in schemas) - { - var schemaValue = schema.Value; - Visit(ref schemaValue); - resolvedSchemas[schema.Key] = schemaValue; - } - - return resolvedSchemas; - } - - /// - /// Resolves the target to a JsonSchema reference by retrieval from Schema registry - /// - /// The JSON schema reference. - /// The schema's description. - /// The schema's summary. - /// - public JsonSchema ResolveJsonSchemaReference(Uri reference, string description = null, string summary = null) - { - var resolvedSchema = _currentDocument.ResolveJsonSchemaReference(reference); - - if (resolvedSchema != null) - { - var resolvedSchemaBuilder = new JsonSchemaBuilder(); - - foreach (var keyword in resolvedSchema.Keywords) - { - resolvedSchemaBuilder.Add(keyword); - - // Replace the resolved schema's description with that of the schema reference - if (!string.IsNullOrEmpty(description)) - { - resolvedSchemaBuilder.Description(description); - } - - // Replace the resolved schema's summary with that of the schema reference - if (!string.IsNullOrEmpty(summary)) - { - resolvedSchemaBuilder.Summary(summary); - } - } - - return resolvedSchemaBuilder.Build(); - } - else - { - var referenceId = reference.OriginalString.Split('/').LastOrDefault(); - throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, referenceId)); - } - } - - private void ResolveJsonSchema(JsonSchema schema, Action assign) - { - if (schema == null) return; - var reference = schema.GetRef(); - var description = schema.GetDescription(); - var summary = schema.GetSummary(); - - if (reference != null) - { - assign(ResolveJsonSchemaReference(reference, description, summary)); - } - } - - private void ResolveJsonSchemaList(IList list, Action> assign) - { - if (list == null) return; - - for (int i = 0; i < list.Count; i++) - { - var entity = list[i]; - var reference = entity?.GetRef(); - if (reference != null) - { - list[i] = ResolveJsonSchemaReference(reference); - } - } - - assign(list.ToList()); - } - - private void ResolveJsonSchemaMap(IDictionary map, Action> assign) - { - if (map == null) return; - - foreach (var key in map.Keys.ToList()) - { - var entity = map[key]; - var reference = entity.GetRef(); - if (reference != null) - { - map[key] = ResolveJsonSchemaReference(reference); - } - } - - assign(map.ToDictionary(e => e.Key, e => e.Value)); - } - } -} diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 2a38c360d..8be8318e3 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -19,9 +18,9 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo // Register Schema foreach (var item in document.Components.Schemas) { - if (item.Value.GetId() != null) + if (item.Value.Id != null) { - location = document.BaseUri + item.Value.GetId().ToString(); + location = document.BaseUri + item.Value.Id; } else { diff --git a/src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs similarity index 55% rename from src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs rename to src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index 0443b9fb8..5f75be881 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -2,58 +2,40 @@ // Licensed under the MIT license. using System.Collections.Generic; -using System.Linq; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules { /// - /// The validation rules for . + /// The validation rules for . /// [OpenApiRule] - public static class JsonSchemaRules + public static class OpenApiSchemaRules { /// /// Validate the data matches with the given data type. /// - public static ValidationRule SchemaMismatchedDataType => - new ValidationRule(nameof(SchemaMismatchedDataType), - (context, jsonSchema) => + public static ValidationRule SchemaMismatchedDataType => + new(nameof(SchemaMismatchedDataType), + (context, schema) => { // default context.Enter("default"); - if (jsonSchema.GetDefault() != null) + if (schema.Default != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetDefault(), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Default.Node, schema); } context.Exit(); - // examples - context.Enter("examples"); - - if (jsonSchema.GetExamples() is { } examples) - { - for (int i = 0; i < examples.Count; i++) - { - context.Enter(i.ToString()); - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), examples.ElementAt(i), jsonSchema); - context.Exit(); - } - } - - context.Exit(); - // example context.Enter("example"); - if (jsonSchema.GetExample() != null) + if (schema.Example != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetExample(), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Example.Node, schema); } context.Exit(); @@ -61,12 +43,12 @@ public static class JsonSchemaRules // enum context.Enter("enum"); - if (jsonSchema.GetEnum() != null) + if (schema.Enum != null) { - for (int i = 0; i < jsonSchema.GetEnum().Count; i++) + for (var i = 0; i < schema.Enum.Count; i++) { context.Enter(i.ToString()); - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetEnum().ElementAt(i), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Enum[i], schema); context.Exit(); } } @@ -77,22 +59,22 @@ public static class JsonSchemaRules /// /// Validates Schema Discriminator /// - public static ValidationRule ValidateSchemaDiscriminator => - new ValidationRule(nameof(ValidateSchemaDiscriminator), - (context, jsonSchema) => + public static ValidationRule ValidateSchemaDiscriminator => + new(nameof(ValidateSchemaDiscriminator), + (context, schema) => { // discriminator context.Enter("discriminator"); - if (jsonSchema.GetRef() != null && jsonSchema.GetOpenApiDiscriminator() != null) + if (schema.Reference != null && schema.Discriminator != null) { - var discriminatorName = jsonSchema.GetOpenApiDiscriminator()?.PropertyName; + var discriminatorName = schema.Discriminator?.PropertyName; - if (!ValidateChildSchemaAgainstDiscriminator(jsonSchema, discriminatorName)) + if (!ValidateChildSchemaAgainstDiscriminator(schema, discriminatorName)) { context.CreateError(nameof(ValidateSchemaDiscriminator), string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, - jsonSchema.GetRef(), discriminatorName)); + schema.Reference.Id, discriminatorName)); } } @@ -105,22 +87,22 @@ public static class JsonSchemaRules /// The parent schema. /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate /// between other schemas which may satisfy the payload description. - public static bool ValidateChildSchemaAgainstDiscriminator(JsonSchema schema, string discriminatorName) + public static bool ValidateChildSchemaAgainstDiscriminator(OpenApiSchema schema, string discriminatorName) { - if (!schema.GetRequired()?.Contains(discriminatorName) ?? true) + if (!schema.Required?.Contains(discriminatorName) ?? false) { // recursively check nested schema.OneOf, schema.AnyOf or schema.AllOf and their required fields for the discriminator - if (schema.GetOneOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetOneOf())) + if (schema.OneOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.OneOf); } - if (schema.GetAnyOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetAnyOf())) + if (schema.AnyOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.AnyOf); } - if (schema.GetAllOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetAllOf())) + if (schema.AllOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.AllOf); } } else @@ -138,15 +120,12 @@ public static bool ValidateChildSchemaAgainstDiscriminator(JsonSchema schema, st /// between other schemas which may satisfy the payload description. /// The child schema. /// - public static bool TraverseSchemaElements(string discriminatorName, IReadOnlyCollection childSchema) + public static bool TraverseSchemaElements(string discriminatorName, IList childSchema) { - if (!childSchema?.Any() ?? true) - return false; - foreach (var childItem in childSchema) { - if ((!childItem.GetProperties()?.ContainsKey(discriminatorName) ?? true) && - (!childItem.GetRequired()?.Contains(discriminatorName) ?? true)) + if ((!childItem.Properties?.ContainsKey(discriminatorName) ?? false) && + (!childItem.Required?.Contains(discriminatorName) ?? false)) { return ValidateChildSchemaAgainstDiscriminator(childItem, discriminatorName); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index e57d67a89..a2ac63a6e 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -2,10 +2,9 @@ // Licensed under the MIT license. using System; -using System.Linq; +using System.Text.Json; using System.Text.Json.Nodes; -using Json.Schema; -using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Validations.Rules { @@ -20,7 +19,7 @@ internal static class RuleHelpers /// True if it's an email address. Otherwise False. public static bool IsEmailAddress(this string input) { - if (String.IsNullOrEmpty(input)) + if (string.IsNullOrEmpty(input)) { return false; } @@ -31,7 +30,7 @@ public static bool IsEmailAddress(this string input) return false; } - if (String.IsNullOrEmpty(splits[0]) || String.IsNullOrEmpty(splits[1])) + if (string.IsNullOrEmpty(splits[0]) || string.IsNullOrEmpty(splits[1])) { return false; } @@ -42,40 +41,248 @@ public static bool IsEmailAddress(this string input) } public static void ValidateDataTypeMismatch( - IValidationContext context, - string ruleName, - JsonNode value, - JsonSchema schema) - { - if (schema is not null) + IValidationContext context, + string ruleName, + JsonNode value, + OpenApiSchema schema) + { + if (schema == null) { - var options = new EvaluationOptions(); - options.OutputFormat = OutputFormat.List; + return; + } + + var type = schema.Type.ToString(); + var format = schema.Format; + var nullable = schema.Nullable; + + // convert JsonNode to JsonElement + JsonElement element = value.GetValue(); + + // Before checking the type, check first if the schema allows null. + // If so and the data given is also null, this is allowed for any type. + if (nullable) + { + if (element.ValueKind is JsonValueKind.Null) + { + return; + } + } + + if (type == "object") + { + // It is not against the spec to have a string representing an object value. + // To represent examples of media types that cannot naturally be represented in JSON or YAML, + // a string value can contain the example with escaping where necessary + if (element.ValueKind is JsonValueKind.String) + { + return; + } - if (context.HostDocument != null) + // If value is not a string and also not an object, there is a data mismatch. + if (element.ValueKind is not JsonValueKind.Object) { - options.SchemaRegistry.Register(context.HostDocument.BaseUri, context.HostDocument); + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + return; } - var results = schema.Evaluate(value, options); + // Else, cast element to object + var anyObject = value.AsObject(); - if (!results.IsValid) + foreach (var kvp in anyObject) { - foreach (var detail in results.Details) + string key = kvp.Key; + context.Enter(key); + + if (schema.Properties != null && + schema.Properties.TryGetValue(key, out var property)) + { + ValidateDataTypeMismatch(context, ruleName, anyObject[key], property); + } + else { - if (detail.Errors != null && detail.Errors.Any()) - { - foreach (var error in detail.Errors) - { - if (!string.IsNullOrEmpty(error.Key) || !string.IsNullOrEmpty(error.Value.Trim())) - { - context.CreateWarning(ruleName, string.Format("{0} : {1} at {2}", error.Key, error.Value.Trim(), detail.InstanceLocation)); - } - } - } + ValidateDataTypeMismatch(context, ruleName, anyObject[key], schema.AdditionalProperties); } + + context.Exit(); + } + + return; + } + + if (type == "array") + { + // It is not against the spec to have a string representing an array value. + // To represent examples of media types that cannot naturally be represented in JSON or YAML, + // a string value can contain the example with escaping where necessary + if (element.ValueKind is JsonValueKind.String) + { + return; + } + + // If value is not a string and also not an array, there is a data mismatch. + if (element.ValueKind is not JsonValueKind.Array) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + return; } - } + + // Else, cast element to array + var anyArray = value.AsArray(); + + for (var i = 0; i < anyArray.Count; i++) + { + context.Enter(i.ToString()); + + ValidateDataTypeMismatch(context, ruleName, anyArray[i], schema.Items); + + context.Exit(); + } + + return; + } + + if (type == "integer" && format == "int32") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "integer" && format == "int64") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "integer" && element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + if (type == "number" && format == "float") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "number" && format == "double") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "number") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "byte") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "date") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "date-time") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "password") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "boolean") + { + if (element.ValueKind is not JsonValueKind.True || element.ValueKind is not JsonValueKind.True) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } } } } From 396d450ab71178e1e3394bde1f72c5524791ef28 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 18:39:32 +0300 Subject: [PATCH 09/44] Clean up tests --- .../Formatters/PowerShellFormatterTests.cs | 84 +-- .../UtilityFiles/OpenApiDocumentMock.cs | 208 +++++-- .../OpenApiWorkspaceStreamTests.cs | 2 - .../TryLoadReferenceV2Tests.cs | 41 +- .../V2Tests/OpenApiDocumentTests.cs | 400 ++++++++++---- .../V2Tests/OpenApiHeaderTests.cs | 30 +- .../V2Tests/OpenApiOperationTests.cs | 98 +++- .../V2Tests/OpenApiParameterTests.cs | 53 +- .../V2Tests/OpenApiPathItemTests.cs | 141 ++++- ...onSchemaTests.cs => OpenApiSchemaTests.cs} | 45 +- .../V31Tests/JsonSchemaTests.cs | 178 ------ .../V31Tests/OpenApiDocumentTests.cs | 296 +++++++--- .../V31Tests/OpenApiSchemaTests.cs | 131 +++++ .../V3Tests/JsonSchemaTests.cs | 340 ------------ .../V3Tests/OpenApiCallbackTests.cs | 23 +- .../V3Tests/OpenApiDocumentTests.cs | 419 ++++++++++---- .../V3Tests/OpenApiEncodingTests.cs | 6 +- .../V3Tests/OpenApiMediaTypeTests.cs | 13 +- .../V3Tests/OpenApiOperationTests.cs | 13 +- .../V3Tests/OpenApiParameterTests.cs | 116 ++-- .../V3Tests/OpenApiSchemaTests.cs | 515 ++++++++++++++++++ .../Extensions/OpenApiTypeMapperTests.cs | 39 +- .../Models/OpenApiCallbackTests.cs | 11 +- .../Models/OpenApiComponentsTests.cs | 220 ++++++-- .../Models/OpenApiDocumentTests.cs | 503 ++++++++++++----- .../Models/OpenApiHeaderTests.cs | 13 +- .../Models/OpenApiOperationTests.cs | 86 ++- .../Models/OpenApiParameterTests.cs | 86 +-- .../Models/OpenApiRequestBodyTests.cs | 11 +- .../Models/OpenApiResponseTests.cs | 85 ++- .../References/OpenApiHeaderReferenceTests.cs | 3 +- .../OpenApiRequestBodyReferenceTests.cs | 8 +- .../OpenApiResponseReferenceTest.cs | 5 +- .../OpenApiHeaderValidationTests.cs | 74 +-- .../OpenApiMediaTypeValidationTests.cs | 21 +- .../OpenApiParameterValidationTests.cs | 36 +- .../OpenApiReferenceValidationTests.cs | 31 +- .../OpenApiSchemaValidationTests.cs | 161 ++++-- .../Visitors/InheritanceTests.cs | 7 +- .../Walkers/WalkerLocationTests.cs | 67 +-- .../Workspaces/OpenApiReferencableTests.cs | 9 +- .../Workspaces/OpenApiWorkspaceTests.cs | 44 +- .../Writers/OpenApiJsonWriterTests.cs | 21 +- .../Writers/OpenApiYamlWriterTests.cs | 13 +- 44 files changed, 3183 insertions(+), 1523 deletions(-) rename test/Microsoft.OpenApi.Readers.Tests/V2Tests/{JsonSchemaTests.cs => OpenApiSchemaTests.cs} (68%) delete mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs delete mode 100644 test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index 6bd55a4aa..94f99a1d2 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -1,11 +1,9 @@ -using Json.Schema; -using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Hidi.Formatters; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; -using Microsoft.OpenApi.Extensions; namespace Microsoft.OpenApi.Hidi.Tests.Formatters { @@ -60,18 +58,18 @@ public void RemoveAnyOfAndOneOfFromSchema() walker.Walk(openApiDocument); var testSchema = openApiDocument.Components.Schemas["TestSchema"]; - var averageAudioDegradationProperty = testSchema.GetProperties()?.GetValueOrDefault("averageAudioDegradation"); - var defaultPriceProperty = testSchema.GetProperties()?.GetValueOrDefault("defaultPrice"); + var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema.Properties["defaultPrice"]; // Assert - Assert.Null(averageAudioDegradationProperty?.GetAnyOf()); - Assert.Equal(SchemaValueType.Number, averageAudioDegradationProperty?.GetJsonType()); - Assert.Equal("float", averageAudioDegradationProperty?.GetFormat()?.Key); - Assert.True(averageAudioDegradationProperty?.GetNullable()); - Assert.Null(defaultPriceProperty?.GetOneOf()); - Assert.Equal(SchemaValueType.Number, defaultPriceProperty?.GetJsonType()); - Assert.Equal("double", defaultPriceProperty?.GetFormat()?.Key); - Assert.NotNull(testSchema.GetAdditionalProperties()); + Assert.Null(averageAudioDegradationProperty.AnyOf); + Assert.Equal("number", averageAudioDegradationProperty.Type); + Assert.Equal("float", averageAudioDegradationProperty.Format); + Assert.True(averageAudioDegradationProperty.Nullable); + Assert.Null(defaultPriceProperty.OneOf); + Assert.Equal("number", defaultPriceProperty.Type); + Assert.Equal("double", defaultPriceProperty.Format); + Assert.NotNull(testSchema.AdditionalProperties); } [Fact] @@ -90,7 +88,7 @@ public void ResolveFunctionParameters() // Assert Assert.Null(idsParameter?.Content); Assert.NotNull(idsParameter?.Schema); - Assert.Equal(SchemaValueType.Array, idsParameter?.Schema.GetJsonType()); + Assert.Equal("array", idsParameter?.Schema.Type); } private static OpenApiDocument GetSampleOpenApiDocument() @@ -120,10 +118,14 @@ private static OpenApiDocument GetSampleOpenApiDocument() "application/json", new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } } } } @@ -143,22 +145,38 @@ private static OpenApiDocument GetSampleOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - { "TestSchema", new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("averageAudioDegradation", new JsonSchemaBuilder() - .AnyOf( - new JsonSchemaBuilder().Type(SchemaValueType.Number), - new JsonSchemaBuilder().Type(SchemaValueType.String)) - .Format("float") - .Nullable(true)), - - ("defaultPrice", new JsonSchemaBuilder() - .OneOf( - new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double"), - new JsonSchemaBuilder().Type(SchemaValueType.String)))) - } + { "TestSchema", new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + { + "averageAudioDegradation", new OpenApiSchema + { + AnyOf = new List + { + new() { Type = "number" }, + new() { Type = "string" } + }, + Format = "float", + Nullable = true + } + }, + { + "defaultPrice", new OpenApiSchema + { + OneOf = new List + { + new() { Type = "number", Format = "double" }, + new() { Type = "string" } + } + } + } + } + } + } } } }; diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index 65ef08628..98ed181f4 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -1,7 +1,6 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -84,7 +83,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -100,7 +102,10 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array) + Schema = new() + { + Type = "array" + } } } } @@ -118,7 +123,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } } @@ -149,7 +157,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -165,7 +176,10 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array) + Schema = new() + { + Type = "array" + } } } } @@ -182,7 +196,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -216,17 +233,29 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Title("Collection of user") - .Type(SchemaValueType.Object) - .Properties(("value", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Ref("microsoft.graph.user") - .Build()) - .Build())) - .Build() + Schema = new() + { + Title = "Collection of user", + Type = "object", + Properties = new Dictionary + { + { + "value", + new OpenApiSchema + { + Type = "array", + Items = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.user" + } + } + } + } + } + } } } } @@ -267,7 +296,14 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("microsoft.graph.user").Build() + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.user" + } + } } } } @@ -330,7 +366,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Query, Required = true, Description = "Select properties to be returned", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Build() + Schema = new() + { + Type = "array" + } // missing explode parameter } }, @@ -346,7 +385,14 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("microsoft.graph.message").Build() + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.message" + } + } } } } @@ -384,7 +430,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Required = true, Description = "key: id of administrativeUnit", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }, @@ -400,12 +449,17 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .AnyOf( - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build()) - .Build() + Schema = new() + { + AnyOf = new List + { + new() + { + Type = "string" + } + }, + Nullable = true + } } } } @@ -477,14 +531,29 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Title("Collection of hostSecurityProfile") - .Type(SchemaValueType.Object) - .Properties(("value1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("microsoft.graph.networkInterface")))) - .Build() + Schema = new() + { + Title = "Collection of hostSecurityProfile", + Type = "object", + Properties = new Dictionary + { + { + "value", + new OpenApiSchema + { + Type = "array", + Items = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.networkInterface" + } + } + } + } + } + } } } } @@ -521,7 +590,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of call", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), + Schema = new() + { + Type = "string" + }, Extensions = new Dictionary { { @@ -573,8 +645,16 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of group", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), - Extensions = new Dictionary { { "x-ms-docs-key-type", new OpenApiAny("group") } } + Schema = new() + { + Type = "string" + }, + Extensions = new Dictionary + { + { + "x-ms-docs-key-type", new OpenApiAny("group") + } + } }, new() { @@ -582,8 +662,16 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of event", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), - Extensions = new Dictionary { { "x-ms-docs-key-type", new OpenApiAny("event") } } + Schema = new() + { + Type = "string" + }, + Extensions = new Dictionary + { + { + "x-ms-docs-key-type", new OpenApiAny("event") + } + } } }, Responses = new() @@ -598,7 +686,15 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Ref("microsoft.graph.event").Build() + Schema = new() + { + Type = "array", + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.event" + } + } } } } @@ -638,17 +734,25 @@ public static OpenApiDocument CreateOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { { - "microsoft.graph.networkInterface", new JsonSchemaBuilder() - .Title("networkInterface") - .Type(SchemaValueType.Object) - .Properties( - ("description", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.)."))) - .Build() + "microsoft.graph.networkInterface", new OpenApiSchema + { + Title = "networkInterface", + Type = "object", + Properties = new Dictionary + { + { + "description", new OpenApiSchema + { + Type = "string", + Description = "Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.).", + Nullable = true + } + } + } + } } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs index 128430218..2ee51bc06 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs @@ -1,8 +1,6 @@ using System; using System.IO; -using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 26afc9720..010604750 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -3,9 +3,7 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -38,9 +36,12 @@ public void LoadParameterReference() In = ParameterLocation.Query, Description = "number of items to skip", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } + }, options => options.Excluding(x => x.Reference) ); } @@ -98,10 +99,34 @@ public void LoadResponseAndSchemaReference() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder() - .Ref("#/definitions/SampleObject2") - .Build() + Schema = new() + { + Description = "Sample description", + Required = new HashSet {"name" }, + Properties = { + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + } + }, + + Reference = new() + { + Type = ReferenceType.Schema, + Id = "SampleObject2", + HostDocument = result.OpenApiDocument + } + } } + }, + Reference = new() + { + Type = ReferenceType.Response, + Id = "GeneralError" } }, options => options.Excluding(x => x.Reference) ); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index df26255db..f369e5028 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -2,10 +2,13 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; using Xunit; @@ -19,22 +22,198 @@ public class OpenApiDocumentTests public OpenApiDocumentTests() { OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); - } + } + + [Fact] + public void ShouldThrowWhenReferenceTypeIsInvalid() + { + var input = + """ + swagger: 2.0 + info: + title: test + version: 1.0.0 + paths: + '/': + get: + responses: + '200': + description: ok + schema: + $ref: '#/defi888nition/does/notexist' + """; + + var result = OpenApiDocument.Parse(input, "yaml"); + + result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { + new( new OpenApiException("Unknown reference type 'defi888nition'")) }); + result.OpenApiDocument.Should().NotBeNull(); + } + + [Fact] + public void ShouldThrowWhenReferenceDoesNotExist() + { + var input = + """ + swagger: 2.0 + info: + title: test + version: 1.0.0 + paths: + '/': + get: + produces: ['application/json'] + responses: + '200': + description: ok + schema: + $ref: '#/definitions/doesnotexist' + """; + + var result = OpenApiDocument.Parse(input, "yaml"); + + result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { + new( new OpenApiException("Invalid Reference identifier 'doesnotexist'.")) }); + result.OpenApiDocument.Should().NotBeNull(); + } + + [Theory] + [InlineData("en-US")] + [InlineData("hi-IN")] + // The equivalent of English 1,000.36 in French and Danish is 1.000,36 + [InlineData("fr-FR")] + [InlineData("da-DK")] + public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) + { + Thread.CurrentThread.CurrentCulture = new(culture); + Thread.CurrentThread.CurrentUICulture = new(culture); + + var result = OpenApiDocument.Parse( + """ + swagger: 2.0 + info: + title: Simple Document + version: 0.9.1 + x-extension: 2.335 + definitions: + sampleSchema: + type: object + properties: + sampleProperty: + type: double + minimum: 100.54 + maximum: 60000000.35 + exclusiveMaximum: true + exclusiveMinimum: false + paths: {} + """, + "yaml"); + + result.OpenApiDocument.Should().BeEquivalentTo( + new OpenApiDocument + { + Info = new() + { + Title = "Simple Document", + Version = "0.9.1", + Extensions = + { + ["x-extension"] = new OpenApiAny(2.335) + } + }, + Components = new() + { + Schemas = + { + ["sampleSchema"] = new() + { + Type = "object", + Properties = + { + ["sampleProperty"] = new() + { + Type = "double", + Minimum = (decimal)100.54, + Maximum = (decimal)60000000.35, + ExclusiveMaximum = true, + ExclusiveMinimum = false + } + }, + Reference = new() + { + Id = "sampleSchema", + Type = ReferenceType.Schema + } + } + } + }, + Paths = new() + }); + + result.OpenApiDiagnostic.Should().BeEquivalentTo( + new OpenApiDiagnostic { SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 }); + } [Fact] public void ShouldParseProducesInAnyOrder() { var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "twoResponses.json")); - var okSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Item"); + var okSchema = new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Item", + HostDocument = result.OpenApiDocument + }, + Properties = new Dictionary + { + { "id", new OpenApiSchema + { + Type = "string", + Description = "Item identifier." + } + } + } + }; - var errorSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Error"); + var errorSchema = new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Error", + HostDocument = result.OpenApiDocument + }, + Properties = new Dictionary + { + { "code", new OpenApiSchema + { + Type = "integer", + Format = "int32" + } + }, + { "message", new OpenApiSchema + { + Type = "string" + } + }, + { "fields", new OpenApiSchema + { + Type = "string" + } + } + } + }; var okMediaType = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(okSchema) + Schema = new() + { + Type = "array", + Items = okSchema + } }; var errorMediaType = new OpenApiMediaType @@ -44,111 +223,106 @@ public void ShouldParseProducesInAnyOrder() result.OpenApiDocument.Should().BeEquivalentTo(new OpenApiDocument { - Info = new OpenApiInfo + Info = new() { Title = "Two responses", Version = "1.0.0" }, Servers = + { + new OpenApiServer { - new OpenApiServer - { - Url = "https://" - } - }, - Paths = new OpenApiPaths + Url = "https://" + } + }, + Paths = new() { - ["/items"] = new OpenApiPathItem + ["/items"] = new() { Operations = + { + [OperationType.Get] = new() { - [OperationType.Get] = new OpenApiOperation + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["application/json"] = okMediaType, - ["application/xml"] = okMediaType, - } - }, - ["default"] = new OpenApiResponse + ["application/json"] = okMediaType, + ["application/xml"] = okMediaType, + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["application/json"] = errorMediaType, - ["application/xml"] = errorMediaType - } + ["application/json"] = errorMediaType, + ["application/xml"] = errorMediaType } } - }, - [OperationType.Post] = new OpenApiOperation + } + }, + [OperationType.Post] = new() + { + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["html/text"] = okMediaType - } - }, - ["default"] = new OpenApiResponse + ["html/text"] = okMediaType + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["html/text"] = errorMediaType - } + ["html/text"] = errorMediaType } } - }, - [OperationType.Patch] = new OpenApiOperation + } + }, + [OperationType.Patch] = new() + { + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["application/json"] = okMediaType, - ["application/xml"] = okMediaType, - } - }, - ["default"] = new OpenApiResponse + ["application/json"] = okMediaType, + ["application/xml"] = okMediaType, + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["application/json"] = errorMediaType, - ["application/xml"] = errorMediaType - } + ["application/json"] = errorMediaType, + ["application/xml"] = errorMediaType } } } } + } } }, - Components = new OpenApiComponents + Components = new() { Schemas = - { - ["Item"] = new JsonSchemaBuilder() - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Item identifier."))), - ["Error"] = new JsonSchemaBuilder() - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("fields", new JsonSchemaBuilder().Type(SchemaValueType.String))) - } + { + ["Item"] = okSchema, + ["Error"] = errorSchema + } } - }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); + }); } [Fact] @@ -159,26 +333,66 @@ public void ShouldAssignSchemaToAllResponses() Assert.Equal(OpenApiSpecVersion.OpenApi2_0, result.OpenApiDiagnostic.SpecificationVersion); - var successSchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Item identifier.")))); - - var errorSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Error"); - + var successSchema = new OpenApiSchema + { + Type = "array", + Items = new() + { + Properties = { + { "id", new OpenApiSchema + { + Type = "string", + Description = "Item identifier." + } + } + }, + Reference = new() + { + Id = "Item", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + } + }; + var errorSchema = new OpenApiSchema + { + Properties = { + { "code", new OpenApiSchema + { + Type = "integer", + Format = "int32" + } + }, + { "message", new OpenApiSchema + { + Type = "string" + } + }, + { "fields", new OpenApiSchema + { + Type = "string" + } + } + }, + Reference = new() + { + Id = "Error", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }; var responses = result.OpenApiDocument.Paths["/items"].Operations[OperationType.Get].Responses; foreach (var response in responses) { - var targetSchema = response.Key == "200" ? successSchema.Build() : errorSchema.Build(); + var targetSchema = response.Key == "200" ? successSchema : errorSchema; var json = response.Value.Content["application/json"]; Assert.NotNull(json); - Assert.Equal(json.Schema.Keywords.Count, targetSchema.Keywords.Count); + json.Schema.Should().BeEquivalentTo(targetSchema); var xml = response.Value.Content["application/xml"]; Assert.NotNull(xml); - Assert.Equal(xml.Schema.Keywords.Count, targetSchema.Keywords.Count); + xml.Schema.Should().BeEquivalentTo(targetSchema); } } @@ -187,12 +401,10 @@ public void ShouldAllowComponentsThatJustContainAReference() { // Act var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "ComponentRootReference.json")).OpenApiDocument; - JsonSchema schema = actual.Components.Schemas["AllPets"]; - - schema = actual.ResolveJsonSchemaReference(schema.GetRef()) ?? schema; - - // Assert - if (schema.Keywords.Count.Equals(1) && schema.GetRef() != null) + var schema1 = actual.Components.Schemas["AllPets"]; + Assert.False(schema1.UnresolvedReference); + var schema2 = actual.ResolveReferenceTo(schema1.Reference); + if (schema2.UnresolvedReference && schema1.Reference.Id == schema2.Reference.Id) { // detected a cycle - this code gets triggered Assert.Fail("A cycle should not be detected"); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index 220087401..14bbdfc32 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -3,7 +3,7 @@ using System.IO; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -33,10 +33,12 @@ public void ParseHeaderWithDefaultShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Default(5) + Schema = new() + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + } }, options => options .IgnoringCyclicReferences()); @@ -59,11 +61,19 @@ public void ParseHeaderWithEnumShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Enum(7, 8, 9) - }, options => options.IgnoringCyclicReferences()); + Schema = new() + { + Type = "number", + Format = "float", + Enum = + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + } + }, options => options.IgnoringCyclicReferences() + ); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index f264c23f6..ad1ca897f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -6,7 +6,6 @@ using System.Text; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -38,7 +37,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, Responses = new OpenApiResponses @@ -69,8 +71,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new OpenApiRequestBody @@ -79,19 +83,51 @@ public class OpenApiOperationTests { ["application/x-www-form-urlencoded"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, @@ -132,7 +168,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, }, RequestBody = new OpenApiRequestBody @@ -143,7 +182,10 @@ public class OpenApiOperationTests { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } }, Extensions = { @@ -270,9 +312,15 @@ public void ParseOperationWithResponseExamplesShouldSucceed() { ["application/json"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float")), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "number", + Format = "float" + } + }, Example = new OpenApiAny(new JsonArray() { 5.0, @@ -282,9 +330,15 @@ public void ParseOperationWithResponseExamplesShouldSucceed() }, ["application/xml"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float")) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "number", + Format = "float" + } + } } } }} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 1d9b1e22a..7ccbc1c8b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -3,7 +3,7 @@ using System.IO; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -56,8 +56,10 @@ public void ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -82,9 +84,14 @@ public void ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Form, Explode = true }); @@ -111,7 +118,10 @@ public void ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -136,7 +146,10 @@ public void ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -185,7 +198,10 @@ public void ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -210,7 +226,12 @@ public void ParseParameterWithDefaultShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float").Default(5) + Schema = new() + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + } }, options => options.IgnoringCyclicReferences()); } @@ -235,7 +256,17 @@ public void ParseParameterWithEnumShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float").Enum(7, 8, 9) + Schema = new() + { + Type = "number", + Format = "float", + Enum = + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + } }, options => options.IgnoringCyclicReferences()); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index 08a82885e..ef85cd712 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -29,7 +28,14 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet to use", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Simple } }, @@ -48,7 +54,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -57,19 +66,51 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, @@ -108,7 +149,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, new() { @@ -116,7 +160,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "Name of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -125,21 +172,61 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String)), - ("skill", new JsonSchemaBuilder().Description("Updated skill of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + }, + ["skill"] = new() + { + Description = "Updated skill of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String)), - ("skill", new JsonSchemaBuilder().Description("Updated skill of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + }, + ["skill"] = new() + { + Description = "Updated skill of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs similarity index 68% rename from test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs rename to test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index 050e9ed65..d827f62ee 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -3,16 +3,18 @@ using System.IO; using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Reader.V2; using Xunit; using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; +using System.Collections.Generic; namespace Microsoft.OpenApi.Readers.Tests.V2Tests { [Collection("DefaultSettings")] - public class JsonSchemaTests + public class OpenApiSchemaTests { private const string SampleFolderPath = "V2Tests/Samples/OpenApiSchema/"; @@ -30,9 +32,12 @@ public void ParseSchemaWithDefaultShouldSucceed() var schema = OpenApiV2Deserializer.LoadSchema(node); // Assert - schema.Should().BeEquivalentTo(new JsonSchemaBuilder() - .Type(SchemaValueType.Number).Format("float").Default(5).Build(), - options => options.IgnoringCyclicReferences()); + schema.Should().BeEquivalentTo(new OpenApiSchema + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + }); } [Fact] @@ -50,12 +55,12 @@ public void ParseSchemaWithExampleShouldSucceed() // Assert schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Example(5) - .Build(), - options => options.IgnoringCyclicReferences()); + new OpenApiSchema + { + Type = "number", + Format = "float", + Example = new OpenApiAny(5) + }); } [Fact] @@ -72,11 +77,17 @@ public void ParseSchemaWithEnumShouldSucceed() var schema = OpenApiV2Deserializer.LoadSchema(node); // Assert - var expected = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Enum(7, 8, 9) - .Build(); + var expected = new OpenApiSchema + { + Type = "number", + Format = "float", + Enum = new List + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + }; schema.Should().BeEquivalentTo(expected, options => options.IgnoringCyclicReferences()); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs deleted file mode 100644 index 48b5282d4..000000000 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System.IO; -using System.Linq; -using System.Text.Json; -using FluentAssertions; -using Json.Schema; -using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Reader.ParseNodes; -using Microsoft.OpenApi.Reader.V31; -using SharpYaml.Serialization; -using Xunit; - -namespace Microsoft.OpenApi.Readers.Tests.V31Tests -{ - public class JsonSchemaTests - { - private const string SampleFolderPath = "V31Tests/Samples/OpenApiSchema/"; - - [Fact] - public void ParseV31SchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "schema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); - var jsonString = @"{ - ""type"": ""object"", - ""properties"": { - ""one"": { - ""description"": ""type array"", - ""type"": [ - ""integer"", - ""string"" - ] - } - } -}"; - var expectedSchema = JsonSerializer.Deserialize(jsonString); - - // Assert - Assert.Equal(schema, expectedSchema); - } - - [Fact] - public void ParseAdvancedV31SchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedSchema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); - var jsonString = @"{ - ""type"": ""object"", - ""properties"": { - ""one"": { - ""description"": ""type array"", - ""type"": [ - ""integer"", - ""string"" - ] - }, - ""two"": { - ""description"": ""type 'null'"", - ""type"": ""null"" - }, - ""three"": { - ""description"": ""type array including 'null'"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""four"": { - ""description"": ""array with no items"", - ""type"": ""array"" - }, - ""five"": { - ""description"": ""singular example"", - ""type"": ""string"", - ""examples"": [ - ""exampleValue"" - ] - }, - ""six"": { - ""description"": ""exclusiveMinimum true"", - ""exclusiveMinimum"": 10 - }, - ""seven"": { - ""description"": ""exclusiveMinimum false"", - ""minimum"": 10 - }, - ""eight"": { - ""description"": ""exclusiveMaximum true"", - ""exclusiveMaximum"": 20 - }, - ""nine"": { - ""description"": ""exclusiveMaximum false"", - ""maximum"": 20 - }, - ""ten"": { - ""description"": ""nullable string"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""eleven"": { - ""description"": ""x-nullable string"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""twelve"": { - ""description"": ""file/binary"" - } - } -}"; - var expectedSchema = JsonSerializer.Deserialize(jsonString); - - // Assert - schema.Should().BeEquivalentTo(expectedSchema); - } - - [Fact] - public void ParseStandardSchemaExampleSucceeds() - { - // Arrange - var builder = new JsonSchemaBuilder(); - var myschema = builder.Title("My Schema") - .Description("A schema for testing") - .Type(SchemaValueType.Object) - .Properties( - ("name", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("The name of the person")), - ("age", - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Description("The age of the person"))) - .Build(); - - // Act - var title = myschema.Get().Value; - var description = myschema.Get().Value; - var nameProperty = myschema.Get().Properties["name"]; - - // Assert - Assert.Equal("My Schema", title); - Assert.Equal("A schema for testing", description); - } - } - - public static class SchemaExtensions - { - public static T Get(this JsonSchema schema) - { - return (T)schema.Keywords.FirstOrDefault(x => x is T); - } - } -} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index d4ee7bdf1..66b00c9f7 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -45,36 +44,83 @@ public void ParseDocumentWithWebhooksShouldSucceed() { // Arrange and Act var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema"); + var petSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "petSchema" + } + }; + + var newPetSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "newPetSchema" + } + }; var components = new OpenApiComponents { Schemas = { - ["petSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")), - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String)) - ), - ["newPetSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")), - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["petSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPetSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + } } }; @@ -103,11 +149,14 @@ public void ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -115,8 +164,11 @@ public void ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -128,16 +180,19 @@ public void ParseDocumentWithWebhooksShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) - + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } } @@ -191,30 +246,84 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["petSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPetSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["petSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPetSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + } } }; - - // Create a clone of the schema to avoid modifying things in components. - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema"); + var petSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "petSchema" + } + }; + + var newPetSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "newPetSchema" + } + }; components.PathItems = new Dictionary { @@ -234,9 +343,14 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -244,8 +358,11 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -257,15 +374,19 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new OpenApiSchema + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new OpenApiSchema + { + Type = "array", + Items = petSchema + } } } } @@ -350,15 +471,32 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "docWithPatternPropertiesInSchema.yaml")); var actualSchema = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("prop1", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("prop2", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("prop3", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .PatternProperties( - ("^x-.*$", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build(); + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["prop1"] = new OpenApiSchema + { + Type = "string" + }, + ["prop2"] = new OpenApiSchema + { + Type = "string" + }, + ["prop3"] = new OpenApiSchema + { + Type = "string" + } + }, + PatternProperties = new Dictionary + { + ["^x-.*$"] = new OpenApiSchema + { + Type = "string" + } + } + }; // Serialization var mediaType = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index 72c5289e5..ae83a3abe 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -3,9 +3,15 @@ using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text.Json.Nodes; using FluentAssertions; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; +using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Reader.V31; +using SharpYaml.Serialization; using Xunit; namespace Microsoft.OpenApi.Readers.Tests.V31Tests @@ -133,5 +139,130 @@ public void TestSchemaCopyConstructorWithTypeArrayWorks() simpleSchemaCopy.Type.Should().NotBeEquivalentTo(simpleSchema.Type); simpleSchema.Type = "string"; } + + [Fact] + public void ParseV31SchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "schema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV31Deserializer.LoadSchema(node); + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["one"] = new() + { + Description = "type array", + Type = new HashSet { "integer", "string" } + } + } + }; + + // Assert + Assert.Equal(schema, expectedSchema); + } + + [Fact] + public void ParseAdvancedV31SchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedSchema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV31Deserializer.LoadSchema(node); + + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["one"] = new() + { + Description = "type array", + Type = new HashSet { "integer", "string" } + }, + ["two"] = new() + { + Description = "type 'null'", + Type = "null" + }, + ["three"] = new() + { + Description = "type array including 'null'", + Type = new HashSet { "string", "null" } + }, + ["four"] = new() + { + Description = "array with no items", + Type = "array" + }, + ["five"] = new() + { + Description = "singular example", + Type = "string", + Examples = new List + { + new OpenApiAny("exampleValue").Node + } + }, + ["six"] = new() + { + Description = "exclusiveMinimum true", + V31ExclusiveMinimum = 10 + }, + ["seven"] = new() + { + Description = "exclusiveMinimum false", + Minimum = 10 + }, + ["eight"] = new() + { + Description = "exclusiveMaximum true", + V31ExclusiveMaximum = 20 + }, + ["nine"] = new() + { + Description = "exclusiveMaximum false", + Maximum = 20 + }, + ["ten"] = new() + { + Description = "nullable string", + Type = new HashSet { "string", "null" } + }, + ["eleven"] = new() + { + Description = "x-nullable string", + Type = new HashSet { "string", "null" } + }, + ["twelve"] = new() + { + Description = "file/binary" + } + } + }; + + // Assert + schema.Should().BeEquivalentTo(expectedSchema); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs deleted file mode 100644 index dd98bdb92..000000000 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json.Nodes; -using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using SharpYaml.Serialization; -using Xunit; -using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Reader.ParseNodes; -using Microsoft.OpenApi.Reader.V3; - -namespace Microsoft.OpenApi.Readers.Tests.V3Tests -{ - [Collection("DefaultSettings")] - public class JsonSchemaTests - { - private const string SampleFolderPath = "V3Tests/Samples/OpenApiSchema/"; - - public JsonSchemaTests() - { - OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); - } - - [Fact] - public void ParsePrimitiveSchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "primitiveSchema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format("email") - .Build()); - } - - [Fact] - public void ParseExampleStringFragmentShouldSucceed() - { - var input = @" -{ - ""foo"": ""bar"", - ""baz"": [ 1,2] -}"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo(new OpenApiAny( - new JsonObject - { - ["foo"] = "bar", - ["baz"] = new JsonArray() { 1, 2 } - }), options => options.IgnoringCyclicReferences()); - } - - [Fact] - public void ParseEnumFragmentShouldSucceed() - { - var input = @" -[ - ""foo"", - ""baz"" -]"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo(new OpenApiAny( - new JsonArray - { - "foo", - "baz" - }), options => options.IgnoringCyclicReferences()); - } - - [Fact] - public void ParsePathFragmentShouldSucceed() - { - var input = @" -summary: externally referenced path item -get: - responses: - '200': - description: Ok -"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic, "yaml"); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo( - new OpenApiPathItem - { - Summary = "externally referenced path item", - Operations = new Dictionary - { - [OperationType.Get] = new OpenApiOperation() - { - Responses = new OpenApiResponses - { - ["200"] = new OpenApiResponse - { - Description = "Ok" - } - } - } - } - }); - } - - [Fact] - public void ParseDictionarySchemaShouldSucceed() - { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "dictionarySchema.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.String)) - .Build()); - } - } - - [Fact] - public void ParseBasicSchemaWithExampleShouldSucceed() - { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Required("name") - .Example(new JsonObject { ["name"] = "Puma", ["id"] = 1 }) - .Build(), - options => options.IgnoringCyclicReferences()); - } - } - - [Fact] - public void ParseBasicSchemaWithReferenceShouldSucceed() - { - // Act - var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "basicSchemaWithReference.yaml")); - - // Assert - var components = result.OpenApiDocument.Components; - - result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic() - { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } - }); - - var expectedComponents = new OpenApiComponents - { - Schemas = - { - ["ErrorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("message", "code") - .Properties( - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Minimum(100).Maximum(600))), - ["ExtendedErrorModel"] = new JsonSchemaBuilder() - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/ErrorModel"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("rootCause") - .Properties(("rootCause", new JsonSchemaBuilder().Type(SchemaValueType.String)))) - } - }; - - components.Should().BeEquivalentTo(expectedComponents); - } - - [Fact] - public void ParseAdvancedSchemaWithReferenceShouldSucceed() - { - // Act - var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "advancedSchemaWithReference.yaml")); - - var expectedComponents = new OpenApiComponents - { - Schemas = - { - ["Pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - ["Cat"] = new JsonSchemaBuilder() - .Description("A representation of a cat") - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet1") - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("huntingSkill") - .Properties( - ("huntingSkill", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("The measured skill for hunting") - .Enum("clueless", "lazy", "adventurous", "aggressive") - ) - ) - ), - ["Dog"] = new JsonSchemaBuilder() - .Description("A representation of a dog") - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet1") - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("packSize") - .Properties( - ("packSize", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Description("the size of the pack the dog is from") - .Default(0) - .Minimum(0) - ) - ) - ) - } - }; - - // We serialize so that we can get rid of the schema BaseUri properties which show up as diffs - var actual = result.OpenApiDocument.Components.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); - var expected = expectedComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); - - // Assert - actual.Should().Be(expected); - } - } -} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 5deea9e83..544fec90b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -1,10 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -96,7 +95,10 @@ public void ParseCallbackWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, @@ -149,7 +151,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, @@ -188,7 +193,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -220,7 +228,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index c694c392e..0d3bb622f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -7,9 +7,7 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -209,39 +207,130 @@ public void ParseMinimalDocumentShouldSucceed() public void ParseStandardPetStoreDocumentShouldSucceed() { using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "petStore.yaml")); - var result = OpenApiDocument.Load(stream, OpenApiConstants.Yaml); + var actual = OpenApiDocument.Load(stream, OpenApiConstants.Yaml); var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "pet", + HostDocument = actual.OpenApiDocument + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "errorModel", + HostDocument = actual.OpenApiDocument + } + }, } }; - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet"); + // Create a clone of the schema to avoid modifying things in components. + var petSchema = Clone(components.Schemas["pet"]); - var errorModelSchema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel"); + petSchema.Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; + + var newPetSchema = Clone(components.Schemas["newPet"]); + + newPetSchema.Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; + + var errorModelSchema = Clone(components.Schemas["errorModel"]); + + errorModelSchema.Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; var expectedDoc = new OpenApiDocument { @@ -289,9 +378,14 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -299,7 +393,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -311,11 +409,19 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } }, @@ -415,7 +521,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -471,7 +581,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -510,9 +624,9 @@ public void ParseStandardPetStoreDocumentShouldSucceed() Components = components }; - result.OpenApiDocument.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); + actual.OpenApiDocument.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); - result.OpenApiDiagnostic.Should().BeEquivalentTo( + actual.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); } @@ -524,28 +638,95 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "pet", + HostDocument = actual.OpenApiDocument + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "errorModel" + } + }, }, SecuritySchemes = new Dictionary { @@ -563,11 +744,29 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }; - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1"); + // Create a clone of the schema to avoid modifying things in components. + var petSchema = Clone(components.Schemas["pet"]); + petSchema.Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema + }; - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet"); + var newPetSchema = Clone(components.Schemas["newPet"]); - var errorModelSchema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel"); + newPetSchema.Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema + }; + + var errorModelSchema = Clone(components.Schemas["errorModel"]); + + errorModelSchema.Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema + }; var tag1 = new OpenApiTag { @@ -658,9 +857,14 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -668,9 +872,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -682,15 +888,19 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } }, @@ -807,9 +1017,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -865,9 +1077,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -982,9 +1196,11 @@ public void HeaderParameterShouldAllowExample() Style = ParameterStyle.Simple, Explode = true, Example = new OpenApiAny("99391c7e-ad88-49ec-a2ad-99ddcb1f7721"), - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format(Formats.Uuid) + Schema = new() + { + Type = "string", + Format = "uuid" + }, }, options => options.IgnoringCyclicReferences() .Excluding(e => e.Example.Node.Parent) .Excluding(x => x.Reference)); @@ -1014,9 +1230,11 @@ public void HeaderParameterShouldAllowExample() } } }, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format(Formats.Uuid) + Schema = new() + { + Type = "string", + Format = "uuid" + }, }, options => options.IgnoringCyclicReferences() .Excluding(e => e.Examples["uuid1"].Value.Node.Parent) .Excluding(e => e.Examples["uuid2"].Value.Node.Parent)); @@ -1054,9 +1272,14 @@ public void ParseDocumentWithJsonSchemaReferencesWorks() var actualSchema = result.OpenApiDocument.Paths["/users/{userId}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new JsonSchemaBuilder() - .Ref("#/components/schemas/User") - .Build(); + var expectedSchema = new OpenApiSchema() + { + Reference = new OpenApiReference + { + Id = "User", + Type = ReferenceType.Schema + } + }; // Assert actualSchema.Should().BeEquivalentTo(expectedSchema); @@ -1105,10 +1328,12 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() In = ParameterLocation.Query, Description = "Limit the number of pets returned", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Default(10), + Schema = new() + { + Type = "integer", + Format = "int32", + Default = new OpenApiAny(10) + }, Reference = new OpenApiReference { Id = "LimitParameter", @@ -1131,10 +1356,12 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() In = ParameterLocation.Query, Description = "Limit the number of pets returned", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Default(10) + Schema = new() + { + Type = "integer", + Format = "int32", + Default = new OpenApiAny(10) + }, } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs index 837b1d4f1..01239e415 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs @@ -3,7 +3,6 @@ using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; using Xunit; @@ -53,7 +52,10 @@ public void ParseAdvancedEncodingShouldSucceed() new() { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } } } }); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index 37b055bb3..90c797723 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -3,7 +3,6 @@ using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -32,7 +31,11 @@ public void ParseMediaTypeWithExampleShouldSucceed() new OpenApiMediaType { Example = new OpenApiAny(5), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(m => m.Example.Node.Parent) ); @@ -59,7 +62,11 @@ public void ParseMediaTypeWithExamplesShouldSucceed() Value = new OpenApiAny(7.5) } }, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(m => m.Examples["example1"].Value.Node.Parent) .Excluding(m => m.Examples["example2"].Value.Node.Parent)); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs index ff03c553f..d6570f17b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -53,8 +52,10 @@ public void ParseOperationWithParameterWithNoLocationShouldSucceed() Name = "username", Description = "The user name for login", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, new OpenApiParameter { @@ -62,8 +63,10 @@ public void ParseOperationWithParameterWithNoLocationShouldSucceed() Description = "The password for login in clear text", In = ParameterLocation.Query, Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 5a6e9fd41..1a6cb9aa9 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -5,7 +5,6 @@ using System; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -42,7 +41,10 @@ public void ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -60,7 +62,14 @@ public void ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Form, Explode = true }); @@ -78,9 +87,14 @@ public void ParseQueryParameterWithObjectTypeShouldSucceed() { In = ParameterLocation.Query, Name = "freeForm", - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer)), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + }, Style = ParameterStyle.Form }); } @@ -104,17 +118,26 @@ public void ParseQueryParameterWithObjectTypeAndContentShouldSucceed() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("lat", "long") - .Properties( - ("lat", new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - ), - ("long", new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - ) - ) + Schema = new() + { + Type = "object", + Required = + { + "lat", + "long" + }, + Properties = + { + ["lat"] = new() + { + Type = "number" + }, + ["long"] = new() + { + Type = "number" + } + } + } } } }); @@ -136,11 +159,15 @@ public void ParseHeaderParameterShouldSucceed() Required = true, Style = ParameterStyle.Simple, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "integer", + Format = "int64", + } + } }); } @@ -158,8 +185,10 @@ public void ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -180,8 +209,10 @@ public void ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -202,8 +233,10 @@ public void ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -222,9 +255,11 @@ public void ParseParameterWithExampleShouldSucceed() Description = "username to fetch", Required = true, Example = new OpenApiAny((float)5.0), - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences().Excluding(p => p.Example.Node.Parent)); } @@ -253,9 +288,11 @@ public void ParseParameterWithExamplesShouldSucceed() Value = new OpenApiAny((float)7.5) } }, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(p => p.Examples["example1"].Value.Node.Parent) .Excluding(p => p.Examples["example2"].Value.Node.Parent)); @@ -313,9 +350,14 @@ public void ParseParameterWithReferenceWorks() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)).Build(), + Schema = new() + { + Type = "array", + Items = new OpenApiSchema + { + Type = "string" + } + }, Reference = new OpenApiReference { Type = ReferenceType.Parameter, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs new file mode 100644 index 000000000..4d3055668 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json.Nodes; +using FluentAssertions; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Extensions; +using SharpYaml.Serialization; +using Xunit; +using Microsoft.OpenApi.Reader; +using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Reader.V3; + +namespace Microsoft.OpenApi.Readers.Tests.V3Tests +{ + [Collection("DefaultSettings")] + public class OpenApiSchemaTests + { + private const string SampleFolderPath = "V3Tests/Samples/OpenApiSchema/"; + + public OpenApiSchemaTests() + { + OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); + } + + [Fact] + public void ParsePrimitiveSchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "primitiveSchema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "string", + Format = "email" + }); + } + + [Fact] + public void ParseExampleStringFragmentShouldSucceed() + { + var input = @" +{ + ""foo"": ""bar"", + ""baz"": [ 1,2] +}"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo(new OpenApiAny( + new JsonObject + { + ["foo"] = "bar", + ["baz"] = new JsonArray() { 1, 2 } + }), options => options.IgnoringCyclicReferences()); + } + + [Fact] + public void ParseEnumFragmentShouldSucceed() + { + var input = @" +[ + ""foo"", + ""baz"" +]"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo(new OpenApiAny( + new JsonArray + { + "foo", + "baz" + }), options => options.IgnoringCyclicReferences()); + } + + [Fact] + public void ParsePathFragmentShouldSucceed() + { + var input = @" +summary: externally referenced path item +get: + responses: + '200': + description: Ok +"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic, "yaml"); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo( + new OpenApiPathItem + { + Summary = "externally referenced path item", + Operations = new Dictionary + { + [OperationType.Get] = new OpenApiOperation() + { + Responses = new OpenApiResponses + { + ["200"] = new OpenApiResponse + { + Description = "Ok" + } + } + } + } + }); + } + + [Fact] + public void ParseDictionarySchemaShouldSucceed() + { + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "dictionarySchema.yaml"))) + { + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + AdditionalProperties = new() + { + Type = "string" + } + }); + } + } + + [Fact] + public void ParseBasicSchemaWithExampleShouldSucceed() + { + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) + { + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + Properties = + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + } + }, + Required = + { + "name" + }, + Example = new OpenApiAny(new JsonObject + { + ["name"] = new OpenApiAny("Puma").Node, + ["id"] = new OpenApiAny(1).Node + }) + }); + } + } + + [Fact] + public void ParseBasicSchemaWithReferenceShouldSucceed() + { + // Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "basicSchemaWithReference.yaml")); + + // Assert + var components = result.OpenApiDocument.Components; + + result.OpenApiDiagnostic.Should().BeEquivalentTo( + new OpenApiDiagnostic() + { + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Errors = new List() + { + new OpenApiError("", "Paths is a REQUIRED field at #/") + } + }); + + var expectedComponents = new OpenApiComponents + { + Schemas = + { + ["ErrorModel"] = new() + { + Type = "object", + Properties = + { + ["code"] = new() + { + Type = "integer", + Minimum = 100, + Maximum = 600 + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ErrorModel", + HostDocument = result.OpenApiDocument + }, + Required = + { + "message", + "code" + } + }, + ["ExtendedErrorModel"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ExtendedErrorModel", + HostDocument = result.OpenApiDocument + }, + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ErrorModel", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the ErrorModel above should be propagated here. + Type = "object", + Properties = + { + ["code"] = new() + { + Type = "integer", + Minimum = 100, + Maximum = 600 + }, + ["message"] = new() + { + Type = "string" + } + }, + Required = + { + "message", + "code" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"rootCause"}, + Properties = + { + ["rootCause"] = new() + { + Type = "string" + } + } + } + } + } + } + }; + + components.Should().BeEquivalentTo(expectedComponents); + } + + [Fact] + public void ParseAdvancedSchemaWithReferenceShouldSucceed() + { + // Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "advancedSchemaWithReference.yaml")); + + var expectedComponents = new OpenApiComponents + { + Schemas = + { + ["Pet"] = new() + { + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + }, + Reference = new() + { + Id= "Pet", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }, + ["Cat"] = new() + { + Description = "A representation of a cat", + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Pet", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the Pet above should be propagated here. + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"huntingSkill"}, + Properties = + { + ["huntingSkill"] = new() + { + Type = "string", + Description = "The measured skill for hunting", + Enum = + { + new OpenApiAny("clueless").Node, + new OpenApiAny("lazy").Node, + new OpenApiAny("adventurous").Node, + new OpenApiAny("aggressive").Node + } + } + } + } + }, + Reference = new() + { + Id= "Cat", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }, + ["Dog"] = new() + { + Description = "A representation of a dog", + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Pet", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the Pet above should be propagated here. + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"packSize"}, + Properties = + { + ["packSize"] = new() + { + Type = "integer", + Format = "int32", + Description = "the size of the pack the dog is from", + Default = new OpenApiAny(0), + Minimum = 0 + } + } + } + }, + Reference = new() + { + Id= "Dog", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + } + } + }; + + // We serialize so that we can get rid of the schema BaseUri properties which show up as diffs + var actual = result.OpenApiDocument.Components.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + var expected = expectedComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + + // Assert + actual.Should().Be(expected); + } + } +} diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs index eb1476f7b..ee6d6e658 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs @@ -1,11 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; using Xunit; namespace Microsoft.OpenApi.Tests.Extensions @@ -14,40 +14,41 @@ public class OpenApiTypeMapperTests { public static IEnumerable PrimitiveTypeData => new List { - new object[] { typeof(int), new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() }, - new object[] { typeof(string), new JsonSchemaBuilder().Type(SchemaValueType.String).Build() }, - new object[] { typeof(double), new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build() }, - new object[] { typeof(DateTimeOffset), new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build() } + new object[] { typeof(int), new OpenApiSchema { Type = "integer", Format = "int32" } }, + new object[] { typeof(string), new OpenApiSchema { Type = "string" } }, + new object[] { typeof(double), new OpenApiSchema { Type = "number", Format = "double" } }, + new object[] { typeof(float?), new OpenApiSchema { Type = "number", Format = "float", Nullable = true } }, + new object[] { typeof(DateTimeOffset), new OpenApiSchema { Type = "string", Format = "date-time" } } }; - public static IEnumerable JsonSchemaDataTypes => new List + public static IEnumerable OpenApiDataTypes => new List { - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build(), typeof(int) }, - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), typeof(double) }, - new object[] { new JsonSchemaBuilder().AnyOf( - new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build(), - new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .Format("float").Build(), typeof(float?) }, - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build(), typeof(DateTimeOffset) } + new object[] { new OpenApiSchema { Type = "integer", Format = "int32"}, typeof(int) }, + new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = false}, typeof(int) }, + new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = true}, typeof(int?) }, + new object[] { new OpenApiSchema { Type = "string" }, typeof(string) }, + new object[] { new OpenApiSchema { Type = "number", Format = "double" }, typeof(double) }, + new object[] { new OpenApiSchema { Type = "number", Format = "float", Nullable = true }, typeof(float?) }, + new object[] { new OpenApiSchema { Type = "string", Format = "date-time" }, typeof(DateTimeOffset) } }; [Theory] [MemberData(nameof(PrimitiveTypeData))] - public void MapTypeToJsonPrimitiveTypeShouldSucceed(Type type, JsonSchema expected) + public void MapTypeToOpenApiPrimitiveTypeShouldSucceed(Type type, OpenApiSchema expected) { // Arrange & Act - var actual = OpenApiTypeMapper.MapTypeToJsonPrimitiveType(type); + var actual = OpenApiTypeMapper.MapTypeToOpenApiPrimitiveType(type); // Assert actual.Should().BeEquivalentTo(expected); } [Theory] - [MemberData(nameof(JsonSchemaDataTypes))] - public void MapOpenApiSchemaTypeToSimpleTypeShouldSucceed(JsonSchema schema, Type expected) + [MemberData(nameof(OpenApiDataTypes))] + public void MapOpenApiSchemaTypeToSimpleTypeShouldSucceed(OpenApiSchema schema, Type expected) { // Arrange & Act - var actual = OpenApiTypeMapper.MapJsonSchemaValueTypeToSimpleType(schema); + var actual = OpenApiTypeMapper.MapOpenApiPrimitiveTypeToSimpleType(schema); // Assert actual.Should().Be(expected); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 310511db8..083b89ffc 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -35,7 +34,10 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Build() + Schema = new() + { + Type = "object" + } } } }, @@ -72,7 +74,10 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Build() + Schema = new() + { + Type = "object" + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index e99072d50..74ec5a8b9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -16,14 +15,23 @@ public class OpenApiComponentsTests { public static OpenApiComponents AdvancedComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()), - ("property3", new JsonSchemaBuilder().Type(SchemaValueType.String).MaxLength(15).Build())) - .Build() - + ["schema1"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + }, + ["property3"] = new() + { + Type = "string", + MaxLength = 15 + } + } + } }, SecuritySchemes = new Dictionary { @@ -56,15 +64,41 @@ public class OpenApiComponentsTests public static OpenApiComponents AdvancedComponentsWithReference = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer)), - ("property3", new JsonSchemaBuilder().Ref("#/components/schemas/schema2"))), - ["schema2"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer))) + ["schema1"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + }, + ["property3"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + } + } + }, }, SecuritySchemes = new Dictionary { @@ -109,13 +143,29 @@ public class OpenApiComponentsTests public static OpenApiComponents BrokenComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder().Type(SchemaValueType.String), - ["schema4"] = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .AllOf(new JsonSchemaBuilder().Type(SchemaValueType.String).Build()) - .Build() + ["schema1"] = new() + { + Type = "string" + }, + ["schema2"] = null, + ["schema3"] = null, + ["schema4"] = new() + { + Type = "string", + AllOf = new List + { + null, + null, + new() + { + Type = "string" + }, + null, + null + } + } } }; @@ -123,12 +173,25 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Ref("#/components/schemas/schema2").Build(), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -136,18 +199,33 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Ref("#/components/schemas/schema1") - .Build(), - - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build() + ["schema1"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -155,25 +233,50 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Ref("schema1").Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } }; public static OpenApiComponents ComponentsWithPathItem = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary() { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()), - ("property3", new JsonSchemaBuilder().Ref("#/components/schemas/schema2").Build())) - .Build(), - - ["schema2"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer))) - .Build() + ["schema1"] = new OpenApiSchema() + { + Properties = new Dictionary() + { + ["property2"] = new OpenApiSchema() + { + Type = "integer" + }, + ["property3"] = new OpenApiSchema() + { + Reference = new OpenApiReference() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + } + } + }, + + ["schema2"] = new() + { + Properties = new Dictionary() + { + ["property2"] = new OpenApiSchema() + { + Type = "integer" + } + } + } }, PathItems = new Dictionary { @@ -190,7 +293,14 @@ public class OpenApiComponentsTests { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("#/components/schemas/schema1") + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index ba2e9a89e..5b95221e3 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -34,11 +33,25 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder().Ref("#/definitions/schema2"), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + }, + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string", + } + } + }, } }; @@ -46,13 +59,33 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/definitions/schema1"), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) + ["schema1"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string", + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -61,7 +94,14 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder().Ref("#/definitions/schemas/schema1") + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } }; @@ -94,38 +134,101 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponentsWithReference = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/pet").Build(), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/newPet").Build(), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build()), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/errorModel").Build() + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema + } + }, } }; - public static readonly JsonSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"]; + public static OpenApiSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"]; - public static readonly JsonSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"]; + public static OpenApiSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"]; - public static readonly JsonSchema ErrorModelSchemaWithReference = + public static OpenApiSchema ErrorModelSchemaWithReference = AdvancedComponentsWithReference.Schemas["errorModel"]; public static readonly OpenApiDocument AdvancedDocumentWithReference = new OpenApiDocument @@ -174,9 +277,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)).Build() + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -184,9 +292,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -198,15 +308,19 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchemaWithReference).Build() + Schema = new() + { + Type = "array", + Items = PetSchemaWithReference + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchemaWithReference).Build() + Schema = new() + { + Type = "array", + Items = PetSchemaWithReference + } } } }, @@ -306,10 +420,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -365,10 +480,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -409,35 +525,86 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponents = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build()), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + } + }, } }; - public static readonly JsonSchema PetSchema = AdvancedComponents.Schemas["pet"]; + public static readonly OpenApiSchema PetSchema = AdvancedComponents.Schemas["pet"]; - public static readonly JsonSchema NewPetSchema = AdvancedComponents.Schemas["newPet"]; + public static readonly OpenApiSchema NewPetSchema = AdvancedComponents.Schemas["newPet"]; - public static readonly JsonSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"]; + public static readonly OpenApiSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"]; public OpenApiDocument AdvancedDocument = new OpenApiDocument { @@ -485,12 +652,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build()) - .Build() + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -498,10 +667,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -513,17 +683,19 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } } } }, @@ -623,10 +795,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -682,10 +855,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -746,9 +920,14 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet") - .Build() + Schema = new() + { + Reference = new OpenApiReference + { + Id = "Pet", + Type = ReferenceType.Schema + } + } } } }, @@ -765,15 +944,31 @@ public OpenApiDocumentTests() }, Components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["Pet"] = new JsonSchemaBuilder() - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Build() + ["Pet"] = new OpenApiSchema() + { + Required = new HashSet + { + "id", "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + } } } }; @@ -810,12 +1005,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The first operand", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Extensions(new Dictionary + Schema = new() + { + Type = "integer", + Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4) - }), + } + }, Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4), @@ -827,12 +1024,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The second operand", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Extensions(new Dictionary - { - ["my-extension"] = new OpenApiAny(4) - }), + Schema = new() + { + Type = "integer", + Extensions = new Dictionary + { + ["my-extension"] = new OpenApiAny(4) + } + }, Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4), @@ -848,10 +1047,11 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } }, } } @@ -1066,7 +1266,14 @@ public void SerializeDocumentWithReferenceButNoComponents() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("test") + Schema = new() + { + Reference = new() + { + Id = "test", + Type = ReferenceType.Schema + } + } } } } @@ -1077,7 +1284,7 @@ public void SerializeDocumentWithReferenceButNoComponents() } }; - var reference = document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.GetRef(); + var reference = document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Reference; // Act var actual = document.Serialize(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json); @@ -1236,7 +1443,10 @@ public void SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollectionFo new OpenApiParameter { In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } }, Responses = new OpenApiResponses() @@ -1302,11 +1512,14 @@ public void SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { Name = "id", In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .AdditionalPropertiesAllowed(true) - .Build() + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + } } }, Responses = new OpenApiResponses @@ -1318,8 +1531,10 @@ public void SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index d63330a09..de569bb49 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -19,7 +18,11 @@ public class OpenApiHeaderTests public static OpenApiHeader AdvancedHeader = new() { Description = "sampleHeader", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } }; public static OpenApiHeaderReference OpenApiHeaderReference = new(ReferencedHeader, "example1"); @@ -27,7 +30,11 @@ public class OpenApiHeaderTests public static OpenApiHeader ReferencedHeader = new() { Description = "sampleHeader", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } }; [Theory] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 756b10514..7c729341d 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -47,7 +46,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } }, @@ -60,7 +64,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } } @@ -115,7 +124,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } }, @@ -128,7 +142,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } } @@ -169,7 +188,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -178,21 +200,49 @@ public class OpenApiOperationTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated name of the pet")), - ("status", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated status of the pet"))) - .Required("name") - .Build() + Schema = new() + { + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated name of the pet")), - ("status", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated status of the pet"))) - .Required("name") - .Build() + Schema = new() + { + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index b173f2363..7f3b0b140 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -7,7 +7,6 @@ using System.Text.Json.Nodes; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -43,13 +42,16 @@ public class OpenApiParameterTests Deprecated = false, Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder() - .Title("title2") - .Description("description2") - .OneOf(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), - new JsonSchemaBuilder().Type(SchemaValueType.String).Build()) - .Build(), - + Schema = new() + { + Title = "title2", + Description = "description2", + OneOf = new List + { + new() { Type = "number", Format = "double" }, + new() { Type = "string" } + } + }, Examples = new Dictionary { ["test"] = new() @@ -67,18 +69,18 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items( - new JsonSchemaBuilder() - .Enum(new List + Schema = new() + { + Type = "array", + Items = new() + { + Enum = { new OpenApiAny("value1").Node, new OpenApiAny("value2").Node - }) - .Build()) - .Build() - + } + } + } }; public static OpenApiParameter ParameterWithFormStyleAndExplodeTrue = new() @@ -88,31 +90,32 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items( - new JsonSchemaBuilder() - .Enum(new List - { + Schema = new() + { + Type = "array", + Items = new() + { + Enum = + [ new OpenApiAny("value1").Node, new OpenApiAny("value2").Node - }) - .Build()) - .Build() - + ] + } + } }; public static OpenApiParameter QueryParameterWithMissingStyle = new OpenApiParameter { Name = "id", In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Build()) - .AdditionalPropertiesAllowed(true) - .Build() + Schema = new() + { + Type = "array", + AdditionalProperties = new OpenApiSchema + { + Type = "integer" + } + } }; public static OpenApiParameter AdvancedHeaderParameterWithSchemaReference = new OpenApiParameter @@ -125,7 +128,15 @@ public class OpenApiParameterTests Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder().Ref("schemaObject1").Build(), + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + }, + UnresolvedReference = true + }, Examples = new Dictionary { ["test"] = new() @@ -146,7 +157,10 @@ public class OpenApiParameterTests Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object), + Schema = new() + { + Type = "object" + }, Examples = new Dictionary { ["test"] = new() diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index 93d9f337f..5101bb22b 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -24,7 +23,10 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }; @@ -38,7 +40,10 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index d9006ec09..a07362c32 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -31,9 +30,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/definitions/customType")), + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary { @@ -46,12 +50,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -62,9 +72,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/components/schemas/customType")), + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary { @@ -77,12 +92,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -95,9 +116,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/definitions/customType")) + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + } } }, Headers = @@ -105,12 +131,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -123,9 +155,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/components/schemas/customType")) + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + } } }, Headers = @@ -133,12 +170,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs index e55acf5f3..5773c178e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -103,7 +102,7 @@ public OpenApiHeaderReferenceTests() public void HeaderReferenceResolutionWorks() { // Assert - Assert.Equal(SchemaValueType.String, _externalHeaderReference.Schema.GetJsonType()); + Assert.Equal("string", _externalHeaderReference.Schema.Type); Assert.Equal("Location of the locally referenced post", _localHeaderReference.Description); Assert.Equal("Location of the externally referenced post", _externalHeaderReference.Description); Assert.Equal("The URL of the newly created post", diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs index b6467d1c1..54521e83c 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; -using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -112,13 +110,13 @@ public void RequestBodyReferenceResolutionWorks() // Assert var localContent = _localRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(localContent); - Assert.Equal("#/components/schemas/UserSchema", localContent.Schema.GetRef().OriginalString); + Assert.Equal("UserSchema", localContent.Schema.Reference.Id); Assert.Equal("User request body", _localRequestBodyReference.Description); Assert.Equal("application/json", _localRequestBodyReference.Content.First().Key); var externalContent = _externalRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(externalContent); - Assert.Equal("#/components/schemas/UserSchema", externalContent.Schema.GetRef().OriginalString); + Assert.Equal("UserSchema", externalContent.Schema.Reference.Id); Assert.Equal("External Reference: User request body", _externalRequestBodyReference.Description); Assert.Equal("User creation request body", _openApiDoc_2.Components.RequestBodies.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs index 42d0532e7..4b6b25564 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -94,12 +93,12 @@ public void ResponseReferenceResolutionWorks() // Assert var localContent = _localResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", localContent.Key); - Assert.Equal("#/components/schemas/Pong", localContent.Value.Schema.GetRef().OriginalString); + Assert.Equal("Pong", localContent.Value.Schema.Reference.Id); Assert.Equal("OK response", _localResponseReference.Description); var externalContent = _externalResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", externalContent.Key); - Assert.Equal("#/components/schemas/Pong", externalContent.Value.Schema.GetRef().OriginalString); + Assert.Equal("Pong", externalContent.Value.Schema.Reference.Id); Assert.Equal("External reference: OK response", _externalResponseReference.Description); Assert.Equal("OK", _openApiDoc_2.Components.Responses.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index d9397a933..958466da2 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -1,15 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; -using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -25,7 +23,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() { Required = true, Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new OpenApiSchema + { + Type = "string" + } }; // Act @@ -58,42 +59,43 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() var header = new OpenApiHeader { Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Build()) - .Build(), + Schema = new OpenApiSchema + { + Type = "object", + AdditionalProperties = new OpenApiSchema + { + Type = "integer" + } + }, Examples = + { + ["example0"] = new() { - ["example0"] = new() - { - Value = new OpenApiAny("1"), - }, - ["example1"] = new() - { - Value = new OpenApiAny(new JsonObject() - { - ["x"] = 2, - ["y"] = "20", - ["z"] = "200" - }) - }, - ["example2"] = new() + Value = new OpenApiAny("1"), + }, + ["example1"] = new() + { + Value = new OpenApiAny(new JsonObject() { - Value =new OpenApiAny( - new JsonArray(){3}) - }, - ["example3"] = new() + ["x"] = 2, + ["y"] = "20", + ["z"] = "200" + }) + }, + ["example2"] = new() + { + Value =new OpenApiAny( + new JsonArray(){3}) + }, + ["example3"] = new() + { + Value = new OpenApiAny(new JsonObject() { - Value = new OpenApiAny(new JsonObject() - { - ["x"] = 4, - ["y"] = 40 - }) - }, - } + ["x"] = 4, + ["y"] = 40 + }) + }, + } }; // Act diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index a9ef6ec25..be6e86194 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -1,11 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -23,7 +22,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), + Schema = new() + { + Type = "string", + } }; // Act @@ -55,11 +57,14 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Build()) - .Build(), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer", + } + }, Examples = { ["example0"] = new() diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 3f7a2d20c..5048e1040 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -1,20 +1,16 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; -using Microsoft.OpenApi.Validations.Rules; using Xunit; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace Microsoft.OpenApi.Validations.Tests { @@ -75,7 +71,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() In = ParameterLocation.Path, Required = true, Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string", + } }; // Act @@ -110,13 +109,14 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Build()) - .Build(), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer", + } + }, Examples = { ["example0"] = new() @@ -187,7 +187,10 @@ public void PathParameterNotInThePathShouldReturnAnError() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string", + } }; // Act @@ -222,7 +225,10 @@ public void PathParameterInThePathShouldBeOk() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string", + } }; // Act diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index e011d80ee..f41009fbc 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Validations; @@ -19,12 +18,20 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() { // Arrange - var sharedSchema = new JsonSchemaBuilder().Type(SchemaValueType.String).Ref("test"); + var sharedSchema = new OpenApiSchema + { + Type = "string", + Reference = new() + { + Id = "test" + }, + UnresolvedReference = false + }; var document = new OpenApiDocument(); document.Components = new() { - Schemas = new Dictionary() + Schemas = new Dictionary() { ["test"] = sharedSchema } @@ -59,8 +66,8 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() // Act var rules = new Dictionary>() { - { typeof(JsonSchema), - new List() { new AlwaysFailRule() } + { typeof(OpenApiSchema), + new List() { new AlwaysFailRule() } } }; @@ -76,7 +83,15 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() { // Arrange - var sharedSchema = new JsonSchemaBuilder().Type(SchemaValueType.String).Ref("test").Build(); + var sharedSchema = new OpenApiSchema + { + Type = "string", + Reference = new() + { + Id = "test" + }, + UnresolvedReference = true + }; var document = new OpenApiDocument(); @@ -109,8 +124,8 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() // Act var rules = new Dictionary>() { - { typeof(JsonSchema), - new List() { new AlwaysFailRule() } + { typeof(OpenApiSchema), + new List() { new AlwaysFailRule() } } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index b5491c40c..a7a026a4b 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -6,8 +6,6 @@ using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; @@ -26,7 +24,11 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder().Default(new OpenApiAny(55).Node).Type(SchemaValueType.String); + var schema = new OpenApiSchema + { + Default = new OpenApiAny(55), + Type = "string", + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -53,12 +55,13 @@ public void ValidateExampleAndDefaultShouldNotHaveDataTypeMismatchForSimpleSchem { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Default(new OpenApiAny("1234").Node) - .Type(SchemaValueType.String) - .Example(new OpenApiAny(55).Node) - .Build(); - + var schema = new OpenApiSchema + { + Example = new OpenApiAny(55), + Default = new OpenApiAny("1234"), + Type = "string", + }; + // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); var walker = new OpenApiWalker(validator); @@ -85,8 +88,10 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Enum( + var schema = new OpenApiSchema() + { + Enum = + { new OpenApiAny("1").Node, new OpenApiAny(new JsonObject() { @@ -99,10 +104,14 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() { ["x"] = 4, ["y"] = 40, - }).Node) - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .Build(); + }).Node + }, + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -135,32 +144,43 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int64").Build()).Build()), - ("property2", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Boolean).Build()) - .Build()) - .Build()), - ("property3", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format("password") - .Build()), - ("property4", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build())) - .Default(new JsonObject() + var schema = new OpenApiSchema + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "array", + Items = new() + { + Type = "integer", + Format = "int64" + } + }, + ["property2"] = new() + { + Type = "array", + Items = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "boolean" + } + } + }, + ["property3"] = new() + { + Type = "string", + Format = "password" + }, + ["property4"] = new() + { + Type = "string" + } + }, + Default = new OpenApiAny(new JsonObject() { ["property1"] = new JsonArray() { @@ -180,7 +200,8 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() }, ["property3"] = "123", ["property4"] = DateTime.UtcNow.ToString() - }).Build(); + }) + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -215,11 +236,12 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD Schemas = { { "schema1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator() { PropertyName = "property1" }) - .Ref("schema1") - .Build() + new OpenApiSchema + { + Type = "object", + Discriminator = new() { PropertyName = "property1" }, + Reference = new() { Id = "schema1" } + } } } }; @@ -235,7 +257,7 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD result.Should().BeFalse(); errors.Should().BeEquivalentTo(new List { - new OpenApiValidatorError(nameof(JsonSchemaRules.ValidateSchemaDiscriminator),"#/schemas/schema1/discriminator", + new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateSchemaDiscriminator),"#/schemas/schema1/discriminator", string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, "schema1", "property1")) }); @@ -251,17 +273,36 @@ public void ValidateOneOfSchemaPropertyNameContainsPropertySpecifiedInTheDiscrim { { "Person", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Discriminator(new OpenApiDiscriminator - { - PropertyName = "type" - }) - .OneOf(new JsonSchemaBuilder() - .Properties(("type", new JsonSchemaBuilder().Type(SchemaValueType.Array).Ref("Person").Build())) - .Build()) - .Ref("Person") - .Build() + new OpenApiSchema + { + Type = "array", + Discriminator = new() + { + PropertyName = "type" + }, + OneOf = new List + { + new() + { + Properties = + { + { + "type", + new OpenApiSchema + { + Type = "array" + } + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Person" + } + } + }, + Reference = new() { Id = "Person" } + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 208fd357c..e805d4673 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -43,7 +42,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiComponents)); visitor.Visit(default(OpenApiExternalDocs)); - // visitor.Visit(default(JsonSchema)); + visitor.Visit(default(OpenApiSchema)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiLink)); visitor.Visit(default(OpenApiCallback)); @@ -232,10 +231,10 @@ public override void Visit(OpenApiExternalDocs externalDocs) base.Visit(externalDocs); } - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { EncodeCall(); - base.Visit(ref schema); + base.Visit(schema); } public override void Visit(IDictionary links) diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 7878aaa4b..4df416d43 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -82,7 +81,10 @@ public void LocatePathOperationContentSchema() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new OpenApiSchema + { + Type = "string" + } } } } @@ -116,18 +118,23 @@ public void LocatePathOperationContentSchema() [Fact] public void WalkDOMWithCycles() { - var loopySchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("name", new JsonSchemaBuilder().Type(SchemaValueType.String))); + var loopySchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["name"] = new() { Type = "string" } + } + }; - loopySchema.Properties(("parent", loopySchema)); + loopySchema.Properties.Add("parent", loopySchema); var doc = new OpenApiDocument { Paths = new(), Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { ["loopy"] = loopySchema } @@ -155,10 +162,26 @@ public void WalkDOMWithCycles() [Fact] public void LocateReferences() { + var baseSchema = new OpenApiSchema + { + Reference = new() + { + Id = "base", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; - var baseSchema = new JsonSchemaBuilder().Ref("base").Build(); - - var derivedSchema = new JsonSchemaBuilder().AnyOf(baseSchema).Ref("derived").Build(); + var derivedSchema = new OpenApiSchema + { + AnyOf = new List { baseSchema }, + Reference = new() + { + Id = "derived", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; var testHeader = new OpenApiHeader() { Schema = derivedSchema, @@ -203,7 +226,7 @@ public void LocateReferences() }, Components = new() { - Schemas = new Dictionary() + Schemas = new Dictionary { ["derived"] = derivedSchema, ["base"] = baseSchema, @@ -297,15 +320,9 @@ public override void Visit(OpenApiMediaType mediaType) Locations.Add(this.PathString); } - public override void Visit(IBaseDocument document) - { - var schema = document as JsonSchema; - VisitJsonSchema(schema); - } - - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { - VisitJsonSchema(schema); + Locations.Add(this.PathString); } public override void Visit(IList openApiTags) @@ -322,17 +339,5 @@ public override void Visit(OpenApiServer server) { Locations.Add(this.PathString); } - - private void VisitJsonSchema(JsonSchema schema) - { - if (schema.GetRef() != null) - { - Locations.Add("referenceAt: " + this.PathString); - } - else - { - Locations.Add(this.PathString); - } - } } } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs index 41ef76960..e015da4f4 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -20,7 +19,7 @@ public class OpenApiReferencableTests private static readonly OpenApiLink _linkFragment = new(); private static readonly OpenApiHeader _headerFragment = new() { - Schema = new JsonSchemaBuilder().Build(), + Schema = new OpenApiSchema(), Examples = new Dictionary { { "example1", new OpenApiExample() } @@ -28,7 +27,7 @@ public class OpenApiReferencableTests }; private static readonly OpenApiParameter _parameterFragment = new() { - Schema = new JsonSchemaBuilder().Build(), + Schema = new OpenApiSchema(), Examples = new Dictionary { { "example1", new OpenApiExample() } @@ -46,7 +45,7 @@ public class OpenApiReferencableTests { "link1", new OpenApiLink() } } }; - private static readonly JsonSchema _schemaFragment = new JsonSchemaBuilder().Build(); + private static readonly OpenApiSchema _schemaFragment = new OpenApiSchema(); private static readonly OpenApiSecurityScheme _securitySchemeFragment = new OpenApiSecurityScheme(); private static readonly OpenApiTag _tagFragment = new OpenApiTag(); diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index f3afe2ac1..c2b956feb 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using Json.Schema; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; @@ -33,7 +33,14 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { ["application/json"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder().Ref("test").Build() + Schema = new() + { + Reference = new() + { + Id = "test", + Type = ReferenceType.Schema + } + } } } } @@ -49,7 +56,11 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() Components = new OpenApiComponents() { Schemas = { - ["test"] = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("The referenced one").Build() + ["test"] = new() + { + Type = "string", + Description = "The referenced one" + } } } }; @@ -66,12 +77,12 @@ public void OpenApiWorkspacesCanResolveExternalReferences() var workspace = new OpenApiWorkspace(); var externalDoc = CreateCommonDocument(); - workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]); + workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]); - var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test"); + var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test"); Assert.NotNull(schema); - Assert.Equal("The referenced one", schema.GetDescription()); + Assert.Equal("The referenced one", schema.Description); } [Fact] @@ -79,15 +90,19 @@ public void OpenApiWorkspacesCanResolveReferencesToDocumentFragments() { // Arrange var workspace = new OpenApiWorkspace(); - var schemaFragment = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Schema from a fragment").Build(); - workspace.RegisterComponent("common#/components/schemas/test", schemaFragment); + var schemaFragment = new OpenApiSchema() + { + Type = "string", + Description = "Schema from a fragment" + }; + workspace.RegisterComponent("common#/components/schemas/test", schemaFragment); // Act - var schema = workspace.ResolveReference("common#/components/schemas/test"); + var schema = workspace.ResolveReference("common#/components/schemas/test"); // Assert Assert.NotNull(schema); - Assert.Equal("Schema from a fragment", schema.GetDescription()); + Assert.Equal("Schema from a fragment", schema.Description); } [Fact] @@ -119,8 +134,13 @@ private static OpenApiDocument CreateCommonDocument() { Components = new() { - Schemas = { - ["test"] = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("The referenced one").Build() + Schemas = + { + ["test"] = new() + { + Type = "string", + Description = "The referenced one" + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs index 11b429300..a967c43a0 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs @@ -8,8 +8,8 @@ using System.IO; using System.Linq; using System.Text; +using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; @@ -21,15 +21,14 @@ namespace Microsoft.OpenApi.Tests.Writers [Collection("DefaultSettings")] public class OpenApiJsonWriterTests { - static bool[] shouldProduceTerseOutputValues = new[] { true, false }; + static bool[] shouldProduceTerseOutputValues = [true, false]; public static IEnumerable WriteStringListAsJsonShouldMatchExpectedTestCases() { return from input in new[] { - new[] - { + [ "string1", "string2", "string3", @@ -38,7 +37,7 @@ from input in new[] "string6", "string7", "string8" - }, + ], new[] {"string1", "string1", "string1", "string1"} } from shouldBeTerse in shouldProduceTerseOutputValues @@ -274,12 +273,20 @@ public void WriteDateTimeAsJsonShouldMatchExpected(DateTimeOffset dateTimeOffset public void OpenApiJsonWriterOutputsValidJsonValueWhenSchemaHasNanOrInfinityValues() { // Arrange - var schema = new JsonSchemaBuilder().Enum("NaN", "Infinity", "-Infinity"); + var schema = new OpenApiSchema + { + Enum = new List + { + new OpenApiAny("NaN").Node, + new OpenApiAny("Infinity").Node, + new OpenApiAny("-Infinity").Node + } + }; // Act var schemaBuilder = new StringBuilder(); var jsonWriter = new OpenApiJsonWriter(new StringWriter(schemaBuilder)); - jsonWriter.WriteJsonSchema(schema, OpenApiSpecVersion.OpenApi3_0); + schema.SerializeAsV3(jsonWriter); var jsonString = schemaBuilder.ToString(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index ea5442402..56b8fd83c 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -7,7 +7,6 @@ using System.Globalization; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; using Xunit; @@ -440,8 +439,16 @@ public void WriteInlineSchemaV2() private static OpenApiDocument CreateDocWithSimpleSchemaToInline() { // Arrange - - var thingSchema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Ref("#/components/schemas/thing").Build(); + var thingSchema = new OpenApiSchema + { + Type = "object", + UnresolvedReference = false, + Reference = new() + { + Id = "thing", + Type = ReferenceType.Schema + } + }; var doc = new OpenApiDocument() { From 086fc56d0996e33e77358c84a893a88e91cdc4d2 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 19:22:56 +0300 Subject: [PATCH 10/44] Create a proxy object for resolving referenced schemas --- .../References/OpenApiSchemaReference.cs | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs new file mode 100644 index 000000000..502fba095 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Writers; +using System; +using System.Collections.Generic; +using System.Text.Json.Nodes; + +namespace Microsoft.OpenApi.Models.References +{ + /// + /// Schema reference object + /// + public class OpenApiSchemaReference : OpenApiSchema + { + internal OpenApiSchema _target; + private readonly OpenApiReference _reference; + private string _description; + + private OpenApiSchema Target + { + get + { + _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); + OpenApiSchema resolved = new OpenApiSchema(_target); + if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; + return resolved; + } + } + + /// + /// Constructor initializing the reference object. + /// + /// The reference Id. + /// The host OpenAPI document. + /// Optional: External resource in the reference. + /// It may be: + /// 1. a absolute/relative file path, for example: ../commons/pet.json + /// 2. a Url, for example: http://localhost/pet.json + /// + public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + { + if (string.IsNullOrEmpty(referenceId)) + { + Utils.CheckArgumentNullOrEmpty(referenceId); + } + + _reference = new OpenApiReference() + { + Id = referenceId, + HostDocument = hostDocument, + Type = ReferenceType.Schema, + ExternalResource = externalResource + }; + + Reference = _reference; + } + + internal OpenApiSchemaReference(OpenApiSchema target, string referenceId) + { + _target = target; + + _reference = new OpenApiReference() + { + Id = referenceId, + Type = ReferenceType.Schema, + }; + } + + /// + public override string Title { get => Target.Title; set => Target.Title = value; } + /// + public override string Schema { get => Target.Schema; set => Target.Schema = value; } + /// + public override string Id { get => Target.Id; set => Target.Id = value; } + /// + public override string Comment { get => Target.Comment; set => Target.Comment = value; } + /// + public override string Vocabulary { get => Target.Vocabulary; set => Target.Vocabulary = value; } + /// + public override string DynamicRef { get => Target.DynamicRef; set => Target.DynamicRef = value; } + /// + public override string DynamicAnchor { get => Target.DynamicAnchor; set => Target.DynamicAnchor = value; } + /// + public override string RecursiveAnchor { get => Target.RecursiveAnchor; set => Target.RecursiveAnchor = value; } + /// + public override string RecursiveRef { get => Target.RecursiveRef; set => Target.RecursiveRef = value; } + /// + public override IDictionary Definitions { get => Target.Definitions; set => Target.Definitions = value; } + /// + public override decimal? V31ExclusiveMaximum { get => Target.V31ExclusiveMaximum; set => Target.V31ExclusiveMaximum = value; } + /// + public override decimal? V31ExclusiveMinimum { get => Target.V31ExclusiveMinimum; set => Target.V31ExclusiveMinimum = value; } + /// + public override bool UnEvaluatedProperties { get => Target.UnEvaluatedProperties; set => Target.UnEvaluatedProperties = value; } + /// + public override object Type { get => Target.Type; set => Target.Type = value; } + /// + public override string Format { get => Target.Format; set => Target.Format = value; } + /// + public override string Description { get => Target.Description; set => Target.Description = value; } + /// + public override decimal? Maximum { get => Target.Maximum; set => Target.Maximum = value; } + /// + public override bool? ExclusiveMaximum { get => Target.ExclusiveMaximum; set => Target.ExclusiveMaximum = value; } + /// + public override decimal? Minimum { get => Target.Minimum; set => Target.Minimum = value; } + /// + public override bool? ExclusiveMinimum { get => Target.ExclusiveMinimum; set => Target.ExclusiveMinimum = value; } + /// + public override int? MaxLength { get => Target.MaxLength; set => Target.MaxLength = value; } + /// + public override int? MinLength { get => Target.MinLength; set => Target.MinLength = value; } + /// + public override string Pattern { get => Target.Pattern; set => Target.Pattern = value; } + /// + public override decimal? MultipleOf { get => Target.MultipleOf; set => Target.MultipleOf = value; } + /// + public override OpenApiAny Default { get => Target.Default; set => Target.Default = value; } + /// + public override bool ReadOnly { get => Target.ReadOnly; set => Target.ReadOnly = value; } + /// + public override bool WriteOnly { get => Target.WriteOnly; set => Target.WriteOnly = value; } + /// + public override IList AllOf { get => Target.AllOf; set => Target.AllOf = value; } + /// + public override IList OneOf { get => Target.OneOf; set => Target.OneOf = value; } + /// + public override IList AnyOf { get => Target.AnyOf; set => Target.AnyOf = value; } + /// + public override OpenApiSchema Not { get => Target.Not; set => Target.Not = value; } + /// + public override ISet Required { get => Target.Required; set => Target.Required = value; } + /// + public override OpenApiSchema Items { get => Target.Items; set => Target.Items = value; } + /// + public override int? MaxItems { get => Target.MaxItems; set => Target.MaxItems = value; } + /// + public override int? MinItems { get => Target.MinItems; set => Target.MinItems = value; } + /// + public override bool? UniqueItems { get => Target.UniqueItems; set => Target.UniqueItems = value; } + /// + public override IDictionary Properties { get => Target.Properties; set => Target.Properties = value; } + /// + public override IDictionary PatternProperties { get => Target.PatternProperties; set => Target.PatternProperties = value; } + /// + public override int? MaxProperties { get => Target.MaxProperties; set => Target.MaxProperties = value; } + /// + public override int? MinProperties { get => Target.MinProperties; set => Target.MinProperties = value; } + /// + public override bool AdditionalPropertiesAllowed { get => Target.AdditionalPropertiesAllowed; set => Target.AdditionalPropertiesAllowed = value; } + /// + public override OpenApiSchema AdditionalProperties { get => Target.AdditionalProperties; set => Target.AdditionalProperties = value; } + /// + public override OpenApiDiscriminator Discriminator { get => Target.Discriminator; set => Target.Discriminator = value; } + /// + public override OpenApiAny Example { get => Target.Example; set => Target.Example = value; } + /// + public override IList Examples { get => Target.Examples; set => Target.Examples = value; } + /// + public override IList Enum { get => Target.Enum; set => Target.Enum = value; } + /// + public override bool Nullable { get => Target.Nullable; set => Target.Nullable = value; } + /// + public override bool UnevaluatedProperties { get => Target.UnevaluatedProperties; set => Target.UnevaluatedProperties = value; } + /// + public override OpenApiExternalDocs ExternalDocs { get => Target.ExternalDocs; set => Target.ExternalDocs = value; } + /// + public override bool Deprecated { get => Target.Deprecated; set => Target.Deprecated = value; } + /// + public override OpenApiXml Xml { get => Target.Xml; set => Target.Xml = value; } + /// + public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + + /// + public override void SerializeAsV31(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV31(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + } + } + + /// + public override void SerializeAsV3(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV3(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + } + } + + /// + public override void SerializeAsV2(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV2(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + } + } + + /// + private void SerializeInternal(IOpenApiWriter writer, + Action action) + { + Utils.CheckArgumentNull(writer); + action(writer, Target); + } + } +} From e9b1c57ea6eed9de0065394e6a3652ac8d59a7e4 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 19:23:36 +0300 Subject: [PATCH 11/44] Mark all properties as virtual to be overriden in the proxy class --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index c6f6f25ee..e19705065 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -19,128 +19,128 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// /// Follow JSON Schema definition. Short text providing information about the data. /// - public string Title { get; set; } + public virtual string Title { get; set; } /// /// $schema, a JSON Schema dialect identifier. Value must be a URI /// - public string Schema { get; set; } + public virtual string Schema { get; set; } /// /// $id - Identifies a schema resource with its canonical URI. /// - public string Id { get; set; } + public virtual string Id { get; set; } /// /// $comment - reserves a location for comments from schema authors to readers or maintainers of the schema. /// - public string Comment { get; set; } + public virtual string Comment { get; set; } /// /// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema. /// - public string Vocabulary { get; set; } + public virtual string Vocabulary { get; set; } /// /// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance /// - public string DynamicRef { get; set; } + public virtual string DynamicRef { get; set; } /// /// $dynamicAnchor - used to create plain name fragments that are not tied to any particular structural location for referencing purposes, which are taken into consideration for dynamic referencing. /// - public string DynamicAnchor { get; set; } + public virtual string DynamicAnchor { get; set; } /// /// $recursiveAnchor - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#") /// - public string RecursiveAnchor { get; set; } + public virtual string RecursiveAnchor { get; set; } /// /// $recursiveRef - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#") /// - public string RecursiveRef { get; set; } + public virtual string RecursiveRef { get; set; } /// /// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema. /// The keyword does not directly affect the validation result /// - public IDictionary Definitions { get; set; } + public virtual IDictionary Definitions { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? V31ExclusiveMaximum { get; set; } + public virtual decimal? V31ExclusiveMaximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? V31ExclusiveMinimum { get; set; } + public virtual decimal? V31ExclusiveMinimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool UnEvaluatedProperties { get; set; } + public virtual bool UnEvaluatedProperties { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value MUST be a string in V2 and V3. /// - public object Type { get; set; } + public virtual object Type { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// While relying on JSON Schema's defined formats, /// the OAS offers a few additional predefined formats. /// - public string Format { get; set; } + public virtual string Format { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// CommonMark syntax MAY be used for rich text representation. /// - public string Description { get; set; } + public virtual string Description { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? Maximum { get; set; } + public virtual decimal? Maximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? ExclusiveMaximum { get; set; } + public virtual bool? ExclusiveMaximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? Minimum { get; set; } + public virtual decimal? Minimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? ExclusiveMinimum { get; set; } + public virtual bool? ExclusiveMinimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxLength { get; set; } + public virtual int? MaxLength { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinLength { get; set; } + public virtual int? MinLength { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect /// - public string Pattern { get; set; } + public virtual string Pattern { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? MultipleOf { get; set; } + public virtual decimal? MultipleOf { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 @@ -148,7 +148,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. /// For example, if type is string, then default can be "foo" but cannot be 1. /// - public OpenApiAny Default { get; set; } + public virtual OpenApiAny Default { get; set; } /// /// Relevant only for Schema "properties" definitions. Declares the property as "read only". @@ -158,7 +158,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// A property MUST NOT be marked as both readOnly and writeOnly being true. /// Default value is false. /// - public bool ReadOnly { get; set; } + public virtual bool ReadOnly { get; set; } /// /// Relevant only for Schema "properties" definitions. Declares the property as "write only". @@ -168,64 +168,64 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// A property MUST NOT be marked as both readOnly and writeOnly being true. /// Default value is false. /// - public bool WriteOnly { get; set; } + public virtual bool WriteOnly { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList AllOf { get; set; } = new List(); + public virtual IList AllOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList OneOf { get; set; } = new List(); + public virtual IList OneOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList AnyOf { get; set; } = new List(); + public virtual IList AnyOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public OpenApiSchema Not { get; set; } + public virtual OpenApiSchema Not { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public ISet Required { get; set; } = new HashSet(); + public virtual ISet Required { get; set; } = new HashSet(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object /// and not a standard JSON Schema. items MUST be present if the type is array. /// - public OpenApiSchema Items { get; set; } + public virtual OpenApiSchema Items { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxItems { get; set; } + public virtual int? MaxItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinItems { get; set; } + public virtual int? MinItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? UniqueItems { get; set; } + public virtual bool? UniqueItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced). /// - public IDictionary Properties { get; set; } = new Dictionary(); + public virtual IDictionary Properties { get; set; } = new Dictionary(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 @@ -234,96 +234,96 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST /// be a valid Schema Object not a standard JSON Schema. /// - public IDictionary PatternProperties { get; set; } = new Dictionary(); + public virtual IDictionary PatternProperties { get; set; } = new Dictionary(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxProperties { get; set; } + public virtual int? MaxProperties { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinProperties { get; set; } + public virtual int? MinProperties { get; set; } /// /// Indicates if the schema can contain properties other than those defined by the properties map. /// - public bool AdditionalPropertiesAllowed { get; set; } = true; + public virtual bool AdditionalPropertiesAllowed { get; set; } = true; /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value can be boolean or object. Inline or referenced schema /// MUST be of a Schema Object and not a standard JSON Schema. /// - public OpenApiSchema AdditionalProperties { get; set; } + public virtual OpenApiSchema AdditionalProperties { get; set; } /// /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate /// between other schemas which may satisfy the payload description. /// - public OpenApiDiscriminator Discriminator { get; set; } + public virtual OpenApiDiscriminator Discriminator { get; set; } /// /// A free-form property to include an example of an instance for this schema. /// To represent examples that cannot be naturally represented in JSON or YAML, /// a string value can be used to contain the example with escaping where necessary. /// - public OpenApiAny Example { get; set; } + public virtual OpenApiAny Example { get; set; } /// /// A free-form property to include examples of an instance for this schema. /// To represent examples that cannot be naturally represented in JSON or YAML, /// a list of values can be used to contain the examples with escaping where necessary. /// - public IList Examples { get; set; } + public virtual IList Examples { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public IList Enum { get; set; } = new List(); + public virtual IList Enum { get; set; } = new List(); /// /// Allows sending a null value for the defined schema. Default value is false. /// - public bool Nullable { get; set; } + public virtual bool Nullable { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool UnevaluatedProperties { get; set;} + public virtual bool UnevaluatedProperties { get; set;} /// /// Additional external documentation for this schema. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public virtual OpenApiExternalDocs ExternalDocs { get; set; } /// /// Specifies that a schema is deprecated and SHOULD be transitioned out of usage. /// Default value is false. /// - public bool Deprecated { get; set; } + public virtual bool Deprecated { get; set; } /// /// This MAY be used only on properties schemas. It has no effect on root schemas. /// Adds additional metadata to describe the XML representation of this property. /// - public OpenApiXml Xml { get; set; } + public virtual OpenApiXml Xml { get; set; } /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public virtual IDictionary Extensions { get; set; } = new Dictionary(); /// /// Indicates object is a placeholder reference to an actual object and does not contain valid data. /// - public bool UnresolvedReference { get; set; } + public virtual bool UnresolvedReference { get; set; } /// /// Reference object. /// - public OpenApiReference Reference { get; set; } + public virtual OpenApiReference Reference { get; set; } /// /// Parameterless constructor @@ -586,7 +586,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) /// - public void SerializeAsV2(IOpenApiWriter writer) + public virtual void SerializeAsV2(IOpenApiWriter writer) { SerializeAsV2(writer: writer, parentRequiredProperties: new HashSet(), propertyName: null); } From ecbdd5f410b07136600b7ed877842fe87a18c6f6 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:34:36 +0300 Subject: [PATCH 12/44] Return schema proxy reference if reference pointer exists --- .../Models/References/OpenApiSchemaReference.cs | 8 ++++++-- .../Reader/V2/OpenApiSchemaDeserializer.cs | 4 +++- .../Reader/V3/OpenApiSchemaDeserializer.cs | 8 +++----- .../Reader/V31/OpenApiSchemaDeserializer.cs | 8 +++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 502fba095..bbd2c1af7 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Any; @@ -100,7 +100,11 @@ internal OpenApiSchemaReference(OpenApiSchema target, string referenceId) /// public override string Format { get => Target.Format; set => Target.Format = value; } /// - public override string Description { get => Target.Description; set => Target.Description = value; } + public override string Description + { + get => string.IsNullOrEmpty(_description) ? Target.Description : _description; + set => _description = value; + } /// public override decimal? Maximum { get => Target.Maximum; set => Target.Maximum = value; } /// diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 96ed771f1..66c45c641 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -6,6 +6,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Reader.V2 { @@ -162,7 +163,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum var pointer = mapNode.GetReferencePointer(); if (pointer != null) { - return mapNode.GetReferencedObject(ReferenceType.Schema, pointer); + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index bacd72e4c..2dd2e4f6a 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using System.Collections.Generic; using System.Globalization; @@ -181,11 +182,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum if (pointer != null) { - return new() - { - UnresolvedReference = true, - Reference = node.Context.VersionService.ConvertToOpenApiReference(pointer, ReferenceType.Schema) - }; + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 9d27d811d..f8d197170 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using System.Collections.Generic; using System.Globalization; @@ -230,11 +231,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum if (pointer != null) { - return new() - { - UnresolvedReference = true, - Reference = node.Context.VersionService.ConvertToOpenApiReference(pointer, ReferenceType.Schema) - }; + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); From 853c2f9f32ce04351d3aa85687ace8458c40af7d Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:35:33 +0300 Subject: [PATCH 13/44] code cleanup --- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 10 +--------- src/Microsoft.OpenApi/Models/OpenApiParameter.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs | 10 ---------- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 2 +- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index aa060baf9..ab82061ad 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -464,14 +464,6 @@ internal T ResolveReferenceTo(OpenApiReference reference) where T : class, IO } } - /// - /// Load the referenced object from a object - /// - public IOpenApiReferenceable ResolveReference(OpenApiReference reference) - { - return ResolveReference(reference, false); - } - /// /// Takes in an OpenApi document instance and generates its hash value /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index a169f786c..69f6201a2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -327,7 +327,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) } // In V2 parameter's type can't be a reference to a custom object schema or can't be of type object // So in that case map the type as string. - else if (Schema?.UnresolvedReference == true || "object".Equals(Schema?.Type.ToString(), StringComparison.OrdinalIgnoreCase)) + else if (Schema?.UnresolvedReference == true || "object".Equals(Schema?.Type?.ToString(), StringComparison.OrdinalIgnoreCase)) { writer.WriteProperty(OpenApiConstants.Type, "string"); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 11b1af6be..e937ad565 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -92,16 +92,6 @@ private void SerializeInternal(IOpenApiWriter writer, Action - /// Returns an effective OpenApiRequestBody object based on the presence of a $ref - /// - /// The host OpenApiDocument that contains the reference. - /// OpenApiRequestBody - public OpenApiRequestBody GetEffective(OpenApiDocument doc) - { - return Reference != null ? doc.ResolveReferenceTo(Reference) : this; - } - /// /// Serialize to OpenAPI V31 document without using reference. /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index e19705065..d2cf23506 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -495,7 +495,7 @@ public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpec writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); // type - if (Type.GetType() == typeof(string)) + if (Type?.GetType() == typeof(string)) { writer.WriteProperty(OpenApiConstants.Type, (string)Type); } From d2cf6c81831011d330034ba8c6e79f40446e6a46 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:37:18 +0300 Subject: [PATCH 14/44] Refactor validation logic for examples --- .../Validations/Rules/RuleHelpers.cs | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index a2ac63a6e..471c79d5c 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -4,6 +4,7 @@ using System; using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Validations.Rules @@ -41,28 +42,28 @@ public static bool IsEmailAddress(this string input) } public static void ValidateDataTypeMismatch( - IValidationContext context, - string ruleName, - JsonNode value, - OpenApiSchema schema) + IValidationContext context, + string ruleName, + JsonNode value, + OpenApiSchema schema) { if (schema == null) { return; } - var type = schema.Type.ToString(); + // convert value to JsonElement and access the ValueKind property to determine the type. + var jsonElement = JsonDocument.Parse(JsonSerializer.Serialize(value)).RootElement; + + var type = (string)schema.Type; var format = schema.Format; var nullable = schema.Nullable; - // convert JsonNode to JsonElement - JsonElement element = value.GetValue(); - // Before checking the type, check first if the schema allows null. // If so and the data given is also null, this is allowed for any type. if (nullable) { - if (element.ValueKind is JsonValueKind.Null) + if (jsonElement.ValueKind is JsonValueKind.Null) { return; } @@ -73,13 +74,13 @@ public static void ValidateDataTypeMismatch( // It is not against the spec to have a string representing an object value. // To represent examples of media types that cannot naturally be represented in JSON or YAML, // a string value can contain the example with escaping where necessary - if (element.ValueKind is JsonValueKind.String) + if (jsonElement.ValueKind is JsonValueKind.String) { return; } // If value is not a string and also not an object, there is a data mismatch. - if (element.ValueKind is not JsonValueKind.Object) + if (value is not JsonObject anyObject) { context.CreateWarning( ruleName, @@ -87,12 +88,9 @@ public static void ValidateDataTypeMismatch( return; } - // Else, cast element to object - var anyObject = value.AsObject(); - foreach (var kvp in anyObject) { - string key = kvp.Key; + var key = kvp.Key; context.Enter(key); if (schema.Properties != null && @@ -116,13 +114,13 @@ public static void ValidateDataTypeMismatch( // It is not against the spec to have a string representing an array value. // To represent examples of media types that cannot naturally be represented in JSON or YAML, // a string value can contain the example with escaping where necessary - if (element.ValueKind is JsonValueKind.String) + if (jsonElement.ValueKind is JsonValueKind.String) { return; } // If value is not a string and also not an array, there is a data mismatch. - if (element.ValueKind is not JsonValueKind.Array) + if (value is not JsonArray anyArray) { context.CreateWarning( ruleName, @@ -130,9 +128,6 @@ public static void ValidateDataTypeMismatch( return; } - // Else, cast element to array - var anyArray = value.AsArray(); - for (var i = 0; i < anyArray.Count; i++) { context.Enter(i.ToString()); @@ -147,7 +142,7 @@ public static void ValidateDataTypeMismatch( if (type == "integer" && format == "int32") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -159,7 +154,7 @@ public static void ValidateDataTypeMismatch( if (type == "integer" && format == "int64") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -169,16 +164,21 @@ public static void ValidateDataTypeMismatch( return; } - if (type == "integer" && element.ValueKind is not JsonValueKind.Number) + if (type == "integer" && jsonElement.ValueKind is not JsonValueKind.Number) { - context.CreateWarning( - ruleName, - DataTypeMismatchedErrorMessage); + if (jsonElement.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; } if (type == "number" && format == "float") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -190,7 +190,7 @@ public static void ValidateDataTypeMismatch( if (type == "number" && format == "double") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -202,7 +202,7 @@ public static void ValidateDataTypeMismatch( if (type == "number") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -214,7 +214,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "byte") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -226,7 +226,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "date") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -238,7 +238,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "date-time") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -250,7 +250,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "password") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -262,7 +262,7 @@ public static void ValidateDataTypeMismatch( if (type == "string") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -274,7 +274,7 @@ public static void ValidateDataTypeMismatch( if (type == "boolean") { - if (element.ValueKind is not JsonValueKind.True || element.ValueKind is not JsonValueKind.True) + if (jsonElement.ValueKind is not JsonValueKind.True && jsonElement.ValueKind is not JsonValueKind.False) { context.CreateWarning( ruleName, From 49a94355540cb9eba9a8b50c70da0a2333eb8660 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:07:24 +0300 Subject: [PATCH 15/44] code cleanup --- .../Models/References/OpenApiSchemaReference.cs | 4 ++-- .../Reader/V2/OpenApiOperationDeserializer.cs | 3 +++ .../Services/OpenApiComponentsRegistryExtensions.cs | 4 +--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index bbd2c1af7..665120d2c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Any; @@ -23,7 +23,7 @@ private OpenApiSchema Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); + _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); OpenApiSchema resolved = new OpenApiSchema(_target); if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; return resolved; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index a2faa5810..67e6ecca5 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -173,6 +173,9 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List mediaType) }; + foreach (var value in formBody.Content.Values.Where(static x => x.Schema is not null && x.Schema.Properties.Any() && string.IsNullOrEmpty((string)x.Schema.Type))) + value.Schema.Type = "object"; + return formBody; } diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 8be8318e3..9a5b62d37 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -24,9 +24,7 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo } else { - location = version == OpenApiSpecVersion.OpenApi2_0 - ? document.BaseUri + "/" + OpenApiConstants.Definitions + "/" + item.Key - : baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; + location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; } workspace.RegisterComponent(location, item.Value); From 82ea7b736cadc18fa52c84f93dca4048b5f37bed Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:10:03 +0300 Subject: [PATCH 16/44] Fix failing tests --- .../V2Tests/OpenApiDocumentTests.cs | 141 ++--------- .../V2Tests/OpenApiHeaderTests.cs | 7 +- .../V2Tests/OpenApiParameterTests.cs | 36 +-- .../V2Tests/OpenApiSchemaTests.cs | 12 +- .../V31Tests/OpenApiDocumentTests.cs | 57 +---- .../V31Tests/OpenApiSchemaTests.cs | 8 +- .../V3Tests/OpenApiDocumentTests.cs | 97 ++------ .../V3Tests/OpenApiSchemaTests.cs | 190 +++------------ .../advancedSchemaWithReference.yaml | 16 +- .../Models/OpenApiComponentsTests.cs | 121 ++++------ ...orks_produceTerseOutput=False.verified.txt | 30 +-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 197 +++++++++++++-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 227 ++++++++++++++++-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 2 +- ...Works_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiDocumentTests.cs | 34 +-- .../Models/OpenApiOperationTests.cs | 16 +- .../Models/OpenApiParameterTests.cs | 2 +- .../Models/OpenApiResponseTests.cs | 20 +- .../OpenApiHeaderValidationTests.cs | 17 +- .../OpenApiMediaTypeValidationTests.cs | 19 +- .../OpenApiParameterValidationTests.cs | 17 +- .../OpenApiSchemaValidationTests.cs | 38 +-- .../Walkers/WalkerLocationTests.cs | 17 +- 27 files changed, 658 insertions(+), 671 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index f369e5028..8af3f1f3c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -7,9 +7,10 @@ using System.Linq; using System.Threading; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Xunit; @@ -24,59 +25,6 @@ public OpenApiDocumentTests() OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); } - [Fact] - public void ShouldThrowWhenReferenceTypeIsInvalid() - { - var input = - """ - swagger: 2.0 - info: - title: test - version: 1.0.0 - paths: - '/': - get: - responses: - '200': - description: ok - schema: - $ref: '#/defi888nition/does/notexist' - """; - - var result = OpenApiDocument.Parse(input, "yaml"); - - result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { - new( new OpenApiException("Unknown reference type 'defi888nition'")) }); - result.OpenApiDocument.Should().NotBeNull(); - } - - [Fact] - public void ShouldThrowWhenReferenceDoesNotExist() - { - var input = - """ - swagger: 2.0 - info: - title: test - version: 1.0.0 - paths: - '/': - get: - produces: ['application/json'] - responses: - '200': - description: ok - schema: - $ref: '#/definitions/doesnotexist' - """; - - var result = OpenApiDocument.Parse(input, "yaml"); - - result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { - new( new OpenApiException("Invalid Reference identifier 'doesnotexist'.")) }); - result.OpenApiDocument.Should().NotBeNull(); - } - [Theory] [InlineData("en-US")] [InlineData("hi-IN")] @@ -138,20 +86,26 @@ public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) ExclusiveMaximum = true, ExclusiveMinimum = false } - }, - Reference = new() - { - Id = "sampleSchema", - Type = ReferenceType.Schema } } } }, Paths = new() - }); + }, options => options + .Excluding(x=> x.BaseUri) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent")) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Root"))); result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic { SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 }); + new OpenApiDiagnostic { + SpecificationVersion = OpenApiSpecVersion.OpenApi2_0, + Errors = new List() + { + new OpenApiError("", "Paths is a REQUIRED field at #/") + } + }); } [Fact] @@ -161,12 +115,6 @@ public void ShouldParseProducesInAnyOrder() var okSchema = new OpenApiSchema { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Item", - HostDocument = result.OpenApiDocument - }, Properties = new Dictionary { { "id", new OpenApiSchema @@ -180,12 +128,6 @@ public void ShouldParseProducesInAnyOrder() var errorSchema = new OpenApiSchema { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Error", - HostDocument = result.OpenApiDocument - }, Properties = new Dictionary { { "code", new OpenApiSchema @@ -212,13 +154,13 @@ public void ShouldParseProducesInAnyOrder() Schema = new() { Type = "array", - Items = okSchema + Items = new OpenApiSchemaReference("Item", result.OpenApiDocument) } }; var errorMediaType = new OpenApiMediaType { - Schema = errorSchema + Schema = new OpenApiSchemaReference("Error", result.OpenApiDocument) }; result.OpenApiDocument.Should().BeEquivalentTo(new OpenApiDocument @@ -322,7 +264,7 @@ public void ShouldParseProducesInAnyOrder() ["Error"] = errorSchema } } - }); + }, options => options.Excluding(x => x.BaseUri)); } [Fact] @@ -336,51 +278,10 @@ public void ShouldAssignSchemaToAllResponses() var successSchema = new OpenApiSchema { Type = "array", - Items = new() - { - Properties = { - { "id", new OpenApiSchema - { - Type = "string", - Description = "Item identifier." - } - } - }, - Reference = new() - { - Id = "Item", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument - } - } - }; - var errorSchema = new OpenApiSchema - { - Properties = { - { "code", new OpenApiSchema - { - Type = "integer", - Format = "int32" - } - }, - { "message", new OpenApiSchema - { - Type = "string" - } - }, - { "fields", new OpenApiSchema - { - Type = "string" - } - } - }, - Reference = new() - { - Id = "Error", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument - } + Items = new OpenApiSchemaReference("Item", result.OpenApiDocument) }; + var errorSchema = new OpenApiSchemaReference("Error", result.OpenApiDocument); + var responses = result.OpenApiDocument.Paths["/items"].Operations[OperationType.Get].Responses; foreach (var response in responses) { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index 14bbdfc32..a78bd1180 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -3,6 +3,7 @@ using System.IO; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -41,7 +42,8 @@ public void ParseHeaderWithDefaultShouldSucceed() } }, options => options - .IgnoringCyclicReferences()); + .IgnoringCyclicReferences() + .Excluding(x => x.Schema.Default.Node.Parent)); } [Fact] @@ -73,7 +75,8 @@ public void ParseHeaderWithEnumShouldSucceed() } } }, options => options.IgnoringCyclicReferences() - ); + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 7ccbc1c8b..9324c5132 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -3,6 +3,7 @@ using System.IO; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -232,7 +233,7 @@ public void ParseParameterWithDefaultShouldSucceed() Format = "float", Default = new OpenApiAny(5) } - }, options => options.IgnoringCyclicReferences()); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Schema.Default.Node.Parent)); } [Fact] @@ -247,27 +248,30 @@ public void ParseParameterWithEnumShouldSucceed() // Act var parameter = OpenApiV2Deserializer.LoadParameter(node); - - // Assert - parameter.Should().BeEquivalentTo( - new OpenApiParameter + var expected = new OpenApiParameter + { + In = ParameterLocation.Path, + Name = "username", + Description = "username to fetch", + Required = true, + Schema = new() { - In = ParameterLocation.Path, - Name = "username", - Description = "username to fetch", - Required = true, - Schema = new() - { - Type = "number", - Format = "float", - Enum = + Type = "number", + Format = "float", + Enum = { new OpenApiAny(7).Node, new OpenApiAny(8).Node, new OpenApiAny(9).Node } - } - }, options => options.IgnoringCyclicReferences()); + } + }; + + // Assert + parameter.Should().BeEquivalentTo(expected, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index d827f62ee..a9b646040 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Any; using System.Text.Json.Nodes; using System.Collections.Generic; +using FluentAssertions.Equivalency; namespace Microsoft.OpenApi.Readers.Tests.V2Tests { @@ -37,7 +38,7 @@ public void ParseSchemaWithDefaultShouldSucceed() Type = "number", Format = "float", Default = new OpenApiAny(5) - }); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Default.Node.Parent)); } [Fact] @@ -60,7 +61,7 @@ public void ParseSchemaWithExampleShouldSucceed() Type = "number", Format = "float", Example = new OpenApiAny(5) - }); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Example.Node.Parent)); } [Fact] @@ -88,8 +89,11 @@ public void ParseSchemaWithEnumShouldSucceed() new OpenApiAny(9).Node } }; - schema.Should().BeEquivalentTo(expected, - options => options.IgnoringCyclicReferences()); + + schema.Should().BeEquivalentTo(expected, options => + options.IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 66b00c9f7..6f6ed0faa 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -5,6 +5,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Writers; @@ -43,24 +44,10 @@ public static T Clone(T element) where T : IOpenApiSerializable public void ParseDocumentWithWebhooksShouldSucceed() { // Arrange and Act - var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); - var petSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "petSchema" - } - }; + var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); + var petSchema = new OpenApiSchemaReference("petSchema", actual.OpenApiDocument); - var newPetSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "newPetSchema" - } - }; + var newPetSchema = new OpenApiSchemaReference("newPetSchema", actual.OpenApiDocument); var components = new OpenApiComponents { @@ -113,12 +100,6 @@ public void ParseDocumentWithWebhooksShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } } } @@ -295,35 +276,15 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } } } }; // Create a clone of the schema to avoid modifying things in components. - var petSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "petSchema" - } - }; + var petSchema = new OpenApiSchemaReference("petSchema", actual.OpenApiDocument); - var newPetSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "newPetSchema" - } - }; + var newPetSchema = new OpenApiSchemaReference("newPetSchema", actual.OpenApiDocument); components.PathItems = new Dictionary { @@ -502,6 +463,9 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() var mediaType = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; var expectedMediaType = @"schema: + patternProperties: + ^x-.*$: + type: string type: object properties: prop1: @@ -509,9 +473,6 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() prop2: type: string prop3: - type: string - patternProperties: - ^x-.*$: type: string"; var actualMediaType = mediaType.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index ae83a3abe..a534d3dd1 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -170,7 +171,7 @@ public void ParseV31SchemaShouldSucceed() }; // Assert - Assert.Equal(schema, expectedSchema); + schema.Should().BeEquivalentTo(expectedSchema); } [Fact] @@ -262,7 +263,10 @@ public void ParseAdvancedV31SchemaShouldSucceed() }; // Assert - schema.Should().BeEquivalentTo(expectedSchema); + schema.Should().BeEquivalentTo(expectedSchema, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 0d3bb622f..bd72ff78a 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Validations; @@ -213,7 +214,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Schemas = new Dictionary { - ["pet"] = new() + ["pet1"] = new() { Type = "object", Required = new HashSet @@ -236,12 +237,6 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "pet", - HostDocument = actual.OpenApiDocument } }, ["newPet"] = new() @@ -266,12 +261,6 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } }, ["errorModel"] = new() @@ -293,44 +282,15 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "errorModel", - HostDocument = actual.OpenApiDocument } }, } }; - // Create a clone of the schema to avoid modifying things in components. - var petSchema = Clone(components.Schemas["pet"]); - - petSchema.Reference = new() - { - Id = "pet", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; - - var newPetSchema = Clone(components.Schemas["newPet"]); - - newPetSchema.Reference = new() - { - Id = "newPet", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; - - var errorModelSchema = Clone(components.Schemas["errorModel"]); + var petSchema = new OpenApiSchemaReference("pet1", actual.OpenApiDocument); + var newPetSchema = new OpenApiSchemaReference("newPet", actual.OpenApiDocument); - errorModelSchema.Reference = new() - { - Id = "errorModel", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; + var errorModelSchema = new OpenApiSchemaReference("errorModel", actual.OpenApiDocument); var expectedDoc = new OpenApiDocument { @@ -640,7 +600,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Schemas = new Dictionary { - ["pet"] = new() + ["pet1"] = new() { Type = "object", Required = new HashSet @@ -663,12 +623,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "pet", - HostDocument = actual.OpenApiDocument } }, ["newPet"] = new() @@ -693,12 +647,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } }, ["errorModel"] = new() @@ -720,11 +668,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "errorModel" } }, }, @@ -745,11 +688,12 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() }; // Create a clone of the schema to avoid modifying things in components. - var petSchema = Clone(components.Schemas["pet"]); + var petSchema = Clone(components.Schemas["pet1"]); petSchema.Reference = new() { - Id = "pet", - Type = ReferenceType.Schema + Id = "pet1", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var newPetSchema = Clone(components.Schemas["newPet"]); @@ -757,7 +701,8 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() newPetSchema.Reference = new() { Id = "newPet", - Type = ReferenceType.Schema + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var errorModelSchema = Clone(components.Schemas["errorModel"]); @@ -765,7 +710,8 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() errorModelSchema.Reference = new() { Id = "errorModel", - Type = ReferenceType.Schema + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var tag1 = new OpenApiTag @@ -1272,15 +1218,7 @@ public void ParseDocumentWithJsonSchemaReferencesWorks() var actualSchema = result.OpenApiDocument.Paths["/users/{userId}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new OpenApiSchema() - { - Reference = new OpenApiReference - { - Id = "User", - Type = ReferenceType.Schema - } - }; - + var expectedSchema = new OpenApiSchemaReference("User", result.OpenApiDocument); // Assert actualSchema.Should().BeEquivalentTo(expectedSchema); } @@ -1399,7 +1337,10 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters.First(); // Assert - actualParam.Should().BeEquivalentTo(expectedParam, options => options.Excluding(x => x.Reference.HostDocument)); + actualParam.Should().BeEquivalentTo(expectedParam, options => options + .Excluding(x => x.Reference.HostDocument) + .Excluding(x => x.Schema.Default.Node.Parent) + .IgnoringCyclicReferences()); outputDoc.Should().BeEquivalentTo(expectedSerializedDoc.MakeLineBreaksEnvironmentNeutral()); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 4d3055668..52e879aca 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -14,6 +14,8 @@ using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V3; +using FluentAssertions.Equivalency; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Readers.Tests.V3Tests { @@ -177,30 +179,29 @@ public void ParseDictionarySchemaShouldSucceed() [Fact] public void ParseBasicSchemaWithExampleShouldSucceed() { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - schema.Should().BeEquivalentTo( - new OpenApiSchema + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + Properties = { - Type = "object", - Properties = - { ["id"] = new() { Type = "integer", @@ -210,18 +211,22 @@ public void ParseBasicSchemaWithExampleShouldSucceed() { Type = "string" } - }, - Required = - { + }, + Required = + { "name" - }, - Example = new OpenApiAny(new JsonObject - { - ["name"] = new OpenApiAny("Puma").Node, - ["id"] = new OpenApiAny(1).Node - }) - }); - } + }, + Example = new OpenApiAny(new JsonObject + { + ["name"] = new OpenApiAny("Puma").Node, + ["id"] = new OpenApiAny(1).Node + }) + }, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent")) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Root"))); } [Fact] @@ -263,12 +268,6 @@ public void ParseBasicSchemaWithReferenceShouldSucceed() Type = "string" } }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ErrorModel", - HostDocument = result.OpenApiDocument - }, Required = { "message", @@ -277,44 +276,9 @@ public void ParseBasicSchemaWithReferenceShouldSucceed() }, ["ExtendedErrorModel"] = new() { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ExtendedErrorModel", - HostDocument = result.OpenApiDocument - }, AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ErrorModel", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the ErrorModel above should be propagated here. - Type = "object", - Properties = - { - ["code"] = new() - { - Type = "integer", - Minimum = 100, - Maximum = 600 - }, - ["message"] = new() - { - Type = "string" - } - }, - Required = - { - "message", - "code" - } - }, + new OpenApiSchemaReference("ErrorModel", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -367,12 +331,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() { "name", "petType" - }, - Reference = new() - { - Id= "Pet", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } }, ["Cat"] = new() @@ -380,38 +338,7 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Description = "A representation of a cat", AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Pet", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the Pet above should be propagated here. - Type = "object", - Discriminator = new() - { - PropertyName = "petType" - }, - Properties = - { - ["name"] = new() - { - Type = "string" - }, - ["petType"] = new() - { - Type = "string" - } - }, - Required = - { - "name", - "petType" - } - }, + new OpenApiSchemaReference("Pet", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -432,12 +359,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() } } } - }, - Reference = new() - { - Id= "Cat", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } }, ["Dog"] = new() @@ -445,38 +366,7 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Description = "A representation of a dog", AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Pet", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the Pet above should be propagated here. - Type = "object", - Discriminator = new() - { - PropertyName = "petType" - }, - Properties = - { - ["name"] = new() - { - Type = "string" - }, - ["petType"] = new() - { - Type = "string" - } - }, - Required = - { - "name", - "petType" - } - }, + new OpenApiSchemaReference("Pet", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -493,12 +383,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() } } } - }, - Reference = new() - { - Id= "Dog", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml index 170958591..3d9f0343b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml @@ -1,5 +1,3 @@ -# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject -# Add required properties in the Open API document object to avoid errors openapi: 3.0.0 info: title: Simple Document @@ -7,9 +5,7 @@ info: paths: { } components: schemas: - ## Naming this schema Pet1 to disambiguate it from another schema `pet` contained in other test files. - ## SchemaRegistry.Global.Register() is global and can only register 1 schema with the same name. - Pet1: + Pet: type: object discriminator: propertyName: petType @@ -21,10 +17,10 @@ components: required: - name - petType - Cat: ## "Cat" will be used as the discriminator value + Cat: description: A representation of a cat allOf: - - $ref: '#/components/schemas/Pet1' + - $ref: '#/components/schemas/Pet' - type: object properties: huntingSkill: @@ -37,10 +33,10 @@ components: - aggressive required: - huntingSkill - Dog: ## "Dog" will be used as the discriminator value + Dog: description: A representation of a dog allOf: - - $ref: '#/components/schemas/Pet1' + - $ref: '#/components/schemas/Pet' - type: object properties: packSize: @@ -50,4 +46,4 @@ components: default: 0 minimum: 0 required: - - packSize \ No newline at end of file + - packSize diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 74ec5a8b9..0f9ace617 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -6,6 +6,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Xunit; namespace Microsoft.OpenApi.Tests.Models @@ -74,19 +75,7 @@ public class OpenApiComponentsTests { Type = "integer" }, - ["property3"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" + ["property3"] = new OpenApiSchemaReference("schema2", null) } }, ["schema2"] = new() @@ -173,14 +162,7 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - }, + ["schema1"] = new OpenApiSchemaReference("schema2", null), ["schema2"] = new() { Type = "object", @@ -191,7 +173,7 @@ public class OpenApiComponentsTests Type = "string" } } - }, + } } }; @@ -208,11 +190,6 @@ public class OpenApiComponentsTests { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" } }, ["schema2"] = new() @@ -233,14 +210,7 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" - } - } + ["schema1"] = new OpenApiSchemaReference("schema1", null) } }; @@ -256,14 +226,7 @@ public class OpenApiComponentsTests { Type = "integer" }, - ["property3"] = new OpenApiSchema() - { - Reference = new OpenApiReference() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - } + ["property3"] = new OpenApiSchemaReference("schema2", null) } }, @@ -293,14 +256,7 @@ public class OpenApiComponentsTests { ["application/json"] = new OpenApiMediaType { - Schema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "schema1" - } - } + Schema = new OpenApiSchemaReference("schema1", null) } } }, @@ -314,7 +270,6 @@ public class OpenApiComponentsTests } } } - } }; @@ -543,21 +498,29 @@ public void SerializeAdvancedComponentsWithReferenceAsYamlV3Works() public void SerializeBrokenComponentsAsJsonV3Works() { // Arrange - var expected = @"{ - ""schemas"": { - ""schema1"": { - ""type"": ""string"" - }, - ""schema4"": { - ""type"": ""string"", - ""allOf"": [ - { - ""type"": ""string"" - } - ] - } - } -}"; + var expected = """ + { + "schemas": { + "schema1": { + "type": "string" + }, + "schema2": null, + "schema3": null, + "schema4": { + "type": "string", + "allOf": [ + null, + null, + { + "type": "string" + }, + null, + null + ] + } + } + } + """; // Act var actual = BrokenComponents.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); @@ -572,13 +535,22 @@ public void SerializeBrokenComponentsAsJsonV3Works() public void SerializeBrokenComponentsAsYamlV3Works() { // Arrange - var expected = @"schemas: - schema1: - type: string - schema4: - type: string - allOf: - - type: string"; + var expected = + """ + schemas: + schema1: + type: string + schema2: + schema3: + schema4: + type: string + allOf: + - + - + - type: string + - + - + """; // Act var actual = BrokenComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); @@ -592,6 +564,7 @@ public void SerializeBrokenComponentsAsYamlV3Works() [Fact] public void SerializeTopLevelReferencingComponentsAsYamlV3Works() { + // Arrange // Arrange var expected = """ diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt index 245cca5ca..46c5b2e30 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -55,11 +55,11 @@ "schema": { "type": "array", "items": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -78,11 +78,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -97,11 +97,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -132,10 +132,10 @@ "description": "Pet to add to the store", "required": true, "schema": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -155,11 +155,11 @@ "200": { "description": "pet response", "schema": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -177,11 +177,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -196,11 +196,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -238,11 +238,11 @@ "200": { "description": "pet response", "schema": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -260,11 +260,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -279,11 +279,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -320,11 +320,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -339,11 +339,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -361,11 +361,11 @@ }, "definitions": { "pet": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -380,10 +380,10 @@ } }, "newPet": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -398,11 +398,11 @@ } }, "errorModel": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt index 8bf9f35bc..0248156d9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt index 06e0f2ca9..46c5b2e30 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -55,20 +55,62 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -90,7 +132,22 @@ "description": "Pet to add to the store", "required": true, "schema": { - "$ref": "#/definitions/newPet" + "type": "object", + "required": [ + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } ], @@ -98,19 +155,61 @@ "200": { "description": "pet response", "schema": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -139,19 +238,61 @@ "200": { "description": "pet response", "schema": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -179,13 +320,39 @@ "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -194,11 +361,11 @@ }, "definitions": { "pet": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -213,10 +380,10 @@ } }, "newPet": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -231,11 +398,11 @@ } }, "errorModel": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt index ae1db5447..0248156d9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"$ref":"#/definitions/pet"}}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"$ref":"#/definitions/newPet"}}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt index f1da0b354..a688f8525 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt @@ -55,7 +55,23 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, @@ -63,7 +79,23 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -74,7 +106,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -84,7 +129,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -99,7 +157,22 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/newPet" + "required": [ + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, @@ -111,7 +184,23 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -121,7 +210,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -131,7 +233,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -161,12 +276,44 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "application/xml": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -176,7 +323,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -186,7 +346,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -217,7 +390,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -227,7 +413,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt index be8dcc627..0bb1c9679 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/newPet"}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} \ No newline at end of file +{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"application/xml":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"application/xml":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt index 08622d6b1..52c6a3734 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -41,11 +41,11 @@ "schema": { "type": "array", "items": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt index 8cecc96a4..d8e55a839 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","produces":["application/json"],"parameters":[{"in":"path","name":"operand1","description":"The first operand","required":true,"type":"integer","my-extension":4},{"in":"path","name":"operand2","description":"The second operand","required":true,"type":"integer","my-extension":4}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","produces":["application/json"],"parameters":[{"in":"path","name":"operand1","description":"The first operand","required":true,"type":"integer","my-extension":4},{"in":"path","name":"operand2","description":"The second operand","required":true,"type":"integer","my-extension":4}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 5b95221e3..d0b6f8904 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Writers; @@ -33,14 +34,7 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - }, - }, + ["schema1"] = new OpenApiSchemaReference("schema2", null), ["schema2"] = new() { Type = "object", @@ -159,11 +153,6 @@ public OpenApiDocumentTests() { Type = "string" }, - }, - Reference = new() - { - Id = "pet", - Type = ReferenceType.Schema } }, ["newPet"] = new() @@ -188,11 +177,6 @@ public OpenApiDocumentTests() { Type = "string" }, - }, - Reference = new() - { - Id = "newPet", - Type = ReferenceType.Schema } }, ["errorModel"] = new() @@ -214,11 +198,6 @@ public OpenApiDocumentTests() { Type = "string" } - }, - Reference = new() - { - Id = "errorModel", - Type = ReferenceType.Schema } }, } @@ -920,14 +899,7 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new() - { - Reference = new OpenApiReference - { - Id = "Pet", - Type = ReferenceType.Schema - } - } + Schema = new OpenApiSchemaReference("Pet", null) } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 7c729341d..dc18a1341 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -626,9 +626,9 @@ public void SerializeOperationWithBodyAsV2JsonWorks() "description": "description2", "required": true, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } ], @@ -639,9 +639,9 @@ public void SerializeOperationWithBodyAsV2JsonWorks() "400": { "description": null, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } }, @@ -699,9 +699,9 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() "description": "description2", "required": true, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } ], @@ -712,9 +712,9 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() "400": { "description": null, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index 7f3b0b140..f40913dd4 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -110,7 +110,7 @@ public class OpenApiParameterTests In = ParameterLocation.Query, Schema = new() { - Type = "array", + Type = "object", AdditionalProperties = new OpenApiSchema { Type = "integer" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index a07362c32..14a29a907 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -33,10 +33,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary @@ -75,10 +72,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary @@ -119,10 +113,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) } } }, @@ -158,10 +149,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) } } }, diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index 958466da2..a189a3575 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -42,7 +43,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -110,16 +111,16 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/examples/example0/value", - "#/examples/example1/value", - "#/examples/example1/value", + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/examples/example1/value/y", + "#/examples/example1/value/z", "#/examples/example2/value" }); } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index be6e86194..d735e87d2 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -41,7 +42,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -109,17 +110,17 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/examples/example0/value", - "#/examples/example1/value", - "#/examples/example1/value", - "#/examples/example2/value" + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/examples/example1/value/y", + "#/examples/example1/value/z", + "#/examples/example2/value" }); } } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 5048e1040..197d0dbb7 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -90,7 +91,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -160,19 +161,17 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { // #enum/0 is not an error since the spec allows // representing an object using a string. - "#/{parameter1}/examples/example0/value", - "#/{parameter1}/examples/example1/value", - "#/{parameter1}/examples/example1/value", - "#/{parameter1}/examples/example2/value" + "#/{parameter1}/examples/example1/value/y", + "#/{parameter1}/examples/example1/value/z", + "#/{parameter1}/examples/example2/value" }); } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index a7a026a4b..3144955b3 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -42,7 +42,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -75,11 +75,11 @@ public void ValidateExampleAndDefaultShouldNotHaveDataTypeMismatchForSimpleSchem result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/example" + "#/example", }); } @@ -125,16 +125,16 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/enum/0", - "#/enum/1", - "#/enum/1", + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/enum/1/y", + "#/enum/1/z", "#/enum/2" }); } @@ -199,7 +199,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() } }, ["property3"] = "123", - ["property4"] = DateTime.UtcNow.ToString() + ["property4"] = DateTime.UtcNow }) }; @@ -209,21 +209,21 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() walker.Walk(schema); warnings = validator.Warnings; - bool result = warnings.Any(); + bool result = !warnings.Any(); // Assert - result.Should().BeTrue(); + result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"integer\" at /property1/2", - "type : Value is \"integer\" but should be \"object\" at /property2/0", - "type : Value is \"string\" but should be \"boolean\" at /property2/1/z", + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/default", - "#/default", - "#/default" + "#/default/property1/2", + "#/default/property2/0", + "#/default/property2/1/z" }); } diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 4df416d43..924364ccd 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -150,8 +150,7 @@ public void WalkDOMWithCycles() "#/paths", "#/components", "#/components/schemas/loopy", - "#/components/schemas/loopy/properties/parent", - "#/components/schemas/loopy/properties/parent/properties/name", + "#/components/schemas/loopy/properties/name", "#/tags" }); } @@ -162,15 +161,7 @@ public void WalkDOMWithCycles() [Fact] public void LocateReferences() { - var baseSchema = new OpenApiSchema - { - Reference = new() - { - Id = "base", - Type = ReferenceType.Schema - }, - UnresolvedReference = false - }; + var baseSchema = new OpenApiSchemaReference("base", null); var derivedSchema = new OpenApiSchema { @@ -249,9 +240,7 @@ public void LocateReferences() locator.Locations.Where(l => l.StartsWith("referenceAt:")).Should().BeEquivalentTo(new List { "referenceAt: #/paths/~1/get/responses/200/content/application~1json/schema", "referenceAt: #/paths/~1/get/responses/200/headers/test-header/schema", - "referenceAt: #/components/schemas/derived", - "referenceAt: #/components/schemas/derived/anyOf", - "referenceAt: #/components/schemas/base", + "referenceAt: #/components/schemas/derived/anyOf/0", "referenceAt: #/components/securitySchemes/test-secScheme", "referenceAt: #/components/headers/test-header/schema" }); From 8261af6f75f5d9826b5e9c166c9c74c3af63e94b Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:10:21 +0300 Subject: [PATCH 17/44] Update public API --- .../PublicApi/PublicApi.approved.txt | 299 ++++++++---------- 1 file changed, 133 insertions(+), 166 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 5d8f06a7c..f15f19bff 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -146,87 +146,12 @@ namespace Microsoft.OpenApi.Expressions } namespace Microsoft.OpenApi.Extensions { - [Json.Schema.SchemaKeyword("additionalPropertiesAllowed")] - public class AdditionalPropertiesAllowedKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "additionalPropertiesAllowed"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("discriminator")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class DiscriminatorKeyword : Microsoft.OpenApi.Models.OpenApiDiscriminator, Json.Schema.IJsonSchemaKeyword - { - public const string Name = "discriminator"; - public DiscriminatorKeyword() { } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("exclusiveMaximum")] - public class Draft4ExclusiveMaximumKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "exclusiveMaximum"; - public bool MaxValue { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("exclusiveMinimum")] - public class Draft4ExclusiveMinimumKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "exclusiveMinimum"; - public bool MinValue { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } public static class EnumExtensions { public static T GetAttributeOfType(this System.Enum enumValue) where T : System.Attribute { } public static string GetDisplayName(this System.Enum enumValue) { } } - [Json.Schema.SchemaKeyword("extensions")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class ExtensionsKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "extensions"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("externalDocs")] - public class ExternalDocsKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "externalDocs"; - public ExternalDocsKeyword(Microsoft.OpenApi.Models.OpenApiExternalDocs value) { } - public Microsoft.OpenApi.Models.OpenApiExternalDocs Value { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - public static class JsonSchemaBuilderExtensions - { - public static Json.Schema.JsonSchemaBuilder AdditionalPropertiesAllowed(this Json.Schema.JsonSchemaBuilder builder, bool additionalPropertiesAllowed) { } - public static Json.Schema.JsonSchemaBuilder Discriminator(this Json.Schema.JsonSchemaBuilder builder, Microsoft.OpenApi.Models.OpenApiDiscriminator discriminator) { } - public static Json.Schema.JsonSchemaBuilder ExclusiveMaximum(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder ExclusiveMinimum(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder Extensions(this Json.Schema.JsonSchemaBuilder builder, System.Collections.Generic.IDictionary extensions) { } - public static Json.Schema.JsonSchemaBuilder Nullable(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder OpenApiExternalDocs(this Json.Schema.JsonSchemaBuilder builder, Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } - public static Json.Schema.JsonSchemaBuilder Remove(this Json.Schema.JsonSchemaBuilder builder, string keyword) { } - public static Json.Schema.JsonSchemaBuilder Summary(this Json.Schema.JsonSchemaBuilder builder, string summary) { } - } - public static class JsonSchemaExtensions - { - public static bool? GetAdditionalPropertiesAllowed(this Json.Schema.JsonSchema schema) { } - public static System.Collections.Generic.IDictionary GetExtensions(this Json.Schema.JsonSchema schema) { } - public static bool? GetNullable(this Json.Schema.JsonSchema schema) { } - public static Microsoft.OpenApi.Extensions.DiscriminatorKeyword GetOpenApiDiscriminator(this Json.Schema.JsonSchema schema) { } - public static bool? GetOpenApiExclusiveMaximum(this Json.Schema.JsonSchema schema) { } - public static bool? GetOpenApiExclusiveMinimum(this Json.Schema.JsonSchema schema) { } - public static Microsoft.OpenApi.Models.OpenApiExternalDocs GetOpenApiExternalDocs(this Json.Schema.JsonSchema schema) { } - public static string GetSummary(this Json.Schema.JsonSchema schema) { } - } - [Json.Schema.SchemaKeyword("nullable")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class NullableKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "nullable"; - public NullableKeyword(bool value) { } - public bool Value { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } public static class OpenApiElementExtensions { public static System.Collections.Generic.IEnumerable Validate(this Microsoft.OpenApi.Interfaces.IOpenApiElement element, Microsoft.OpenApi.Validations.ValidationRuleSet ruleSet) { } @@ -261,19 +186,13 @@ namespace Microsoft.OpenApi.Extensions } public static class OpenApiTypeMapper { - public static System.Type MapJsonSchemaValueTypeToSimpleType(this Json.Schema.JsonSchema schema) { } - public static Json.Schema.JsonSchema MapTypeToJsonPrimitiveType(this System.Type type) { } + public static System.Type MapOpenApiPrimitiveTypeToSimpleType(this Microsoft.OpenApi.Models.OpenApiSchema schema) { } + public static Microsoft.OpenApi.Models.OpenApiSchema MapTypeToOpenApiPrimitiveType(this System.Type type) { } } public static class StringExtensions { public static T GetEnumFromDisplayName(this string displayName) { } } - [Json.Schema.SchemaKeyword("summary")] - public class SummaryKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "summary"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } } namespace Microsoft.OpenApi.Interfaces { @@ -424,7 +343,7 @@ namespace Microsoft.OpenApi.Models { public OpenApiComponents() { } public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents components) { } - public System.Collections.Generic.IDictionary Schemas { get; set; } + public System.Collections.Generic.IDictionary Schemas { get; set; } public virtual System.Collections.Generic.IDictionary Callbacks { get; set; } public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } @@ -615,7 +534,7 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiDocument : Json.Schema.IBaseDocument, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiDocument() { } public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument document) { } @@ -632,9 +551,6 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IList Tags { get; set; } public System.Collections.Generic.IDictionary Webhooks { get; set; } public Microsoft.OpenApi.Services.OpenApiWorkspace Workspace { get; set; } - public Json.Schema.JsonSchema FindSubschema(Json.Pointer.JsonPointer pointer, Json.Schema.EvaluationOptions options) { } - public Json.Schema.JsonSchema ResolveJsonSchemaReference(System.Uri referenceUri) { } - public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -726,7 +642,7 @@ namespace Microsoft.OpenApi.Models public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -792,7 +708,7 @@ namespace Microsoft.OpenApi.Models public Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } public System.Collections.Generic.IDictionary Examples { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -862,7 +778,7 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } public virtual string Name { get; set; } public virtual bool Required { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -926,7 +842,6 @@ namespace Microsoft.OpenApi.Models public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } - public Microsoft.OpenApi.Models.OpenApiRequestBody GetEffective(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -961,59 +876,61 @@ namespace Microsoft.OpenApi.Models { public OpenApiSchema() { } public OpenApiSchema(Microsoft.OpenApi.Models.OpenApiSchema schema) { } - public Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } - public bool AdditionalPropertiesAllowed { get; set; } - public System.Collections.Generic.IList AllOf { get; set; } - public System.Collections.Generic.IList AnyOf { get; set; } - public string Comment { get; set; } - public Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } - public System.Collections.Generic.IDictionary Definitions { get; set; } - public bool Deprecated { get; set; } - public string Description { get; set; } - public Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } - public string DynamicAnchor { get; set; } - public string DynamicRef { get; set; } - public System.Collections.Generic.IList Enum { get; set; } - public Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } - public bool? ExclusiveMaximum { get; set; } - public bool? ExclusiveMinimum { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public string Format { get; set; } - public string Id { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } - public int? MaxItems { get; set; } - public int? MaxLength { get; set; } - public int? MaxProperties { get; set; } - public decimal? Maximum { get; set; } - public int? MinItems { get; set; } - public int? MinLength { get; set; } - public int? MinProperties { get; set; } - public decimal? Minimum { get; set; } - public decimal? MultipleOf { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } - public bool Nullable { get; set; } - public System.Collections.Generic.IList OneOf { get; set; } - public string Pattern { get; set; } - public System.Collections.Generic.IDictionary Properties { get; set; } - public bool ReadOnly { get; set; } - public string RecursiveAnchor { get; set; } - public string RecursiveRef { get; set; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public System.Collections.Generic.ISet Required { get; set; } - public string Schema { get; set; } - public string Title { get; set; } - public object Type { get; set; } - public bool UnEvaluatedProperties { get; set; } - public bool UnevaluatedProperties { get; set; } - public bool? UniqueItems { get; set; } - public bool UnresolvedReference { get; set; } - public decimal? V31ExclusiveMaximum { get; set; } - public decimal? V31ExclusiveMinimum { get; set; } - public string Vocabulary { get; set; } - public bool WriteOnly { get; set; } - public Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public virtual Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } + public virtual bool AdditionalPropertiesAllowed { get; set; } + public virtual System.Collections.Generic.IList AllOf { get; set; } + public virtual System.Collections.Generic.IList AnyOf { get; set; } + public virtual string Comment { get; set; } + public virtual Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public virtual System.Collections.Generic.IDictionary Definitions { get; set; } + public virtual bool Deprecated { get; set; } + public virtual string Description { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } + public virtual string DynamicAnchor { get; set; } + public virtual string DynamicRef { get; set; } + public virtual System.Collections.Generic.IList Enum { get; set; } + public virtual Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public virtual System.Collections.Generic.IList Examples { get; set; } + public virtual bool? ExclusiveMaximum { get; set; } + public virtual bool? ExclusiveMinimum { get; set; } + public virtual System.Collections.Generic.IDictionary Extensions { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public virtual string Format { get; set; } + public virtual string Id { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } + public virtual int? MaxItems { get; set; } + public virtual int? MaxLength { get; set; } + public virtual int? MaxProperties { get; set; } + public virtual decimal? Maximum { get; set; } + public virtual int? MinItems { get; set; } + public virtual int? MinLength { get; set; } + public virtual int? MinProperties { get; set; } + public virtual decimal? Minimum { get; set; } + public virtual decimal? MultipleOf { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } + public virtual bool Nullable { get; set; } + public virtual System.Collections.Generic.IList OneOf { get; set; } + public virtual string Pattern { get; set; } + public virtual System.Collections.Generic.IDictionary PatternProperties { get; set; } + public virtual System.Collections.Generic.IDictionary Properties { get; set; } + public virtual bool ReadOnly { get; set; } + public virtual string RecursiveAnchor { get; set; } + public virtual string RecursiveRef { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public virtual System.Collections.Generic.ISet Required { get; set; } + public virtual string Schema { get; set; } + public virtual string Title { get; set; } + public virtual object Type { get; set; } + public virtual bool UnEvaluatedProperties { get; set; } + public virtual bool UnevaluatedProperties { get; set; } + public virtual bool? UniqueItems { get; set; } + public virtual bool UnresolvedReference { get; set; } + public virtual decimal? V31ExclusiveMaximum { get; set; } + public virtual decimal? V31ExclusiveMinimum { get; set; } + public virtual string Vocabulary { get; set; } + public virtual bool WriteOnly { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1231,7 +1148,7 @@ namespace Microsoft.OpenApi.Models.References public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override bool Required { get; set; } - public override Json.Schema.JsonSchema Schema { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1265,7 +1182,7 @@ namespace Microsoft.OpenApi.Models.References public override Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } public override string Name { get; set; } public override bool Required { get; set; } - public override Json.Schema.JsonSchema Schema { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1304,6 +1221,65 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema + { + public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public override Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } + public override bool AdditionalPropertiesAllowed { get; set; } + public override System.Collections.Generic.IList AllOf { get; set; } + public override System.Collections.Generic.IList AnyOf { get; set; } + public override string Comment { get; set; } + public override Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public override System.Collections.Generic.IDictionary Definitions { get; set; } + public override bool Deprecated { get; set; } + public override string Description { get; set; } + public override Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } + public override string DynamicAnchor { get; set; } + public override string DynamicRef { get; set; } + public override System.Collections.Generic.IList Enum { get; set; } + public override Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public override System.Collections.Generic.IList Examples { get; set; } + public override bool? ExclusiveMaximum { get; set; } + public override bool? ExclusiveMinimum { get; set; } + public override System.Collections.Generic.IDictionary Extensions { get; set; } + public override Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public override string Format { get; set; } + public override string Id { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } + public override int? MaxItems { get; set; } + public override int? MaxLength { get; set; } + public override int? MaxProperties { get; set; } + public override decimal? Maximum { get; set; } + public override int? MinItems { get; set; } + public override int? MinLength { get; set; } + public override int? MinProperties { get; set; } + public override decimal? Minimum { get; set; } + public override decimal? MultipleOf { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } + public override bool Nullable { get; set; } + public override System.Collections.Generic.IList OneOf { get; set; } + public override string Pattern { get; set; } + public override System.Collections.Generic.IDictionary PatternProperties { get; set; } + public override System.Collections.Generic.IDictionary Properties { get; set; } + public override bool ReadOnly { get; set; } + public override string RecursiveAnchor { get; set; } + public override string RecursiveRef { get; set; } + public override System.Collections.Generic.ISet Required { get; set; } + public override string Schema { get; set; } + public override string Title { get; set; } + public override object Type { get; set; } + public override bool UnEvaluatedProperties { get; set; } + public override bool UnevaluatedProperties { get; set; } + public override bool? UniqueItems { get; set; } + public override decimal? V31ExclusiveMaximum { get; set; } + public override decimal? V31ExclusiveMinimum { get; set; } + public override string Vocabulary { get; set; } + public override bool WriteOnly { get; set; } + public override Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + } public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1508,8 +1484,6 @@ namespace Microsoft.OpenApi.Services public string PathString { get; } public virtual void Enter(string segment) { } public virtual void Exit() { } - public virtual void Visit(Json.Schema.IBaseDocument document) { } - public virtual void Visit(ref Json.Schema.JsonSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceable referenceable) { } @@ -1533,6 +1507,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } + public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } @@ -1552,7 +1527,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IList openApiSecurityRequirements) { } public virtual void Visit(System.Collections.Generic.IList servers) { } public virtual void Visit(System.Collections.Generic.IList openApiTags) { } - public virtual void Visit(System.Collections.Generic.IReadOnlyCollection schema) { } public virtual void Visit(System.Text.Json.Nodes.JsonNode node) { } } public class OpenApiWalker @@ -1607,7 +1581,6 @@ namespace Microsoft.OpenApi.Validations public System.Collections.Generic.IEnumerable Warnings { get; } public void AddError(Microsoft.OpenApi.Validations.OpenApiValidatorError error) { } public void AddWarning(Microsoft.OpenApi.Validations.OpenApiValidatorWarning warning) { } - public override void Visit(ref Json.Schema.JsonSchema item) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible item) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiCallback item) { } @@ -1630,6 +1603,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponse item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses item) { } + public override void Visit(Microsoft.OpenApi.Models.OpenApiSchema item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiServer item) { } @@ -1697,14 +1671,6 @@ namespace Microsoft.OpenApi.Validations } namespace Microsoft.OpenApi.Validations.Rules { - [Microsoft.OpenApi.Validations.Rules.OpenApiRule] - public static class JsonSchemaRules - { - public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } - public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } - public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IReadOnlyCollection childSchema) { } - public static bool ValidateChildSchemaAgainstDiscriminator(Json.Schema.JsonSchema schema, string discriminatorName) { } - } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiComponentsRules { @@ -1787,6 +1753,14 @@ namespace Microsoft.OpenApi.Validations.Rules public OpenApiRuleAttribute() { } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] + public static class OpenApiSchemaRules + { + public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } + public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } + public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IList childSchema) { } + public static bool ValidateChildSchemaAgainstDiscriminator(Microsoft.OpenApi.Models.OpenApiSchema schema, string discriminatorName) { } + } + [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiServerRules { public static Microsoft.OpenApi.Validations.ValidationRule ServerRequiredFields { get; } @@ -1809,9 +1783,6 @@ namespace Microsoft.OpenApi.Writers void Flush(); void WriteEndArray(); void WriteEndObject(); - void WriteJsonSchema(Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version); - void WriteJsonSchemaReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Uri reference, Microsoft.OpenApi.OpenApiSpecVersion version); - void WriteJsonSchemaWithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version); void WriteNull(); void WritePropertyName(string name); void WriteRaw(string value); @@ -1872,9 +1843,6 @@ namespace Microsoft.OpenApi.Writers public abstract void WriteEndArray(); public abstract void WriteEndObject(); public virtual void WriteIndentation() { } - public void WriteJsonSchema(Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version) { } - public void WriteJsonSchemaReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Uri reference, Microsoft.OpenApi.OpenApiSpecVersion version) { } - public void WriteJsonSchemaWithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version) { } public abstract void WriteNull(); public abstract void WritePropertyName(string name); public abstract void WriteRaw(string value); @@ -1897,7 +1865,6 @@ namespace Microsoft.OpenApi.Writers { public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { } public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { } - public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } From e9c5c05f78155963f455923a2fd7660a406c0549 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 14:39:06 +0300 Subject: [PATCH 18/44] Use schema 'id' as a locator for schema registration and performing lookups in the component registry --- .../Models/OpenApiDocument.cs | 19 +++++++++++++------ .../Reader/V31/OpenApiV31Deserializer.cs | 14 +++++++++++--- .../OpenApiComponentsRegistryExtensions.cs | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index ab82061ad..5762223c3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -529,15 +529,22 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool } string uriLocation; - string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id; + if (reference.Id.Contains("/")) // this means its a URL reference + { + uriLocation = reference.Id; + } + else + { + string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id; - uriLocation = useExternal - ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath - : BaseUri + relativePath; + uriLocation = useExternal + ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath + : BaseUri + relativePath; + } return Workspace.ResolveReference(uriLocation); } - + /// /// Parses a local file path or Url into an Open API document. /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index aa38c326d..33eb3e11e 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -147,11 +147,19 @@ private static string LoadString(ParseNode node) private static (string, string) GetReferenceIdAndExternalResource(string pointer) { + /* Check whether the reference pointer is a URL + * (id keyword allows you to supply a URL for the schema as a target for referencing) + * E.g. $ref: 'https://example.com/schemas/resource.json' + * or its a normal json pointer fragment syntax + * E.g. $ref: '#/components/schemas/pet' + */ var refSegments = pointer.Split('/'); - var refId = refSegments.Last(); - var isExternalResource = !refSegments.First().StartsWith("#"); + string refId = !pointer.Contains('#') ? pointer : refSegments.Last(); - string externalResource = isExternalResource ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" : null; + var isExternalResource = !refSegments.First().StartsWith("#"); + string externalResource = isExternalResource + ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" + : null; return (refId, externalResource); } diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 9a5b62d37..226853a13 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -20,7 +20,7 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo { if (item.Value.Id != null) { - location = document.BaseUri + item.Value.Id; + location = item.Value.Id; } else { From 1dbd8701fa26ad91f202e93455e74eed7c70c620 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 14:39:28 +0300 Subject: [PATCH 19/44] Add test to validate --- .../V31Tests/OpenApiDocumentTests.cs | 16 +++++++ .../OpenApiDocument/docWithReferenceById.yaml | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 6f6ed0faa..b22e428f2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -481,5 +481,21 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() actualSchema.Should().BeEquivalentTo(expectedSchema); actualMediaType.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expectedMediaType.MakeLineBreaksEnvironmentNeutral()); } + + [Fact] + public void ParseDocumentWithReferenceByIdGetsResolved() + { + // Arrange and Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "docWithReferenceById.yaml")); + + var responseSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; + var requestBodySchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content["application/json"].Schema; + var parameterSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Parameters[0].Schema; + + // Assert + Assert.Equal("object", responseSchema.Type); + Assert.Equal("object", requestBodySchema.Type); + Assert.Equal("string", parameterSchema.Type); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml new file mode 100644 index 000000000..d6c0121e4 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml @@ -0,0 +1,45 @@ +openapi: 3.1.0 +info: + title: ReferenceById + version: 1.0.0 +paths: + /resource: + get: + parameters: + - name: id + in: query + required: true + schema: + $ref: 'https://example.com/schemas/id.json' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: 'https://example.com/schemas/resource.json' + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: 'https://example.com/schemas/resource.json' + responses: + '200': + description: OK +components: + schemas: + Resource: + $id: 'https://example.com/schemas/resource.json' + type: object + properties: + id: + type: string + name: + type: string + reference: + $ref: '#/components/schemas/Resource' + Id: + $id: 'https://example.com/schemas/id.json' + type: string \ No newline at end of file From 04d39528d838678f71fdf227aa76c0505391407f Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 17:51:48 +0300 Subject: [PATCH 20/44] Add support for pattern properties # Conflicts: # src/Microsoft.OpenApi/Models/OpenApiSchema.cs --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 15 +++++++++++++-- .../Reader/V31/OpenApiSchemaDeserializer.cs | 4 ++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index ae1e63196..16b50383a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -227,6 +227,15 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// public IDictionary Properties { get; set; } = new Dictionary(); + /// + /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 + /// PatternProperty definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced) + /// Each property name of this object SHOULD be a valid regular expression according to the ECMA 262 r + /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST + /// be a valid Schema Object not a standard JSON Schema. + /// + public IDictionary PatternProperties { get; set; } = new Dictionary(); + /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// @@ -363,11 +372,12 @@ public OpenApiSchema(OpenApiSchema schema) MinItems = schema?.MinItems ?? MinItems; UniqueItems = schema?.UniqueItems ?? UniqueItems; Properties = schema?.Properties != null ? new Dictionary(schema.Properties) : null; + PatternProperties = schema?.PatternProperties != null ? new Dictionary(schema.PatternProperties) : null; MaxProperties = schema?.MaxProperties ?? MaxProperties; MinProperties = schema?.MinProperties ?? MinProperties; AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; - Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; + Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; Example = schema?.Example != null ? new(schema?.Example.Node) : null; Examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; @@ -596,6 +606,7 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 1df2d6014..116674238 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -150,6 +150,10 @@ internal static partial class OpenApiV31Deserializer "properties", (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) }, + { + "patternProperties", + (o, n, t) => o.PatternProperties = n.CreateMap(LoadOpenApiSchema, t) + }, { "additionalProperties", (o, n, _) => { From 6bf026f9c5c5b9f62a0e72a02e3aac2e1716752e Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 18:38:36 +0300 Subject: [PATCH 21/44] Code refactoring; replace JsonSchema with OpenApiSchema --- src/Microsoft.OpenApi.Hidi/StatsVisitor.cs | 3 +- src/Microsoft.OpenApi.Workbench/MainModel.cs | 1 - .../Helpers/JsonNodeCloneHelper.cs | 13 - .../Models/OpenApiRequestBody.cs | 22 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 14 +- .../References/OpenApiHeaderReference.cs | 3 +- .../References/OpenApiParameterReference.cs | 3 +- .../Reader/ParseNodes/AnyFieldMapParameter.cs | 6 +- .../ParseNodes/AnyListFieldMapParameter.cs | 8 +- .../ParseNodes/AnyMapFieldMapParameter.cs | 8 +- .../Reader/ParseNodes/MapNode.cs | 35 -- .../Reader/ParseNodes/ParseNode.cs | 13 +- .../Reader/SchemaTypeConverter.cs | 26 -- .../Reader/V2/JsonSchemaDeserializer.cs | 269 --------------- .../Reader/V2/OpenApiDocumentDeserializer.cs | 2 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 108 ++---- .../Reader/V2/OpenApiOperationDeserializer.cs | 25 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 80 ++--- .../Reader/V2/OpenApiResponseDeserializer.cs | 5 +- .../Reader/V2/OpenApiSchemaDeserializer.cs | 10 +- .../Reader/V2/OpenApiV2VersionService.cs | 3 +- .../Reader/V3/JsonSchemaDeserializer.cs | 309 ----------------- .../V3/OpenApiComponentsDeserializer.cs | 3 +- .../Reader/V3/OpenApiSchemaDeserializer.cs | 16 +- .../Reader/V3/OpenApiV3VersionService.cs | 3 +- .../Reader/V31/JsonSchemaDeserializer.cs | 312 ------------------ .../V31/OpenApiComponentsDeserializer.cs | 1 - .../Reader/V31/OpenApiSchemaDeserializer.cs | 22 +- .../Reader/V31/OpenApiV31VersionService.cs | 4 +- .../Services/CopyReferences.cs | 21 +- .../Services/JsonSchemaReferenceResolver.cs | 199 ----------- .../OpenApiComponentsRegistryExtensions.cs | 5 +- ...onSchemaRules.cs => OpenApiSchemaRules.cs} | 83 ++--- .../Validations/Rules/RuleHelpers.cs | 265 +++++++++++++-- 34 files changed, 413 insertions(+), 1487 deletions(-) delete mode 100644 src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs delete mode 100644 src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs rename src/Microsoft.OpenApi/Validations/Rules/{JsonSchemaRules.cs => OpenApiSchemaRules.cs} (55%) diff --git a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs index bc68746d9..b6af07778 100644 --- a/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs +++ b/src/Microsoft.OpenApi.Hidi/StatsVisitor.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -20,7 +19,7 @@ public override void Visit(OpenApiParameter parameter) public int SchemaCount { get; set; } - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { SchemaCount++; } diff --git a/src/Microsoft.OpenApi.Workbench/MainModel.cs b/src/Microsoft.OpenApi.Workbench/MainModel.cs index e46b83b67..d9b2a0fa1 100644 --- a/src/Microsoft.OpenApi.Workbench/MainModel.cs +++ b/src/Microsoft.OpenApi.Workbench/MainModel.cs @@ -11,7 +11,6 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Validations; diff --git a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs index 32025d198..9f89ddc11 100644 --- a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs +++ b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs @@ -4,7 +4,6 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; -using Json.Schema; using Microsoft.OpenApi.Any; namespace Microsoft.OpenApi.Helpers @@ -28,18 +27,6 @@ internal static OpenApiAny Clone(OpenApiAny value) return new OpenApiAny(result); } - internal static JsonSchema CloneJsonSchema(JsonSchema schema) - { - var jsonString = Serialize(schema); - if (string.IsNullOrEmpty(jsonString)) - { - return null; - } - - var result = JsonSerializer.Deserialize(jsonString, options); - return result; - } - private static string Serialize(object obj) { if (obj == null) diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 00d50a7be..11b1af6be 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -1,10 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -165,7 +164,7 @@ internal OpenApiBodyParameter ConvertToBodyParameter() // V2 spec actually allows the body to have custom name. // To allow round-tripping we use an extension to hold the name Name = "body", - Schema = Content.Values.FirstOrDefault()?.Schema ?? new JsonSchemaBuilder(), + Schema = Content.Values.FirstOrDefault()?.Schema ?? new OpenApiSchema(), Examples = Content.Values.FirstOrDefault()?.Examples, Required = Required, Extensions = Extensions.ToDictionary(static k => k.Key, static v => v.Value) // Clone extensions so we can remove the x-bodyName extensions from the output V2 model. @@ -184,24 +183,23 @@ internal IEnumerable ConvertToFormDataParameters() if (Content == null || !Content.Any()) yield break; - foreach (var property in Content.First().Value.Schema.GetProperties()) + foreach (var property in Content.First().Value.Schema.Properties) { var paramSchema = property.Value; - if (paramSchema.GetType().Equals(SchemaValueType.String) - && ("binary".Equals(paramSchema.GetFormat().Key, StringComparison.OrdinalIgnoreCase) - || "base64".Equals(paramSchema.GetFormat().Key, StringComparison.OrdinalIgnoreCase))) + if ("string".Equals(paramSchema.Type.ToString(), StringComparison.OrdinalIgnoreCase) + && ("binary".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase) + || "base64".Equals(paramSchema.Format, StringComparison.OrdinalIgnoreCase))) { - // JsonSchema is immutable so these can't be set - //paramSchema.Type("file"); - //paramSchema.Format(null); + paramSchema.Type = "file"; + paramSchema.Format = null; } yield return new() { - Description = property.Value.GetDescription(), + Description = property.Value.Description, Name = property.Key, Schema = property.Value, Examples = Content.Values.FirstOrDefault()?.Examples, - Required = Content.First().Value.Schema.GetRequired().Contains(property.Key) + Required = Content.First().Value.Schema.Required?.Contains(property.Key) ?? false }; } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 16b50383a..c6f6f25ee 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -715,6 +715,12 @@ internal void WriteAsSchemaProperties( ISet parentRequiredProperties, string propertyName) { + // type + writer.WriteProperty(OpenApiConstants.Type, (string)Type); + + // description + writer.WriteProperty(OpenApiConstants.Description, Description); + // format if (string.IsNullOrEmpty(Format)) { @@ -728,9 +734,6 @@ internal void WriteAsSchemaProperties( // title writer.WriteProperty(OpenApiConstants.Title, Title); - // description - writer.WriteProperty(OpenApiConstants.Description, Description); - // default writer.WriteOptionalObject(OpenApiConstants.Default, Default, (w, d) => w.WriteAny(d)); @@ -779,9 +782,6 @@ internal void WriteAsSchemaProperties( // enum writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s))); - // type - writer.WriteProperty(OpenApiConstants.Type, (string)Type); - // items writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w)); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index b878898bf..64111c477 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -86,7 +85,7 @@ public override string Description public override bool AllowEmptyValue { get => Target.AllowEmptyValue; set => Target.AllowEmptyValue = value; } /// - public override JsonSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } /// public override ParameterStyle? Style { get => Target.Style; set => Target.Style = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 6722bf1bd..488e054a4 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -94,7 +93,7 @@ public override string Description public override bool AllowReserved { get => Target.AllowReserved; set => Target.AllowReserved = value; } /// - public override JsonSchema Schema { get => Target.Schema; set => Target.Schema = value; } + public override OpenApiSchema Schema { get => Target.Schema; set => Target.Schema = value; } /// public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs index 9b674c408..933040da6 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs @@ -2,8 +2,8 @@ // Licensed under the MIT license. using System; -using Json.Schema; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -15,7 +15,7 @@ internal class AnyFieldMapParameter public AnyFieldMapParameter( Func propertyGetter, Action propertySetter, - Func SchemaGetter = null) + Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -35,6 +35,6 @@ public AnyFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs index 32342d594..fc87a548e 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyListFieldMapParameter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Json.Schema; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -16,7 +16,7 @@ internal class AnyListFieldMapParameter public AnyListFieldMapParameter( Func> propertyGetter, Action> propertySetter, - Func SchemaGetter = null) + Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; this.PropertySetter = propertySetter; @@ -36,6 +36,6 @@ public AnyListFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs index 43468acfc..b0c38247c 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes { @@ -17,7 +17,7 @@ public AnyMapFieldMapParameter( Func> propertyMapGetter, Func propertyGetter, Action propertySetter, - Func schemaGetter) + Func schemaGetter) { this.PropertyMapGetter = propertyMapGetter; this.PropertyGetter = propertyGetter; @@ -43,6 +43,6 @@ public AnyMapFieldMapParameter( /// /// Function to get the schema to apply to the property. /// - public Func SchemaGetter { get; } + public Func SchemaGetter { get; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs index 0cc8539cf..c251bce3c 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; @@ -79,40 +78,6 @@ public override Dictionary CreateMap(Func k.key, v => v.value); } - public override Dictionary CreateJsonSchemaMap( - ReferenceType referenceType, - Func map, - OpenApiSpecVersion version, - OpenApiDocument hostDocument = null) - { - var jsonMap = _node ?? throw new OpenApiReaderException($"Expected map while parsing {typeof(JsonSchema).Name}", Context); - - var nodes = jsonMap.Select( - n => - { - var key = n.Key; - (string key, JsonSchema value) entry; - try - { - Context.StartObject(key); - entry = (key, - value: map(new MapNode(Context, (JsonObject)n.Value), hostDocument) - ); - if (entry.value == null) - { - return default; // Body Parameters shouldn't be converted to Parameters - } - } - finally - { - Context.EndObject(); - } - return entry; - } - ); - return nodes.Where(n => n != default).ToDictionary(k => k.key, v => v.value); - } - public override Dictionary CreateSimpleMap(Func map) { var jsonMap = _node ?? throw new OpenApiReaderException($"Expected map while parsing {typeof(T).Name}", Context); diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs index a72f1bed9..250581fbd 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs @@ -4,10 +4,8 @@ using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; -using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Reader.ParseNodes @@ -59,15 +57,6 @@ public virtual Dictionary CreateMap(Func CreateJsonSchemaMap( - ReferenceType referenceType, - Func map, - OpenApiSpecVersion version, - OpenApiDocument hostDocument = null) - { - throw new OpenApiReaderException("Cannot create map from this reference.", Context); - } - public virtual List CreateSimpleList(Func map) { throw new OpenApiReaderException("Cannot create simple list from this type of node.", Context); @@ -96,6 +85,6 @@ public virtual string GetScalarValue() public virtual List CreateListOfAny() { throw new OpenApiReaderException("Cannot create a list from this type of node.", Context); - } + } } } diff --git a/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs b/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs deleted file mode 100644 index f446fa78b..000000000 --- a/src/Microsoft.OpenApi/Reader/SchemaTypeConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System; -using Json.Schema; - -namespace Microsoft.OpenApi.Reader -{ - internal static class SchemaTypeConverter - { - internal static SchemaValueType ConvertToSchemaValueType(string value) - { - return value.ToLowerInvariant() switch - { - "string" => SchemaValueType.String, - "number" or "double" => SchemaValueType.Number, - "integer" => SchemaValueType.Integer, - "boolean" => SchemaValueType.Boolean, - "array" => SchemaValueType.Array, - "object" => SchemaValueType.Object, - "null" => SchemaValueType.Null, - _ => throw new NotSupportedException(), - }; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs deleted file mode 100644 index 176593c94..000000000 --- a/src/Microsoft.OpenApi/Reader/V2/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Reader.ParseNodes; - -namespace Microsoft.OpenApi.Reader.V2 -{ - /// - /// Class containing logic to deserialize Open API V2 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV2Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(bool.Parse(n.GetScalarValue())); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalProperties(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "discriminator", (o, n, _) => - { - var discriminator = new OpenApiDiscriminator - { - PropertyName = n.GetScalarValue() - }; - o.Discriminator(discriminator.PropertyName, (IReadOnlyDictionary)discriminator.Mapping, - (IReadOnlyDictionary)discriminator.Extensions); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n, t); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - o.Example(n.CreateAny().Node); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var schemaBuilder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - var jsonSchema = schemaBuilder.Ref(pointer).Build(); - if (hostDocument != null) - { - jsonSchema.BaseUri = hostDocument.BaseUri; - } - - return jsonSchema; - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(schemaBuilder, _schemaFixedFields, _schemaPatternFields); - } - - var schema = schemaBuilder.Build(); - - if (hostDocument != null) - { - schema.BaseUri = hostDocument.BaseUri; - } - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index a402ce9ca..b0e2a29ae 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -59,7 +59,7 @@ internal static partial class OpenApiV2Deserializer (o, n, _) => { o.Components ??= new(); - o.Components.Schemas = n.CreateJsonSchemaMap(ReferenceType.Schema, LoadSchema, OpenApiSpecVersion.OpenApi2_0, o); + o.Components.Schemas = n.CreateMap(LoadSchema, o); } }, { diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index 4c2431721..500f10353 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -3,7 +3,6 @@ using System; using System.Globalization; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Exceptions; @@ -17,7 +16,6 @@ namespace Microsoft.OpenApi.Reader.V2 /// internal static partial class OpenApiV2Deserializer { - private static JsonSchemaBuilder _headerJsonSchemaBuilder; private static readonly FixedFieldMap _headerFixedFields = new() { { @@ -25,105 +23,73 @@ internal static partial class OpenApiV2Deserializer (o, n, _) => o.Description = n.GetScalarValue() }, { - "type", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } + "type", + (o, n, _) => GetOrCreateSchema(o).Type = n.GetScalarValue() }, { - "format", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Format(n.GetScalarValue()); - } + "format", + (o, n, _) => GetOrCreateSchema(o).Format = n.GetScalarValue() }, { - "items", (o, n, t) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Items(LoadSchema(n, t)); - } + "items", + (o, n, _) => GetOrCreateSchema(o).Items = LoadSchema(n) }, { "collectionFormat", (o, n, _) => LoadStyle(o, n.GetScalarValue()) }, { - "default", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Default(n.CreateAny().Node); - } + "default", + (o, n, _) => GetOrCreateSchema(o).Default = n.CreateAny() }, { - "maximum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Maximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maximum", + (o, n, _) => GetOrCreateSchema(o).Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue) }, { - "exclusiveMaximum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().ExclusiveMaximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "exclusiveMaximum", + (o, n, _) => GetOrCreateSchema(o).ExclusiveMaximum = bool.Parse(n.GetScalarValue()) }, { - "minimum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Minimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minimum", + (o, n, _) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue) }, { - "exclusiveMinimum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().ExclusiveMinimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "exclusiveMinimum", + (o, n, _) => GetOrCreateSchema(o).ExclusiveMinimum = bool.Parse(n.GetScalarValue()) }, { - "maxLength", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxLength", + (o, n, _) => GetOrCreateSchema(o).MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minLength", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minLength", + (o, n, _) => GetOrCreateSchema(o).MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "pattern", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Pattern(n.GetScalarValue()); - } + "pattern", + (o, n, _) => GetOrCreateSchema(o).Pattern = n.GetScalarValue() }, { - "maxItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxItems", + (o, n, _) => GetOrCreateSchema(o).MaxItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minItems", + (o, n, _) => GetOrCreateSchema(o).MinItems = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "uniqueItems", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().UniqueItems(bool.Parse(n.GetScalarValue())); - } + "uniqueItems", + (o, n, _) => GetOrCreateSchema(o).UniqueItems = bool.Parse(n.GetScalarValue()) }, { - "multipleOf", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().MultipleOf(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "multipleOf", + (o, n, _) => GetOrCreateSchema(o).MultipleOf = decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "enum", (o, n, _) => - { - o.Schema = GetOrCreateHeaderSchemaBuilder().Enum(n.CreateListOfAny()).Build(); - } - } + "enum", + (o, n, _) => GetOrCreateSchema(o).Enum = n.CreateListOfAny() + } }; private static readonly PatternFieldMap _headerPatternFields = new() @@ -131,24 +97,22 @@ internal static partial class OpenApiV2Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - private static JsonSchemaBuilder GetOrCreateHeaderSchemaBuilder() + private static OpenApiSchema GetOrCreateSchema(OpenApiHeader p) { - _headerJsonSchemaBuilder ??= new JsonSchemaBuilder(); - return _headerJsonSchemaBuilder; + return p.Schema ??= new(); } public static OpenApiHeader LoadHeader(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode("header"); var header = new OpenApiHeader(); - _headerJsonSchemaBuilder = null; foreach (var property in mapNode) { property.ParseField(header, _headerFixedFields, _headerPatternFields); } - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { header.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index 5dfc3b9a1..a2faa5810 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -148,25 +147,19 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List k.Name, v => { - var schemaBuilder = new JsonSchemaBuilder(); var schema = v.Schema; - - foreach (var keyword in schema.Keywords) - { - schemaBuilder.Add(keyword); - } - - schemaBuilder.Description(v.Description); - if (v.Extensions.Any()) - { - schemaBuilder.Extensions(v.Extensions); - } - return schemaBuilder.Build(); - })).Required(new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name))).Build() + schema.Description = v.Description; + schema.Extensions = v.Extensions; + return schema; + }), + Required = new HashSet(formParameters.Where(p => p.Required).Select(p => p.Name)) + } }; var consumes = context.GetFromTempStorage>(TempStorageKeys.OperationConsumes) ?? diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 54c584df2..2823974de 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -4,9 +4,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using Json.Schema; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -20,7 +17,6 @@ namespace Microsoft.OpenApi.Reader.V2 /// internal static partial class OpenApiV2Deserializer { - private static JsonSchemaBuilder _parameterJsonSchemaBuilder; private static readonly FixedFieldMap _parameterFixedFields = new() { @@ -49,74 +45,52 @@ internal static partial class OpenApiV2Deserializer (o, n, t) => o.AllowEmptyValue = bool.Parse(n.GetScalarValue()) }, { - "type", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } + "type", + (o, n, t) => GetOrCreateSchema(o).Type = n.GetScalarValue() }, { - "items", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Items(LoadSchema(n, t)); - } + "items", + (o, n, t) => GetOrCreateSchema(o).Items = LoadSchema(n) }, { "collectionFormat", (o, n, t) => LoadStyle(o, n.GetScalarValue()) }, { - "format", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Format(n.GetScalarValue()); - } + "format", + (o, n, t) => GetOrCreateSchema(o).Format = n.GetScalarValue() }, { - "minimum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Minimum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minimum", + (o, n, t) => GetOrCreateSchema(o).Minimum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MinValue) }, { - "maximum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Maximum(decimal.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maximum", + (o, n, t) => GetOrCreateSchema(o).Maximum = ParserHelper.ParseDecimalWithFallbackOnOverflow(n.GetScalarValue(), decimal.MaxValue) }, { - "maxLength", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "maxLength", + (o, n, t) => GetOrCreateSchema(o).MaxLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "minLength", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } + "minLength", + (o, n, t) => GetOrCreateSchema(o).MinLength = int.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture) }, { - "readOnly", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().ReadOnly(bool.Parse(n.GetScalarValue())); - } + "readOnly", + (o, n, t) => GetOrCreateSchema(o).ReadOnly = bool.Parse(n.GetScalarValue()) }, { - "default", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Default(n.CreateAny().Node); - } + "default", + (o, n, t) => GetOrCreateSchema(o).Default = n.CreateAny() }, { - "pattern", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Pattern(n.GetScalarValue()); - } + "pattern", + (o, n, t) => GetOrCreateSchema(o).Pattern = n.GetScalarValue() }, { - "enum", (o, n, t) => - { - o.Schema = GetOrCreateParameterSchemaBuilder().Enum(n.CreateListOfAny()).Build(); - } + "enum", + (o, n, t) => GetOrCreateSchema(o).Enum = n.CreateListOfAny() }, { "schema", @@ -169,11 +143,10 @@ private static void LoadParameterExamplesExtension(OpenApiParameter parameter, P var examples = LoadExamplesExtension(node); node.Context.SetTempStorage(TempStorageKeys.Examples, examples, parameter); } - - private static JsonSchemaBuilder GetOrCreateParameterSchemaBuilder() + + private static OpenApiSchema GetOrCreateSchema(OpenApiParameter p) { - _parameterJsonSchemaBuilder ??= new JsonSchemaBuilder(); - return _parameterJsonSchemaBuilder; + return p.Schema ??= new(); } private static void ProcessIn(OpenApiParameter o, ParseNode n, OpenApiDocument hostDocument = null) @@ -228,11 +201,10 @@ public static OpenApiParameter LoadParameter(ParseNode node, bool loadRequestBod } var parameter = new OpenApiParameter(); - _parameterJsonSchemaBuilder = null; ParseMap(mapNode, parameter, _parameterFixedFields, _parameterPatternFields, doc: hostDocument); - var schema = node.Context.GetFromTempStorage("schema"); + var schema = node.Context.GetFromTempStorage("schema"); if (schema != null) { parameter.Schema = schema; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs index 05b89cfff..8436a09cd 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiResponseDeserializer.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -74,7 +73,7 @@ private static void ProcessProduces(MapNode mapNode, OpenApiResponse response, P ?? context.GetFromTempStorage>(TempStorageKeys.GlobalProduces) ?? context.DefaultContentType ?? new List { "application/octet-stream" }; - var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); + var schema = context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response); var examples = context.GetFromTempStorage>(TempStorageKeys.Examples, response) ?? new Dictionary(); @@ -171,7 +170,7 @@ private static void LoadExample(OpenApiResponse response, string mediaType, Pars { mediaTypeObject = new() { - Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) + Schema = node.Context.GetFromTempStorage(TempStorageKeys.ResponseSchema, response) }; response.Content.Add(mediaType, mediaTypeObject); } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 868ea2d32..96ed771f1 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -88,15 +88,15 @@ internal static partial class OpenApiV2Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -107,7 +107,7 @@ internal static partial class OpenApiV2Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -155,7 +155,7 @@ internal static partial class OpenApiV2Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode("schema"); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs index ea5e66f0a..c9e58b519 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2VersionService.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Interfaces; @@ -44,7 +43,7 @@ public OpenApiV2VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiPaths)] = OpenApiV2Deserializer.LoadPaths, [typeof(OpenApiResponse)] = OpenApiV2Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV2Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV2Deserializer.LoadSchema, + [typeof(OpenApiSchema)] = OpenApiV2Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV2Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV2Deserializer.LoadSecurityScheme, [typeof(OpenApiTag)] = OpenApiV2Deserializer.LoadTag, diff --git a/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs deleted file mode 100644 index 0f6be069a..000000000 --- a/src/Microsoft.OpenApi/Reader/V3/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using JsonSchema = Json.Schema.JsonSchema; -using Microsoft.OpenApi.Reader.ParseNodes; - -namespace Microsoft.OpenApi.Reader.V3 -{ - /// - /// Class containing logic to deserialize Open API V3 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV3Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(bool.Parse(n.GetScalarValue())); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "oneOf", (o, n, t) => - { - o.OneOf(n.CreateList(LoadSchema, t)); - } - }, - { - "anyOf", (o, n, t) => - { - o.AnyOf(n.CreateList(LoadSchema, t)); - } - }, - { - "not", (o, n, t) => - { - o.Not(LoadSchema(n, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalPropertiesAllowed(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "nullable", (o, n, _) => - { - o.Nullable(bool.Parse(n.GetScalarValue())); - } - }, - { - "discriminator", (o, n, t) => - { - var discriminator = LoadDiscriminator(n, t); - o.Discriminator(discriminator); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "writeOnly", (o, n, _) => - { - o.WriteOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n, t); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - if(n is ListNode) - { - o.Examples(n.CreateSimpleList((s, p) => (JsonNode)s.GetScalarValue())); - } - else - { - o.Example(n.CreateAny().Node); - } - } - }, - { - "deprecated", (o, n, _) => - { - o.Deprecated(bool.Parse(n.GetScalarValue())); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var builder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - var jsonSchema = builder.Ref(pointer).Build(); - if (hostDocument != null) - { - jsonSchema.BaseUri = hostDocument.BaseUri; - } - - return jsonSchema; - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(builder, _schemaFixedFields, _schemaPatternFields, hostDocument); - } - - var schema = builder.Build(); - - if (hostDocument != null) - { - schema.BaseUri = hostDocument.BaseUri; - } - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } -} diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs index 3e1d2539b..cc51187d2 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiComponentsDeserializer.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -16,7 +15,7 @@ internal static partial class OpenApiV3Deserializer { private static readonly FixedFieldMap _componentsFixedFields = new() { - {"schemas", (o, n, t) => o.Schemas = n.CreateJsonSchemaMap(ReferenceType.Schema, LoadSchema, OpenApiSpecVersion.OpenApi3_0, t)}, + {"schemas", (o, n, t) => o.Schemas = n.CreateMap(LoadSchema, t)}, {"responses", (o, n, t) => o.Responses = n.CreateMap(LoadResponse, t)}, {"parameters", (o, n, t) => o.Parameters = n.CreateMap(LoadParameter, t)}, {"examples", (o, n, t) => o.Examples = n.CreateMap(LoadExample, t)}, diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index 51b427321..bacd72e4c 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -87,27 +87,27 @@ internal static partial class OpenApiV3Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "oneOf", - (o, n, _) => o.OneOf = n.CreateList(LoadOpenApiSchema) + (o, n, _) => o.OneOf = n.CreateList(LoadSchema) }, { "anyOf", - (o, n, t) => o.AnyOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AnyOf = n.CreateList(LoadSchema, t) }, { "not", - (o, n, _) => o.Not = LoadOpenApiSchema(n) + (o, n, _) => o.Not = LoadSchema(n) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -118,7 +118,7 @@ internal static partial class OpenApiV3Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -173,7 +173,7 @@ internal static partial class OpenApiV3Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index 4479332bd..7ffc907fc 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; @@ -57,7 +56,7 @@ public OpenApiV3VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiRequestBody)] = OpenApiV3Deserializer.LoadRequestBody, [typeof(OpenApiResponse)] = OpenApiV3Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV3Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV3Deserializer.LoadSchema, + [typeof(OpenApiSchema)] = OpenApiV3Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV3Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV3Deserializer.LoadSecurityScheme, [typeof(OpenApiServer)] = OpenApiV3Deserializer.LoadServer, diff --git a/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs deleted file mode 100644 index 02bf282a6..000000000 --- a/src/Microsoft.OpenApi/Reader/V31/JsonSchemaDeserializer.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json.Nodes; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Extensions; -using Microsoft.OpenApi.Interfaces; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Reader.ParseNodes; -using JsonSchema = Json.Schema.JsonSchema; - -namespace Microsoft.OpenApi.Reader.V31 -{ - /// - /// Class containing logic to deserialize Open API V31 document into - /// runtime Open API object model. - /// - internal static partial class OpenApiV31Deserializer - { - private static readonly FixedFieldMap _schemaFixedFields = new() - { - { - "title", (o, n, _) => - { - o.Title(n.GetScalarValue()); - } - }, - { - "multipleOf", (o, n, _) => - { - o.MultipleOf(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maximum", (o, n, _) => - { - o.Maximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMaximum", (o, n, _) => - { - o.ExclusiveMaximum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "minimum", (o, n, _) => - { - o.Minimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "exclusiveMinimum", (o, n, _) => - { - o.ExclusiveMinimum(decimal.Parse(n.GetScalarValue(), NumberStyles.Float, CultureInfo.InvariantCulture)); - } - }, - { - "maxLength", (o, n, _) => - { - o.MaxLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minLength", (o, n, _) => - { - o.MinLength(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "pattern", (o, n, _) => - { - o.Pattern(n.GetScalarValue()); - } - }, - { - "maxItems", (o, n, _) => - { - o.MaxItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minItems", (o, n, _) => - { - o.MinItems(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "uniqueItems", (o, n, _) => - { - o.UniqueItems(bool.Parse(n.GetScalarValue())); - } - }, - { - "maxProperties", (o, n, _) => - { - o.MaxProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "minProperties", (o, n, _) => - { - o.MinProperties(uint.Parse(n.GetScalarValue(), CultureInfo.InvariantCulture)); - } - }, - { - "required", (o, n, _) => - { - o.Required(new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue()))); - } - }, - { - "enum", (o, n, _) => - { - o.Enum(n.CreateListOfAny()); - } - }, - { - "type", (o, n, _) => - { - if(n is ListNode) - { - o.Type(n.CreateSimpleList((s, p) => SchemaTypeConverter.ConvertToSchemaValueType(s.GetScalarValue()))); - } - else - { - o.Type(SchemaTypeConverter.ConvertToSchemaValueType(n.GetScalarValue())); - } - } - }, - { - "allOf", (o, n, t) => - { - o.AllOf(n.CreateList(LoadSchema, t)); - } - }, - { - "oneOf", (o, n, t) => - { - o.OneOf(n.CreateList(LoadSchema, t)); - } - }, - { - "anyOf", (o, n, t) => - { - o.AnyOf(n.CreateList(LoadSchema, t)); - } - }, - { - "not", (o, n, t) => - { - o.Not(LoadSchema(n, t)); - } - }, - { - "items", (o, n, t) => - { - o.Items(LoadSchema(n, t)); - } - }, - { - "properties", (o, n, t) => - { - o.Properties(n.CreateMap(LoadSchema, t)); - } - }, - { - "patternProperties", (o, n, t) => - { - o.PatternProperties(n.CreateMap(LoadSchema, t)); - } - }, - { - "additionalProperties", (o, n, t) => - { - if (n is ValueNode) - { - o.AdditionalPropertiesAllowed(bool.Parse(n.GetScalarValue())); - } - else - { - o.AdditionalProperties(LoadSchema(n, t)); - } - } - }, - { - "description", (o, n, _) => - { - o.Description(n.GetScalarValue()); - } - }, - { - "format", (o, n, _) => - { - o.Format(n.GetScalarValue()); - } - }, - { - "default", (o, n, _) => - { - o.Default(n.CreateAny().Node); - } - }, - { - "discriminator", (o, n, t) => - { - var discriminator = LoadDiscriminator(n, t); - o.Discriminator(discriminator); - } - }, - { - "readOnly", (o, n, _) => - { - o.ReadOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "writeOnly", (o, n, _) => - { - o.WriteOnly(bool.Parse(n.GetScalarValue())); - } - }, - { - "xml", (o, n, t) => - { - var xml = LoadXml(n); - o.Xml(xml.Namespace, xml.Name, xml.Prefix, xml.Attribute, xml.Wrapped, - (IReadOnlyDictionary)xml.Extensions); - } - }, - { - "externalDocs", (o, n, t) => - { - var externalDocs = LoadExternalDocs(n, t); - o.ExternalDocs(externalDocs.Url, externalDocs.Description, - (IReadOnlyDictionary)externalDocs.Extensions); - } - }, - { - "example", (o, n, _) => - { - o.Example(n.CreateAny().Node); - } - }, - { - "examples", (o, n, _) => - { - o.Examples(n.CreateSimpleList((s, p) =>(JsonNode) s.GetScalarValue())); - } - }, - { - "deprecated", (o, n, _) => - { - o.Deprecated(bool.Parse(n.GetScalarValue())); - } - }, - }; - - private static readonly PatternFieldMap _schemaPatternFields = new PatternFieldMap - { - {s => s.StartsWith("x-"), (o, p, n, _) => o.Extensions(LoadExtensions(p, LoadExtension(p, n)))} - }; - - public static JsonSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) - { - var mapNode = node.CheckMapNode(OpenApiConstants.Schema); - var builder = new JsonSchemaBuilder(); - - // check for a $ref and if present, add it to the builder as a Ref keyword - var pointer = mapNode.GetReferencePointer(); - if (pointer != null) - { - builder = builder.Ref(pointer); - - // Check for summary and description and append to builder - var summary = mapNode.GetSummaryValue(); - var description = mapNode.GetDescriptionValue(); - if (!string.IsNullOrEmpty(summary)) - { - builder.Summary(summary); - } - if (!string.IsNullOrEmpty(description)) - { - builder.Description(description); - } - - return builder.Build(); - } - - foreach (var propertyNode in mapNode) - { - propertyNode.ParseField(builder, _schemaFixedFields, _schemaPatternFields); - } - - var schema = builder.Build(); - return schema; - } - - private static Dictionary LoadExtensions(string value, IOpenApiExtension extension) - { - var extensions = new Dictionary - { - { value, extension } - }; - return extensions; - } - } - -} diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs index a9c543813..e70087d4b 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiComponentsDeserializer.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 116674238..9d27d811d 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Extensions; @@ -51,7 +51,7 @@ internal static partial class OpenApiV31Deserializer }, { "$defs", - (o, n, t) => o.Definitions = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Definitions = n.CreateMap(LoadSchema, t) }, { "multipleOf", @@ -128,31 +128,31 @@ internal static partial class OpenApiV31Deserializer }, { "allOf", - (o, n, t) => o.AllOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AllOf = n.CreateList(LoadSchema, t) }, { "oneOf", - (o, n, t) => o.OneOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.OneOf = n.CreateList(LoadSchema, t) }, { "anyOf", - (o, n, t) => o.AnyOf = n.CreateList(LoadOpenApiSchema, t) + (o, n, t) => o.AnyOf = n.CreateList(LoadSchema, t) }, { "not", - (o, n, _) => o.Not = LoadOpenApiSchema(n) + (o, n, _) => o.Not = LoadSchema(n) }, { "items", - (o, n, _) => o.Items = LoadOpenApiSchema(n) + (o, n, _) => o.Items = LoadSchema(n) }, { "properties", - (o, n, t) => o.Properties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.Properties = n.CreateMap(LoadSchema, t) }, { "patternProperties", - (o, n, t) => o.PatternProperties = n.CreateMap(LoadOpenApiSchema, t) + (o, n, t) => o.PatternProperties = n.CreateMap(LoadSchema, t) }, { "additionalProperties", (o, n, _) => @@ -163,7 +163,7 @@ internal static partial class OpenApiV31Deserializer } else { - o.AdditionalProperties = LoadOpenApiSchema(n); + o.AdditionalProperties = LoadSchema(n); } } }, @@ -222,7 +222,7 @@ internal static partial class OpenApiV31Deserializer {s => s.StartsWith("x-"), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))} }; - public static OpenApiSchema LoadOpenApiSchema(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocument = null) { var mapNode = node.CheckMapNode(OpenApiConstants.Schema); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs index 5e47f03b6..333ec53bb 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; @@ -56,8 +55,7 @@ public OpenApiV31VersionService(OpenApiDiagnostic diagnostic) [typeof(OpenApiRequestBody)] = OpenApiV31Deserializer.LoadRequestBody, [typeof(OpenApiResponse)] = OpenApiV31Deserializer.LoadResponse, [typeof(OpenApiResponses)] = OpenApiV31Deserializer.LoadResponses, - [typeof(JsonSchema)] = OpenApiV31Deserializer.LoadSchema, - [typeof(OpenApiSchema)] = OpenApiV31Deserializer.LoadOpenApiSchema, + [typeof(OpenApiSchema)] = OpenApiV31Deserializer.LoadSchema, [typeof(OpenApiSecurityRequirement)] = OpenApiV31Deserializer.LoadSecurityRequirement, [typeof(OpenApiSecurityScheme)] = OpenApiV31Deserializer.LoadSecurityScheme, [typeof(OpenApiServer)] = OpenApiV31Deserializer.LoadServer, diff --git a/src/Microsoft.OpenApi/Services/CopyReferences.cs b/src/Microsoft.OpenApi/Services/CopyReferences.cs index f6b53c3f1..757471466 100644 --- a/src/Microsoft.OpenApi/Services/CopyReferences.cs +++ b/src/Microsoft.OpenApi/Services/CopyReferences.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -26,12 +25,12 @@ public override void Visit(IOpenApiReferenceable referenceable) { switch (referenceable) { - case JsonSchema schema: + case OpenApiSchema schema: EnsureComponentsExists(); EnsureSchemasExists(); - if (!Components.Schemas.ContainsKey(schema.GetRef().OriginalString)) + if (!Components.Schemas.ContainsKey(schema.Reference.Id)) { - Components.Schemas.Add(schema.GetRef().OriginalString, schema); + Components.Schemas.Add(schema.Reference.Id, schema); } break; @@ -70,22 +69,22 @@ public override void Visit(IOpenApiReferenceable referenceable) } /// - /// Visits + /// Visits /// /// The OpenApiSchema to be visited. - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { // This is needed to handle schemas used in Responses in components - if (schema.GetRef() != null) + if (schema.Reference != null) { EnsureComponentsExists(); EnsureSchemasExists(); - if (!Components.Schemas.ContainsKey(schema.GetRef().OriginalString)) + if (!Components.Schemas.ContainsKey(schema.Reference.Id)) { - Components.Schemas.Add(schema.GetRef().OriginalString, schema); + Components.Schemas.Add(schema.Reference.Id, schema); } } - base.Visit(ref schema); + base.Visit(schema); } private void EnsureComponentsExists() @@ -100,7 +99,7 @@ private void EnsureSchemasExists() { if (_target.Components.Schemas == null) { - _target.Components.Schemas = new Dictionary(); + _target.Components.Schemas = new Dictionary(); } } diff --git a/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs b/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs deleted file mode 100644 index 87e493b3c..000000000 --- a/src/Microsoft.OpenApi/Services/JsonSchemaReferenceResolver.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System; -using System.Collections.Generic; -using Json.Schema; -using Microsoft.OpenApi.Exceptions; -using System.Linq; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; - -namespace Microsoft.OpenApi.Services -{ - /// - /// This class is used to walk an OpenApiDocument and resolves JsonSchema references. - /// - internal class JsonSchemaReferenceResolver : OpenApiVisitorBase - { - private readonly OpenApiDocument _currentDocument; - private readonly List _errors = new(); - - public JsonSchemaReferenceResolver(OpenApiDocument currentDocument) - { - _currentDocument = currentDocument; - } - - /// - /// List of errors related to the OpenApiDocument - /// - public IEnumerable Errors => _errors; - - /// - /// Resolves schemas in components - /// - /// - public override void Visit(OpenApiComponents components) - { - components.Schemas = ResolveJsonSchemas(components.Schemas); - } - - /// - /// Resolve all JsonSchema references used in mediaType object - /// - /// - public override void Visit(OpenApiMediaType mediaType) - { - ResolveJsonSchema(mediaType.Schema, r => mediaType.Schema = r ?? mediaType.Schema); - } - - /// - /// Resolve all JsonSchema references used in a parameter - /// - public override void Visit(OpenApiParameter parameter) - { - ResolveJsonSchema(parameter.Schema, r => parameter.Schema = r); - } - - /// - /// Resolve all references used in a JsonSchema - /// - /// - public override void Visit(ref JsonSchema schema) - { - var reference = schema.GetRef(); - var description = schema.GetDescription(); - var summary = schema.GetSummary(); - - if (schema.Keywords.Count.Equals(1) && reference != null) - { - schema = ResolveJsonSchemaReference(reference, description, summary); - } - - var builder = new JsonSchemaBuilder(); - if (schema?.Keywords is { } keywords) - { - foreach (var keyword in keywords) - { - builder.Add(keyword); - } - } - - ResolveJsonSchema(schema.GetItems(), r => builder.Items(r)); - ResolveJsonSchemaList((IList)schema.GetOneOf(), r => builder.OneOf(r)); - ResolveJsonSchemaList((IList)schema.GetAllOf(), r => builder.AllOf(r)); - ResolveJsonSchemaList((IList)schema.GetAnyOf(), r => builder.AnyOf(r)); - ResolveJsonSchemaMap((IDictionary)schema.GetProperties(), r => builder.Properties((IReadOnlyDictionary)r)); - ResolveJsonSchema(schema.GetAdditionalProperties(), r => builder.AdditionalProperties(r)); - - schema = builder.Build(); - } - - /// - /// Visits an IBaseDocument instance - /// - /// - public override void Visit(IBaseDocument document) { } - - private Dictionary ResolveJsonSchemas(IDictionary schemas) - { - var resolvedSchemas = new Dictionary(); - foreach (var schema in schemas) - { - var schemaValue = schema.Value; - Visit(ref schemaValue); - resolvedSchemas[schema.Key] = schemaValue; - } - - return resolvedSchemas; - } - - /// - /// Resolves the target to a JsonSchema reference by retrieval from Schema registry - /// - /// The JSON schema reference. - /// The schema's description. - /// The schema's summary. - /// - public JsonSchema ResolveJsonSchemaReference(Uri reference, string description = null, string summary = null) - { - var resolvedSchema = _currentDocument.ResolveJsonSchemaReference(reference); - - if (resolvedSchema != null) - { - var resolvedSchemaBuilder = new JsonSchemaBuilder(); - - foreach (var keyword in resolvedSchema.Keywords) - { - resolvedSchemaBuilder.Add(keyword); - - // Replace the resolved schema's description with that of the schema reference - if (!string.IsNullOrEmpty(description)) - { - resolvedSchemaBuilder.Description(description); - } - - // Replace the resolved schema's summary with that of the schema reference - if (!string.IsNullOrEmpty(summary)) - { - resolvedSchemaBuilder.Summary(summary); - } - } - - return resolvedSchemaBuilder.Build(); - } - else - { - var referenceId = reference.OriginalString.Split('/').LastOrDefault(); - throw new OpenApiException(string.Format(Properties.SRResource.InvalidReferenceId, referenceId)); - } - } - - private void ResolveJsonSchema(JsonSchema schema, Action assign) - { - if (schema == null) return; - var reference = schema.GetRef(); - var description = schema.GetDescription(); - var summary = schema.GetSummary(); - - if (reference != null) - { - assign(ResolveJsonSchemaReference(reference, description, summary)); - } - } - - private void ResolveJsonSchemaList(IList list, Action> assign) - { - if (list == null) return; - - for (int i = 0; i < list.Count; i++) - { - var entity = list[i]; - var reference = entity?.GetRef(); - if (reference != null) - { - list[i] = ResolveJsonSchemaReference(reference); - } - } - - assign(list.ToList()); - } - - private void ResolveJsonSchemaMap(IDictionary map, Action> assign) - { - if (map == null) return; - - foreach (var key in map.Keys.ToList()) - { - var entity = map[key]; - var reference = entity.GetRef(); - if (reference != null) - { - map[key] = ResolveJsonSchemaReference(reference); - } - } - - assign(map.ToDictionary(e => e.Key, e => e.Value)); - } - } -} diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 2a38c360d..8be8318e3 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -19,9 +18,9 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo // Register Schema foreach (var item in document.Components.Schemas) { - if (item.Value.GetId() != null) + if (item.Value.Id != null) { - location = document.BaseUri + item.Value.GetId().ToString(); + location = document.BaseUri + item.Value.Id; } else { diff --git a/src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs similarity index 55% rename from src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs rename to src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index 0443b9fb8..5f75be881 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/JsonSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -2,58 +2,40 @@ // Licensed under the MIT license. using System.Collections.Generic; -using System.Linq; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; namespace Microsoft.OpenApi.Validations.Rules { /// - /// The validation rules for . + /// The validation rules for . /// [OpenApiRule] - public static class JsonSchemaRules + public static class OpenApiSchemaRules { /// /// Validate the data matches with the given data type. /// - public static ValidationRule SchemaMismatchedDataType => - new ValidationRule(nameof(SchemaMismatchedDataType), - (context, jsonSchema) => + public static ValidationRule SchemaMismatchedDataType => + new(nameof(SchemaMismatchedDataType), + (context, schema) => { // default context.Enter("default"); - if (jsonSchema.GetDefault() != null) + if (schema.Default != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetDefault(), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Default.Node, schema); } context.Exit(); - // examples - context.Enter("examples"); - - if (jsonSchema.GetExamples() is { } examples) - { - for (int i = 0; i < examples.Count; i++) - { - context.Enter(i.ToString()); - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), examples.ElementAt(i), jsonSchema); - context.Exit(); - } - } - - context.Exit(); - // example context.Enter("example"); - if (jsonSchema.GetExample() != null) + if (schema.Example != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetExample(), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Example.Node, schema); } context.Exit(); @@ -61,12 +43,12 @@ public static class JsonSchemaRules // enum context.Enter("enum"); - if (jsonSchema.GetEnum() != null) + if (schema.Enum != null) { - for (int i = 0; i < jsonSchema.GetEnum().Count; i++) + for (var i = 0; i < schema.Enum.Count; i++) { context.Enter(i.ToString()); - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), jsonSchema.GetEnum().ElementAt(i), jsonSchema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Enum[i], schema); context.Exit(); } } @@ -77,22 +59,22 @@ public static class JsonSchemaRules /// /// Validates Schema Discriminator /// - public static ValidationRule ValidateSchemaDiscriminator => - new ValidationRule(nameof(ValidateSchemaDiscriminator), - (context, jsonSchema) => + public static ValidationRule ValidateSchemaDiscriminator => + new(nameof(ValidateSchemaDiscriminator), + (context, schema) => { // discriminator context.Enter("discriminator"); - if (jsonSchema.GetRef() != null && jsonSchema.GetOpenApiDiscriminator() != null) + if (schema.Reference != null && schema.Discriminator != null) { - var discriminatorName = jsonSchema.GetOpenApiDiscriminator()?.PropertyName; + var discriminatorName = schema.Discriminator?.PropertyName; - if (!ValidateChildSchemaAgainstDiscriminator(jsonSchema, discriminatorName)) + if (!ValidateChildSchemaAgainstDiscriminator(schema, discriminatorName)) { context.CreateError(nameof(ValidateSchemaDiscriminator), string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, - jsonSchema.GetRef(), discriminatorName)); + schema.Reference.Id, discriminatorName)); } } @@ -105,22 +87,22 @@ public static class JsonSchemaRules /// The parent schema. /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate /// between other schemas which may satisfy the payload description. - public static bool ValidateChildSchemaAgainstDiscriminator(JsonSchema schema, string discriminatorName) + public static bool ValidateChildSchemaAgainstDiscriminator(OpenApiSchema schema, string discriminatorName) { - if (!schema.GetRequired()?.Contains(discriminatorName) ?? true) + if (!schema.Required?.Contains(discriminatorName) ?? false) { // recursively check nested schema.OneOf, schema.AnyOf or schema.AllOf and their required fields for the discriminator - if (schema.GetOneOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetOneOf())) + if (schema.OneOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.OneOf); } - if (schema.GetAnyOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetAnyOf())) + if (schema.AnyOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.AnyOf); } - if (schema.GetAllOf()?.Count != 0 && TraverseSchemaElements(discriminatorName, schema.GetAllOf())) + if (schema.AllOf.Count != 0) { - return true; + return TraverseSchemaElements(discriminatorName, schema.AllOf); } } else @@ -138,15 +120,12 @@ public static bool ValidateChildSchemaAgainstDiscriminator(JsonSchema schema, st /// between other schemas which may satisfy the payload description. /// The child schema. /// - public static bool TraverseSchemaElements(string discriminatorName, IReadOnlyCollection childSchema) + public static bool TraverseSchemaElements(string discriminatorName, IList childSchema) { - if (!childSchema?.Any() ?? true) - return false; - foreach (var childItem in childSchema) { - if ((!childItem.GetProperties()?.ContainsKey(discriminatorName) ?? true) && - (!childItem.GetRequired()?.Contains(discriminatorName) ?? true)) + if ((!childItem.Properties?.ContainsKey(discriminatorName) ?? false) && + (!childItem.Required?.Contains(discriminatorName) ?? false)) { return ValidateChildSchemaAgainstDiscriminator(childItem, discriminatorName); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index e57d67a89..a2ac63a6e 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -2,10 +2,9 @@ // Licensed under the MIT license. using System; -using System.Linq; +using System.Text.Json; using System.Text.Json.Nodes; -using Json.Schema; -using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Validations.Rules { @@ -20,7 +19,7 @@ internal static class RuleHelpers /// True if it's an email address. Otherwise False. public static bool IsEmailAddress(this string input) { - if (String.IsNullOrEmpty(input)) + if (string.IsNullOrEmpty(input)) { return false; } @@ -31,7 +30,7 @@ public static bool IsEmailAddress(this string input) return false; } - if (String.IsNullOrEmpty(splits[0]) || String.IsNullOrEmpty(splits[1])) + if (string.IsNullOrEmpty(splits[0]) || string.IsNullOrEmpty(splits[1])) { return false; } @@ -42,40 +41,248 @@ public static bool IsEmailAddress(this string input) } public static void ValidateDataTypeMismatch( - IValidationContext context, - string ruleName, - JsonNode value, - JsonSchema schema) - { - if (schema is not null) + IValidationContext context, + string ruleName, + JsonNode value, + OpenApiSchema schema) + { + if (schema == null) { - var options = new EvaluationOptions(); - options.OutputFormat = OutputFormat.List; + return; + } + + var type = schema.Type.ToString(); + var format = schema.Format; + var nullable = schema.Nullable; + + // convert JsonNode to JsonElement + JsonElement element = value.GetValue(); + + // Before checking the type, check first if the schema allows null. + // If so and the data given is also null, this is allowed for any type. + if (nullable) + { + if (element.ValueKind is JsonValueKind.Null) + { + return; + } + } + + if (type == "object") + { + // It is not against the spec to have a string representing an object value. + // To represent examples of media types that cannot naturally be represented in JSON or YAML, + // a string value can contain the example with escaping where necessary + if (element.ValueKind is JsonValueKind.String) + { + return; + } - if (context.HostDocument != null) + // If value is not a string and also not an object, there is a data mismatch. + if (element.ValueKind is not JsonValueKind.Object) { - options.SchemaRegistry.Register(context.HostDocument.BaseUri, context.HostDocument); + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + return; } - var results = schema.Evaluate(value, options); + // Else, cast element to object + var anyObject = value.AsObject(); - if (!results.IsValid) + foreach (var kvp in anyObject) { - foreach (var detail in results.Details) + string key = kvp.Key; + context.Enter(key); + + if (schema.Properties != null && + schema.Properties.TryGetValue(key, out var property)) + { + ValidateDataTypeMismatch(context, ruleName, anyObject[key], property); + } + else { - if (detail.Errors != null && detail.Errors.Any()) - { - foreach (var error in detail.Errors) - { - if (!string.IsNullOrEmpty(error.Key) || !string.IsNullOrEmpty(error.Value.Trim())) - { - context.CreateWarning(ruleName, string.Format("{0} : {1} at {2}", error.Key, error.Value.Trim(), detail.InstanceLocation)); - } - } - } + ValidateDataTypeMismatch(context, ruleName, anyObject[key], schema.AdditionalProperties); } + + context.Exit(); + } + + return; + } + + if (type == "array") + { + // It is not against the spec to have a string representing an array value. + // To represent examples of media types that cannot naturally be represented in JSON or YAML, + // a string value can contain the example with escaping where necessary + if (element.ValueKind is JsonValueKind.String) + { + return; + } + + // If value is not a string and also not an array, there is a data mismatch. + if (element.ValueKind is not JsonValueKind.Array) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + return; } - } + + // Else, cast element to array + var anyArray = value.AsArray(); + + for (var i = 0; i < anyArray.Count; i++) + { + context.Enter(i.ToString()); + + ValidateDataTypeMismatch(context, ruleName, anyArray[i], schema.Items); + + context.Exit(); + } + + return; + } + + if (type == "integer" && format == "int32") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "integer" && format == "int64") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "integer" && element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + if (type == "number" && format == "float") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "number" && format == "double") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "number") + { + if (element.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "byte") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "date") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "date-time") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string" && format == "password") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "string") + { + if (element.ValueKind is not JsonValueKind.String) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } + + if (type == "boolean") + { + if (element.ValueKind is not JsonValueKind.True || element.ValueKind is not JsonValueKind.True) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; + } } } } From 4b8c697ac37eb7cc34ed4048c2e4ca80525f53d6 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 18:39:32 +0300 Subject: [PATCH 22/44] Clean up tests --- .../Formatters/PowerShellFormatterTests.cs | 84 +-- .../UtilityFiles/OpenApiDocumentMock.cs | 208 +++++-- .../OpenApiWorkspaceStreamTests.cs | 2 - .../TryLoadReferenceV2Tests.cs | 41 +- .../V2Tests/OpenApiDocumentTests.cs | 400 ++++++++++---- .../V2Tests/OpenApiHeaderTests.cs | 30 +- .../V2Tests/OpenApiOperationTests.cs | 98 +++- .../V2Tests/OpenApiParameterTests.cs | 53 +- .../V2Tests/OpenApiPathItemTests.cs | 141 ++++- ...onSchemaTests.cs => OpenApiSchemaTests.cs} | 45 +- .../V31Tests/JsonSchemaTests.cs | 178 ------ .../V31Tests/OpenApiDocumentTests.cs | 296 +++++++--- .../V31Tests/OpenApiSchemaTests.cs | 131 +++++ .../V3Tests/JsonSchemaTests.cs | 340 ------------ .../V3Tests/OpenApiCallbackTests.cs | 23 +- .../V3Tests/OpenApiDocumentTests.cs | 419 ++++++++++---- .../V3Tests/OpenApiEncodingTests.cs | 6 +- .../V3Tests/OpenApiMediaTypeTests.cs | 13 +- .../V3Tests/OpenApiOperationTests.cs | 13 +- .../V3Tests/OpenApiParameterTests.cs | 116 ++-- .../V3Tests/OpenApiSchemaTests.cs | 515 ++++++++++++++++++ .../Extensions/OpenApiTypeMapperTests.cs | 39 +- .../Models/OpenApiCallbackTests.cs | 11 +- .../Models/OpenApiComponentsTests.cs | 220 ++++++-- .../Models/OpenApiDocumentTests.cs | 503 ++++++++++++----- .../Models/OpenApiHeaderTests.cs | 13 +- .../Models/OpenApiOperationTests.cs | 86 ++- .../Models/OpenApiParameterTests.cs | 86 +-- .../Models/OpenApiRequestBodyTests.cs | 11 +- .../Models/OpenApiResponseTests.cs | 85 ++- .../References/OpenApiHeaderReferenceTests.cs | 3 +- .../OpenApiRequestBodyReferenceTests.cs | 8 +- .../OpenApiResponseReferenceTest.cs | 5 +- .../OpenApiHeaderValidationTests.cs | 74 +-- .../OpenApiMediaTypeValidationTests.cs | 21 +- .../OpenApiParameterValidationTests.cs | 36 +- .../OpenApiReferenceValidationTests.cs | 31 +- .../OpenApiSchemaValidationTests.cs | 161 ++++-- .../Visitors/InheritanceTests.cs | 7 +- .../Walkers/WalkerLocationTests.cs | 67 +-- .../Workspaces/OpenApiReferencableTests.cs | 9 +- .../Workspaces/OpenApiWorkspaceTests.cs | 44 +- .../Writers/OpenApiJsonWriterTests.cs | 21 +- .../Writers/OpenApiYamlWriterTests.cs | 13 +- 44 files changed, 3183 insertions(+), 1523 deletions(-) rename test/Microsoft.OpenApi.Readers.Tests/V2Tests/{JsonSchemaTests.cs => OpenApiSchemaTests.cs} (68%) delete mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs delete mode 100644 test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index 6bd55a4aa..94f99a1d2 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -1,11 +1,9 @@ -using Json.Schema; -using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Hidi.Formatters; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; -using Microsoft.OpenApi.Extensions; namespace Microsoft.OpenApi.Hidi.Tests.Formatters { @@ -60,18 +58,18 @@ public void RemoveAnyOfAndOneOfFromSchema() walker.Walk(openApiDocument); var testSchema = openApiDocument.Components.Schemas["TestSchema"]; - var averageAudioDegradationProperty = testSchema.GetProperties()?.GetValueOrDefault("averageAudioDegradation"); - var defaultPriceProperty = testSchema.GetProperties()?.GetValueOrDefault("defaultPrice"); + var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema.Properties["defaultPrice"]; // Assert - Assert.Null(averageAudioDegradationProperty?.GetAnyOf()); - Assert.Equal(SchemaValueType.Number, averageAudioDegradationProperty?.GetJsonType()); - Assert.Equal("float", averageAudioDegradationProperty?.GetFormat()?.Key); - Assert.True(averageAudioDegradationProperty?.GetNullable()); - Assert.Null(defaultPriceProperty?.GetOneOf()); - Assert.Equal(SchemaValueType.Number, defaultPriceProperty?.GetJsonType()); - Assert.Equal("double", defaultPriceProperty?.GetFormat()?.Key); - Assert.NotNull(testSchema.GetAdditionalProperties()); + Assert.Null(averageAudioDegradationProperty.AnyOf); + Assert.Equal("number", averageAudioDegradationProperty.Type); + Assert.Equal("float", averageAudioDegradationProperty.Format); + Assert.True(averageAudioDegradationProperty.Nullable); + Assert.Null(defaultPriceProperty.OneOf); + Assert.Equal("number", defaultPriceProperty.Type); + Assert.Equal("double", defaultPriceProperty.Format); + Assert.NotNull(testSchema.AdditionalProperties); } [Fact] @@ -90,7 +88,7 @@ public void ResolveFunctionParameters() // Assert Assert.Null(idsParameter?.Content); Assert.NotNull(idsParameter?.Schema); - Assert.Equal(SchemaValueType.Array, idsParameter?.Schema.GetJsonType()); + Assert.Equal("array", idsParameter?.Schema.Type); } private static OpenApiDocument GetSampleOpenApiDocument() @@ -120,10 +118,14 @@ private static OpenApiDocument GetSampleOpenApiDocument() "application/json", new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } } } } @@ -143,22 +145,38 @@ private static OpenApiDocument GetSampleOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - { "TestSchema", new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("averageAudioDegradation", new JsonSchemaBuilder() - .AnyOf( - new JsonSchemaBuilder().Type(SchemaValueType.Number), - new JsonSchemaBuilder().Type(SchemaValueType.String)) - .Format("float") - .Nullable(true)), - - ("defaultPrice", new JsonSchemaBuilder() - .OneOf( - new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double"), - new JsonSchemaBuilder().Type(SchemaValueType.String)))) - } + { "TestSchema", new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + { + "averageAudioDegradation", new OpenApiSchema + { + AnyOf = new List + { + new() { Type = "number" }, + new() { Type = "string" } + }, + Format = "float", + Nullable = true + } + }, + { + "defaultPrice", new OpenApiSchema + { + OneOf = new List + { + new() { Type = "number", Format = "double" }, + new() { Type = "string" } + } + } + } + } + } + } } } }; diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index 65ef08628..98ed181f4 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -1,7 +1,6 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -84,7 +83,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -100,7 +102,10 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array) + Schema = new() + { + Type = "array" + } } } } @@ -118,7 +123,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } } @@ -149,7 +157,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -165,7 +176,10 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array) + Schema = new() + { + Type = "array" + } } } } @@ -182,7 +196,10 @@ public static OpenApiDocument CreateOpenApiDocument() Name = "period", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -216,17 +233,29 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Title("Collection of user") - .Type(SchemaValueType.Object) - .Properties(("value", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Ref("microsoft.graph.user") - .Build()) - .Build())) - .Build() + Schema = new() + { + Title = "Collection of user", + Type = "object", + Properties = new Dictionary + { + { + "value", + new OpenApiSchema + { + Type = "array", + Items = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.user" + } + } + } + } + } + } } } } @@ -267,7 +296,14 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("microsoft.graph.user").Build() + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.user" + } + } } } } @@ -330,7 +366,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Query, Required = true, Description = "Select properties to be returned", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Build() + Schema = new() + { + Type = "array" + } // missing explode parameter } }, @@ -346,7 +385,14 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("microsoft.graph.message").Build() + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.message" + } + } } } } @@ -384,7 +430,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Required = true, Description = "key: id of administrativeUnit", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }, @@ -400,12 +449,17 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .AnyOf( - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build()) - .Build() + Schema = new() + { + AnyOf = new List + { + new() + { + Type = "string" + } + }, + Nullable = true + } } } } @@ -477,14 +531,29 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Title("Collection of hostSecurityProfile") - .Type(SchemaValueType.Object) - .Properties(("value1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("microsoft.graph.networkInterface")))) - .Build() + Schema = new() + { + Title = "Collection of hostSecurityProfile", + Type = "object", + Properties = new Dictionary + { + { + "value", + new OpenApiSchema + { + Type = "array", + Items = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.networkInterface" + } + } + } + } + } + } } } } @@ -521,7 +590,10 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of call", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), + Schema = new() + { + Type = "string" + }, Extensions = new Dictionary { { @@ -573,8 +645,16 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of group", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), - Extensions = new Dictionary { { "x-ms-docs-key-type", new OpenApiAny("group") } } + Schema = new() + { + Type = "string" + }, + Extensions = new Dictionary + { + { + "x-ms-docs-key-type", new OpenApiAny("group") + } + } }, new() { @@ -582,8 +662,16 @@ public static OpenApiDocument CreateOpenApiDocument() In = ParameterLocation.Path, Description = "key: id of event", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), - Extensions = new Dictionary { { "x-ms-docs-key-type", new OpenApiAny("event") } } + Schema = new() + { + Type = "string" + }, + Extensions = new Dictionary + { + { + "x-ms-docs-key-type", new OpenApiAny("event") + } + } } }, Responses = new() @@ -598,7 +686,15 @@ public static OpenApiDocument CreateOpenApiDocument() applicationJsonMediaType, new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Ref("microsoft.graph.event").Build() + Schema = new() + { + Type = "array", + Reference = new() + { + Type = ReferenceType.Schema, + Id = "microsoft.graph.event" + } + } } } } @@ -638,17 +734,25 @@ public static OpenApiDocument CreateOpenApiDocument() }, Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { { - "microsoft.graph.networkInterface", new JsonSchemaBuilder() - .Title("networkInterface") - .Type(SchemaValueType.Object) - .Properties( - ("description", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.)."))) - .Build() + "microsoft.graph.networkInterface", new OpenApiSchema + { + Title = "networkInterface", + Type = "object", + Properties = new Dictionary + { + { + "description", new OpenApiSchema + { + Type = "string", + Description = "Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.).", + Nullable = true + } + } + } + } } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs index 128430218..2ee51bc06 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiWorkspaceTests/OpenApiWorkspaceStreamTests.cs @@ -1,8 +1,6 @@ using System; using System.IO; -using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; diff --git a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs index 26afc9720..010604750 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ReferenceService/TryLoadReferenceV2Tests.cs @@ -3,9 +3,7 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -38,9 +36,12 @@ public void LoadParameterReference() In = ParameterLocation.Query, Description = "number of items to skip", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } + }, options => options.Excluding(x => x.Reference) ); } @@ -98,10 +99,34 @@ public void LoadResponseAndSchemaReference() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder() - .Ref("#/definitions/SampleObject2") - .Build() + Schema = new() + { + Description = "Sample description", + Required = new HashSet {"name" }, + Properties = { + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + } + }, + + Reference = new() + { + Type = ReferenceType.Schema, + Id = "SampleObject2", + HostDocument = result.OpenApiDocument + } + } } + }, + Reference = new() + { + Type = ReferenceType.Response, + Id = "GeneralError" } }, options => options.Excluding(x => x.Reference) ); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index df26255db..f369e5028 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -2,10 +2,13 @@ // Licensed under the MIT license. using System; +using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; using Xunit; @@ -19,22 +22,198 @@ public class OpenApiDocumentTests public OpenApiDocumentTests() { OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); - } + } + + [Fact] + public void ShouldThrowWhenReferenceTypeIsInvalid() + { + var input = + """ + swagger: 2.0 + info: + title: test + version: 1.0.0 + paths: + '/': + get: + responses: + '200': + description: ok + schema: + $ref: '#/defi888nition/does/notexist' + """; + + var result = OpenApiDocument.Parse(input, "yaml"); + + result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { + new( new OpenApiException("Unknown reference type 'defi888nition'")) }); + result.OpenApiDocument.Should().NotBeNull(); + } + + [Fact] + public void ShouldThrowWhenReferenceDoesNotExist() + { + var input = + """ + swagger: 2.0 + info: + title: test + version: 1.0.0 + paths: + '/': + get: + produces: ['application/json'] + responses: + '200': + description: ok + schema: + $ref: '#/definitions/doesnotexist' + """; + + var result = OpenApiDocument.Parse(input, "yaml"); + + result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { + new( new OpenApiException("Invalid Reference identifier 'doesnotexist'.")) }); + result.OpenApiDocument.Should().NotBeNull(); + } + + [Theory] + [InlineData("en-US")] + [InlineData("hi-IN")] + // The equivalent of English 1,000.36 in French and Danish is 1.000,36 + [InlineData("fr-FR")] + [InlineData("da-DK")] + public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) + { + Thread.CurrentThread.CurrentCulture = new(culture); + Thread.CurrentThread.CurrentUICulture = new(culture); + + var result = OpenApiDocument.Parse( + """ + swagger: 2.0 + info: + title: Simple Document + version: 0.9.1 + x-extension: 2.335 + definitions: + sampleSchema: + type: object + properties: + sampleProperty: + type: double + minimum: 100.54 + maximum: 60000000.35 + exclusiveMaximum: true + exclusiveMinimum: false + paths: {} + """, + "yaml"); + + result.OpenApiDocument.Should().BeEquivalentTo( + new OpenApiDocument + { + Info = new() + { + Title = "Simple Document", + Version = "0.9.1", + Extensions = + { + ["x-extension"] = new OpenApiAny(2.335) + } + }, + Components = new() + { + Schemas = + { + ["sampleSchema"] = new() + { + Type = "object", + Properties = + { + ["sampleProperty"] = new() + { + Type = "double", + Minimum = (decimal)100.54, + Maximum = (decimal)60000000.35, + ExclusiveMaximum = true, + ExclusiveMinimum = false + } + }, + Reference = new() + { + Id = "sampleSchema", + Type = ReferenceType.Schema + } + } + } + }, + Paths = new() + }); + + result.OpenApiDiagnostic.Should().BeEquivalentTo( + new OpenApiDiagnostic { SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 }); + } [Fact] public void ShouldParseProducesInAnyOrder() { var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "twoResponses.json")); - var okSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Item"); + var okSchema = new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Item", + HostDocument = result.OpenApiDocument + }, + Properties = new Dictionary + { + { "id", new OpenApiSchema + { + Type = "string", + Description = "Item identifier." + } + } + } + }; - var errorSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Error"); + var errorSchema = new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Error", + HostDocument = result.OpenApiDocument + }, + Properties = new Dictionary + { + { "code", new OpenApiSchema + { + Type = "integer", + Format = "int32" + } + }, + { "message", new OpenApiSchema + { + Type = "string" + } + }, + { "fields", new OpenApiSchema + { + Type = "string" + } + } + } + }; var okMediaType = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(okSchema) + Schema = new() + { + Type = "array", + Items = okSchema + } }; var errorMediaType = new OpenApiMediaType @@ -44,111 +223,106 @@ public void ShouldParseProducesInAnyOrder() result.OpenApiDocument.Should().BeEquivalentTo(new OpenApiDocument { - Info = new OpenApiInfo + Info = new() { Title = "Two responses", Version = "1.0.0" }, Servers = + { + new OpenApiServer { - new OpenApiServer - { - Url = "https://" - } - }, - Paths = new OpenApiPaths + Url = "https://" + } + }, + Paths = new() { - ["/items"] = new OpenApiPathItem + ["/items"] = new() { Operations = + { + [OperationType.Get] = new() { - [OperationType.Get] = new OpenApiOperation + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["application/json"] = okMediaType, - ["application/xml"] = okMediaType, - } - }, - ["default"] = new OpenApiResponse + ["application/json"] = okMediaType, + ["application/xml"] = okMediaType, + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["application/json"] = errorMediaType, - ["application/xml"] = errorMediaType - } + ["application/json"] = errorMediaType, + ["application/xml"] = errorMediaType } } - }, - [OperationType.Post] = new OpenApiOperation + } + }, + [OperationType.Post] = new() + { + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["html/text"] = okMediaType - } - }, - ["default"] = new OpenApiResponse + ["html/text"] = okMediaType + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["html/text"] = errorMediaType - } + ["html/text"] = errorMediaType } } - }, - [OperationType.Patch] = new OpenApiOperation + } + }, + [OperationType.Patch] = new() + { + Responses = { - Responses = + ["200"] = new() { - ["200"] = new OpenApiResponse + Description = "An OK response", + Content = { - Description = "An OK response", - Content = - { - ["application/json"] = okMediaType, - ["application/xml"] = okMediaType, - } - }, - ["default"] = new OpenApiResponse + ["application/json"] = okMediaType, + ["application/xml"] = okMediaType, + } + }, + ["default"] = new() + { + Description = "An error response", + Content = { - Description = "An error response", - Content = - { - ["application/json"] = errorMediaType, - ["application/xml"] = errorMediaType - } + ["application/json"] = errorMediaType, + ["application/xml"] = errorMediaType } } } } + } } }, - Components = new OpenApiComponents + Components = new() { Schemas = - { - ["Item"] = new JsonSchemaBuilder() - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Item identifier."))), - ["Error"] = new JsonSchemaBuilder() - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("fields", new JsonSchemaBuilder().Type(SchemaValueType.String))) - } + { + ["Item"] = okSchema, + ["Error"] = errorSchema + } } - }, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); + }); } [Fact] @@ -159,26 +333,66 @@ public void ShouldAssignSchemaToAllResponses() Assert.Equal(OpenApiSpecVersion.OpenApi2_0, result.OpenApiDiagnostic.SpecificationVersion); - var successSchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Item identifier.")))); - - var errorSchema = new JsonSchemaBuilder() - .Ref("#/definitions/Error"); - + var successSchema = new OpenApiSchema + { + Type = "array", + Items = new() + { + Properties = { + { "id", new OpenApiSchema + { + Type = "string", + Description = "Item identifier." + } + } + }, + Reference = new() + { + Id = "Item", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + } + }; + var errorSchema = new OpenApiSchema + { + Properties = { + { "code", new OpenApiSchema + { + Type = "integer", + Format = "int32" + } + }, + { "message", new OpenApiSchema + { + Type = "string" + } + }, + { "fields", new OpenApiSchema + { + Type = "string" + } + } + }, + Reference = new() + { + Id = "Error", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }; var responses = result.OpenApiDocument.Paths["/items"].Operations[OperationType.Get].Responses; foreach (var response in responses) { - var targetSchema = response.Key == "200" ? successSchema.Build() : errorSchema.Build(); + var targetSchema = response.Key == "200" ? successSchema : errorSchema; var json = response.Value.Content["application/json"]; Assert.NotNull(json); - Assert.Equal(json.Schema.Keywords.Count, targetSchema.Keywords.Count); + json.Schema.Should().BeEquivalentTo(targetSchema); var xml = response.Value.Content["application/xml"]; Assert.NotNull(xml); - Assert.Equal(xml.Schema.Keywords.Count, targetSchema.Keywords.Count); + xml.Schema.Should().BeEquivalentTo(targetSchema); } } @@ -187,12 +401,10 @@ public void ShouldAllowComponentsThatJustContainAReference() { // Act var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "ComponentRootReference.json")).OpenApiDocument; - JsonSchema schema = actual.Components.Schemas["AllPets"]; - - schema = actual.ResolveJsonSchemaReference(schema.GetRef()) ?? schema; - - // Assert - if (schema.Keywords.Count.Equals(1) && schema.GetRef() != null) + var schema1 = actual.Components.Schemas["AllPets"]; + Assert.False(schema1.UnresolvedReference); + var schema2 = actual.ResolveReferenceTo(schema1.Reference); + if (schema2.UnresolvedReference && schema1.Reference.Id == schema2.Reference.Id) { // detected a cycle - this code gets triggered Assert.Fail("A cycle should not be detected"); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index 220087401..14bbdfc32 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -3,7 +3,7 @@ using System.IO; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -33,10 +33,12 @@ public void ParseHeaderWithDefaultShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Default(5) + Schema = new() + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + } }, options => options .IgnoringCyclicReferences()); @@ -59,11 +61,19 @@ public void ParseHeaderWithEnumShouldSucceed() header.Should().BeEquivalentTo( new OpenApiHeader { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Enum(7, 8, 9) - }, options => options.IgnoringCyclicReferences()); + Schema = new() + { + Type = "number", + Format = "float", + Enum = + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + } + }, options => options.IgnoringCyclicReferences() + ); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index f264c23f6..ad1ca897f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -6,7 +6,6 @@ using System.Text; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -38,7 +37,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, Responses = new OpenApiResponses @@ -69,8 +71,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new OpenApiRequestBody @@ -79,19 +83,51 @@ public class OpenApiOperationTests { ["application/x-www-form-urlencoded"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, @@ -132,7 +168,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, }, RequestBody = new OpenApiRequestBody @@ -143,7 +182,10 @@ public class OpenApiOperationTests { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } }, Extensions = { @@ -270,9 +312,15 @@ public void ParseOperationWithResponseExamplesShouldSucceed() { ["application/json"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float")), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "number", + Format = "float" + } + }, Example = new OpenApiAny(new JsonArray() { 5.0, @@ -282,9 +330,15 @@ public void ParseOperationWithResponseExamplesShouldSucceed() }, ["application/xml"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float")) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "number", + Format = "float" + } + } } } }} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 1d9b1e22a..7ccbc1c8b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -3,7 +3,7 @@ using System.IO; using FluentAssertions; -using Json.Schema; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -56,8 +56,10 @@ public void ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -82,9 +84,14 @@ public void ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Form, Explode = true }); @@ -111,7 +118,10 @@ public void ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -136,7 +146,10 @@ public void ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -185,7 +198,10 @@ public void ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -210,7 +226,12 @@ public void ParseParameterWithDefaultShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float").Default(5) + Schema = new() + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + } }, options => options.IgnoringCyclicReferences()); } @@ -235,7 +256,17 @@ public void ParseParameterWithEnumShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float").Enum(7, 8, 9) + Schema = new() + { + Type = "number", + Format = "float", + Enum = + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + } }, options => options.IgnoringCyclicReferences()); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs index 08a82885e..ef85cd712 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiPathItemTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V2; @@ -29,7 +28,14 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet to use", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Simple } }, @@ -48,7 +54,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -57,19 +66,51 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, @@ -108,7 +149,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, new() { @@ -116,7 +160,10 @@ public class OpenApiPathItemTests In = ParameterLocation.Path, Description = "Name of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -125,21 +172,61 @@ public class OpenApiPathItemTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String)), - ("skill", new JsonSchemaBuilder().Description("Updated skill of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + }, + ["skill"] = new() + { + Description = "Updated skill of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Description("Updated name of the pet").Type(SchemaValueType.String)), - ("status", new JsonSchemaBuilder().Description("Updated status of the pet").Type(SchemaValueType.String)), - ("skill", new JsonSchemaBuilder().Description("Updated skill of the pet").Type(SchemaValueType.String))) - .Required("name") + Schema = new() + { + Type = "object", + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + }, + ["skill"] = new() + { + Description = "Updated skill of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs similarity index 68% rename from test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs rename to test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index 050e9ed65..d827f62ee 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/JsonSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -3,16 +3,18 @@ using System.IO; using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Reader.V2; using Xunit; using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Any; +using System.Text.Json.Nodes; +using System.Collections.Generic; namespace Microsoft.OpenApi.Readers.Tests.V2Tests { [Collection("DefaultSettings")] - public class JsonSchemaTests + public class OpenApiSchemaTests { private const string SampleFolderPath = "V2Tests/Samples/OpenApiSchema/"; @@ -30,9 +32,12 @@ public void ParseSchemaWithDefaultShouldSucceed() var schema = OpenApiV2Deserializer.LoadSchema(node); // Assert - schema.Should().BeEquivalentTo(new JsonSchemaBuilder() - .Type(SchemaValueType.Number).Format("float").Default(5).Build(), - options => options.IgnoringCyclicReferences()); + schema.Should().BeEquivalentTo(new OpenApiSchema + { + Type = "number", + Format = "float", + Default = new OpenApiAny(5) + }); } [Fact] @@ -50,12 +55,12 @@ public void ParseSchemaWithExampleShouldSucceed() // Assert schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Example(5) - .Build(), - options => options.IgnoringCyclicReferences()); + new OpenApiSchema + { + Type = "number", + Format = "float", + Example = new OpenApiAny(5) + }); } [Fact] @@ -72,11 +77,17 @@ public void ParseSchemaWithEnumShouldSucceed() var schema = OpenApiV2Deserializer.LoadSchema(node); // Assert - var expected = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") - .Enum(7, 8, 9) - .Build(); + var expected = new OpenApiSchema + { + Type = "number", + Format = "float", + Enum = new List + { + new OpenApiAny(7).Node, + new OpenApiAny(8).Node, + new OpenApiAny(9).Node + } + }; schema.Should().BeEquivalentTo(expected, options => options.IgnoringCyclicReferences()); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs deleted file mode 100644 index 48b5282d4..000000000 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/JsonSchemaTests.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System.IO; -using System.Linq; -using System.Text.Json; -using FluentAssertions; -using Json.Schema; -using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Reader.ParseNodes; -using Microsoft.OpenApi.Reader.V31; -using SharpYaml.Serialization; -using Xunit; - -namespace Microsoft.OpenApi.Readers.Tests.V31Tests -{ - public class JsonSchemaTests - { - private const string SampleFolderPath = "V31Tests/Samples/OpenApiSchema/"; - - [Fact] - public void ParseV31SchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "schema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); - var jsonString = @"{ - ""type"": ""object"", - ""properties"": { - ""one"": { - ""description"": ""type array"", - ""type"": [ - ""integer"", - ""string"" - ] - } - } -}"; - var expectedSchema = JsonSerializer.Deserialize(jsonString); - - // Assert - Assert.Equal(schema, expectedSchema); - } - - [Fact] - public void ParseAdvancedV31SchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedSchema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); - var jsonString = @"{ - ""type"": ""object"", - ""properties"": { - ""one"": { - ""description"": ""type array"", - ""type"": [ - ""integer"", - ""string"" - ] - }, - ""two"": { - ""description"": ""type 'null'"", - ""type"": ""null"" - }, - ""three"": { - ""description"": ""type array including 'null'"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""four"": { - ""description"": ""array with no items"", - ""type"": ""array"" - }, - ""five"": { - ""description"": ""singular example"", - ""type"": ""string"", - ""examples"": [ - ""exampleValue"" - ] - }, - ""six"": { - ""description"": ""exclusiveMinimum true"", - ""exclusiveMinimum"": 10 - }, - ""seven"": { - ""description"": ""exclusiveMinimum false"", - ""minimum"": 10 - }, - ""eight"": { - ""description"": ""exclusiveMaximum true"", - ""exclusiveMaximum"": 20 - }, - ""nine"": { - ""description"": ""exclusiveMaximum false"", - ""maximum"": 20 - }, - ""ten"": { - ""description"": ""nullable string"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""eleven"": { - ""description"": ""x-nullable string"", - ""type"": [ - ""string"", - ""null"" - ] - }, - ""twelve"": { - ""description"": ""file/binary"" - } - } -}"; - var expectedSchema = JsonSerializer.Deserialize(jsonString); - - // Assert - schema.Should().BeEquivalentTo(expectedSchema); - } - - [Fact] - public void ParseStandardSchemaExampleSucceeds() - { - // Arrange - var builder = new JsonSchemaBuilder(); - var myschema = builder.Title("My Schema") - .Description("A schema for testing") - .Type(SchemaValueType.Object) - .Properties( - ("name", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("The name of the person")), - ("age", - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Description("The age of the person"))) - .Build(); - - // Act - var title = myschema.Get().Value; - var description = myschema.Get().Value; - var nameProperty = myschema.Get().Properties["name"]; - - // Assert - Assert.Equal("My Schema", title); - Assert.Equal("A schema for testing", description); - } - } - - public static class SchemaExtensions - { - public static T Get(this JsonSchema schema) - { - return (T)schema.Keywords.FirstOrDefault(x => x is T); - } - } -} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index d4ee7bdf1..66b00c9f7 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -45,36 +44,83 @@ public void ParseDocumentWithWebhooksShouldSucceed() { // Arrange and Act var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema"); + var petSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "petSchema" + } + }; + + var newPetSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "newPetSchema" + } + }; var components = new OpenApiComponents { Schemas = { - ["petSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")), - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String)) - ), - ["newPetSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")), - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["petSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPetSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + } } }; @@ -103,11 +149,14 @@ public void ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -115,8 +164,11 @@ public void ParseDocumentWithWebhooksShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -128,16 +180,19 @@ public void ParseDocumentWithWebhooksShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) - + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } } @@ -191,30 +246,84 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["petSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPetSchema"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["petSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPetSchema"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + } } }; - - // Create a clone of the schema to avoid modifying things in components. - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/petSchema"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPetSchema"); + var petSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "petSchema" + } + }; + + var newPetSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "newPetSchema" + } + }; components.PathItems = new Dictionary { @@ -234,9 +343,14 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -244,8 +358,11 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -257,15 +374,19 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new OpenApiSchema + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new OpenApiSchema + { + Type = "array", + Items = petSchema + } } } } @@ -350,15 +471,32 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "docWithPatternPropertiesInSchema.yaml")); var actualSchema = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("prop1", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("prop2", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("prop3", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .PatternProperties( - ("^x-.*$", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build(); + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["prop1"] = new OpenApiSchema + { + Type = "string" + }, + ["prop2"] = new OpenApiSchema + { + Type = "string" + }, + ["prop3"] = new OpenApiSchema + { + Type = "string" + } + }, + PatternProperties = new Dictionary + { + ["^x-.*$"] = new OpenApiSchema + { + Type = "string" + } + } + }; // Serialization var mediaType = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index 72c5289e5..ae83a3abe 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -3,9 +3,15 @@ using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text.Json.Nodes; using FluentAssertions; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; +using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Reader.V31; +using SharpYaml.Serialization; using Xunit; namespace Microsoft.OpenApi.Readers.Tests.V31Tests @@ -133,5 +139,130 @@ public void TestSchemaCopyConstructorWithTypeArrayWorks() simpleSchemaCopy.Type.Should().NotBeEquivalentTo(simpleSchema.Type); simpleSchema.Type = "string"; } + + [Fact] + public void ParseV31SchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "schema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV31Deserializer.LoadSchema(node); + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["one"] = new() + { + Description = "type array", + Type = new HashSet { "integer", "string" } + } + } + }; + + // Assert + Assert.Equal(schema, expectedSchema); + } + + [Fact] + public void ParseAdvancedV31SchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedSchema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV31Deserializer.LoadSchema(node); + + var expectedSchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["one"] = new() + { + Description = "type array", + Type = new HashSet { "integer", "string" } + }, + ["two"] = new() + { + Description = "type 'null'", + Type = "null" + }, + ["three"] = new() + { + Description = "type array including 'null'", + Type = new HashSet { "string", "null" } + }, + ["four"] = new() + { + Description = "array with no items", + Type = "array" + }, + ["five"] = new() + { + Description = "singular example", + Type = "string", + Examples = new List + { + new OpenApiAny("exampleValue").Node + } + }, + ["six"] = new() + { + Description = "exclusiveMinimum true", + V31ExclusiveMinimum = 10 + }, + ["seven"] = new() + { + Description = "exclusiveMinimum false", + Minimum = 10 + }, + ["eight"] = new() + { + Description = "exclusiveMaximum true", + V31ExclusiveMaximum = 20 + }, + ["nine"] = new() + { + Description = "exclusiveMaximum false", + Maximum = 20 + }, + ["ten"] = new() + { + Description = "nullable string", + Type = new HashSet { "string", "null" } + }, + ["eleven"] = new() + { + Description = "x-nullable string", + Type = new HashSet { "string", "null" } + }, + ["twelve"] = new() + { + Description = "file/binary" + } + } + }; + + // Assert + schema.Should().BeEquivalentTo(expectedSchema); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs deleted file mode 100644 index dd98bdb92..000000000 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/JsonSchemaTests.cs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT license. - -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json.Nodes; -using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Extensions; -using SharpYaml.Serialization; -using Xunit; -using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Reader.ParseNodes; -using Microsoft.OpenApi.Reader.V3; - -namespace Microsoft.OpenApi.Readers.Tests.V3Tests -{ - [Collection("DefaultSettings")] - public class JsonSchemaTests - { - private const string SampleFolderPath = "V3Tests/Samples/OpenApiSchema/"; - - public JsonSchemaTests() - { - OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); - } - - [Fact] - public void ParsePrimitiveSchemaShouldSucceed() - { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "primitiveSchema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format("email") - .Build()); - } - - [Fact] - public void ParseExampleStringFragmentShouldSucceed() - { - var input = @" -{ - ""foo"": ""bar"", - ""baz"": [ 1,2] -}"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo(new OpenApiAny( - new JsonObject - { - ["foo"] = "bar", - ["baz"] = new JsonArray() { 1, 2 } - }), options => options.IgnoringCyclicReferences()); - } - - [Fact] - public void ParseEnumFragmentShouldSucceed() - { - var input = @" -[ - ""foo"", - ""baz"" -]"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo(new OpenApiAny( - new JsonArray - { - "foo", - "baz" - }), options => options.IgnoringCyclicReferences()); - } - - [Fact] - public void ParsePathFragmentShouldSucceed() - { - var input = @" -summary: externally referenced path item -get: - responses: - '200': - description: Ok -"; - var diagnostic = new OpenApiDiagnostic(); - - // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic, "yaml"); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - openApiAny.Should().BeEquivalentTo( - new OpenApiPathItem - { - Summary = "externally referenced path item", - Operations = new Dictionary - { - [OperationType.Get] = new OpenApiOperation() - { - Responses = new OpenApiResponses - { - ["200"] = new OpenApiResponse - { - Description = "Ok" - } - } - } - } - }); - } - - [Fact] - public void ParseDictionarySchemaShouldSucceed() - { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "dictionarySchema.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.String)) - .Build()); - } - } - - [Fact] - public void ParseBasicSchemaWithExampleShouldSucceed() - { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); - - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - - schema.Should().BeEquivalentTo( - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Required("name") - .Example(new JsonObject { ["name"] = "Puma", ["id"] = 1 }) - .Build(), - options => options.IgnoringCyclicReferences()); - } - } - - [Fact] - public void ParseBasicSchemaWithReferenceShouldSucceed() - { - // Act - var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "basicSchemaWithReference.yaml")); - - // Assert - var components = result.OpenApiDocument.Components; - - result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic() - { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } - }); - - var expectedComponents = new OpenApiComponents - { - Schemas = - { - ["ErrorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("message", "code") - .Properties( - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Minimum(100).Maximum(600))), - ["ExtendedErrorModel"] = new JsonSchemaBuilder() - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/ErrorModel"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("rootCause") - .Properties(("rootCause", new JsonSchemaBuilder().Type(SchemaValueType.String)))) - } - }; - - components.Should().BeEquivalentTo(expectedComponents); - } - - [Fact] - public void ParseAdvancedSchemaWithReferenceShouldSucceed() - { - // Act - var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "advancedSchemaWithReference.yaml")); - - var expectedComponents = new OpenApiComponents - { - Schemas = - { - ["Pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - ["Cat"] = new JsonSchemaBuilder() - .Description("A representation of a cat") - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet1") - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("huntingSkill") - .Properties( - ("huntingSkill", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Description("The measured skill for hunting") - .Enum("clueless", "lazy", "adventurous", "aggressive") - ) - ) - ), - ["Dog"] = new JsonSchemaBuilder() - .Description("A representation of a dog") - .AllOf( - new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet1") - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator { PropertyName = "petType" }) - .Properties( - ("name", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ), - ("petType", new JsonSchemaBuilder() - .Type(SchemaValueType.String) - ) - ) - .Required("name", "petType"), - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("packSize") - .Properties( - ("packSize", new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Description("the size of the pack the dog is from") - .Default(0) - .Minimum(0) - ) - ) - ) - } - }; - - // We serialize so that we can get rid of the schema BaseUri properties which show up as diffs - var actual = result.OpenApiDocument.Components.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); - var expected = expectedComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); - - // Assert - actual.Should().Be(expected); - } - } -} diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 5deea9e83..544fec90b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -1,10 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -96,7 +95,10 @@ public void ParseCallbackWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, @@ -149,7 +151,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, @@ -188,7 +193,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }, @@ -220,7 +228,10 @@ public void ParseMultipleCallbacksWithReferenceShouldSucceed() { ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object) + Schema = new() + { + Type = "object" + } } } }, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index c694c392e..0d3bb622f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -7,9 +7,7 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; @@ -209,39 +207,130 @@ public void ParseMinimalDocumentShouldSucceed() public void ParseStandardPetStoreDocumentShouldSucceed() { using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "petStore.yaml")); - var result = OpenApiDocument.Load(stream, OpenApiConstants.Yaml); + var actual = OpenApiDocument.Load(stream, OpenApiConstants.Yaml); var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "pet", + HostDocument = actual.OpenApiDocument + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "errorModel", + HostDocument = actual.OpenApiDocument + } + }, } }; - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1"); - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet"); + // Create a clone of the schema to avoid modifying things in components. + var petSchema = Clone(components.Schemas["pet"]); - var errorModelSchema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel"); + petSchema.Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; + + var newPetSchema = Clone(components.Schemas["newPet"]); + + newPetSchema.Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; + + var errorModelSchema = Clone(components.Schemas["errorModel"]); + + errorModelSchema.Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument + }; var expectedDoc = new OpenApiDocument { @@ -289,9 +378,14 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -299,7 +393,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -311,11 +409,19 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } }, @@ -415,7 +521,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -471,7 +581,11 @@ public void ParseStandardPetStoreDocumentShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -510,9 +624,9 @@ public void ParseStandardPetStoreDocumentShouldSucceed() Components = components }; - result.OpenApiDocument.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); + actual.OpenApiDocument.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); - result.OpenApiDiagnostic.Should().BeEquivalentTo( + actual.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); } @@ -524,28 +638,95 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() var components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64")), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String)), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String))), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32")), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String))) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "pet", + HostDocument = actual.OpenApiDocument + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "newPet", + HostDocument = actual.OpenApiDocument + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "errorModel" + } + }, }, SecuritySchemes = new Dictionary { @@ -563,11 +744,29 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }; - var petSchema = new JsonSchemaBuilder().Ref("#/components/schemas/pet1"); + // Create a clone of the schema to avoid modifying things in components. + var petSchema = Clone(components.Schemas["pet"]); + petSchema.Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema + }; - var newPetSchema = new JsonSchemaBuilder().Ref("#/components/schemas/newPet"); + var newPetSchema = Clone(components.Schemas["newPet"]); - var errorModelSchema = new JsonSchemaBuilder().Ref("#/components/schemas/errorModel"); + newPetSchema.Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema + }; + + var errorModelSchema = Clone(components.Schemas["errorModel"]); + + errorModelSchema.Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema + }; var tag1 = new OpenApiTag { @@ -658,9 +857,14 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -668,9 +872,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -682,15 +888,19 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(petSchema) + Schema = new() + { + Type = "array", + Items = petSchema + } } } }, @@ -807,9 +1017,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -865,9 +1077,11 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -982,9 +1196,11 @@ public void HeaderParameterShouldAllowExample() Style = ParameterStyle.Simple, Explode = true, Example = new OpenApiAny("99391c7e-ad88-49ec-a2ad-99ddcb1f7721"), - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format(Formats.Uuid) + Schema = new() + { + Type = "string", + Format = "uuid" + }, }, options => options.IgnoringCyclicReferences() .Excluding(e => e.Example.Node.Parent) .Excluding(x => x.Reference)); @@ -1014,9 +1230,11 @@ public void HeaderParameterShouldAllowExample() } } }, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format(Formats.Uuid) + Schema = new() + { + Type = "string", + Format = "uuid" + }, }, options => options.IgnoringCyclicReferences() .Excluding(e => e.Examples["uuid1"].Value.Node.Parent) .Excluding(e => e.Examples["uuid2"].Value.Node.Parent)); @@ -1054,9 +1272,14 @@ public void ParseDocumentWithJsonSchemaReferencesWorks() var actualSchema = result.OpenApiDocument.Paths["/users/{userId}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new JsonSchemaBuilder() - .Ref("#/components/schemas/User") - .Build(); + var expectedSchema = new OpenApiSchema() + { + Reference = new OpenApiReference + { + Id = "User", + Type = ReferenceType.Schema + } + }; // Assert actualSchema.Should().BeEquivalentTo(expectedSchema); @@ -1105,10 +1328,12 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() In = ParameterLocation.Query, Description = "Limit the number of pets returned", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Default(10), + Schema = new() + { + Type = "integer", + Format = "int32", + Default = new OpenApiAny(10) + }, Reference = new OpenApiReference { Id = "LimitParameter", @@ -1131,10 +1356,12 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() In = ParameterLocation.Query, Description = "Limit the number of pets returned", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Default(10) + Schema = new() + { + Type = "integer", + Format = "int32", + Default = new OpenApiAny(10) + }, } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs index 837b1d4f1..01239e415 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs @@ -3,7 +3,6 @@ using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; using Xunit; @@ -53,7 +52,10 @@ public void ParseAdvancedEncodingShouldSucceed() new() { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } } } }); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index 37b055bb3..90c797723 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -3,7 +3,6 @@ using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -32,7 +31,11 @@ public void ParseMediaTypeWithExampleShouldSucceed() new OpenApiMediaType { Example = new OpenApiAny(5), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(m => m.Example.Node.Parent) ); @@ -59,7 +62,11 @@ public void ParseMediaTypeWithExamplesShouldSucceed() Value = new OpenApiAny(7.5) } }, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(m => m.Examples["example1"].Value.Node.Parent) .Excluding(m => m.Examples["example2"].Value.Node.Parent)); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs index ff03c553f..d6570f17b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -53,8 +52,10 @@ public void ParseOperationWithParameterWithNoLocationShouldSucceed() Name = "username", Description = "The user name for login", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }, new OpenApiParameter { @@ -62,8 +63,10 @@ public void ParseOperationWithParameterWithNoLocationShouldSucceed() Description = "The password for login in clear text", In = ParameterLocation.Query, Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } }; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 5a6e9fd41..1a6cb9aa9 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -5,7 +5,6 @@ using System; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -42,7 +41,10 @@ public void ParsePathParameterShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -60,7 +62,14 @@ public void ParseQueryParameterShouldSucceed() Name = "id", Description = "ID of the object to fetch", Required = false, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Array).Items(new JsonSchemaBuilder().Type(SchemaValueType.String)), + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + }, Style = ParameterStyle.Form, Explode = true }); @@ -78,9 +87,14 @@ public void ParseQueryParameterWithObjectTypeShouldSucceed() { In = ParameterLocation.Query, Name = "freeForm", - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer)), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + }, Style = ParameterStyle.Form }); } @@ -104,17 +118,26 @@ public void ParseQueryParameterWithObjectTypeAndContentShouldSucceed() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("lat", "long") - .Properties( - ("lat", new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - ), - ("long", new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - ) - ) + Schema = new() + { + Type = "object", + Required = + { + "lat", + "long" + }, + Properties = + { + ["lat"] = new() + { + Type = "number" + }, + ["long"] = new() + { + Type = "number" + } + } + } } } }); @@ -136,11 +159,15 @@ public void ParseHeaderParameterShouldSucceed() Required = true, Style = ParameterStyle.Simple, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64")) + Schema = new() + { + Type = "array", + Items = new() + { + Type = "integer", + Format = "int64", + } + } }); } @@ -158,8 +185,10 @@ public void ParseParameterWithNullLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -180,8 +209,10 @@ public void ParseParameterWithNoLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -202,8 +233,10 @@ public void ParseParameterWithUnknownLocationShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } }); } @@ -222,9 +255,11 @@ public void ParseParameterWithExampleShouldSucceed() Description = "username to fetch", Required = true, Example = new OpenApiAny((float)5.0), - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences().Excluding(p => p.Example.Node.Parent)); } @@ -253,9 +288,11 @@ public void ParseParameterWithExamplesShouldSucceed() Value = new OpenApiAny((float)7.5) } }, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Number) - .Format("float") + Schema = new() + { + Type = "number", + Format = "float" + } }, options => options.IgnoringCyclicReferences() .Excluding(p => p.Examples["example1"].Value.Node.Parent) .Excluding(p => p.Examples["example2"].Value.Node.Parent)); @@ -313,9 +350,14 @@ public void ParseParameterWithReferenceWorks() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)).Build(), + Schema = new() + { + Type = "array", + Items = new OpenApiSchema + { + Type = "string" + } + }, Reference = new OpenApiReference { Type = ReferenceType.Parameter, diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs new file mode 100644 index 000000000..4d3055668 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json.Nodes; +using FluentAssertions; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Extensions; +using SharpYaml.Serialization; +using Xunit; +using Microsoft.OpenApi.Reader; +using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Reader.V3; + +namespace Microsoft.OpenApi.Readers.Tests.V3Tests +{ + [Collection("DefaultSettings")] + public class OpenApiSchemaTests + { + private const string SampleFolderPath = "V3Tests/Samples/OpenApiSchema/"; + + public OpenApiSchemaTests() + { + OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); + } + + [Fact] + public void ParsePrimitiveSchemaShouldSucceed() + { + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "primitiveSchema.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "string", + Format = "email" + }); + } + + [Fact] + public void ParseExampleStringFragmentShouldSucceed() + { + var input = @" +{ + ""foo"": ""bar"", + ""baz"": [ 1,2] +}"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo(new OpenApiAny( + new JsonObject + { + ["foo"] = "bar", + ["baz"] = new JsonArray() { 1, 2 } + }), options => options.IgnoringCyclicReferences()); + } + + [Fact] + public void ParseEnumFragmentShouldSucceed() + { + var input = @" +[ + ""foo"", + ""baz"" +]"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo(new OpenApiAny( + new JsonArray + { + "foo", + "baz" + }), options => options.IgnoringCyclicReferences()); + } + + [Fact] + public void ParsePathFragmentShouldSucceed() + { + var input = @" +summary: externally referenced path item +get: + responses: + '200': + description: Ok +"; + var diagnostic = new OpenApiDiagnostic(); + + // Act + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out diagnostic, "yaml"); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + openApiAny.Should().BeEquivalentTo( + new OpenApiPathItem + { + Summary = "externally referenced path item", + Operations = new Dictionary + { + [OperationType.Get] = new OpenApiOperation() + { + Responses = new OpenApiResponses + { + ["200"] = new OpenApiResponse + { + Description = "Ok" + } + } + } + } + }); + } + + [Fact] + public void ParseDictionarySchemaShouldSucceed() + { + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "dictionarySchema.yaml"))) + { + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + AdditionalProperties = new() + { + Type = "string" + } + }); + } + } + + [Fact] + public void ParseBasicSchemaWithExampleShouldSucceed() + { + using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) + { + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; + + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); + + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); + + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); + + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + Properties = + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + } + }, + Required = + { + "name" + }, + Example = new OpenApiAny(new JsonObject + { + ["name"] = new OpenApiAny("Puma").Node, + ["id"] = new OpenApiAny(1).Node + }) + }); + } + } + + [Fact] + public void ParseBasicSchemaWithReferenceShouldSucceed() + { + // Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "basicSchemaWithReference.yaml")); + + // Assert + var components = result.OpenApiDocument.Components; + + result.OpenApiDiagnostic.Should().BeEquivalentTo( + new OpenApiDiagnostic() + { + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Errors = new List() + { + new OpenApiError("", "Paths is a REQUIRED field at #/") + } + }); + + var expectedComponents = new OpenApiComponents + { + Schemas = + { + ["ErrorModel"] = new() + { + Type = "object", + Properties = + { + ["code"] = new() + { + Type = "integer", + Minimum = 100, + Maximum = 600 + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ErrorModel", + HostDocument = result.OpenApiDocument + }, + Required = + { + "message", + "code" + } + }, + ["ExtendedErrorModel"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ExtendedErrorModel", + HostDocument = result.OpenApiDocument + }, + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "ErrorModel", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the ErrorModel above should be propagated here. + Type = "object", + Properties = + { + ["code"] = new() + { + Type = "integer", + Minimum = 100, + Maximum = 600 + }, + ["message"] = new() + { + Type = "string" + } + }, + Required = + { + "message", + "code" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"rootCause"}, + Properties = + { + ["rootCause"] = new() + { + Type = "string" + } + } + } + } + } + } + }; + + components.Should().BeEquivalentTo(expectedComponents); + } + + [Fact] + public void ParseAdvancedSchemaWithReferenceShouldSucceed() + { + // Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "advancedSchemaWithReference.yaml")); + + var expectedComponents = new OpenApiComponents + { + Schemas = + { + ["Pet"] = new() + { + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + }, + Reference = new() + { + Id= "Pet", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }, + ["Cat"] = new() + { + Description = "A representation of a cat", + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Pet", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the Pet above should be propagated here. + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"huntingSkill"}, + Properties = + { + ["huntingSkill"] = new() + { + Type = "string", + Description = "The measured skill for hunting", + Enum = + { + new OpenApiAny("clueless").Node, + new OpenApiAny("lazy").Node, + new OpenApiAny("adventurous").Node, + new OpenApiAny("aggressive").Node + } + } + } + } + }, + Reference = new() + { + Id= "Cat", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + }, + ["Dog"] = new() + { + Description = "A representation of a dog", + AllOf = + { + new OpenApiSchema + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Pet", + HostDocument = result.OpenApiDocument + }, + // Schema should be dereferenced in our model, so all the properties + // from the Pet above should be propagated here. + Type = "object", + Discriminator = new() + { + PropertyName = "petType" + }, + Properties = + { + ["name"] = new() + { + Type = "string" + }, + ["petType"] = new() + { + Type = "string" + } + }, + Required = + { + "name", + "petType" + } + }, + new OpenApiSchema + { + Type = "object", + Required = {"packSize"}, + Properties = + { + ["packSize"] = new() + { + Type = "integer", + Format = "int32", + Description = "the size of the pack the dog is from", + Default = new OpenApiAny(0), + Minimum = 0 + } + } + } + }, + Reference = new() + { + Id= "Dog", + Type = ReferenceType.Schema, + HostDocument = result.OpenApiDocument + } + } + } + }; + + // We serialize so that we can get rid of the schema BaseUri properties which show up as diffs + var actual = result.OpenApiDocument.Components.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + var expected = expectedComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); + + // Assert + actual.Should().Be(expected); + } + } +} diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs index eb1476f7b..ee6d6e658 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs @@ -1,11 +1,11 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; using Xunit; namespace Microsoft.OpenApi.Tests.Extensions @@ -14,40 +14,41 @@ public class OpenApiTypeMapperTests { public static IEnumerable PrimitiveTypeData => new List { - new object[] { typeof(int), new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() }, - new object[] { typeof(string), new JsonSchemaBuilder().Type(SchemaValueType.String).Build() }, - new object[] { typeof(double), new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build() }, - new object[] { typeof(DateTimeOffset), new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build() } + new object[] { typeof(int), new OpenApiSchema { Type = "integer", Format = "int32" } }, + new object[] { typeof(string), new OpenApiSchema { Type = "string" } }, + new object[] { typeof(double), new OpenApiSchema { Type = "number", Format = "double" } }, + new object[] { typeof(float?), new OpenApiSchema { Type = "number", Format = "float", Nullable = true } }, + new object[] { typeof(DateTimeOffset), new OpenApiSchema { Type = "string", Format = "date-time" } } }; - public static IEnumerable JsonSchemaDataTypes => new List + public static IEnumerable OpenApiDataTypes => new List { - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build(), typeof(int) }, - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), typeof(double) }, - new object[] { new JsonSchemaBuilder().AnyOf( - new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build(), - new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .Format("float").Build(), typeof(float?) }, - new object[] { new JsonSchemaBuilder().Type(SchemaValueType.String).Format("date-time").Build(), typeof(DateTimeOffset) } + new object[] { new OpenApiSchema { Type = "integer", Format = "int32"}, typeof(int) }, + new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = false}, typeof(int) }, + new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = true}, typeof(int?) }, + new object[] { new OpenApiSchema { Type = "string" }, typeof(string) }, + new object[] { new OpenApiSchema { Type = "number", Format = "double" }, typeof(double) }, + new object[] { new OpenApiSchema { Type = "number", Format = "float", Nullable = true }, typeof(float?) }, + new object[] { new OpenApiSchema { Type = "string", Format = "date-time" }, typeof(DateTimeOffset) } }; [Theory] [MemberData(nameof(PrimitiveTypeData))] - public void MapTypeToJsonPrimitiveTypeShouldSucceed(Type type, JsonSchema expected) + public void MapTypeToOpenApiPrimitiveTypeShouldSucceed(Type type, OpenApiSchema expected) { // Arrange & Act - var actual = OpenApiTypeMapper.MapTypeToJsonPrimitiveType(type); + var actual = OpenApiTypeMapper.MapTypeToOpenApiPrimitiveType(type); // Assert actual.Should().BeEquivalentTo(expected); } [Theory] - [MemberData(nameof(JsonSchemaDataTypes))] - public void MapOpenApiSchemaTypeToSimpleTypeShouldSucceed(JsonSchema schema, Type expected) + [MemberData(nameof(OpenApiDataTypes))] + public void MapOpenApiSchemaTypeToSimpleTypeShouldSucceed(OpenApiSchema schema, Type expected) { // Arrange & Act - var actual = OpenApiTypeMapper.MapJsonSchemaValueTypeToSimpleType(schema); + var actual = OpenApiTypeMapper.MapOpenApiPrimitiveTypeToSimpleType(schema); // Assert actual.Should().Be(expected); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 310511db8..083b89ffc 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Expressions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -35,7 +34,10 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Build() + Schema = new() + { + Type = "object" + } } } }, @@ -72,7 +74,10 @@ public class OpenApiCallbackTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Build() + Schema = new() + { + Type = "object" + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index e99072d50..74ec5a8b9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -16,14 +15,23 @@ public class OpenApiComponentsTests { public static OpenApiComponents AdvancedComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()), - ("property3", new JsonSchemaBuilder().Type(SchemaValueType.String).MaxLength(15).Build())) - .Build() - + ["schema1"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + }, + ["property3"] = new() + { + Type = "string", + MaxLength = 15 + } + } + } }, SecuritySchemes = new Dictionary { @@ -56,15 +64,41 @@ public class OpenApiComponentsTests public static OpenApiComponents AdvancedComponentsWithReference = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer)), - ("property3", new JsonSchemaBuilder().Ref("#/components/schemas/schema2"))), - ["schema2"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer))) + ["schema1"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + }, + ["property3"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Properties = new Dictionary + { + ["property2"] = new() + { + Type = "integer" + } + } + }, }, SecuritySchemes = new Dictionary { @@ -109,13 +143,29 @@ public class OpenApiComponentsTests public static OpenApiComponents BrokenComponents = new() { - Schemas = new Dictionary + Schemas = new Dictionary { - ["schema1"] = new JsonSchemaBuilder().Type(SchemaValueType.String), - ["schema4"] = new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .AllOf(new JsonSchemaBuilder().Type(SchemaValueType.String).Build()) - .Build() + ["schema1"] = new() + { + Type = "string" + }, + ["schema2"] = null, + ["schema3"] = null, + ["schema4"] = new() + { + Type = "string", + AllOf = new List + { + null, + null, + new() + { + Type = "string" + }, + null, + null + } + } } }; @@ -123,12 +173,25 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Ref("#/components/schemas/schema2").Build(), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -136,18 +199,33 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Ref("#/components/schemas/schema1") - .Build(), - - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", new JsonSchemaBuilder().Type(SchemaValueType.String))) - .Build() + ["schema1"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -155,25 +233,50 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Ref("schema1").Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } }; public static OpenApiComponents ComponentsWithPathItem = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary() { - ["schema1"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()), - ("property3", new JsonSchemaBuilder().Ref("#/components/schemas/schema2").Build())) - .Build(), - - ["schema2"] = new JsonSchemaBuilder() - .Properties( - ("property2", new JsonSchemaBuilder().Type(SchemaValueType.Integer))) - .Build() + ["schema1"] = new OpenApiSchema() + { + Properties = new Dictionary() + { + ["property2"] = new OpenApiSchema() + { + Type = "integer" + }, + ["property3"] = new OpenApiSchema() + { + Reference = new OpenApiReference() + { + Type = ReferenceType.Schema, + Id = "schema2" + } + } + } + }, + + ["schema2"] = new() + { + Properties = new Dictionary() + { + ["property2"] = new OpenApiSchema() + { + Type = "integer" + } + } + } }, PathItems = new Dictionary { @@ -190,7 +293,14 @@ public class OpenApiComponentsTests { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("#/components/schemas/schema1") + Schema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index ba2e9a89e..5b95221e3 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -34,11 +33,25 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder().Ref("#/definitions/schema2"), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Build() + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema2" + }, + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string", + } + } + }, } }; @@ -46,13 +59,33 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/definitions/schema1"), - ["schema2"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("property1", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) + ["schema1"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string", + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + }, + ["schema2"] = new() + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "string" + } + } + }, } }; @@ -61,7 +94,14 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new JsonSchemaBuilder().Ref("#/definitions/schemas/schema1") + ["schema1"] = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schema1" + } + } } }; @@ -94,38 +134,101 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponentsWithReference = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/pet").Build(), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/newPet").Build(), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build()), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Ref("#/components/schemas/errorModel").Build() + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Id = "pet", + Type = ReferenceType.Schema + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + Reference = new() + { + Id = "newPet", + Type = ReferenceType.Schema + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + }, + Reference = new() + { + Id = "errorModel", + Type = ReferenceType.Schema + } + }, } }; - public static readonly JsonSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"]; + public static OpenApiSchema PetSchemaWithReference = AdvancedComponentsWithReference.Schemas["pet"]; - public static readonly JsonSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"]; + public static OpenApiSchema NewPetSchemaWithReference = AdvancedComponentsWithReference.Schemas["newPet"]; - public static readonly JsonSchema ErrorModelSchemaWithReference = + public static OpenApiSchema ErrorModelSchemaWithReference = AdvancedComponentsWithReference.Schemas["errorModel"]; public static readonly OpenApiDocument AdvancedDocumentWithReference = new OpenApiDocument @@ -174,9 +277,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Type(SchemaValueType.String)).Build() + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -184,9 +292,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -198,15 +308,19 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchemaWithReference).Build() + Schema = new() + { + Type = "array", + Items = PetSchemaWithReference + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchemaWithReference).Build() + Schema = new() + { + Type = "array", + Items = PetSchemaWithReference + } } } }, @@ -306,10 +420,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -365,10 +480,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -409,35 +525,86 @@ public OpenApiDocumentTests() public static readonly OpenApiComponents AdvancedComponents = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["pet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("id", "name") - .Properties(("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())), - ["newPet"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())), - ["errorModel"] = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Required("code", "message") - .Properties( - ("code", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build()), - ("message", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) + ["pet"] = new() + { + Type = "object", + Required = new HashSet + { + "id", + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["newPet"] = new() + { + Type = "object", + Required = new HashSet + { + "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + } + }, + ["errorModel"] = new() + { + Type = "object", + Required = new HashSet + { + "code", + "message" + }, + Properties = new Dictionary + { + ["code"] = new() + { + Type = "integer", + Format = "int32" + }, + ["message"] = new() + { + Type = "string" + } + } + }, } }; - public static readonly JsonSchema PetSchema = AdvancedComponents.Schemas["pet"]; + public static readonly OpenApiSchema PetSchema = AdvancedComponents.Schemas["pet"]; - public static readonly JsonSchema NewPetSchema = AdvancedComponents.Schemas["newPet"]; + public static readonly OpenApiSchema NewPetSchema = AdvancedComponents.Schemas["newPet"]; - public static readonly JsonSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"]; + public static readonly OpenApiSchema ErrorModelSchema = AdvancedComponents.Schemas["errorModel"]; public OpenApiDocument AdvancedDocument = new OpenApiDocument { @@ -485,12 +652,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "tags to filter by", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build()) - .Build() + Schema = new() + { + Type = "array", + Items = new() + { + Type = "string" + } + } }, new OpenApiParameter { @@ -498,10 +667,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Query, Description = "maximum number of results to return", Required = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int32") - .Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } } }, Responses = new OpenApiResponses @@ -513,17 +683,19 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } }, ["application/xml"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } } } }, @@ -623,10 +795,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to fetch", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -682,10 +855,11 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "ID of pet to delete", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Format("int64") - .Build() + Schema = new() + { + Type = "integer", + Format = "int64" + } } }, Responses = new OpenApiResponses @@ -746,9 +920,14 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Ref("#/components/schemas/Pet") - .Build() + Schema = new() + { + Reference = new OpenApiReference + { + Id = "Pet", + Type = ReferenceType.Schema + } + } } } }, @@ -765,15 +944,31 @@ public OpenApiDocumentTests() }, Components = new OpenApiComponents { - Schemas = new Dictionary + Schemas = new Dictionary { - ["Pet"] = new JsonSchemaBuilder() - .Required("id", "name") - .Properties( - ("id", new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int64").Build()), - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Build()), - ("tag", new JsonSchemaBuilder().Type(SchemaValueType.String).Build())) - .Build() + ["Pet"] = new OpenApiSchema() + { + Required = new HashSet + { + "id", "name" + }, + Properties = new Dictionary + { + ["id"] = new() + { + Type = "integer", + Format = "int64" + }, + ["name"] = new() + { + Type = "string" + }, + ["tag"] = new() + { + Type = "string" + }, + }, + } } } }; @@ -810,12 +1005,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The first operand", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Extensions(new Dictionary + Schema = new() + { + Type = "integer", + Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4) - }), + } + }, Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4), @@ -827,12 +1024,14 @@ public OpenApiDocumentTests() In = ParameterLocation.Path, Description = "The second operand", Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Extensions(new Dictionary - { - ["my-extension"] = new OpenApiAny(4) - }), + Schema = new() + { + Type = "integer", + Extensions = new Dictionary + { + ["my-extension"] = new OpenApiAny(4) + } + }, Extensions = new Dictionary { ["my-extension"] = new OpenApiAny(4), @@ -848,10 +1047,11 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(PetSchema) - .Build() + Schema = new() + { + Type = "array", + Items = PetSchema + } }, } } @@ -1066,7 +1266,14 @@ public void SerializeDocumentWithReferenceButNoComponents() { ["application/json"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder().Ref("test") + Schema = new() + { + Reference = new() + { + Id = "test", + Type = ReferenceType.Schema + } + } } } } @@ -1077,7 +1284,7 @@ public void SerializeDocumentWithReferenceButNoComponents() } }; - var reference = document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.GetRef(); + var reference = document.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Reference; // Act var actual = document.Serialize(OpenApiSpecVersion.OpenApi2_0, OpenApiFormat.Json); @@ -1236,7 +1443,10 @@ public void SerializeV2DocumentWithNonArraySchemaTypeDoesNotWriteOutCollectionFo new OpenApiParameter { In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } }, Responses = new OpenApiResponses() @@ -1302,11 +1512,14 @@ public void SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { Name = "id", In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .AdditionalPropertiesAllowed(true) - .Build() + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + } } }, Responses = new OpenApiResponses @@ -1318,8 +1531,10 @@ public void SerializeV2DocumentWithStyleAsNullDoesNotWriteOutStyleValue() { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.String) + Schema = new() + { + Type = "string" + } } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index d63330a09..de569bb49 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -19,7 +18,11 @@ public class OpenApiHeaderTests public static OpenApiHeader AdvancedHeader = new() { Description = "sampleHeader", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } }; public static OpenApiHeaderReference OpenApiHeaderReference = new(ReferencedHeader, "example1"); @@ -27,7 +30,11 @@ public class OpenApiHeaderTests public static OpenApiHeader ReferencedHeader = new() { Description = "sampleHeader", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer).Format("int32").Build() + Schema = new() + { + Type = "integer", + Format = "int32" + } }; [Theory] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 756b10514..7c729341d 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -47,7 +46,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } }, @@ -60,7 +64,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } } @@ -115,7 +124,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } }, @@ -128,7 +142,12 @@ public class OpenApiOperationTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Number).Minimum(5).Maximum(10).Build() + Schema = new() + { + Type = "number", + Minimum = 5, + Maximum = 10 + } } } } @@ -169,7 +188,10 @@ public class OpenApiOperationTests In = ParameterLocation.Path, Description = "ID of pet that needs to be updated", Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } }, RequestBody = new() @@ -178,21 +200,49 @@ public class OpenApiOperationTests { ["application/x-www-form-urlencoded"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated name of the pet")), - ("status", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated status of the pet"))) - .Required("name") - .Build() + Schema = new() + { + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } }, ["multipart/form-data"] = new() { - Schema = new JsonSchemaBuilder() - .Properties( - ("name", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated name of the pet")), - ("status", new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Updated status of the pet"))) - .Required("name") - .Build() + Schema = new() + { + Properties = + { + ["name"] = new() + { + Description = "Updated name of the pet", + Type = "string" + }, + ["status"] = new() + { + Description = "Updated status of the pet", + Type = "string" + } + }, + Required = new HashSet + { + "name" + } + } } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index b173f2363..7f3b0b140 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -7,7 +7,6 @@ using System.Text.Json.Nodes; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; @@ -43,13 +42,16 @@ public class OpenApiParameterTests Deprecated = false, Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder() - .Title("title2") - .Description("description2") - .OneOf(new JsonSchemaBuilder().Type(SchemaValueType.Number).Format("double").Build(), - new JsonSchemaBuilder().Type(SchemaValueType.String).Build()) - .Build(), - + Schema = new() + { + Title = "title2", + Description = "description2", + OneOf = new List + { + new() { Type = "number", Format = "double" }, + new() { Type = "string" } + } + }, Examples = new Dictionary { ["test"] = new() @@ -67,18 +69,18 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = false, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items( - new JsonSchemaBuilder() - .Enum(new List + Schema = new() + { + Type = "array", + Items = new() + { + Enum = { new OpenApiAny("value1").Node, new OpenApiAny("value2").Node - }) - .Build()) - .Build() - + } + } + } }; public static OpenApiParameter ParameterWithFormStyleAndExplodeTrue = new() @@ -88,31 +90,32 @@ public class OpenApiParameterTests Description = "description1", Style = ParameterStyle.Form, Explode = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items( - new JsonSchemaBuilder() - .Enum(new List - { + Schema = new() + { + Type = "array", + Items = new() + { + Enum = + [ new OpenApiAny("value1").Node, new OpenApiAny("value2").Node - }) - .Build()) - .Build() - + ] + } + } }; public static OpenApiParameter QueryParameterWithMissingStyle = new OpenApiParameter { Name = "id", In = ParameterLocation.Query, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Build()) - .AdditionalPropertiesAllowed(true) - .Build() + Schema = new() + { + Type = "array", + AdditionalProperties = new OpenApiSchema + { + Type = "integer" + } + } }; public static OpenApiParameter AdvancedHeaderParameterWithSchemaReference = new OpenApiParameter @@ -125,7 +128,15 @@ public class OpenApiParameterTests Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder().Ref("schemaObject1").Build(), + Schema = new() + { + Reference = new() + { + Type = ReferenceType.Schema, + Id = "schemaObject1" + }, + UnresolvedReference = true + }, Examples = new Dictionary { ["test"] = new() @@ -146,7 +157,10 @@ public class OpenApiParameterTests Style = ParameterStyle.Simple, Explode = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Object), + Schema = new() + { + Type = "object" + }, Examples = new Dictionary { ["test"] = new() diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index 93d9f337f..5101bb22b 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -24,7 +23,10 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }; @@ -38,7 +40,10 @@ public class OpenApiRequestBodyTests { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string" + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index d9006ec09..a07362c32 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -6,7 +6,6 @@ using System.IO; using System.Threading.Tasks; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -31,9 +30,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/definitions/customType")), + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary { @@ -46,12 +50,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -62,9 +72,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/components/schemas/customType")), + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary { @@ -77,12 +92,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -95,9 +116,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/definitions/customType")) + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + } } }, Headers = @@ -105,12 +131,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; @@ -123,9 +155,14 @@ public class OpenApiResponseTests { ["text/plain"] = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder().Ref("#/components/schemas/customType")) + Schema = new() + { + Type = "array", + Items = new() + { + Reference = new() {Type = ReferenceType.Schema, Id = "customType"} + } + } } }, Headers = @@ -133,12 +170,18 @@ public class OpenApiResponseTests ["X-Rate-Limit-Limit"] = new OpenApiHeader { Description = "The number of allowed requests in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, ["X-Rate-Limit-Reset"] = new OpenApiHeader { Description = "The number of seconds left in the current period", - Schema = new JsonSchemaBuilder().Type(SchemaValueType.Integer) + Schema = new() + { + Type = "integer" + } }, } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs index e55acf5f3..5773c178e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiHeaderReferenceTests.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -103,7 +102,7 @@ public OpenApiHeaderReferenceTests() public void HeaderReferenceResolutionWorks() { // Assert - Assert.Equal(SchemaValueType.String, _externalHeaderReference.Schema.GetJsonType()); + Assert.Equal("string", _externalHeaderReference.Schema.Type); Assert.Equal("Location of the locally referenced post", _localHeaderReference.Description); Assert.Equal("Location of the externally referenced post", _externalHeaderReference.Description); Assert.Equal("The URL of the newly created post", diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs index b6467d1c1..54521e83c 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiRequestBodyReferenceTests.cs @@ -1,12 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; -using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -112,13 +110,13 @@ public void RequestBodyReferenceResolutionWorks() // Assert var localContent = _localRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(localContent); - Assert.Equal("#/components/schemas/UserSchema", localContent.Schema.GetRef().OriginalString); + Assert.Equal("UserSchema", localContent.Schema.Reference.Id); Assert.Equal("User request body", _localRequestBodyReference.Description); Assert.Equal("application/json", _localRequestBodyReference.Content.First().Key); var externalContent = _externalRequestBodyReference.Content.Values.FirstOrDefault(); Assert.NotNull(externalContent); - Assert.Equal("#/components/schemas/UserSchema", externalContent.Schema.GetRef().OriginalString); + Assert.Equal("UserSchema", externalContent.Schema.Reference.Id); Assert.Equal("External Reference: User request body", _externalRequestBodyReference.Description); Assert.Equal("User creation request body", _openApiDoc_2.Components.RequestBodies.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs index 42d0532e7..4b6b25564 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiResponseReferenceTest.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; @@ -94,12 +93,12 @@ public void ResponseReferenceResolutionWorks() // Assert var localContent = _localResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", localContent.Key); - Assert.Equal("#/components/schemas/Pong", localContent.Value.Schema.GetRef().OriginalString); + Assert.Equal("Pong", localContent.Value.Schema.Reference.Id); Assert.Equal("OK response", _localResponseReference.Description); var externalContent = _externalResponseReference.Content.FirstOrDefault(); Assert.Equal("text/plain", externalContent.Key); - Assert.Equal("#/components/schemas/Pong", externalContent.Value.Schema.GetRef().OriginalString); + Assert.Equal("Pong", externalContent.Value.Schema.Reference.Id); Assert.Equal("External reference: OK response", _externalResponseReference.Description); Assert.Equal("OK", _openApiDoc_2.Components.Responses.First().Value.Description); diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index d9397a933..958466da2 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -1,15 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; -using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -25,7 +23,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() { Required = true, Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new OpenApiSchema + { + Type = "string" + } }; // Act @@ -58,42 +59,43 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() var header = new OpenApiHeader { Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Build()) - .Build(), + Schema = new OpenApiSchema + { + Type = "object", + AdditionalProperties = new OpenApiSchema + { + Type = "integer" + } + }, Examples = + { + ["example0"] = new() { - ["example0"] = new() - { - Value = new OpenApiAny("1"), - }, - ["example1"] = new() - { - Value = new OpenApiAny(new JsonObject() - { - ["x"] = 2, - ["y"] = "20", - ["z"] = "200" - }) - }, - ["example2"] = new() + Value = new OpenApiAny("1"), + }, + ["example1"] = new() + { + Value = new OpenApiAny(new JsonObject() { - Value =new OpenApiAny( - new JsonArray(){3}) - }, - ["example3"] = new() + ["x"] = 2, + ["y"] = "20", + ["z"] = "200" + }) + }, + ["example2"] = new() + { + Value =new OpenApiAny( + new JsonArray(){3}) + }, + ["example3"] = new() + { + Value = new OpenApiAny(new JsonObject() { - Value = new OpenApiAny(new JsonObject() - { - ["x"] = 4, - ["y"] = 40 - }) - }, - } + ["x"] = 4, + ["y"] = 40 + }) + }, + } }; // Act diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index a9ef6ec25..be6e86194 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -1,11 +1,10 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -23,7 +22,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build(), + Schema = new() + { + Type = "string", + } }; // Act @@ -55,11 +57,14 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() var mediaType = new OpenApiMediaType { - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Build()) - .Build(), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer", + } + }, Examples = { ["example0"] = new() diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 3f7a2d20c..5048e1040 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -1,20 +1,16 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. -using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; -using Microsoft.OpenApi.Validations.Rules; using Xunit; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace Microsoft.OpenApi.Validations.Tests { @@ -75,7 +71,10 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() In = ParameterLocation.Path, Required = true, Example = new OpenApiAny(55), - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new() + { + Type = "string", + } }; // Act @@ -110,13 +109,14 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties( - new JsonSchemaBuilder() - .Type(SchemaValueType.Integer) - .Build()) - .Build(), + Schema = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "integer", + } + }, Examples = { ["example0"] = new() @@ -187,7 +187,10 @@ public void PathParameterNotInThePathShouldReturnAnError() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string", + } }; // Act @@ -222,7 +225,10 @@ public void PathParameterInThePathShouldBeOk() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String) + Schema = new() + { + Type = "string", + } }; // Act diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs index e011d80ee..f41009fbc 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiReferenceValidationTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Json.Schema; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Validations; @@ -19,12 +18,20 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() { // Arrange - var sharedSchema = new JsonSchemaBuilder().Type(SchemaValueType.String).Ref("test"); + var sharedSchema = new OpenApiSchema + { + Type = "string", + Reference = new() + { + Id = "test" + }, + UnresolvedReference = false + }; var document = new OpenApiDocument(); document.Components = new() { - Schemas = new Dictionary() + Schemas = new Dictionary() { ["test"] = sharedSchema } @@ -59,8 +66,8 @@ public void ReferencedSchemaShouldOnlyBeValidatedOnce() // Act var rules = new Dictionary>() { - { typeof(JsonSchema), - new List() { new AlwaysFailRule() } + { typeof(OpenApiSchema), + new List() { new AlwaysFailRule() } } }; @@ -76,7 +83,15 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() { // Arrange - var sharedSchema = new JsonSchemaBuilder().Type(SchemaValueType.String).Ref("test").Build(); + var sharedSchema = new OpenApiSchema + { + Type = "string", + Reference = new() + { + Id = "test" + }, + UnresolvedReference = true + }; var document = new OpenApiDocument(); @@ -109,8 +124,8 @@ public void UnresolvedSchemaReferencedShouldNotBeValidated() // Act var rules = new Dictionary>() { - { typeof(JsonSchema), - new List() { new AlwaysFailRule() } + { typeof(OpenApiSchema), + new List() { new AlwaysFailRule() } } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index b5491c40c..a7a026a4b 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -6,8 +6,6 @@ using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; -using Json.Schema.OpenApi; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; @@ -26,7 +24,11 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder().Default(new OpenApiAny(55).Node).Type(SchemaValueType.String); + var schema = new OpenApiSchema + { + Default = new OpenApiAny(55), + Type = "string", + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -53,12 +55,13 @@ public void ValidateExampleAndDefaultShouldNotHaveDataTypeMismatchForSimpleSchem { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Default(new OpenApiAny("1234").Node) - .Type(SchemaValueType.String) - .Example(new OpenApiAny(55).Node) - .Build(); - + var schema = new OpenApiSchema + { + Example = new OpenApiAny(55), + Default = new OpenApiAny("1234"), + Type = "string", + }; + // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); var walker = new OpenApiWalker(validator); @@ -85,8 +88,10 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Enum( + var schema = new OpenApiSchema() + { + Enum = + { new OpenApiAny("1").Node, new OpenApiAny(new JsonObject() { @@ -99,10 +104,14 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() { ["x"] = 4, ["y"] = 40, - }).Node) - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Integer).Build()) - .Build(); + }).Node + }, + Type = "object", + AdditionalProperties = new() + { + Type = "integer" + } + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -135,32 +144,43 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() { // Arrange IEnumerable warnings; - var schema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties( - ("property1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Integer).Format("int64").Build()).Build()), - ("property2", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Items(new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .AdditionalProperties(new JsonSchemaBuilder().Type(SchemaValueType.Boolean).Build()) - .Build()) - .Build()), - ("property3", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Format("password") - .Build()), - ("property4", - new JsonSchemaBuilder() - .Type(SchemaValueType.String) - .Build())) - .Default(new JsonObject() + var schema = new OpenApiSchema + { + Type = "object", + Properties = + { + ["property1"] = new() + { + Type = "array", + Items = new() + { + Type = "integer", + Format = "int64" + } + }, + ["property2"] = new() + { + Type = "array", + Items = new() + { + Type = "object", + AdditionalProperties = new() + { + Type = "boolean" + } + } + }, + ["property3"] = new() + { + Type = "string", + Format = "password" + }, + ["property4"] = new() + { + Type = "string" + } + }, + Default = new OpenApiAny(new JsonObject() { ["property1"] = new JsonArray() { @@ -180,7 +200,8 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() }, ["property3"] = "123", ["property4"] = DateTime.UtcNow.ToString() - }).Build(); + }) + }; // Act var validator = new OpenApiValidator(ValidationRuleSet.GetDefaultRuleSet()); @@ -215,11 +236,12 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD Schemas = { { "schema1", - new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Discriminator(new OpenApiDiscriminator() { PropertyName = "property1" }) - .Ref("schema1") - .Build() + new OpenApiSchema + { + Type = "object", + Discriminator = new() { PropertyName = "property1" }, + Reference = new() { Id = "schema1" } + } } } }; @@ -235,7 +257,7 @@ public void ValidateSchemaRequiredFieldListMustContainThePropertySpecifiedInTheD result.Should().BeFalse(); errors.Should().BeEquivalentTo(new List { - new OpenApiValidatorError(nameof(JsonSchemaRules.ValidateSchemaDiscriminator),"#/schemas/schema1/discriminator", + new OpenApiValidatorError(nameof(OpenApiSchemaRules.ValidateSchemaDiscriminator),"#/schemas/schema1/discriminator", string.Format(SRResource.Validation_SchemaRequiredFieldListMustContainThePropertySpecifiedInTheDiscriminator, "schema1", "property1")) }); @@ -251,17 +273,36 @@ public void ValidateOneOfSchemaPropertyNameContainsPropertySpecifiedInTheDiscrim { { "Person", - new JsonSchemaBuilder() - .Type(SchemaValueType.Array) - .Discriminator(new OpenApiDiscriminator - { - PropertyName = "type" - }) - .OneOf(new JsonSchemaBuilder() - .Properties(("type", new JsonSchemaBuilder().Type(SchemaValueType.Array).Ref("Person").Build())) - .Build()) - .Ref("Person") - .Build() + new OpenApiSchema + { + Type = "array", + Discriminator = new() + { + PropertyName = "type" + }, + OneOf = new List + { + new() + { + Properties = + { + { + "type", + new OpenApiSchema + { + Type = "array" + } + } + }, + Reference = new() + { + Type = ReferenceType.Schema, + Id = "Person" + } + } + }, + Reference = new() { Id = "Person" } + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs index 208fd357c..e805d4673 100644 --- a/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Visitors/InheritanceTests.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; @@ -43,7 +42,7 @@ public void ExpectedVirtualsInvolved() visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiComponents)); visitor.Visit(default(OpenApiExternalDocs)); - // visitor.Visit(default(JsonSchema)); + visitor.Visit(default(OpenApiSchema)); visitor.Visit(default(IDictionary)); visitor.Visit(default(OpenApiLink)); visitor.Visit(default(OpenApiCallback)); @@ -232,10 +231,10 @@ public override void Visit(OpenApiExternalDocs externalDocs) base.Visit(externalDocs); } - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { EncodeCall(); - base.Visit(ref schema); + base.Visit(schema); } public override void Visit(IDictionary links) diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 7878aaa4b..4df416d43 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; @@ -82,7 +81,10 @@ public void LocatePathOperationContentSchema() { ["application/json"] = new() { - Schema = new JsonSchemaBuilder().Type(SchemaValueType.String).Build() + Schema = new OpenApiSchema + { + Type = "string" + } } } } @@ -116,18 +118,23 @@ public void LocatePathOperationContentSchema() [Fact] public void WalkDOMWithCycles() { - var loopySchema = new JsonSchemaBuilder() - .Type(SchemaValueType.Object) - .Properties(("name", new JsonSchemaBuilder().Type(SchemaValueType.String))); + var loopySchema = new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["name"] = new() { Type = "string" } + } + }; - loopySchema.Properties(("parent", loopySchema)); + loopySchema.Properties.Add("parent", loopySchema); var doc = new OpenApiDocument { Paths = new(), Components = new() { - Schemas = new Dictionary + Schemas = new Dictionary { ["loopy"] = loopySchema } @@ -155,10 +162,26 @@ public void WalkDOMWithCycles() [Fact] public void LocateReferences() { + var baseSchema = new OpenApiSchema + { + Reference = new() + { + Id = "base", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; - var baseSchema = new JsonSchemaBuilder().Ref("base").Build(); - - var derivedSchema = new JsonSchemaBuilder().AnyOf(baseSchema).Ref("derived").Build(); + var derivedSchema = new OpenApiSchema + { + AnyOf = new List { baseSchema }, + Reference = new() + { + Id = "derived", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; var testHeader = new OpenApiHeader() { Schema = derivedSchema, @@ -203,7 +226,7 @@ public void LocateReferences() }, Components = new() { - Schemas = new Dictionary() + Schemas = new Dictionary { ["derived"] = derivedSchema, ["base"] = baseSchema, @@ -297,15 +320,9 @@ public override void Visit(OpenApiMediaType mediaType) Locations.Add(this.PathString); } - public override void Visit(IBaseDocument document) - { - var schema = document as JsonSchema; - VisitJsonSchema(schema); - } - - public override void Visit(ref JsonSchema schema) + public override void Visit(OpenApiSchema schema) { - VisitJsonSchema(schema); + Locations.Add(this.PathString); } public override void Visit(IList openApiTags) @@ -322,17 +339,5 @@ public override void Visit(OpenApiServer server) { Locations.Add(this.PathString); } - - private void VisitJsonSchema(JsonSchema schema) - { - if (schema.GetRef() != null) - { - Locations.Add("referenceAt: " + this.PathString); - } - else - { - Locations.Add(this.PathString); - } - } } } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs index 41ef76960..e015da4f4 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Collections.Generic; -using Json.Schema; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -20,7 +19,7 @@ public class OpenApiReferencableTests private static readonly OpenApiLink _linkFragment = new(); private static readonly OpenApiHeader _headerFragment = new() { - Schema = new JsonSchemaBuilder().Build(), + Schema = new OpenApiSchema(), Examples = new Dictionary { { "example1", new OpenApiExample() } @@ -28,7 +27,7 @@ public class OpenApiReferencableTests }; private static readonly OpenApiParameter _parameterFragment = new() { - Schema = new JsonSchemaBuilder().Build(), + Schema = new OpenApiSchema(), Examples = new Dictionary { { "example1", new OpenApiExample() } @@ -46,7 +45,7 @@ public class OpenApiReferencableTests { "link1", new OpenApiLink() } } }; - private static readonly JsonSchema _schemaFragment = new JsonSchemaBuilder().Build(); + private static readonly OpenApiSchema _schemaFragment = new OpenApiSchema(); private static readonly OpenApiSecurityScheme _securitySchemeFragment = new OpenApiSecurityScheme(); private static readonly OpenApiTag _tagFragment = new OpenApiTag(); diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs index f3afe2ac1..c2b956feb 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiWorkspaceTests.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using Json.Schema; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Xunit; @@ -33,7 +33,14 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() { ["application/json"] = new OpenApiMediaType() { - Schema = new JsonSchemaBuilder().Ref("test").Build() + Schema = new() + { + Reference = new() + { + Id = "test", + Type = ReferenceType.Schema + } + } } } } @@ -49,7 +56,11 @@ public void OpenApiWorkspacesCanAddComponentsFromAnotherDocument() Components = new OpenApiComponents() { Schemas = { - ["test"] = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("The referenced one").Build() + ["test"] = new() + { + Type = "string", + Description = "The referenced one" + } } } }; @@ -66,12 +77,12 @@ public void OpenApiWorkspacesCanResolveExternalReferences() var workspace = new OpenApiWorkspace(); var externalDoc = CreateCommonDocument(); - workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]); + workspace.RegisterComponent("https://everything.json/common#/components/schemas/test", externalDoc.Components.Schemas["test"]); - var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test"); + var schema = workspace.ResolveReference("https://everything.json/common#/components/schemas/test"); Assert.NotNull(schema); - Assert.Equal("The referenced one", schema.GetDescription()); + Assert.Equal("The referenced one", schema.Description); } [Fact] @@ -79,15 +90,19 @@ public void OpenApiWorkspacesCanResolveReferencesToDocumentFragments() { // Arrange var workspace = new OpenApiWorkspace(); - var schemaFragment = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("Schema from a fragment").Build(); - workspace.RegisterComponent("common#/components/schemas/test", schemaFragment); + var schemaFragment = new OpenApiSchema() + { + Type = "string", + Description = "Schema from a fragment" + }; + workspace.RegisterComponent("common#/components/schemas/test", schemaFragment); // Act - var schema = workspace.ResolveReference("common#/components/schemas/test"); + var schema = workspace.ResolveReference("common#/components/schemas/test"); // Assert Assert.NotNull(schema); - Assert.Equal("Schema from a fragment", schema.GetDescription()); + Assert.Equal("Schema from a fragment", schema.Description); } [Fact] @@ -119,8 +134,13 @@ private static OpenApiDocument CreateCommonDocument() { Components = new() { - Schemas = { - ["test"] = new JsonSchemaBuilder().Type(SchemaValueType.String).Description("The referenced one").Build() + Schemas = + { + ["test"] = new() + { + Type = "string", + Description = "The referenced one" + } } } }; diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs index 11b429300..a967c43a0 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs @@ -8,8 +8,8 @@ using System.IO; using System.Linq; using System.Text; +using System.Text.Json.Nodes; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; @@ -21,15 +21,14 @@ namespace Microsoft.OpenApi.Tests.Writers [Collection("DefaultSettings")] public class OpenApiJsonWriterTests { - static bool[] shouldProduceTerseOutputValues = new[] { true, false }; + static bool[] shouldProduceTerseOutputValues = [true, false]; public static IEnumerable WriteStringListAsJsonShouldMatchExpectedTestCases() { return from input in new[] { - new[] - { + [ "string1", "string2", "string3", @@ -38,7 +37,7 @@ from input in new[] "string6", "string7", "string8" - }, + ], new[] {"string1", "string1", "string1", "string1"} } from shouldBeTerse in shouldProduceTerseOutputValues @@ -274,12 +273,20 @@ public void WriteDateTimeAsJsonShouldMatchExpected(DateTimeOffset dateTimeOffset public void OpenApiJsonWriterOutputsValidJsonValueWhenSchemaHasNanOrInfinityValues() { // Arrange - var schema = new JsonSchemaBuilder().Enum("NaN", "Infinity", "-Infinity"); + var schema = new OpenApiSchema + { + Enum = new List + { + new OpenApiAny("NaN").Node, + new OpenApiAny("Infinity").Node, + new OpenApiAny("-Infinity").Node + } + }; // Act var schemaBuilder = new StringBuilder(); var jsonWriter = new OpenApiJsonWriter(new StringWriter(schemaBuilder)); - jsonWriter.WriteJsonSchema(schema, OpenApiSpecVersion.OpenApi3_0); + schema.SerializeAsV3(jsonWriter); var jsonString = schemaBuilder.ToString(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index ea5442402..56b8fd83c 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -7,7 +7,6 @@ using System.Globalization; using System.IO; using FluentAssertions; -using Json.Schema; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Writers; using Xunit; @@ -440,8 +439,16 @@ public void WriteInlineSchemaV2() private static OpenApiDocument CreateDocWithSimpleSchemaToInline() { // Arrange - - var thingSchema = new JsonSchemaBuilder().Type(SchemaValueType.Object).Ref("#/components/schemas/thing").Build(); + var thingSchema = new OpenApiSchema + { + Type = "object", + UnresolvedReference = false, + Reference = new() + { + Id = "thing", + Type = ReferenceType.Schema + } + }; var doc = new OpenApiDocument() { From 883aba1ab0950360f61c6f0972b616862c3a371e Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 19:22:56 +0300 Subject: [PATCH 23/44] Create a proxy object for resolving referenced schemas --- .../References/OpenApiSchemaReference.cs | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs new file mode 100644 index 000000000..502fba095 --- /dev/null +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Writers; +using System; +using System.Collections.Generic; +using System.Text.Json.Nodes; + +namespace Microsoft.OpenApi.Models.References +{ + /// + /// Schema reference object + /// + public class OpenApiSchemaReference : OpenApiSchema + { + internal OpenApiSchema _target; + private readonly OpenApiReference _reference; + private string _description; + + private OpenApiSchema Target + { + get + { + _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); + OpenApiSchema resolved = new OpenApiSchema(_target); + if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; + return resolved; + } + } + + /// + /// Constructor initializing the reference object. + /// + /// The reference Id. + /// The host OpenAPI document. + /// Optional: External resource in the reference. + /// It may be: + /// 1. a absolute/relative file path, for example: ../commons/pet.json + /// 2. a Url, for example: http://localhost/pet.json + /// + public OpenApiSchemaReference(string referenceId, OpenApiDocument hostDocument, string externalResource = null) + { + if (string.IsNullOrEmpty(referenceId)) + { + Utils.CheckArgumentNullOrEmpty(referenceId); + } + + _reference = new OpenApiReference() + { + Id = referenceId, + HostDocument = hostDocument, + Type = ReferenceType.Schema, + ExternalResource = externalResource + }; + + Reference = _reference; + } + + internal OpenApiSchemaReference(OpenApiSchema target, string referenceId) + { + _target = target; + + _reference = new OpenApiReference() + { + Id = referenceId, + Type = ReferenceType.Schema, + }; + } + + /// + public override string Title { get => Target.Title; set => Target.Title = value; } + /// + public override string Schema { get => Target.Schema; set => Target.Schema = value; } + /// + public override string Id { get => Target.Id; set => Target.Id = value; } + /// + public override string Comment { get => Target.Comment; set => Target.Comment = value; } + /// + public override string Vocabulary { get => Target.Vocabulary; set => Target.Vocabulary = value; } + /// + public override string DynamicRef { get => Target.DynamicRef; set => Target.DynamicRef = value; } + /// + public override string DynamicAnchor { get => Target.DynamicAnchor; set => Target.DynamicAnchor = value; } + /// + public override string RecursiveAnchor { get => Target.RecursiveAnchor; set => Target.RecursiveAnchor = value; } + /// + public override string RecursiveRef { get => Target.RecursiveRef; set => Target.RecursiveRef = value; } + /// + public override IDictionary Definitions { get => Target.Definitions; set => Target.Definitions = value; } + /// + public override decimal? V31ExclusiveMaximum { get => Target.V31ExclusiveMaximum; set => Target.V31ExclusiveMaximum = value; } + /// + public override decimal? V31ExclusiveMinimum { get => Target.V31ExclusiveMinimum; set => Target.V31ExclusiveMinimum = value; } + /// + public override bool UnEvaluatedProperties { get => Target.UnEvaluatedProperties; set => Target.UnEvaluatedProperties = value; } + /// + public override object Type { get => Target.Type; set => Target.Type = value; } + /// + public override string Format { get => Target.Format; set => Target.Format = value; } + /// + public override string Description { get => Target.Description; set => Target.Description = value; } + /// + public override decimal? Maximum { get => Target.Maximum; set => Target.Maximum = value; } + /// + public override bool? ExclusiveMaximum { get => Target.ExclusiveMaximum; set => Target.ExclusiveMaximum = value; } + /// + public override decimal? Minimum { get => Target.Minimum; set => Target.Minimum = value; } + /// + public override bool? ExclusiveMinimum { get => Target.ExclusiveMinimum; set => Target.ExclusiveMinimum = value; } + /// + public override int? MaxLength { get => Target.MaxLength; set => Target.MaxLength = value; } + /// + public override int? MinLength { get => Target.MinLength; set => Target.MinLength = value; } + /// + public override string Pattern { get => Target.Pattern; set => Target.Pattern = value; } + /// + public override decimal? MultipleOf { get => Target.MultipleOf; set => Target.MultipleOf = value; } + /// + public override OpenApiAny Default { get => Target.Default; set => Target.Default = value; } + /// + public override bool ReadOnly { get => Target.ReadOnly; set => Target.ReadOnly = value; } + /// + public override bool WriteOnly { get => Target.WriteOnly; set => Target.WriteOnly = value; } + /// + public override IList AllOf { get => Target.AllOf; set => Target.AllOf = value; } + /// + public override IList OneOf { get => Target.OneOf; set => Target.OneOf = value; } + /// + public override IList AnyOf { get => Target.AnyOf; set => Target.AnyOf = value; } + /// + public override OpenApiSchema Not { get => Target.Not; set => Target.Not = value; } + /// + public override ISet Required { get => Target.Required; set => Target.Required = value; } + /// + public override OpenApiSchema Items { get => Target.Items; set => Target.Items = value; } + /// + public override int? MaxItems { get => Target.MaxItems; set => Target.MaxItems = value; } + /// + public override int? MinItems { get => Target.MinItems; set => Target.MinItems = value; } + /// + public override bool? UniqueItems { get => Target.UniqueItems; set => Target.UniqueItems = value; } + /// + public override IDictionary Properties { get => Target.Properties; set => Target.Properties = value; } + /// + public override IDictionary PatternProperties { get => Target.PatternProperties; set => Target.PatternProperties = value; } + /// + public override int? MaxProperties { get => Target.MaxProperties; set => Target.MaxProperties = value; } + /// + public override int? MinProperties { get => Target.MinProperties; set => Target.MinProperties = value; } + /// + public override bool AdditionalPropertiesAllowed { get => Target.AdditionalPropertiesAllowed; set => Target.AdditionalPropertiesAllowed = value; } + /// + public override OpenApiSchema AdditionalProperties { get => Target.AdditionalProperties; set => Target.AdditionalProperties = value; } + /// + public override OpenApiDiscriminator Discriminator { get => Target.Discriminator; set => Target.Discriminator = value; } + /// + public override OpenApiAny Example { get => Target.Example; set => Target.Example = value; } + /// + public override IList Examples { get => Target.Examples; set => Target.Examples = value; } + /// + public override IList Enum { get => Target.Enum; set => Target.Enum = value; } + /// + public override bool Nullable { get => Target.Nullable; set => Target.Nullable = value; } + /// + public override bool UnevaluatedProperties { get => Target.UnevaluatedProperties; set => Target.UnevaluatedProperties = value; } + /// + public override OpenApiExternalDocs ExternalDocs { get => Target.ExternalDocs; set => Target.ExternalDocs = value; } + /// + public override bool Deprecated { get => Target.Deprecated; set => Target.Deprecated = value; } + /// + public override OpenApiXml Xml { get => Target.Xml; set => Target.Xml = value; } + /// + public override IDictionary Extensions { get => Target.Extensions; set => Target.Extensions = value; } + + /// + public override void SerializeAsV31(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV31(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + } + } + + /// + public override void SerializeAsV3(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV3(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + } + } + + /// + public override void SerializeAsV2(IOpenApiWriter writer) + { + if (!writer.GetSettings().ShouldInlineReference(_reference)) + { + _reference.SerializeAsV2(writer); + return; + } + else + { + SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + } + } + + /// + private void SerializeInternal(IOpenApiWriter writer, + Action action) + { + Utils.CheckArgumentNull(writer); + action(writer, Target); + } + } +} From d79beeff76d4d7e83c300db7b88d06e336d9688e Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 13 Aug 2024 19:23:36 +0300 Subject: [PATCH 24/44] Mark all properties as virtual to be overriden in the proxy class --- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index c6f6f25ee..e19705065 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -19,128 +19,128 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// /// Follow JSON Schema definition. Short text providing information about the data. /// - public string Title { get; set; } + public virtual string Title { get; set; } /// /// $schema, a JSON Schema dialect identifier. Value must be a URI /// - public string Schema { get; set; } + public virtual string Schema { get; set; } /// /// $id - Identifies a schema resource with its canonical URI. /// - public string Id { get; set; } + public virtual string Id { get; set; } /// /// $comment - reserves a location for comments from schema authors to readers or maintainers of the schema. /// - public string Comment { get; set; } + public virtual string Comment { get; set; } /// /// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema. /// - public string Vocabulary { get; set; } + public virtual string Vocabulary { get; set; } /// /// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance /// - public string DynamicRef { get; set; } + public virtual string DynamicRef { get; set; } /// /// $dynamicAnchor - used to create plain name fragments that are not tied to any particular structural location for referencing purposes, which are taken into consideration for dynamic referencing. /// - public string DynamicAnchor { get; set; } + public virtual string DynamicAnchor { get; set; } /// /// $recursiveAnchor - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#") /// - public string RecursiveAnchor { get; set; } + public virtual string RecursiveAnchor { get; set; } /// /// $recursiveRef - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#") /// - public string RecursiveRef { get; set; } + public virtual string RecursiveRef { get; set; } /// /// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema. /// The keyword does not directly affect the validation result /// - public IDictionary Definitions { get; set; } + public virtual IDictionary Definitions { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? V31ExclusiveMaximum { get; set; } + public virtual decimal? V31ExclusiveMaximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? V31ExclusiveMinimum { get; set; } + public virtual decimal? V31ExclusiveMinimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool UnEvaluatedProperties { get; set; } + public virtual bool UnEvaluatedProperties { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value MUST be a string in V2 and V3. /// - public object Type { get; set; } + public virtual object Type { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// While relying on JSON Schema's defined formats, /// the OAS offers a few additional predefined formats. /// - public string Format { get; set; } + public virtual string Format { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// CommonMark syntax MAY be used for rich text representation. /// - public string Description { get; set; } + public virtual string Description { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? Maximum { get; set; } + public virtual decimal? Maximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? ExclusiveMaximum { get; set; } + public virtual bool? ExclusiveMaximum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? Minimum { get; set; } + public virtual decimal? Minimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? ExclusiveMinimum { get; set; } + public virtual bool? ExclusiveMinimum { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxLength { get; set; } + public virtual int? MaxLength { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinLength { get; set; } + public virtual int? MinLength { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// This string SHOULD be a valid regular expression, according to the ECMA 262 regular expression dialect /// - public string Pattern { get; set; } + public virtual string Pattern { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public decimal? MultipleOf { get; set; } + public virtual decimal? MultipleOf { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 @@ -148,7 +148,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. /// For example, if type is string, then default can be "foo" but cannot be 1. /// - public OpenApiAny Default { get; set; } + public virtual OpenApiAny Default { get; set; } /// /// Relevant only for Schema "properties" definitions. Declares the property as "read only". @@ -158,7 +158,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// A property MUST NOT be marked as both readOnly and writeOnly being true. /// Default value is false. /// - public bool ReadOnly { get; set; } + public virtual bool ReadOnly { get; set; } /// /// Relevant only for Schema "properties" definitions. Declares the property as "write only". @@ -168,64 +168,64 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// A property MUST NOT be marked as both readOnly and writeOnly being true. /// Default value is false. /// - public bool WriteOnly { get; set; } + public virtual bool WriteOnly { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList AllOf { get; set; } = new List(); + public virtual IList AllOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList OneOf { get; set; } = new List(); + public virtual IList OneOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public IList AnyOf { get; set; } = new List(); + public virtual IList AnyOf { get; set; } = new List(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema. /// - public OpenApiSchema Not { get; set; } + public virtual OpenApiSchema Not { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public ISet Required { get; set; } = new HashSet(); + public virtual ISet Required { get; set; } = new HashSet(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value MUST be an object and not an array. Inline or referenced schema MUST be of a Schema Object /// and not a standard JSON Schema. items MUST be present if the type is array. /// - public OpenApiSchema Items { get; set; } + public virtual OpenApiSchema Items { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxItems { get; set; } + public virtual int? MaxItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinItems { get; set; } + public virtual int? MinItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool? UniqueItems { get; set; } + public virtual bool? UniqueItems { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced). /// - public IDictionary Properties { get; set; } = new Dictionary(); + public virtual IDictionary Properties { get; set; } = new Dictionary(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 @@ -234,96 +234,96 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// egular expression dialect. Each property value of this object MUST be an object, and each object MUST /// be a valid Schema Object not a standard JSON Schema. /// - public IDictionary PatternProperties { get; set; } = new Dictionary(); + public virtual IDictionary PatternProperties { get; set; } = new Dictionary(); /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MaxProperties { get; set; } + public virtual int? MaxProperties { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public int? MinProperties { get; set; } + public virtual int? MinProperties { get; set; } /// /// Indicates if the schema can contain properties other than those defined by the properties map. /// - public bool AdditionalPropertiesAllowed { get; set; } = true; + public virtual bool AdditionalPropertiesAllowed { get; set; } = true; /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// Value can be boolean or object. Inline or referenced schema /// MUST be of a Schema Object and not a standard JSON Schema. /// - public OpenApiSchema AdditionalProperties { get; set; } + public virtual OpenApiSchema AdditionalProperties { get; set; } /// /// Adds support for polymorphism. The discriminator is an object name that is used to differentiate /// between other schemas which may satisfy the payload description. /// - public OpenApiDiscriminator Discriminator { get; set; } + public virtual OpenApiDiscriminator Discriminator { get; set; } /// /// A free-form property to include an example of an instance for this schema. /// To represent examples that cannot be naturally represented in JSON or YAML, /// a string value can be used to contain the example with escaping where necessary. /// - public OpenApiAny Example { get; set; } + public virtual OpenApiAny Example { get; set; } /// /// A free-form property to include examples of an instance for this schema. /// To represent examples that cannot be naturally represented in JSON or YAML, /// a list of values can be used to contain the examples with escaping where necessary. /// - public IList Examples { get; set; } + public virtual IList Examples { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public IList Enum { get; set; } = new List(); + public virtual IList Enum { get; set; } = new List(); /// /// Allows sending a null value for the defined schema. Default value is false. /// - public bool Nullable { get; set; } + public virtual bool Nullable { get; set; } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// - public bool UnevaluatedProperties { get; set;} + public virtual bool UnevaluatedProperties { get; set;} /// /// Additional external documentation for this schema. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public virtual OpenApiExternalDocs ExternalDocs { get; set; } /// /// Specifies that a schema is deprecated and SHOULD be transitioned out of usage. /// Default value is false. /// - public bool Deprecated { get; set; } + public virtual bool Deprecated { get; set; } /// /// This MAY be used only on properties schemas. It has no effect on root schemas. /// Adds additional metadata to describe the XML representation of this property. /// - public OpenApiXml Xml { get; set; } + public virtual OpenApiXml Xml { get; set; } /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public virtual IDictionary Extensions { get; set; } = new Dictionary(); /// /// Indicates object is a placeholder reference to an actual object and does not contain valid data. /// - public bool UnresolvedReference { get; set; } + public virtual bool UnresolvedReference { get; set; } /// /// Reference object. /// - public OpenApiReference Reference { get; set; } + public virtual OpenApiReference Reference { get; set; } /// /// Parameterless constructor @@ -586,7 +586,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) /// - public void SerializeAsV2(IOpenApiWriter writer) + public virtual void SerializeAsV2(IOpenApiWriter writer) { SerializeAsV2(writer: writer, parentRequiredProperties: new HashSet(), propertyName: null); } From b79e37463a49f5741991f013f5aa9bfd97745d41 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:34:36 +0300 Subject: [PATCH 25/44] Return schema proxy reference if reference pointer exists --- .../Models/References/OpenApiSchemaReference.cs | 8 ++++++-- .../Reader/V2/OpenApiSchemaDeserializer.cs | 4 +++- .../Reader/V3/OpenApiSchemaDeserializer.cs | 8 +++----- .../Reader/V31/OpenApiSchemaDeserializer.cs | 8 +++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 502fba095..bbd2c1af7 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Any; @@ -100,7 +100,11 @@ internal OpenApiSchemaReference(OpenApiSchema target, string referenceId) /// public override string Format { get => Target.Format; set => Target.Format = value; } /// - public override string Description { get => Target.Description; set => Target.Description = value; } + public override string Description + { + get => string.IsNullOrEmpty(_description) ? Target.Description : _description; + set => _description = value; + } /// public override decimal? Maximum { get => Target.Maximum; set => Target.Maximum = value; } /// diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 96ed771f1..66c45c641 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -6,6 +6,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Reader.ParseNodes; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Reader.V2 { @@ -162,7 +163,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum var pointer = mapNode.GetReferencePointer(); if (pointer != null) { - return mapNode.GetReferencedObject(ReferenceType.Schema, pointer); + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index bacd72e4c..2dd2e4f6a 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using System.Collections.Generic; using System.Globalization; @@ -181,11 +182,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum if (pointer != null) { - return new() - { - UnresolvedReference = true, - Reference = node.Context.VersionService.ConvertToOpenApiReference(pointer, ReferenceType.Schema) - }; + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index 9d27d811d..f8d197170 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -3,6 +3,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader.ParseNodes; using System.Collections.Generic; using System.Globalization; @@ -230,11 +231,8 @@ public static OpenApiSchema LoadSchema(ParseNode node, OpenApiDocument hostDocum if (pointer != null) { - return new() - { - UnresolvedReference = true, - Reference = node.Context.VersionService.ConvertToOpenApiReference(pointer, ReferenceType.Schema) - }; + var reference = GetReferenceIdAndExternalResource(pointer); + return new OpenApiSchemaReference(reference.Item1, hostDocument, reference.Item2); } var schema = new OpenApiSchema(); From ca19f45d4ecad56b8050ba5d1fe3e5f0d9926995 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:35:33 +0300 Subject: [PATCH 26/44] code cleanup --- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 10 +--------- src/Microsoft.OpenApi/Models/OpenApiParameter.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs | 10 ---------- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 2 +- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index aa060baf9..ab82061ad 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -464,14 +464,6 @@ internal T ResolveReferenceTo(OpenApiReference reference) where T : class, IO } } - /// - /// Load the referenced object from a object - /// - public IOpenApiReferenceable ResolveReference(OpenApiReference reference) - { - return ResolveReference(reference, false); - } - /// /// Takes in an OpenApi document instance and generates its hash value /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index a169f786c..69f6201a2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -327,7 +327,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) } // In V2 parameter's type can't be a reference to a custom object schema or can't be of type object // So in that case map the type as string. - else if (Schema?.UnresolvedReference == true || "object".Equals(Schema?.Type.ToString(), StringComparison.OrdinalIgnoreCase)) + else if (Schema?.UnresolvedReference == true || "object".Equals(Schema?.Type?.ToString(), StringComparison.OrdinalIgnoreCase)) { writer.WriteProperty(OpenApiConstants.Type, "string"); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index 11b1af6be..e937ad565 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -92,16 +92,6 @@ private void SerializeInternal(IOpenApiWriter writer, Action - /// Returns an effective OpenApiRequestBody object based on the presence of a $ref - /// - /// The host OpenApiDocument that contains the reference. - /// OpenApiRequestBody - public OpenApiRequestBody GetEffective(OpenApiDocument doc) - { - return Reference != null ? doc.ResolveReferenceTo(Reference) : this; - } - /// /// Serialize to OpenAPI V31 document without using reference. /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index e19705065..d2cf23506 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -495,7 +495,7 @@ public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpec writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); // type - if (Type.GetType() == typeof(string)) + if (Type?.GetType() == typeof(string)) { writer.WriteProperty(OpenApiConstants.Type, (string)Type); } From eb0cc246b421cb1f9992fc4058e5b6a6b0106add Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Mon, 19 Aug 2024 16:37:18 +0300 Subject: [PATCH 27/44] Refactor validation logic for examples --- .../Validations/Rules/RuleHelpers.cs | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index a2ac63a6e..471c79d5c 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -4,6 +4,7 @@ using System; using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; namespace Microsoft.OpenApi.Validations.Rules @@ -41,28 +42,28 @@ public static bool IsEmailAddress(this string input) } public static void ValidateDataTypeMismatch( - IValidationContext context, - string ruleName, - JsonNode value, - OpenApiSchema schema) + IValidationContext context, + string ruleName, + JsonNode value, + OpenApiSchema schema) { if (schema == null) { return; } - var type = schema.Type.ToString(); + // convert value to JsonElement and access the ValueKind property to determine the type. + var jsonElement = JsonDocument.Parse(JsonSerializer.Serialize(value)).RootElement; + + var type = (string)schema.Type; var format = schema.Format; var nullable = schema.Nullable; - // convert JsonNode to JsonElement - JsonElement element = value.GetValue(); - // Before checking the type, check first if the schema allows null. // If so and the data given is also null, this is allowed for any type. if (nullable) { - if (element.ValueKind is JsonValueKind.Null) + if (jsonElement.ValueKind is JsonValueKind.Null) { return; } @@ -73,13 +74,13 @@ public static void ValidateDataTypeMismatch( // It is not against the spec to have a string representing an object value. // To represent examples of media types that cannot naturally be represented in JSON or YAML, // a string value can contain the example with escaping where necessary - if (element.ValueKind is JsonValueKind.String) + if (jsonElement.ValueKind is JsonValueKind.String) { return; } // If value is not a string and also not an object, there is a data mismatch. - if (element.ValueKind is not JsonValueKind.Object) + if (value is not JsonObject anyObject) { context.CreateWarning( ruleName, @@ -87,12 +88,9 @@ public static void ValidateDataTypeMismatch( return; } - // Else, cast element to object - var anyObject = value.AsObject(); - foreach (var kvp in anyObject) { - string key = kvp.Key; + var key = kvp.Key; context.Enter(key); if (schema.Properties != null && @@ -116,13 +114,13 @@ public static void ValidateDataTypeMismatch( // It is not against the spec to have a string representing an array value. // To represent examples of media types that cannot naturally be represented in JSON or YAML, // a string value can contain the example with escaping where necessary - if (element.ValueKind is JsonValueKind.String) + if (jsonElement.ValueKind is JsonValueKind.String) { return; } // If value is not a string and also not an array, there is a data mismatch. - if (element.ValueKind is not JsonValueKind.Array) + if (value is not JsonArray anyArray) { context.CreateWarning( ruleName, @@ -130,9 +128,6 @@ public static void ValidateDataTypeMismatch( return; } - // Else, cast element to array - var anyArray = value.AsArray(); - for (var i = 0; i < anyArray.Count; i++) { context.Enter(i.ToString()); @@ -147,7 +142,7 @@ public static void ValidateDataTypeMismatch( if (type == "integer" && format == "int32") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -159,7 +154,7 @@ public static void ValidateDataTypeMismatch( if (type == "integer" && format == "int64") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -169,16 +164,21 @@ public static void ValidateDataTypeMismatch( return; } - if (type == "integer" && element.ValueKind is not JsonValueKind.Number) + if (type == "integer" && jsonElement.ValueKind is not JsonValueKind.Number) { - context.CreateWarning( - ruleName, - DataTypeMismatchedErrorMessage); + if (jsonElement.ValueKind is not JsonValueKind.Number) + { + context.CreateWarning( + ruleName, + DataTypeMismatchedErrorMessage); + } + + return; } if (type == "number" && format == "float") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -190,7 +190,7 @@ public static void ValidateDataTypeMismatch( if (type == "number" && format == "double") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -202,7 +202,7 @@ public static void ValidateDataTypeMismatch( if (type == "number") { - if (element.ValueKind is not JsonValueKind.Number) + if (jsonElement.ValueKind is not JsonValueKind.Number) { context.CreateWarning( ruleName, @@ -214,7 +214,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "byte") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -226,7 +226,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "date") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -238,7 +238,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "date-time") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -250,7 +250,7 @@ public static void ValidateDataTypeMismatch( if (type == "string" && format == "password") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -262,7 +262,7 @@ public static void ValidateDataTypeMismatch( if (type == "string") { - if (element.ValueKind is not JsonValueKind.String) + if (jsonElement.ValueKind is not JsonValueKind.String) { context.CreateWarning( ruleName, @@ -274,7 +274,7 @@ public static void ValidateDataTypeMismatch( if (type == "boolean") { - if (element.ValueKind is not JsonValueKind.True || element.ValueKind is not JsonValueKind.True) + if (jsonElement.ValueKind is not JsonValueKind.True && jsonElement.ValueKind is not JsonValueKind.False) { context.CreateWarning( ruleName, From 919c8695d23dd7dae2f9ee16118791096ecfc48f Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:07:24 +0300 Subject: [PATCH 28/44] code cleanup --- .../Models/References/OpenApiSchemaReference.cs | 4 ++-- .../Reader/V2/OpenApiOperationDeserializer.cs | 3 +++ .../Services/OpenApiComponentsRegistryExtensions.cs | 4 +--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index bbd2c1af7..665120d2c 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using Microsoft.OpenApi.Any; @@ -23,7 +23,7 @@ private OpenApiSchema Target { get { - _target ??= Reference.HostDocument.ResolveReferenceTo(_reference); + _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); OpenApiSchema resolved = new OpenApiSchema(_target); if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; return resolved; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index a2faa5810..67e6ecca5 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -173,6 +173,9 @@ private static OpenApiRequestBody CreateFormBody(ParsingContext context, List mediaType) }; + foreach (var value in formBody.Content.Values.Where(static x => x.Schema is not null && x.Schema.Properties.Any() && string.IsNullOrEmpty((string)x.Schema.Type))) + value.Schema.Type = "object"; + return formBody; } diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 8be8318e3..9a5b62d37 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -24,9 +24,7 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo } else { - location = version == OpenApiSpecVersion.OpenApi2_0 - ? document.BaseUri + "/" + OpenApiConstants.Definitions + "/" + item.Key - : baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; + location = baseUri + ReferenceType.Schema.GetDisplayName() + "/" + item.Key; } workspace.RegisterComponent(location, item.Value); From f9f01b75f1d7970391f9567caf951d8e15bd3e42 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:10:03 +0300 Subject: [PATCH 29/44] Fix failing tests --- .../V2Tests/OpenApiDocumentTests.cs | 141 ++--------- .../V2Tests/OpenApiHeaderTests.cs | 7 +- .../V2Tests/OpenApiParameterTests.cs | 36 +-- .../V2Tests/OpenApiSchemaTests.cs | 12 +- .../V31Tests/OpenApiDocumentTests.cs | 57 +---- .../V31Tests/OpenApiSchemaTests.cs | 8 +- .../V3Tests/OpenApiDocumentTests.cs | 97 ++------ .../V3Tests/OpenApiSchemaTests.cs | 190 +++------------ .../advancedSchemaWithReference.yaml | 16 +- .../Models/OpenApiComponentsTests.cs | 121 ++++------ ...orks_produceTerseOutput=False.verified.txt | 30 +-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 197 +++++++++++++-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 227 ++++++++++++++++-- ...Works_produceTerseOutput=True.verified.txt | 2 +- ...orks_produceTerseOutput=False.verified.txt | 2 +- ...Works_produceTerseOutput=True.verified.txt | 2 +- .../Models/OpenApiDocumentTests.cs | 34 +-- .../Models/OpenApiOperationTests.cs | 16 +- .../Models/OpenApiParameterTests.cs | 2 +- .../Models/OpenApiResponseTests.cs | 20 +- .../OpenApiHeaderValidationTests.cs | 17 +- .../OpenApiMediaTypeValidationTests.cs | 19 +- .../OpenApiParameterValidationTests.cs | 17 +- .../OpenApiSchemaValidationTests.cs | 38 +-- .../Walkers/WalkerLocationTests.cs | 17 +- 27 files changed, 658 insertions(+), 671 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index f369e5028..8af3f1f3c 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -7,9 +7,10 @@ using System.Linq; using System.Threading; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Xunit; @@ -24,59 +25,6 @@ public OpenApiDocumentTests() OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); } - [Fact] - public void ShouldThrowWhenReferenceTypeIsInvalid() - { - var input = - """ - swagger: 2.0 - info: - title: test - version: 1.0.0 - paths: - '/': - get: - responses: - '200': - description: ok - schema: - $ref: '#/defi888nition/does/notexist' - """; - - var result = OpenApiDocument.Parse(input, "yaml"); - - result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { - new( new OpenApiException("Unknown reference type 'defi888nition'")) }); - result.OpenApiDocument.Should().NotBeNull(); - } - - [Fact] - public void ShouldThrowWhenReferenceDoesNotExist() - { - var input = - """ - swagger: 2.0 - info: - title: test - version: 1.0.0 - paths: - '/': - get: - produces: ['application/json'] - responses: - '200': - description: ok - schema: - $ref: '#/definitions/doesnotexist' - """; - - var result = OpenApiDocument.Parse(input, "yaml"); - - result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List { - new( new OpenApiException("Invalid Reference identifier 'doesnotexist'.")) }); - result.OpenApiDocument.Should().NotBeNull(); - } - [Theory] [InlineData("en-US")] [InlineData("hi-IN")] @@ -138,20 +86,26 @@ public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) ExclusiveMaximum = true, ExclusiveMinimum = false } - }, - Reference = new() - { - Id = "sampleSchema", - Type = ReferenceType.Schema } } } }, Paths = new() - }); + }, options => options + .Excluding(x=> x.BaseUri) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent")) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Root"))); result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic { SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 }); + new OpenApiDiagnostic { + SpecificationVersion = OpenApiSpecVersion.OpenApi2_0, + Errors = new List() + { + new OpenApiError("", "Paths is a REQUIRED field at #/") + } + }); } [Fact] @@ -161,12 +115,6 @@ public void ShouldParseProducesInAnyOrder() var okSchema = new OpenApiSchema { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Item", - HostDocument = result.OpenApiDocument - }, Properties = new Dictionary { { "id", new OpenApiSchema @@ -180,12 +128,6 @@ public void ShouldParseProducesInAnyOrder() var errorSchema = new OpenApiSchema { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Error", - HostDocument = result.OpenApiDocument - }, Properties = new Dictionary { { "code", new OpenApiSchema @@ -212,13 +154,13 @@ public void ShouldParseProducesInAnyOrder() Schema = new() { Type = "array", - Items = okSchema + Items = new OpenApiSchemaReference("Item", result.OpenApiDocument) } }; var errorMediaType = new OpenApiMediaType { - Schema = errorSchema + Schema = new OpenApiSchemaReference("Error", result.OpenApiDocument) }; result.OpenApiDocument.Should().BeEquivalentTo(new OpenApiDocument @@ -322,7 +264,7 @@ public void ShouldParseProducesInAnyOrder() ["Error"] = errorSchema } } - }); + }, options => options.Excluding(x => x.BaseUri)); } [Fact] @@ -336,51 +278,10 @@ public void ShouldAssignSchemaToAllResponses() var successSchema = new OpenApiSchema { Type = "array", - Items = new() - { - Properties = { - { "id", new OpenApiSchema - { - Type = "string", - Description = "Item identifier." - } - } - }, - Reference = new() - { - Id = "Item", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument - } - } - }; - var errorSchema = new OpenApiSchema - { - Properties = { - { "code", new OpenApiSchema - { - Type = "integer", - Format = "int32" - } - }, - { "message", new OpenApiSchema - { - Type = "string" - } - }, - { "fields", new OpenApiSchema - { - Type = "string" - } - } - }, - Reference = new() - { - Id = "Error", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument - } + Items = new OpenApiSchemaReference("Item", result.OpenApiDocument) }; + var errorSchema = new OpenApiSchemaReference("Error", result.OpenApiDocument); + var responses = result.OpenApiDocument.Paths["/items"].Operations[OperationType.Get].Responses; foreach (var response in responses) { diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index 14bbdfc32..a78bd1180 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -3,6 +3,7 @@ using System.IO; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -41,7 +42,8 @@ public void ParseHeaderWithDefaultShouldSucceed() } }, options => options - .IgnoringCyclicReferences()); + .IgnoringCyclicReferences() + .Excluding(x => x.Schema.Default.Node.Parent)); } [Fact] @@ -73,7 +75,8 @@ public void ParseHeaderWithEnumShouldSucceed() } } }, options => options.IgnoringCyclicReferences() - ); + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 7ccbc1c8b..9324c5132 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -3,6 +3,7 @@ using System.IO; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader.ParseNodes; @@ -232,7 +233,7 @@ public void ParseParameterWithDefaultShouldSucceed() Format = "float", Default = new OpenApiAny(5) } - }, options => options.IgnoringCyclicReferences()); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Schema.Default.Node.Parent)); } [Fact] @@ -247,27 +248,30 @@ public void ParseParameterWithEnumShouldSucceed() // Act var parameter = OpenApiV2Deserializer.LoadParameter(node); - - // Assert - parameter.Should().BeEquivalentTo( - new OpenApiParameter + var expected = new OpenApiParameter + { + In = ParameterLocation.Path, + Name = "username", + Description = "username to fetch", + Required = true, + Schema = new() { - In = ParameterLocation.Path, - Name = "username", - Description = "username to fetch", - Required = true, - Schema = new() - { - Type = "number", - Format = "float", - Enum = + Type = "number", + Format = "float", + Enum = { new OpenApiAny(7).Node, new OpenApiAny(8).Node, new OpenApiAny(9).Node } - } - }, options => options.IgnoringCyclicReferences()); + } + }; + + // Assert + parameter.Should().BeEquivalentTo(expected, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index d827f62ee..a9b646040 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Any; using System.Text.Json.Nodes; using System.Collections.Generic; +using FluentAssertions.Equivalency; namespace Microsoft.OpenApi.Readers.Tests.V2Tests { @@ -37,7 +38,7 @@ public void ParseSchemaWithDefaultShouldSucceed() Type = "number", Format = "float", Default = new OpenApiAny(5) - }); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Default.Node.Parent)); } [Fact] @@ -60,7 +61,7 @@ public void ParseSchemaWithExampleShouldSucceed() Type = "number", Format = "float", Example = new OpenApiAny(5) - }); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Example.Node.Parent)); } [Fact] @@ -88,8 +89,11 @@ public void ParseSchemaWithEnumShouldSucceed() new OpenApiAny(9).Node } }; - schema.Should().BeEquivalentTo(expected, - options => options.IgnoringCyclicReferences()); + + schema.Should().BeEquivalentTo(expected, options => + options.IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 66b00c9f7..6f6ed0faa 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -5,6 +5,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Writers; @@ -43,24 +44,10 @@ public static T Clone(T element) where T : IOpenApiSerializable public void ParseDocumentWithWebhooksShouldSucceed() { // Arrange and Act - var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); - var petSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "petSchema" - } - }; + var actual = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "documentWithWebhooks.yaml")); + var petSchema = new OpenApiSchemaReference("petSchema", actual.OpenApiDocument); - var newPetSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "newPetSchema" - } - }; + var newPetSchema = new OpenApiSchemaReference("newPetSchema", actual.OpenApiDocument); var components = new OpenApiComponents { @@ -113,12 +100,6 @@ public void ParseDocumentWithWebhooksShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } } } @@ -295,35 +276,15 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } } } }; // Create a clone of the schema to avoid modifying things in components. - var petSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "petSchema" - } - }; + var petSchema = new OpenApiSchemaReference("petSchema", actual.OpenApiDocument); - var newPetSchema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "newPetSchema" - } - }; + var newPetSchema = new OpenApiSchemaReference("newPetSchema", actual.OpenApiDocument); components.PathItems = new Dictionary { @@ -502,6 +463,9 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() var mediaType = result.OpenApiDocument.Paths["/example"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; var expectedMediaType = @"schema: + patternProperties: + ^x-.*$: + type: string type: object properties: prop1: @@ -509,9 +473,6 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() prop2: type: string prop3: - type: string - patternProperties: - ^x-.*$: type: string"; var actualMediaType = mediaType.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index ae83a3abe..a534d3dd1 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; +using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; @@ -170,7 +171,7 @@ public void ParseV31SchemaShouldSucceed() }; // Assert - Assert.Equal(schema, expectedSchema); + schema.Should().BeEquivalentTo(expectedSchema); } [Fact] @@ -262,7 +263,10 @@ public void ParseAdvancedV31SchemaShouldSucceed() }; // Assert - schema.Should().BeEquivalentTo(expectedSchema); + schema.Should().BeEquivalentTo(expectedSchema, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent"))); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 0d3bb622f..bd72ff78a 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Tests; using Microsoft.OpenApi.Validations; @@ -213,7 +214,7 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Schemas = new Dictionary { - ["pet"] = new() + ["pet1"] = new() { Type = "object", Required = new HashSet @@ -236,12 +237,6 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "pet", - HostDocument = actual.OpenApiDocument } }, ["newPet"] = new() @@ -266,12 +261,6 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } }, ["errorModel"] = new() @@ -293,44 +282,15 @@ public void ParseStandardPetStoreDocumentShouldSucceed() { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "errorModel", - HostDocument = actual.OpenApiDocument } }, } }; - // Create a clone of the schema to avoid modifying things in components. - var petSchema = Clone(components.Schemas["pet"]); - - petSchema.Reference = new() - { - Id = "pet", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; - - var newPetSchema = Clone(components.Schemas["newPet"]); - - newPetSchema.Reference = new() - { - Id = "newPet", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; - - var errorModelSchema = Clone(components.Schemas["errorModel"]); + var petSchema = new OpenApiSchemaReference("pet1", actual.OpenApiDocument); + var newPetSchema = new OpenApiSchemaReference("newPet", actual.OpenApiDocument); - errorModelSchema.Reference = new() - { - Id = "errorModel", - Type = ReferenceType.Schema, - HostDocument = actual.OpenApiDocument - }; + var errorModelSchema = new OpenApiSchemaReference("errorModel", actual.OpenApiDocument); var expectedDoc = new OpenApiDocument { @@ -640,7 +600,7 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Schemas = new Dictionary { - ["pet"] = new() + ["pet1"] = new() { Type = "object", Required = new HashSet @@ -663,12 +623,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "pet", - HostDocument = actual.OpenApiDocument } }, ["newPet"] = new() @@ -693,12 +647,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" }, - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "newPet", - HostDocument = actual.OpenApiDocument } }, ["errorModel"] = new() @@ -720,11 +668,6 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "errorModel" } }, }, @@ -745,11 +688,12 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() }; // Create a clone of the schema to avoid modifying things in components. - var petSchema = Clone(components.Schemas["pet"]); + var petSchema = Clone(components.Schemas["pet1"]); petSchema.Reference = new() { - Id = "pet", - Type = ReferenceType.Schema + Id = "pet1", + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var newPetSchema = Clone(components.Schemas["newPet"]); @@ -757,7 +701,8 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() newPetSchema.Reference = new() { Id = "newPet", - Type = ReferenceType.Schema + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var errorModelSchema = Clone(components.Schemas["errorModel"]); @@ -765,7 +710,8 @@ public void ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() errorModelSchema.Reference = new() { Id = "errorModel", - Type = ReferenceType.Schema + Type = ReferenceType.Schema, + HostDocument = actual.OpenApiDocument }; var tag1 = new OpenApiTag @@ -1272,15 +1218,7 @@ public void ParseDocumentWithJsonSchemaReferencesWorks() var actualSchema = result.OpenApiDocument.Paths["/users/{userId}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; - var expectedSchema = new OpenApiSchema() - { - Reference = new OpenApiReference - { - Id = "User", - Type = ReferenceType.Schema - } - }; - + var expectedSchema = new OpenApiSchemaReference("User", result.OpenApiDocument); // Assert actualSchema.Should().BeEquivalentTo(expectedSchema); } @@ -1399,7 +1337,10 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() var expectedParam = expected.Paths["/pets"].Operations[OperationType.Get].Parameters.First(); // Assert - actualParam.Should().BeEquivalentTo(expectedParam, options => options.Excluding(x => x.Reference.HostDocument)); + actualParam.Should().BeEquivalentTo(expectedParam, options => options + .Excluding(x => x.Reference.HostDocument) + .Excluding(x => x.Schema.Default.Node.Parent) + .IgnoringCyclicReferences()); outputDoc.Should().BeEquivalentTo(expectedSerializedDoc.MakeLineBreaksEnvironmentNeutral()); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 4d3055668..52e879aca 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -14,6 +14,8 @@ using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Reader.ParseNodes; using Microsoft.OpenApi.Reader.V3; +using FluentAssertions.Equivalency; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Readers.Tests.V3Tests { @@ -177,30 +179,29 @@ public void ParseDictionarySchemaShouldSucceed() [Fact] public void ParseBasicSchemaWithExampleShouldSucceed() { - using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml"))) - { - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; + using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "basicSchemaWithExample.yaml")); + var yamlStream = new YamlStream(); + yamlStream.Load(new StreamReader(stream)); + var yamlNode = yamlStream.Documents.First().RootNode; - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); + var diagnostic = new OpenApiDiagnostic(); + var context = new ParsingContext(diagnostic); - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); + var asJsonNode = yamlNode.ToJsonNode(); + var node = new MapNode(context, asJsonNode); - // Act - var schema = OpenApiV3Deserializer.LoadSchema(node); + // Act + var schema = OpenApiV3Deserializer.LoadSchema(node); - // Assert - diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); + // Assert + diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); - schema.Should().BeEquivalentTo( - new OpenApiSchema + schema.Should().BeEquivalentTo( + new OpenApiSchema + { + Type = "object", + Properties = { - Type = "object", - Properties = - { ["id"] = new() { Type = "integer", @@ -210,18 +211,22 @@ public void ParseBasicSchemaWithExampleShouldSucceed() { Type = "string" } - }, - Required = - { + }, + Required = + { "name" - }, - Example = new OpenApiAny(new JsonObject - { - ["name"] = new OpenApiAny("Puma").Node, - ["id"] = new OpenApiAny(1).Node - }) - }); - } + }, + Example = new OpenApiAny(new JsonObject + { + ["name"] = new OpenApiAny("Puma").Node, + ["id"] = new OpenApiAny(1).Node + }) + }, options => options + .IgnoringCyclicReferences() + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Parent")) + .Excluding((IMemberInfo memberInfo) => + memberInfo.Path.EndsWith("Root"))); } [Fact] @@ -263,12 +268,6 @@ public void ParseBasicSchemaWithReferenceShouldSucceed() Type = "string" } }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ErrorModel", - HostDocument = result.OpenApiDocument - }, Required = { "message", @@ -277,44 +276,9 @@ public void ParseBasicSchemaWithReferenceShouldSucceed() }, ["ExtendedErrorModel"] = new() { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ExtendedErrorModel", - HostDocument = result.OpenApiDocument - }, AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "ErrorModel", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the ErrorModel above should be propagated here. - Type = "object", - Properties = - { - ["code"] = new() - { - Type = "integer", - Minimum = 100, - Maximum = 600 - }, - ["message"] = new() - { - Type = "string" - } - }, - Required = - { - "message", - "code" - } - }, + new OpenApiSchemaReference("ErrorModel", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -367,12 +331,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() { "name", "petType" - }, - Reference = new() - { - Id= "Pet", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } }, ["Cat"] = new() @@ -380,38 +338,7 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Description = "A representation of a cat", AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Pet", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the Pet above should be propagated here. - Type = "object", - Discriminator = new() - { - PropertyName = "petType" - }, - Properties = - { - ["name"] = new() - { - Type = "string" - }, - ["petType"] = new() - { - Type = "string" - } - }, - Required = - { - "name", - "petType" - } - }, + new OpenApiSchemaReference("Pet", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -432,12 +359,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() } } } - }, - Reference = new() - { - Id= "Cat", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } }, ["Dog"] = new() @@ -445,38 +366,7 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Description = "A representation of a dog", AllOf = { - new OpenApiSchema - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "Pet", - HostDocument = result.OpenApiDocument - }, - // Schema should be dereferenced in our model, so all the properties - // from the Pet above should be propagated here. - Type = "object", - Discriminator = new() - { - PropertyName = "petType" - }, - Properties = - { - ["name"] = new() - { - Type = "string" - }, - ["petType"] = new() - { - Type = "string" - } - }, - Required = - { - "name", - "petType" - } - }, + new OpenApiSchemaReference("Pet", result.OpenApiDocument), new OpenApiSchema { Type = "object", @@ -493,12 +383,6 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() } } } - }, - Reference = new() - { - Id= "Dog", - Type = ReferenceType.Schema, - HostDocument = result.OpenApiDocument } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml index 170958591..3d9f0343b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiSchema/advancedSchemaWithReference.yaml @@ -1,5 +1,3 @@ -# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject -# Add required properties in the Open API document object to avoid errors openapi: 3.0.0 info: title: Simple Document @@ -7,9 +5,7 @@ info: paths: { } components: schemas: - ## Naming this schema Pet1 to disambiguate it from another schema `pet` contained in other test files. - ## SchemaRegistry.Global.Register() is global and can only register 1 schema with the same name. - Pet1: + Pet: type: object discriminator: propertyName: petType @@ -21,10 +17,10 @@ components: required: - name - petType - Cat: ## "Cat" will be used as the discriminator value + Cat: description: A representation of a cat allOf: - - $ref: '#/components/schemas/Pet1' + - $ref: '#/components/schemas/Pet' - type: object properties: huntingSkill: @@ -37,10 +33,10 @@ components: - aggressive required: - huntingSkill - Dog: ## "Dog" will be used as the discriminator value + Dog: description: A representation of a dog allOf: - - $ref: '#/components/schemas/Pet1' + - $ref: '#/components/schemas/Pet' - type: object properties: packSize: @@ -50,4 +46,4 @@ components: default: 0 minimum: 0 required: - - packSize \ No newline at end of file + - packSize diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs index 74ec5a8b9..0f9ace617 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs @@ -6,6 +6,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Xunit; namespace Microsoft.OpenApi.Tests.Models @@ -74,19 +75,7 @@ public class OpenApiComponentsTests { Type = "integer" }, - ["property3"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" + ["property3"] = new OpenApiSchemaReference("schema2", null) } }, ["schema2"] = new() @@ -173,14 +162,7 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - }, + ["schema1"] = new OpenApiSchemaReference("schema2", null), ["schema2"] = new() { Type = "object", @@ -191,7 +173,7 @@ public class OpenApiComponentsTests Type = "string" } } - }, + } } }; @@ -208,11 +190,6 @@ public class OpenApiComponentsTests { Type = "string" } - }, - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" } }, ["schema2"] = new() @@ -233,14 +210,7 @@ public class OpenApiComponentsTests { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema1" - } - } + ["schema1"] = new OpenApiSchemaReference("schema1", null) } }; @@ -256,14 +226,7 @@ public class OpenApiComponentsTests { Type = "integer" }, - ["property3"] = new OpenApiSchema() - { - Reference = new OpenApiReference() - { - Type = ReferenceType.Schema, - Id = "schema2" - } - } + ["property3"] = new OpenApiSchemaReference("schema2", null) } }, @@ -293,14 +256,7 @@ public class OpenApiComponentsTests { ["application/json"] = new OpenApiMediaType { - Schema = new OpenApiSchema - { - Reference = new OpenApiReference - { - Type = ReferenceType.Schema, - Id = "schema1" - } - } + Schema = new OpenApiSchemaReference("schema1", null) } } }, @@ -314,7 +270,6 @@ public class OpenApiComponentsTests } } } - } }; @@ -543,21 +498,29 @@ public void SerializeAdvancedComponentsWithReferenceAsYamlV3Works() public void SerializeBrokenComponentsAsJsonV3Works() { // Arrange - var expected = @"{ - ""schemas"": { - ""schema1"": { - ""type"": ""string"" - }, - ""schema4"": { - ""type"": ""string"", - ""allOf"": [ - { - ""type"": ""string"" - } - ] - } - } -}"; + var expected = """ + { + "schemas": { + "schema1": { + "type": "string" + }, + "schema2": null, + "schema3": null, + "schema4": { + "type": "string", + "allOf": [ + null, + null, + { + "type": "string" + }, + null, + null + ] + } + } + } + """; // Act var actual = BrokenComponents.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); @@ -572,13 +535,22 @@ public void SerializeBrokenComponentsAsJsonV3Works() public void SerializeBrokenComponentsAsYamlV3Works() { // Arrange - var expected = @"schemas: - schema1: - type: string - schema4: - type: string - allOf: - - type: string"; + var expected = + """ + schemas: + schema1: + type: string + schema2: + schema3: + schema4: + type: string + allOf: + - + - + - type: string + - + - + """; // Act var actual = BrokenComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0); @@ -592,6 +564,7 @@ public void SerializeBrokenComponentsAsYamlV3Works() [Fact] public void SerializeTopLevelReferencingComponentsAsYamlV3Works() { + // Arrange // Arrange var expected = """ diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt index 245cca5ca..46c5b2e30 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -55,11 +55,11 @@ "schema": { "type": "array", "items": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -78,11 +78,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -97,11 +97,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -132,10 +132,10 @@ "description": "Pet to add to the store", "required": true, "schema": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -155,11 +155,11 @@ "200": { "description": "pet response", "schema": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -177,11 +177,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -196,11 +196,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -238,11 +238,11 @@ "200": { "description": "pet response", "schema": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -260,11 +260,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -279,11 +279,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -320,11 +320,11 @@ "4XX": { "description": "unexpected client error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -339,11 +339,11 @@ "5XX": { "description": "unexpected server error", "schema": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", @@ -361,11 +361,11 @@ }, "definitions": { "pet": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -380,10 +380,10 @@ } }, "newPet": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -398,11 +398,11 @@ } }, "errorModel": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt index 8bf9f35bc..0248156d9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt index 06e0f2ca9..46c5b2e30 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -55,20 +55,62 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -90,7 +132,22 @@ "description": "Pet to add to the store", "required": true, "schema": { - "$ref": "#/definitions/newPet" + "type": "object", + "required": [ + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } ], @@ -98,19 +155,61 @@ "200": { "description": "pet response", "schema": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -139,19 +238,61 @@ "200": { "description": "pet response", "schema": { - "$ref": "#/definitions/pet" + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -179,13 +320,39 @@ "4XX": { "description": "unexpected client error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } }, "5XX": { "description": "unexpected server error", "schema": { - "$ref": "#/definitions/errorModel" + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -194,11 +361,11 @@ }, "definitions": { "pet": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -213,10 +380,10 @@ } }, "newPet": { + "type": "object", "required": [ "name" ], - "type": "object", "properties": { "id": { "type": "integer", @@ -231,11 +398,11 @@ } }, "errorModel": { + "type": "object", "required": [ "code", "message" ], - "type": "object", "properties": { "code": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt index ae1db5447..0248156d9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"$ref":"#/definitions/pet"}}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"$ref":"#/definitions/newPet"}}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"$ref":"#/definitions/pet"}},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"$ref":"#/definitions/errorModel"}},"5XX":{"description":"unexpected server error","schema":{"$ref":"#/definitions/errorModel"}}}}}},"definitions":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"query","name":"tags","description":"tags to filter by","type":"array","items":{"type":"string"},"collectionFormat":"multi"},{"in":"query","name":"limit","description":"maximum number of results to return","type":"integer","format":"int32"}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","consumes":["application/json"],"produces":["application/json","text/html"],"parameters":[{"in":"body","name":"body","description":"Pet to add to the store","required":true,"schema":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","produces":["application/json","application/xml","text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to fetch","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"pet response","schema":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","produces":["text/html"],"parameters":[{"in":"path","name":"id","description":"ID of pet to delete","required":true,"type":"integer","format":"int64"}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}},"5XX":{"description":"unexpected server error","schema":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"definitions":{"pet":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"type":"object","required":["name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"type":"object","required":["code","message"],"properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt index f1da0b354..a688f8525 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=False.verified.txt @@ -55,7 +55,23 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, @@ -63,7 +79,23 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -74,7 +106,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -84,7 +129,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -99,7 +157,22 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/newPet" + "required": [ + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } }, @@ -111,7 +184,23 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -121,7 +210,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -131,7 +233,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -161,12 +276,44 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } }, "application/xml": { "schema": { - "$ref": "#/components/schemas/pet" + "required": [ + "id", + "name" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "tag": { + "type": "string" + } + } } } } @@ -176,7 +323,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -186,7 +346,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -217,7 +390,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } @@ -227,7 +413,20 @@ "content": { "text/html": { "schema": { - "$ref": "#/components/schemas/errorModel" + "required": [ + "code", + "message" + ], + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt index be8dcc627..0bb1c9679 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeAdvancedDocumentWithReferenceAsV3JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/newPet"}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} \ No newline at end of file +{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"foo@example.com"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"application/xml":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}},"application/xml":{"schema":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt index 08622d6b1..52c6a3734 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=False.verified.txt @@ -41,11 +41,11 @@ "schema": { "type": "array", "items": { + "type": "object", "required": [ "id", "name" ], - "type": "object", "properties": { "id": { "type": "integer", diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt index 8cecc96a4..d8e55a839 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.SerializeDuplicateExtensionsAsV2JsonWorks_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","produces":["application/json"],"parameters":[{"in":"path","name":"operand1","description":"The first operand","required":true,"type":"integer","my-extension":4},{"in":"path","name":"operand2","description":"The second operand","required":true,"type":"integer","my-extension":4}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"host":"petstore.swagger.io","basePath":"/api","schemes":["http"],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","produces":["application/json"],"parameters":[{"in":"path","name":"operand1","description":"The first operand","required":true,"type":"integer","my-extension":4},{"in":"path","name":"operand2","description":"The second operand","required":true,"type":"integer","my-extension":4}],"responses":{"200":{"description":"pet response","schema":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index 5b95221e3..d0b6f8904 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -11,6 +11,7 @@ using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Writers; @@ -33,14 +34,7 @@ public OpenApiDocumentTests() { Schemas = { - ["schema1"] = new() - { - Reference = new() - { - Type = ReferenceType.Schema, - Id = "schema2" - }, - }, + ["schema1"] = new OpenApiSchemaReference("schema2", null), ["schema2"] = new() { Type = "object", @@ -159,11 +153,6 @@ public OpenApiDocumentTests() { Type = "string" }, - }, - Reference = new() - { - Id = "pet", - Type = ReferenceType.Schema } }, ["newPet"] = new() @@ -188,11 +177,6 @@ public OpenApiDocumentTests() { Type = "string" }, - }, - Reference = new() - { - Id = "newPet", - Type = ReferenceType.Schema } }, ["errorModel"] = new() @@ -214,11 +198,6 @@ public OpenApiDocumentTests() { Type = "string" } - }, - Reference = new() - { - Id = "errorModel", - Type = ReferenceType.Schema } }, } @@ -920,14 +899,7 @@ public OpenApiDocumentTests() { ["application/json"] = new OpenApiMediaType { - Schema = new() - { - Reference = new OpenApiReference - { - Id = "Pet", - Type = ReferenceType.Schema - } - } + Schema = new OpenApiSchemaReference("Pet", null) } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 7c729341d..dc18a1341 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -626,9 +626,9 @@ public void SerializeOperationWithBodyAsV2JsonWorks() "description": "description2", "required": true, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } ], @@ -639,9 +639,9 @@ public void SerializeOperationWithBodyAsV2JsonWorks() "400": { "description": null, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } }, @@ -699,9 +699,9 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() "description": "description2", "required": true, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } ], @@ -712,9 +712,9 @@ public void SerializeAdvancedOperationWithTagAndSecurityAsV2JsonWorks() "400": { "description": null, "schema": { + "type": "number", "maximum": 10, - "minimum": 5, - "type": "number" + "minimum": 5 } } }, diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index 7f3b0b140..f40913dd4 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -110,7 +110,7 @@ public class OpenApiParameterTests In = ParameterLocation.Query, Schema = new() { - Type = "array", + Type = "object", AdditionalProperties = new OpenApiSchema { Type = "integer" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index a07362c32..14a29a907 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -33,10 +33,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary @@ -75,10 +72,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) }, Example = new OpenApiAny("Blabla"), Extensions = new Dictionary @@ -119,10 +113,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) } } }, @@ -158,10 +149,7 @@ public class OpenApiResponseTests Schema = new() { Type = "array", - Items = new() - { - Reference = new() {Type = ReferenceType.Schema, Id = "customType"} - } + Items = new OpenApiSchemaReference("customType", null) } } }, diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index 958466da2..a189a3575 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -42,7 +43,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -110,16 +111,16 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/examples/example0/value", - "#/examples/example1/value", - "#/examples/example1/value", + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/examples/example1/value/y", + "#/examples/example1/value/z", "#/examples/example2/value" }); } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index be6e86194..d735e87d2 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -8,6 +8,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -41,7 +42,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -109,17 +110,17 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/examples/example0/value", - "#/examples/example1/value", - "#/examples/example1/value", - "#/examples/example2/value" + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/examples/example1/value/y", + "#/examples/example1/value/z", + "#/examples/example2/value" }); } } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 5048e1040..197d0dbb7 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Properties; using Microsoft.OpenApi.Services; +using Microsoft.OpenApi.Validations.Rules; using Xunit; namespace Microsoft.OpenApi.Validations.Tests @@ -90,7 +91,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -160,19 +161,17 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { // #enum/0 is not an error since the spec allows // representing an object using a string. - "#/{parameter1}/examples/example0/value", - "#/{parameter1}/examples/example1/value", - "#/{parameter1}/examples/example1/value", - "#/{parameter1}/examples/example2/value" + "#/{parameter1}/examples/example1/value/y", + "#/{parameter1}/examples/example1/value/z", + "#/{parameter1}/examples/example2/value" }); } diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index a7a026a4b..3144955b3 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -42,7 +42,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { @@ -75,11 +75,11 @@ public void ValidateExampleAndDefaultShouldNotHaveDataTypeMismatchForSimpleSchem result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"integer\" but should be \"string\" at " + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/example" + "#/example", }); } @@ -125,16 +125,16 @@ public void ValidateEnumShouldNotHaveDataTypeMismatchForSimpleSchema() result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"object\" at ", - "type : Value is \"string\" but should be \"integer\" at /y", - "type : Value is \"string\" but should be \"integer\" at /z", - "type : Value is \"array\" but should be \"object\" at " + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/enum/0", - "#/enum/1", - "#/enum/1", + // #enum/0 is not an error since the spec allows + // representing an object using a string. + "#/enum/1/y", + "#/enum/1/z", "#/enum/2" }); } @@ -199,7 +199,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() } }, ["property3"] = "123", - ["property4"] = DateTime.UtcNow.ToString() + ["property4"] = DateTime.UtcNow }) }; @@ -209,21 +209,21 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() walker.Walk(schema); warnings = validator.Warnings; - bool result = warnings.Any(); + bool result = !warnings.Any(); // Assert - result.Should().BeTrue(); + result.Should().BeFalse(); warnings.Select(e => e.Message).Should().BeEquivalentTo(new[] { - "type : Value is \"string\" but should be \"integer\" at /property1/2", - "type : Value is \"integer\" but should be \"object\" at /property2/0", - "type : Value is \"string\" but should be \"boolean\" at /property2/1/z", + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage, + RuleHelpers.DataTypeMismatchedErrorMessage }); warnings.Select(e => e.Pointer).Should().BeEquivalentTo(new[] { - "#/default", - "#/default", - "#/default" + "#/default/property1/2", + "#/default/property2/0", + "#/default/property2/1/z" }); } diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index 4df416d43..924364ccd 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -150,8 +150,7 @@ public void WalkDOMWithCycles() "#/paths", "#/components", "#/components/schemas/loopy", - "#/components/schemas/loopy/properties/parent", - "#/components/schemas/loopy/properties/parent/properties/name", + "#/components/schemas/loopy/properties/name", "#/tags" }); } @@ -162,15 +161,7 @@ public void WalkDOMWithCycles() [Fact] public void LocateReferences() { - var baseSchema = new OpenApiSchema - { - Reference = new() - { - Id = "base", - Type = ReferenceType.Schema - }, - UnresolvedReference = false - }; + var baseSchema = new OpenApiSchemaReference("base", null); var derivedSchema = new OpenApiSchema { @@ -249,9 +240,7 @@ public void LocateReferences() locator.Locations.Where(l => l.StartsWith("referenceAt:")).Should().BeEquivalentTo(new List { "referenceAt: #/paths/~1/get/responses/200/content/application~1json/schema", "referenceAt: #/paths/~1/get/responses/200/headers/test-header/schema", - "referenceAt: #/components/schemas/derived", - "referenceAt: #/components/schemas/derived/anyOf", - "referenceAt: #/components/schemas/base", + "referenceAt: #/components/schemas/derived/anyOf/0", "referenceAt: #/components/securitySchemes/test-secScheme", "referenceAt: #/components/headers/test-header/schema" }); From 7fd7ca9052568d1d905bb1d301fd2e8882b85f8d Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 13:10:21 +0300 Subject: [PATCH 30/44] Update public API --- .../PublicApi/PublicApi.approved.txt | 299 ++++++++---------- 1 file changed, 133 insertions(+), 166 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 5d8f06a7c..f15f19bff 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -146,87 +146,12 @@ namespace Microsoft.OpenApi.Expressions } namespace Microsoft.OpenApi.Extensions { - [Json.Schema.SchemaKeyword("additionalPropertiesAllowed")] - public class AdditionalPropertiesAllowedKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "additionalPropertiesAllowed"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("discriminator")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class DiscriminatorKeyword : Microsoft.OpenApi.Models.OpenApiDiscriminator, Json.Schema.IJsonSchemaKeyword - { - public const string Name = "discriminator"; - public DiscriminatorKeyword() { } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("exclusiveMaximum")] - public class Draft4ExclusiveMaximumKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "exclusiveMaximum"; - public bool MaxValue { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("exclusiveMinimum")] - public class Draft4ExclusiveMinimumKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "exclusiveMinimum"; - public bool MinValue { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } public static class EnumExtensions { public static T GetAttributeOfType(this System.Enum enumValue) where T : System.Attribute { } public static string GetDisplayName(this System.Enum enumValue) { } } - [Json.Schema.SchemaKeyword("extensions")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class ExtensionsKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "extensions"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - [Json.Schema.SchemaKeyword("externalDocs")] - public class ExternalDocsKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "externalDocs"; - public ExternalDocsKeyword(Microsoft.OpenApi.Models.OpenApiExternalDocs value) { } - public Microsoft.OpenApi.Models.OpenApiExternalDocs Value { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } - public static class JsonSchemaBuilderExtensions - { - public static Json.Schema.JsonSchemaBuilder AdditionalPropertiesAllowed(this Json.Schema.JsonSchemaBuilder builder, bool additionalPropertiesAllowed) { } - public static Json.Schema.JsonSchemaBuilder Discriminator(this Json.Schema.JsonSchemaBuilder builder, Microsoft.OpenApi.Models.OpenApiDiscriminator discriminator) { } - public static Json.Schema.JsonSchemaBuilder ExclusiveMaximum(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder ExclusiveMinimum(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder Extensions(this Json.Schema.JsonSchemaBuilder builder, System.Collections.Generic.IDictionary extensions) { } - public static Json.Schema.JsonSchemaBuilder Nullable(this Json.Schema.JsonSchemaBuilder builder, bool value) { } - public static Json.Schema.JsonSchemaBuilder OpenApiExternalDocs(this Json.Schema.JsonSchemaBuilder builder, Microsoft.OpenApi.Models.OpenApiExternalDocs externalDocs) { } - public static Json.Schema.JsonSchemaBuilder Remove(this Json.Schema.JsonSchemaBuilder builder, string keyword) { } - public static Json.Schema.JsonSchemaBuilder Summary(this Json.Schema.JsonSchemaBuilder builder, string summary) { } - } - public static class JsonSchemaExtensions - { - public static bool? GetAdditionalPropertiesAllowed(this Json.Schema.JsonSchema schema) { } - public static System.Collections.Generic.IDictionary GetExtensions(this Json.Schema.JsonSchema schema) { } - public static bool? GetNullable(this Json.Schema.JsonSchema schema) { } - public static Microsoft.OpenApi.Extensions.DiscriminatorKeyword GetOpenApiDiscriminator(this Json.Schema.JsonSchema schema) { } - public static bool? GetOpenApiExclusiveMaximum(this Json.Schema.JsonSchema schema) { } - public static bool? GetOpenApiExclusiveMinimum(this Json.Schema.JsonSchema schema) { } - public static Microsoft.OpenApi.Models.OpenApiExternalDocs GetOpenApiExternalDocs(this Json.Schema.JsonSchema schema) { } - public static string GetSummary(this Json.Schema.JsonSchema schema) { } - } - [Json.Schema.SchemaKeyword("nullable")] - [Json.Schema.SchemaSpecVersion(Json.Schema.SpecVersion.Draft202012)] - public class NullableKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "nullable"; - public NullableKeyword(bool value) { } - public bool Value { get; } - public void Evaluate(Json.Schema.EvaluationContext context) { } - } public static class OpenApiElementExtensions { public static System.Collections.Generic.IEnumerable Validate(this Microsoft.OpenApi.Interfaces.IOpenApiElement element, Microsoft.OpenApi.Validations.ValidationRuleSet ruleSet) { } @@ -261,19 +186,13 @@ namespace Microsoft.OpenApi.Extensions } public static class OpenApiTypeMapper { - public static System.Type MapJsonSchemaValueTypeToSimpleType(this Json.Schema.JsonSchema schema) { } - public static Json.Schema.JsonSchema MapTypeToJsonPrimitiveType(this System.Type type) { } + public static System.Type MapOpenApiPrimitiveTypeToSimpleType(this Microsoft.OpenApi.Models.OpenApiSchema schema) { } + public static Microsoft.OpenApi.Models.OpenApiSchema MapTypeToOpenApiPrimitiveType(this System.Type type) { } } public static class StringExtensions { public static T GetEnumFromDisplayName(this string displayName) { } } - [Json.Schema.SchemaKeyword("summary")] - public class SummaryKeyword : Json.Schema.IJsonSchemaKeyword - { - public const string Name = "summary"; - public void Evaluate(Json.Schema.EvaluationContext context) { } - } } namespace Microsoft.OpenApi.Interfaces { @@ -424,7 +343,7 @@ namespace Microsoft.OpenApi.Models { public OpenApiComponents() { } public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents components) { } - public System.Collections.Generic.IDictionary Schemas { get; set; } + public System.Collections.Generic.IDictionary Schemas { get; set; } public virtual System.Collections.Generic.IDictionary Callbacks { get; set; } public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } @@ -615,7 +534,7 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiDocument : Json.Schema.IBaseDocument, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiDocument() { } public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument document) { } @@ -632,9 +551,6 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IList Tags { get; set; } public System.Collections.Generic.IDictionary Webhooks { get; set; } public Microsoft.OpenApi.Services.OpenApiWorkspace Workspace { get; set; } - public Json.Schema.JsonSchema FindSubschema(Json.Pointer.JsonPointer pointer, Json.Schema.EvaluationOptions options) { } - public Json.Schema.JsonSchema ResolveJsonSchemaReference(System.Uri referenceUri) { } - public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -726,7 +642,7 @@ namespace Microsoft.OpenApi.Models public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -792,7 +708,7 @@ namespace Microsoft.OpenApi.Models public Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } public System.Collections.Generic.IDictionary Examples { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -862,7 +778,7 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } public virtual string Name { get; set; } public virtual bool Required { get; set; } - public virtual Json.Schema.JsonSchema Schema { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -926,7 +842,6 @@ namespace Microsoft.OpenApi.Models public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } - public Microsoft.OpenApi.Models.OpenApiRequestBody GetEffective(Microsoft.OpenApi.Models.OpenApiDocument doc) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -961,59 +876,61 @@ namespace Microsoft.OpenApi.Models { public OpenApiSchema() { } public OpenApiSchema(Microsoft.OpenApi.Models.OpenApiSchema schema) { } - public Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } - public bool AdditionalPropertiesAllowed { get; set; } - public System.Collections.Generic.IList AllOf { get; set; } - public System.Collections.Generic.IList AnyOf { get; set; } - public string Comment { get; set; } - public Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } - public System.Collections.Generic.IDictionary Definitions { get; set; } - public bool Deprecated { get; set; } - public string Description { get; set; } - public Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } - public string DynamicAnchor { get; set; } - public string DynamicRef { get; set; } - public System.Collections.Generic.IList Enum { get; set; } - public Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } - public bool? ExclusiveMaximum { get; set; } - public bool? ExclusiveMinimum { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public string Format { get; set; } - public string Id { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } - public int? MaxItems { get; set; } - public int? MaxLength { get; set; } - public int? MaxProperties { get; set; } - public decimal? Maximum { get; set; } - public int? MinItems { get; set; } - public int? MinLength { get; set; } - public int? MinProperties { get; set; } - public decimal? Minimum { get; set; } - public decimal? MultipleOf { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } - public bool Nullable { get; set; } - public System.Collections.Generic.IList OneOf { get; set; } - public string Pattern { get; set; } - public System.Collections.Generic.IDictionary Properties { get; set; } - public bool ReadOnly { get; set; } - public string RecursiveAnchor { get; set; } - public string RecursiveRef { get; set; } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } - public System.Collections.Generic.ISet Required { get; set; } - public string Schema { get; set; } - public string Title { get; set; } - public object Type { get; set; } - public bool UnEvaluatedProperties { get; set; } - public bool UnevaluatedProperties { get; set; } - public bool? UniqueItems { get; set; } - public bool UnresolvedReference { get; set; } - public decimal? V31ExclusiveMaximum { get; set; } - public decimal? V31ExclusiveMinimum { get; set; } - public string Vocabulary { get; set; } - public bool WriteOnly { get; set; } - public Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public virtual Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } + public virtual bool AdditionalPropertiesAllowed { get; set; } + public virtual System.Collections.Generic.IList AllOf { get; set; } + public virtual System.Collections.Generic.IList AnyOf { get; set; } + public virtual string Comment { get; set; } + public virtual Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public virtual System.Collections.Generic.IDictionary Definitions { get; set; } + public virtual bool Deprecated { get; set; } + public virtual string Description { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } + public virtual string DynamicAnchor { get; set; } + public virtual string DynamicRef { get; set; } + public virtual System.Collections.Generic.IList Enum { get; set; } + public virtual Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public virtual System.Collections.Generic.IList Examples { get; set; } + public virtual bool? ExclusiveMaximum { get; set; } + public virtual bool? ExclusiveMinimum { get; set; } + public virtual System.Collections.Generic.IDictionary Extensions { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public virtual string Format { get; set; } + public virtual string Id { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } + public virtual int? MaxItems { get; set; } + public virtual int? MaxLength { get; set; } + public virtual int? MaxProperties { get; set; } + public virtual decimal? Maximum { get; set; } + public virtual int? MinItems { get; set; } + public virtual int? MinLength { get; set; } + public virtual int? MinProperties { get; set; } + public virtual decimal? Minimum { get; set; } + public virtual decimal? MultipleOf { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } + public virtual bool Nullable { get; set; } + public virtual System.Collections.Generic.IList OneOf { get; set; } + public virtual string Pattern { get; set; } + public virtual System.Collections.Generic.IDictionary PatternProperties { get; set; } + public virtual System.Collections.Generic.IDictionary Properties { get; set; } + public virtual bool ReadOnly { get; set; } + public virtual string RecursiveAnchor { get; set; } + public virtual string RecursiveRef { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public virtual System.Collections.Generic.ISet Required { get; set; } + public virtual string Schema { get; set; } + public virtual string Title { get; set; } + public virtual object Type { get; set; } + public virtual bool UnEvaluatedProperties { get; set; } + public virtual bool UnevaluatedProperties { get; set; } + public virtual bool? UniqueItems { get; set; } + public virtual bool UnresolvedReference { get; set; } + public virtual decimal? V31ExclusiveMaximum { get; set; } + public virtual decimal? V31ExclusiveMinimum { get; set; } + public virtual string Vocabulary { get; set; } + public virtual bool WriteOnly { get; set; } + public virtual Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1231,7 +1148,7 @@ namespace Microsoft.OpenApi.Models.References public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override bool Required { get; set; } - public override Json.Schema.JsonSchema Schema { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1265,7 +1182,7 @@ namespace Microsoft.OpenApi.Models.References public override Microsoft.OpenApi.Models.ParameterLocation? In { get; set; } public override string Name { get; set; } public override bool Required { get; set; } - public override Json.Schema.JsonSchema Schema { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } public override Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -1304,6 +1221,65 @@ namespace Microsoft.OpenApi.Models.References public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } + public class OpenApiSchemaReference : Microsoft.OpenApi.Models.OpenApiSchema + { + public OpenApiSchemaReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } + public override Microsoft.OpenApi.Models.OpenApiSchema AdditionalProperties { get; set; } + public override bool AdditionalPropertiesAllowed { get; set; } + public override System.Collections.Generic.IList AllOf { get; set; } + public override System.Collections.Generic.IList AnyOf { get; set; } + public override string Comment { get; set; } + public override Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public override System.Collections.Generic.IDictionary Definitions { get; set; } + public override bool Deprecated { get; set; } + public override string Description { get; set; } + public override Microsoft.OpenApi.Models.OpenApiDiscriminator Discriminator { get; set; } + public override string DynamicAnchor { get; set; } + public override string DynamicRef { get; set; } + public override System.Collections.Generic.IList Enum { get; set; } + public override Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public override System.Collections.Generic.IList Examples { get; set; } + public override bool? ExclusiveMaximum { get; set; } + public override bool? ExclusiveMinimum { get; set; } + public override System.Collections.Generic.IDictionary Extensions { get; set; } + public override Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public override string Format { get; set; } + public override string Id { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Items { get; set; } + public override int? MaxItems { get; set; } + public override int? MaxLength { get; set; } + public override int? MaxProperties { get; set; } + public override decimal? Maximum { get; set; } + public override int? MinItems { get; set; } + public override int? MinLength { get; set; } + public override int? MinProperties { get; set; } + public override decimal? Minimum { get; set; } + public override decimal? MultipleOf { get; set; } + public override Microsoft.OpenApi.Models.OpenApiSchema Not { get; set; } + public override bool Nullable { get; set; } + public override System.Collections.Generic.IList OneOf { get; set; } + public override string Pattern { get; set; } + public override System.Collections.Generic.IDictionary PatternProperties { get; set; } + public override System.Collections.Generic.IDictionary Properties { get; set; } + public override bool ReadOnly { get; set; } + public override string RecursiveAnchor { get; set; } + public override string RecursiveRef { get; set; } + public override System.Collections.Generic.ISet Required { get; set; } + public override string Schema { get; set; } + public override string Title { get; set; } + public override object Type { get; set; } + public override bool UnEvaluatedProperties { get; set; } + public override bool UnevaluatedProperties { get; set; } + public override bool? UniqueItems { get; set; } + public override decimal? V31ExclusiveMaximum { get; set; } + public override decimal? V31ExclusiveMinimum { get; set; } + public override string Vocabulary { get; set; } + public override bool WriteOnly { get; set; } + public override Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } + public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + } public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.Models.OpenApiSecurityScheme { public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument, string externalResource = null) { } @@ -1508,8 +1484,6 @@ namespace Microsoft.OpenApi.Services public string PathString { get; } public virtual void Enter(string segment) { } public virtual void Exit() { } - public virtual void Visit(Json.Schema.IBaseDocument document) { } - public virtual void Visit(ref Json.Schema.JsonSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible openApiExtensible) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension openApiExtension) { } public virtual void Visit(Microsoft.OpenApi.Interfaces.IOpenApiReferenceable referenceable) { } @@ -1533,6 +1507,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody requestBody) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponse response) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiResponses response) { } + public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSchema schema) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement securityRequirement) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme securityScheme) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } @@ -1552,7 +1527,6 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(System.Collections.Generic.IList openApiSecurityRequirements) { } public virtual void Visit(System.Collections.Generic.IList servers) { } public virtual void Visit(System.Collections.Generic.IList openApiTags) { } - public virtual void Visit(System.Collections.Generic.IReadOnlyCollection schema) { } public virtual void Visit(System.Text.Json.Nodes.JsonNode node) { } } public class OpenApiWalker @@ -1607,7 +1581,6 @@ namespace Microsoft.OpenApi.Validations public System.Collections.Generic.IEnumerable Warnings { get; } public void AddError(Microsoft.OpenApi.Validations.OpenApiValidatorError error) { } public void AddWarning(Microsoft.OpenApi.Validations.OpenApiValidatorWarning warning) { } - public override void Visit(ref Json.Schema.JsonSchema item) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtensible item) { } public override void Visit(Microsoft.OpenApi.Interfaces.IOpenApiExtension item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiCallback item) { } @@ -1630,6 +1603,7 @@ namespace Microsoft.OpenApi.Validations public override void Visit(Microsoft.OpenApi.Models.OpenApiRequestBody item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponse item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiResponses item) { } + public override void Visit(Microsoft.OpenApi.Models.OpenApiSchema item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityRequirement item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiSecurityScheme item) { } public override void Visit(Microsoft.OpenApi.Models.OpenApiServer item) { } @@ -1697,14 +1671,6 @@ namespace Microsoft.OpenApi.Validations } namespace Microsoft.OpenApi.Validations.Rules { - [Microsoft.OpenApi.Validations.Rules.OpenApiRule] - public static class JsonSchemaRules - { - public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } - public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } - public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IReadOnlyCollection childSchema) { } - public static bool ValidateChildSchemaAgainstDiscriminator(Json.Schema.JsonSchema schema, string discriminatorName) { } - } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiComponentsRules { @@ -1787,6 +1753,14 @@ namespace Microsoft.OpenApi.Validations.Rules public OpenApiRuleAttribute() { } } [Microsoft.OpenApi.Validations.Rules.OpenApiRule] + public static class OpenApiSchemaRules + { + public static Microsoft.OpenApi.Validations.ValidationRule SchemaMismatchedDataType { get; } + public static Microsoft.OpenApi.Validations.ValidationRule ValidateSchemaDiscriminator { get; } + public static bool TraverseSchemaElements(string discriminatorName, System.Collections.Generic.IList childSchema) { } + public static bool ValidateChildSchemaAgainstDiscriminator(Microsoft.OpenApi.Models.OpenApiSchema schema, string discriminatorName) { } + } + [Microsoft.OpenApi.Validations.Rules.OpenApiRule] public static class OpenApiServerRules { public static Microsoft.OpenApi.Validations.ValidationRule ServerRequiredFields { get; } @@ -1809,9 +1783,6 @@ namespace Microsoft.OpenApi.Writers void Flush(); void WriteEndArray(); void WriteEndObject(); - void WriteJsonSchema(Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version); - void WriteJsonSchemaReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Uri reference, Microsoft.OpenApi.OpenApiSpecVersion version); - void WriteJsonSchemaWithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version); void WriteNull(); void WritePropertyName(string name); void WriteRaw(string value); @@ -1872,9 +1843,6 @@ namespace Microsoft.OpenApi.Writers public abstract void WriteEndArray(); public abstract void WriteEndObject(); public virtual void WriteIndentation() { } - public void WriteJsonSchema(Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version) { } - public void WriteJsonSchemaReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Uri reference, Microsoft.OpenApi.OpenApiSpecVersion version) { } - public void WriteJsonSchemaWithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Json.Schema.JsonSchema schema, Microsoft.OpenApi.OpenApiSpecVersion version) { } public abstract void WriteNull(); public abstract void WritePropertyName(string name); public abstract void WriteRaw(string value); @@ -1897,7 +1865,6 @@ namespace Microsoft.OpenApi.Writers { public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { } public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { } - public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } From c11bf825eb21b943da62c1d1a5aee385f934bdf1 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 14:39:06 +0300 Subject: [PATCH 31/44] Use schema 'id' as a locator for schema registration and performing lookups in the component registry --- .../Models/OpenApiDocument.cs | 19 +++++++++++++------ .../Reader/V31/OpenApiV31Deserializer.cs | 14 +++++++++++--- .../OpenApiComponentsRegistryExtensions.cs | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index ab82061ad..5762223c3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -529,15 +529,22 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool } string uriLocation; - string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id; + if (reference.Id.Contains("/")) // this means its a URL reference + { + uriLocation = reference.Id; + } + else + { + string relativePath = OpenApiConstants.ComponentsSegment + reference.Type.GetDisplayName() + "/" + reference.Id; - uriLocation = useExternal - ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath - : BaseUri + relativePath; + uriLocation = useExternal + ? Workspace.GetDocumentId(reference.ExternalResource)?.OriginalString + relativePath + : BaseUri + relativePath; + } return Workspace.ResolveReference(uriLocation); } - + /// /// Parses a local file path or Url into an Open API document. /// diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index aa38c326d..33eb3e11e 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -147,11 +147,19 @@ private static string LoadString(ParseNode node) private static (string, string) GetReferenceIdAndExternalResource(string pointer) { + /* Check whether the reference pointer is a URL + * (id keyword allows you to supply a URL for the schema as a target for referencing) + * E.g. $ref: 'https://example.com/schemas/resource.json' + * or its a normal json pointer fragment syntax + * E.g. $ref: '#/components/schemas/pet' + */ var refSegments = pointer.Split('/'); - var refId = refSegments.Last(); - var isExternalResource = !refSegments.First().StartsWith("#"); + string refId = !pointer.Contains('#') ? pointer : refSegments.Last(); - string externalResource = isExternalResource ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" : null; + var isExternalResource = !refSegments.First().StartsWith("#"); + string externalResource = isExternalResource + ? $"{refSegments.First()}/{refSegments[1].TrimEnd('#')}" + : null; return (refId, externalResource); } diff --git a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs index 9a5b62d37..226853a13 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiComponentsRegistryExtensions.cs @@ -20,7 +20,7 @@ public static void RegisterComponents(this OpenApiWorkspace workspace, OpenApiDo { if (item.Value.Id != null) { - location = document.BaseUri + item.Value.Id; + location = item.Value.Id; } else { From 33b4a07f7d8f8f8040752fbf1a873a06c1361051 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 20 Aug 2024 14:39:28 +0300 Subject: [PATCH 32/44] Add test to validate --- .../V31Tests/OpenApiDocumentTests.cs | 16 +++++++ .../OpenApiDocument/docWithReferenceById.yaml | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index 6f6ed0faa..b22e428f2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -481,5 +481,21 @@ public void ParseDocumentWithPatternPropertiesInSchemaWorks() actualSchema.Should().BeEquivalentTo(expectedSchema); actualMediaType.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expectedMediaType.MakeLineBreaksEnvironmentNeutral()); } + + [Fact] + public void ParseDocumentWithReferenceByIdGetsResolved() + { + // Arrange and Act + var result = OpenApiDocument.Load(Path.Combine(SampleFolderPath, "docWithReferenceById.yaml")); + + var responseSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema; + var requestBodySchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Post].RequestBody.Content["application/json"].Schema; + var parameterSchema = result.OpenApiDocument.Paths["/resource"].Operations[OperationType.Get].Parameters[0].Schema; + + // Assert + Assert.Equal("object", responseSchema.Type); + Assert.Equal("object", requestBodySchema.Type); + Assert.Equal("string", parameterSchema.Type); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml new file mode 100644 index 000000000..d6c0121e4 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiDocument/docWithReferenceById.yaml @@ -0,0 +1,45 @@ +openapi: 3.1.0 +info: + title: ReferenceById + version: 1.0.0 +paths: + /resource: + get: + parameters: + - name: id + in: query + required: true + schema: + $ref: 'https://example.com/schemas/id.json' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: 'https://example.com/schemas/resource.json' + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: 'https://example.com/schemas/resource.json' + responses: + '200': + description: OK +components: + schemas: + Resource: + $id: 'https://example.com/schemas/resource.json' + type: object + properties: + id: + type: string + name: + type: string + reference: + $ref: '#/components/schemas/Resource' + Id: + $id: 'https://example.com/schemas/id.json' + type: string \ No newline at end of file From cc1439e53ccb9156b26a1e7008bbac1369897217 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 12:28:22 +0300 Subject: [PATCH 33/44] Use JsonNode in place of OpenApiAny for Enums and Examples --- src/Microsoft.OpenApi/Any/OpenApiAny.cs | 2 +- .../Helpers/JsonNodeCloneHelper.cs | 6 +-- .../OpenApiDeprecationExtension.cs | 4 +- .../OpenApiEnumFlagsExtension.cs | 6 +-- .../OpenApiEnumValuesDescriptionExtension.cs | 4 +- .../OpenApiPagingExtension.cs | 4 +- .../OpenApiPrimaryErrorMessageExtension.cs | 4 +- .../OpenApiReservedParameterExtension.cs | 4 +- .../Models/OpenApiExample.cs | 3 +- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 3 +- .../Models/OpenApiMediaType.cs | 3 +- .../Models/OpenApiParameter.cs | 3 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 17 ++++---- .../References/OpenApiExampleReference.cs | 3 +- .../References/OpenApiHeaderReference.cs | 3 +- .../References/OpenApiParameterReference.cs | 3 +- .../References/OpenApiSchemaReference.cs | 4 +- .../Models/RuntimeExpressionAnyWrapper.cs | 4 +- .../Reader/OpenApiReaderSettings.cs | 3 +- .../Reader/ParseNodes/AnyFieldMapParameter.cs | 9 ++-- .../ParseNodes/AnyMapFieldMapParameter.cs | 9 ++-- .../Reader/ParseNodes/ListNode.cs | 6 +-- .../Reader/ParseNodes/MapNode.cs | 4 +- .../Reader/ParseNodes/ParseNode.cs | 2 +- .../Reader/ParseNodes/PropertyNode.cs | 2 +- .../Reader/ParseNodes/ValueNode.cs | 6 +-- .../Reader/ParsingContext.cs | 2 +- .../Reader/V2/OpenApiHeaderDeserializer.cs | 2 +- .../Reader/V2/OpenApiParameterDeserializer.cs | 2 +- .../Reader/V2/OpenApiV2Deserializer.cs | 4 +- .../Reader/V3/OpenApiV3Deserializer.cs | 4 +- .../Reader/V3/OpenApiV3VersionService.cs | 1 + .../Reader/V31/OpenApiV31Deserializer.cs | 4 +- .../Services/OpenApiWalker.cs | 3 +- .../Validations/Rules/OpenApiHeaderRules.cs | 4 +- .../Rules/OpenApiMediaTypeRules.cs | 4 +- .../Rules/OpenApiParameterRules.cs | 4 +- .../Validations/Rules/OpenApiSchemaRules.cs | 4 +- .../Writers/OpenApiWriterAnyExtensions.cs | 11 +++-- .../TestCustomExtension.cs | 2 +- .../V2Tests/OpenApiHeaderTests.cs | 4 +- .../V2Tests/OpenApiOperationTests.cs | 16 +++---- .../V2Tests/OpenApiParameterTests.cs | 4 +- .../V2Tests/OpenApiSchemaTests.cs | 8 ++-- .../V3Tests/OpenApiDocumentTests.cs | 19 +++++---- .../V3Tests/OpenApiExampleTests.cs | 26 ++++++------ .../V3Tests/OpenApiMediaTypeTests.cs | 12 +++--- .../V3Tests/OpenApiParameterTests.cs | 12 +++--- .../V3Tests/OpenApiSchemaTests.cs | 6 +-- .../OpenApiDeprecationExtensionTests.cs | 2 +- .../OpenApiPagingExtensionsTests.cs | 2 +- ...penApiPrimaryErrorMessageExtensionTests.cs | 2 +- .../OpenApiReservedParameterExtensionTests.cs | 2 +- .../Models/OpenApiExampleTests.cs | 8 ++-- .../Models/OpenApiLinkTests.cs | 8 ++-- .../Models/OpenApiMediaTypeTests.cs | 14 +++---- .../Models/OpenApiResponseTests.cs | 6 +-- .../OpenApiExampleReferenceTests.cs | 2 +- .../PublicApi/PublicApi.approved.txt | 42 +++++++++---------- .../OpenApiHeaderValidationTests.cs | 15 ++++--- .../OpenApiMediaTypeValidationTests.cs | 15 ++++--- .../OpenApiParameterValidationTests.cs | 14 +++---- .../OpenApiSchemaValidationTests.cs | 10 ++--- .../OpenApiWriterAnyExtensionsTests.cs | 4 +- 64 files changed, 218 insertions(+), 207 deletions(-) diff --git a/src/Microsoft.OpenApi/Any/OpenApiAny.cs b/src/Microsoft.OpenApi/Any/OpenApiAny.cs index bee1239fb..54bddf326 100644 --- a/src/Microsoft.OpenApi/Any/OpenApiAny.cs +++ b/src/Microsoft.OpenApi/Any/OpenApiAny.cs @@ -35,7 +35,7 @@ public OpenApiAny(JsonNode jsonNode) /// public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) { - writer.WriteAny(new OpenApiAny(Node)); + writer.WriteAny(Node); } } } diff --git a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs index 9f89ddc11..d6e9cb9df 100644 --- a/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs +++ b/src/Microsoft.OpenApi/Helpers/JsonNodeCloneHelper.cs @@ -15,16 +15,16 @@ internal static class JsonNodeCloneHelper ReferenceHandler = ReferenceHandler.IgnoreCycles }; - internal static OpenApiAny Clone(OpenApiAny value) + internal static JsonNode Clone(JsonNode value) { - var jsonString = Serialize(value?.Node); + var jsonString = Serialize(value); if (string.IsNullOrEmpty(jsonString)) { return null; } var result = JsonSerializer.Deserialize(jsonString, options); - return new OpenApiAny(result); + return result; } private static string Serialize(object obj) diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs index b2ffa1fe4..a5bae9fa9 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiDeprecationExtension.cs @@ -77,9 +77,9 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// The source object. /// The . /// When the source element is not an object - public static OpenApiDeprecationExtension Parse(OpenApiAny source) + public static OpenApiDeprecationExtension Parse(JsonNode source) { - if (source.Node is not JsonObject rawObject) return null; + if (source is not JsonObject rawObject) return null; var extension = new OpenApiDeprecationExtension(); if (rawObject.TryGetPropertyValue(nameof(RemovalDate).ToFirstCharacterLowerCase(), out var removalDate) && removalDate is JsonNode removalDateValue) extension.RemovalDate = removalDateValue.GetValue(); diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs index 26bb0b29c..9cbae6350 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumFlagsExtension.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------ +// ------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ @@ -44,9 +44,9 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// The source element to parse. /// The . /// When the source element is not an object - public static OpenApiEnumFlagsExtension Parse(OpenApiAny source) + public static OpenApiEnumFlagsExtension Parse(JsonNode source) { - if (source.Node is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); + if (source is not JsonObject rawObject) throw new ArgumentOutOfRangeException(nameof(source)); var extension = new OpenApiEnumFlagsExtension(); if (rawObject.TryGetPropertyValue(nameof(IsFlags).ToFirstCharacterLowerCase(), out var flagsValue) && flagsValue is JsonNode isFlags) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs index f657d6459..1235e68b0 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiEnumValuesDescriptionExtension.cs @@ -63,9 +63,9 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// The source element to parse. /// The . /// When the source element is not an object - public static OpenApiEnumValuesDescriptionExtension Parse(OpenApiAny source) + public static OpenApiEnumValuesDescriptionExtension Parse(JsonNode source) { - if (source.Node is not JsonObject rawObject) return null; + if (source is not JsonObject rawObject) return null; var extension = new OpenApiEnumValuesDescriptionExtension(); if (rawObject.TryGetPropertyValue("values", out var values) && values is JsonArray valuesArray) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs index b4d086edc..f64eebf3f 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPagingExtension.cs @@ -72,9 +72,9 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// The source element to parse. /// The . /// When the source element is not an object - public static OpenApiPagingExtension Parse(OpenApiAny source) + public static OpenApiPagingExtension Parse(JsonNode source) { - if (source.Node is not JsonObject rawObject) return null; + if (source is not JsonObject rawObject) return null; var extension = new OpenApiPagingExtension(); if (rawObject.TryGetPropertyValue(nameof(NextLinkName).ToFirstCharacterLowerCase(), out var nextLinkName) && nextLinkName is JsonNode nextLinkNameStr) { diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs index dfa48ba85..ad47db39b 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtension.cs @@ -38,9 +38,9 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion) /// /// The source object. /// The . - public static OpenApiPrimaryErrorMessageExtension Parse(OpenApiAny source) + public static OpenApiPrimaryErrorMessageExtension Parse(JsonNode source) { - if (source.Node is not JsonNode rawObject) return null; + if (source is not JsonNode rawObject) return null; return new() { IsPrimaryErrorMessage = rawObject.GetValue() diff --git a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs index 0839ba945..2d3a8c117 100644 --- a/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs +++ b/src/Microsoft.OpenApi/MicrosoftExtensions/OpenApiReservedParameterExtension.cs @@ -40,9 +40,9 @@ public bool? IsReserved /// The source object. /// The . /// - public static OpenApiReservedParameterExtension Parse(OpenApiAny source) + public static OpenApiReservedParameterExtension Parse(JsonNode source) { - if (source.Node is not JsonNode rawBoolean) return null; + if (source is not JsonNode rawBoolean) return null; return new() { IsReserved = rawBoolean.GetValue() diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index b0e76ca90..785477c9d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; @@ -31,7 +32,7 @@ public class OpenApiExample : IOpenApiReferenceable, IOpenApiExtensible /// exclusive. To represent examples of media types that cannot naturally represented /// in JSON or YAML, use a string value to contain the example, escaping where necessary. /// - public virtual OpenApiAny Value { get; set; } + public virtual JsonNode Value { get; set; } /// /// A URL that points to the literal example. diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 799d4314a..315382a4d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; @@ -77,7 +78,7 @@ public virtual OpenApiSchema Schema /// /// Example of the media type. /// - public virtual OpenApiAny Example { get; set; } + public virtual JsonNode Example { get; set; } /// /// Examples of the media type. diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 8c0ecd4ec..806632bda 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; @@ -30,7 +31,7 @@ public virtual OpenApiSchema Schema /// Example of the media type. /// The example object SHOULD be in the correct format as specified by the media type. /// - public OpenApiAny Example { get; set; } + public JsonNode Example { get; set; } /// /// Examples of the media type. diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 69f6201a2..1b1514733 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; @@ -130,7 +131,7 @@ public virtual OpenApiSchema Schema /// To represent examples of media types that cannot naturally be represented in JSON or YAML, /// a string value can contain the example with escaping where necessary. /// - public virtual OpenApiAny Example { get; set; } + public virtual JsonNode Example { get; set; } /// /// A map containing the representations for the parameter. diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index d2cf23506..90b3f9126 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -148,7 +149,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. /// For example, if type is string, then default can be "foo" but cannot be 1. /// - public virtual OpenApiAny Default { get; set; } + public virtual JsonNode Default { get; set; } /// /// Relevant only for Schema "properties" definitions. Declares the property as "read only". @@ -269,7 +270,7 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// To represent examples that cannot be naturally represented in JSON or YAML, /// a string value can be used to contain the example with escaping where necessary. /// - public virtual OpenApiAny Example { get; set; } + public virtual JsonNode Example { get; set; } /// /// A free-form property to include examples of an instance for this schema. @@ -359,7 +360,7 @@ public OpenApiSchema(OpenApiSchema schema) MinLength = schema?.MinLength ?? MinLength; Pattern = schema?.Pattern ?? Pattern; MultipleOf = schema?.MultipleOf ?? MultipleOf; - Default = schema?.Default != null ? new(schema?.Default.Node) : null; + Default = schema?.Default != null ? JsonNodeCloneHelper.Clone(schema?.Default) : null; ReadOnly = schema?.ReadOnly ?? ReadOnly; WriteOnly = schema?.WriteOnly ?? WriteOnly; AllOf = schema?.AllOf != null ? new List(schema.AllOf) : null; @@ -378,7 +379,7 @@ public OpenApiSchema(OpenApiSchema schema) AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; - Example = schema?.Example != null ? new(schema?.Example.Node) : null; + Example = schema?.Example != null ? JsonNodeCloneHelper.Clone(schema?.Example) : null; Examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; Nullable = schema?.Nullable ?? Nullable; @@ -492,7 +493,7 @@ public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpec writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) => w.WriteValue(s)); // enum - writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (nodeWriter, s) => nodeWriter.WriteAny(s)); // type if (Type?.GetType() == typeof(string)) @@ -605,7 +606,7 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum); writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); - writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(s)); writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } @@ -701,7 +702,7 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.MinItems, MinItems); // enum - writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(s)); // multipleOf writer.WriteProperty(OpenApiConstants.MultipleOf, MultipleOf); @@ -780,7 +781,7 @@ internal void WriteAsSchemaProperties( writer.WriteOptionalCollection(OpenApiConstants.Required, Required, (w, s) => w.WriteValue(s)); // enum - writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(new OpenApiAny(s))); + writer.WriteOptionalCollection(OpenApiConstants.Enum, Enum, (w, s) => w.WriteAny(s)); // items writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV2(w)); diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index eeee360a9..feea24cea 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -91,7 +92,7 @@ public override string Summary public override string ExternalValue { get => Target.ExternalValue; set => Target.ExternalValue = value; } /// - public override OpenApiAny Value { get => Target.Value; set => Target.Value = value; } + public override JsonNode Value { get => Target.Value; set => Target.Value = value; } /// public override void SerializeAsV3(IOpenApiWriter writer) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 64111c477..49f566966 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -97,7 +98,7 @@ public override string Description public override bool AllowReserved { get => Target.AllowReserved; set => Target.AllowReserved = value; } /// - public override OpenApiAny Example { get => Target.Example; set => Target.Example = value; } + public override JsonNode Example { get => Target.Example; set => Target.Example = value; } /// public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index 488e054a4..f677ea0a1 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -99,7 +100,7 @@ public override string Description public override IDictionary Examples { get => Target.Examples; set => Target.Examples = value; } /// - public override OpenApiAny Example { get => Target.Example; set => Target.Example = value; } + public override JsonNode Example { get => Target.Example; set => Target.Example = value; } /// public override ParameterLocation? In { get => Target.In; set => Target.In = value; } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 665120d2c..b4b2b639e 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -122,7 +122,7 @@ public override string Description /// public override decimal? MultipleOf { get => Target.MultipleOf; set => Target.MultipleOf = value; } /// - public override OpenApiAny Default { get => Target.Default; set => Target.Default = value; } + public override JsonNode Default { get => Target.Default; set => Target.Default = value; } /// public override bool ReadOnly { get => Target.ReadOnly; set => Target.ReadOnly = value; } /// @@ -160,7 +160,7 @@ public override string Description /// public override OpenApiDiscriminator Discriminator { get => Target.Discriminator; set => Target.Discriminator = value; } /// - public override OpenApiAny Example { get => Target.Example; set => Target.Example = value; } + public override JsonNode Example { get => Target.Example; set => Target.Example = value; } /// public override IList Examples { get => Target.Examples; set => Target.Examples = value; } /// diff --git a/src/Microsoft.OpenApi/Models/RuntimeExpressionAnyWrapper.cs b/src/Microsoft.OpenApi/Models/RuntimeExpressionAnyWrapper.cs index 705a14738..dca24c3e5 100644 --- a/src/Microsoft.OpenApi/Models/RuntimeExpressionAnyWrapper.cs +++ b/src/Microsoft.OpenApi/Models/RuntimeExpressionAnyWrapper.cs @@ -15,7 +15,7 @@ namespace Microsoft.OpenApi.Models /// public class RuntimeExpressionAnyWrapper : IOpenApiElement { - private OpenApiAny _any; + private JsonNode _any; private RuntimeExpression _expression; /// @@ -35,7 +35,7 @@ public RuntimeExpressionAnyWrapper(RuntimeExpressionAnyWrapper runtimeExpression /// /// Gets/Sets the /// - public OpenApiAny Any + public JsonNode Any { get { diff --git a/src/Microsoft.OpenApi/Reader/OpenApiReaderSettings.cs b/src/Microsoft.OpenApi/Reader/OpenApiReaderSettings.cs index f821bb784..fa0040ff8 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiReaderSettings.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiReaderSettings.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.MicrosoftExtensions; @@ -49,7 +50,7 @@ public class OpenApiReaderSettings /// /// Dictionary of parsers for converting extensions into strongly typed classes /// - public Dictionary> ExtensionParsers { get; set; } = new(); + public Dictionary> ExtensionParsers { get; set; } = new(); /// /// Rules to use for validating OpenAPI specification. If none are provided a default set of rules are applied. diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs index 933040da6..ad8394b58 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyFieldMapParameter.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using System; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -13,8 +14,8 @@ internal class AnyFieldMapParameter /// Constructor. /// public AnyFieldMapParameter( - Func propertyGetter, - Action propertySetter, + Func propertyGetter, + Action propertySetter, Func SchemaGetter = null) { this.PropertyGetter = propertyGetter; @@ -25,12 +26,12 @@ public AnyFieldMapParameter( /// /// Function to retrieve the value of the property. /// - public Func PropertyGetter { get; } + public Func PropertyGetter { get; } /// /// Function to set the value of the property. /// - public Action PropertySetter { get; } + public Action PropertySetter { get; } /// /// Function to get the schema to apply to the property. diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs index b0c38247c..a4dc41b7f 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/AnyMapFieldMapParameter.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -15,8 +16,8 @@ internal class AnyMapFieldMapParameter /// public AnyMapFieldMapParameter( Func> propertyMapGetter, - Func propertyGetter, - Action propertySetter, + Func propertyGetter, + Action propertySetter, Func schemaGetter) { this.PropertyMapGetter = propertyMapGetter; @@ -33,12 +34,12 @@ public AnyMapFieldMapParameter( /// /// Function to retrieve the value of the property from an inner element. /// - public Func PropertyGetter { get; } + public Func PropertyGetter { get; } /// /// Function to set the value of the property. /// - public Action PropertySetter { get; } + public Action PropertySetter { get; } /// /// Function to get the schema to apply to the property. diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs index 306a2f559..6654344cd 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs @@ -37,7 +37,7 @@ public override List CreateList(Func map, Ope public override List CreateListOfAny() { - var list = _nodeList.Select(n => Create(Context, n).CreateAny().Node) + var list = _nodeList.Select(n => Create(Context, n).CreateAny()) .Where(i => i != null) .ToList(); @@ -68,9 +68,9 @@ IEnumerator IEnumerable.GetEnumerator() /// Create a /// /// The created Any object. - public override OpenApiAny CreateAny() + public override JsonNode CreateAny() { - return new OpenApiAny(_nodeList); + return _nodeList; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs index c251bce3c..919f1d85c 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/MapNode.cs @@ -171,9 +171,9 @@ public string GetScalarValue(ValueNode key) /// Create an /// /// The created Json object. - public override OpenApiAny CreateAny() + public override JsonNode CreateAny() { - return new OpenApiAny(_node); + return _node; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs index 250581fbd..44d626f35 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs @@ -67,7 +67,7 @@ public virtual Dictionary CreateSimpleMap(Func map) throw new OpenApiReaderException("Cannot create simple map from this type of node.", Context); } - public virtual OpenApiAny CreateAny() + public virtual JsonNode CreateAny() { throw new OpenApiReaderException("Cannot create an Any object this type of node.", Context); } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/PropertyNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/PropertyNode.cs index 9b59771d5..5f8031e87 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/PropertyNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/PropertyNode.cs @@ -83,7 +83,7 @@ public void ParseField( } } - public override OpenApiAny CreateAny() + public override JsonNode CreateAny() { throw new NotImplementedException(); } diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ValueNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ValueNode.cs index 1d74ff874..ec9fefde5 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ValueNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ValueNode.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -32,9 +32,9 @@ public override string GetScalarValue() /// Create a /// /// The created Any object. - public override OpenApiAny CreateAny() + public override JsonNode CreateAny() { - return new OpenApiAny(_node); + return _node; } } } diff --git a/src/Microsoft.OpenApi/Reader/ParsingContext.cs b/src/Microsoft.OpenApi/Reader/ParsingContext.cs index 58b7151ed..f17e2aacb 100644 --- a/src/Microsoft.OpenApi/Reader/ParsingContext.cs +++ b/src/Microsoft.OpenApi/Reader/ParsingContext.cs @@ -29,7 +29,7 @@ public class ParsingContext /// /// Extension parsers /// - public Dictionary> ExtensionParsers { get; set; } = + public Dictionary> ExtensionParsers { get; set; } = new(); internal RootNode RootNode { get; set; } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs index 500f10353..5667b8f98 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiHeaderDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs index 2823974de..60167f891 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiParameterDeserializer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs index 06c6b4c1f..0bafab857 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiV2Deserializer.cs @@ -72,7 +72,7 @@ private static void ProcessAnyFields( } } - public static OpenApiAny LoadAny(ParseNode node, OpenApiDocument hostDocument = null) + public static JsonNode LoadAny(ParseNode node, OpenApiDocument hostDocument = null) { return node.CreateAny(); } @@ -85,7 +85,7 @@ private static IOpenApiExtension LoadExtension(string name, ParseNode node) } else { - return node.CreateAny(); + return new OpenApiAny(node.CreateAny()); } } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs index c382019f4..6fa8406bf 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3Deserializer.cs @@ -165,7 +165,7 @@ private static RuntimeExpressionAnyWrapper LoadRuntimeExpressionAnyWrapper(Parse public static OpenApiAny LoadAny(ParseNode node, OpenApiDocument hostDocument = null) { - return node.CreateAny(); + return new OpenApiAny(node.CreateAny()); } private static IOpenApiExtension LoadExtension(string name, ParseNode node) @@ -177,7 +177,7 @@ private static IOpenApiExtension LoadExtension(string name, ParseNode node) } else { - return node.CreateAny(); + return new OpenApiAny(node.CreateAny()); } } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs index 7ffc907fc..c2ef954a5 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiV3VersionService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Extensions; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs index 33eb3e11e..a56590bf1 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs @@ -128,7 +128,7 @@ private static RuntimeExpressionAnyWrapper LoadRuntimeExpressionAnyWrapper(Parse }; } - public static OpenApiAny LoadAny(ParseNode node, OpenApiDocument hostDocument = null) + public static JsonNode LoadAny(ParseNode node, OpenApiDocument hostDocument = null) { return node.CreateAny(); } @@ -137,7 +137,7 @@ private static IOpenApiExtension LoadExtension(string name, ParseNode node) { return node.Context.ExtensionParsers.TryGetValue(name, out var parser) ? parser(node.CreateAny(), OpenApiSpecVersion.OpenApi3_1) - : node.CreateAny(); + : new OpenApiAny(node.CreateAny()); } private static string LoadString(ParseNode node) diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index c422007a7..9cf54f65a 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json.Nodes; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; @@ -931,7 +932,7 @@ internal void Walk(IDictionary examples) /// /// Visits and child objects /// - internal void Walk(OpenApiAny example) + internal void Walk(JsonNode example) { if (example == null) { diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs index cf983158e..4bc5aa94a 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiHeaderRules.cs @@ -25,7 +25,7 @@ public static class OpenApiHeaderRules if (header.Example != null) { RuleHelpers.ValidateDataTypeMismatch(context, - nameof(HeaderMismatchedDataType), header.Example.Node, header.Schema); + nameof(HeaderMismatchedDataType), header.Example, header.Schema); } context.Exit(); @@ -42,7 +42,7 @@ public static class OpenApiHeaderRules context.Enter(key); context.Enter("value"); RuleHelpers.ValidateDataTypeMismatch(context, - nameof(HeaderMismatchedDataType), header.Examples[key]?.Value.Node, header.Schema); + nameof(HeaderMismatchedDataType), header.Examples[key]?.Value, header.Schema); context.Exit(); context.Exit(); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs index 3b56bffd7..7ac09cbbf 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiMediaTypeRules.cs @@ -32,7 +32,7 @@ public static class OpenApiMediaTypeRules if (mediaType.Example != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(MediaTypeMismatchedDataType), mediaType.Example.Node, mediaType.Schema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(MediaTypeMismatchedDataType), mediaType.Example, mediaType.Schema); } context.Exit(); @@ -48,7 +48,7 @@ public static class OpenApiMediaTypeRules { context.Enter(key); context.Enter("value"); - RuleHelpers.ValidateDataTypeMismatch(context, nameof(MediaTypeMismatchedDataType), mediaType.Examples[key]?.Value.Node, mediaType.Schema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(MediaTypeMismatchedDataType), mediaType.Examples[key]?.Value, mediaType.Schema); context.Exit(); context.Exit(); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs index 512c518ce..c6ad7835d 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiParameterRules.cs @@ -70,7 +70,7 @@ public static class OpenApiParameterRules if (parameter.Example != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(ParameterMismatchedDataType), parameter.Example.Node, parameter.Schema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(ParameterMismatchedDataType), parameter.Example, parameter.Schema); } context.Exit(); @@ -87,7 +87,7 @@ public static class OpenApiParameterRules context.Enter(key); context.Enter("value"); RuleHelpers.ValidateDataTypeMismatch(context, - nameof(ParameterMismatchedDataType), parameter.Examples[key]?.Value.Node, parameter.Schema); + nameof(ParameterMismatchedDataType), parameter.Examples[key]?.Value, parameter.Schema); context.Exit(); context.Exit(); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs index 5f75be881..e768e8d42 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/OpenApiSchemaRules.cs @@ -25,7 +25,7 @@ public static class OpenApiSchemaRules if (schema.Default != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Default.Node, schema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Default, schema); } context.Exit(); @@ -35,7 +35,7 @@ public static class OpenApiSchemaRules if (schema.Example != null) { - RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Example.Node, schema); + RuleHelpers.ValidateDataTypeMismatch(context, nameof(SchemaMismatchedDataType), schema.Example, schema); } context.Exit(); diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs index 1d5dc720d..b0ef0a174 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterAnyExtensions.cs @@ -46,18 +46,17 @@ public static void WriteExtensions(this IOpenApiWriter writer, IDictionary value. /// /// The Open API writer. - /// The Any value - public static void WriteAny(this IOpenApiWriter writer, OpenApiAny any) + /// The JsonNode value + public static void WriteAny(this IOpenApiWriter writer, JsonNode node) { Utils.CheckArgumentNull(writer);; - if (any.Node == null) + if (node == null) { writer.WriteNull(); return; } - var node = any.Node; var element = JsonDocument.Parse(node.ToJsonString()).RootElement; switch (element.ValueKind) { @@ -90,7 +89,7 @@ private static void WriteArray(this IOpenApiWriter writer, JsonArray array) foreach (var item in array) { - writer.WriteAny(new OpenApiAny(item)); + writer.WriteAny(item); } writer.WriteEndArray(); @@ -103,7 +102,7 @@ private static void WriteObject(this IOpenApiWriter writer, JsonObject entity) foreach (var item in entity) { writer.WritePropertyName(item.Key); - writer.WriteAny(new OpenApiAny(item.Value)); + writer.WriteAny(item.Value); } writer.WriteEndObject(); diff --git a/test/Microsoft.OpenApi.Readers.Tests/TestCustomExtension.cs b/test/Microsoft.OpenApi.Readers.Tests/TestCustomExtension.cs index 25af4cdae..9d7727aae 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/TestCustomExtension.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/TestCustomExtension.cs @@ -30,7 +30,7 @@ public void ParseCustomExtension() var settings = new OpenApiReaderSettings { ExtensionParsers = { { "x-foo", (a,v) => { - var fooNode = (JsonObject)a.Node; + var fooNode = (JsonObject)a; return new FooExtension() { Bar = (fooNode["bar"].ToString()), Baz = (fooNode["baz"].ToString()) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs index a78bd1180..6a2411237 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiHeaderTests.cs @@ -38,12 +38,12 @@ public void ParseHeaderWithDefaultShouldSucceed() { Type = "number", Format = "float", - Default = new OpenApiAny(5) + Default = new OpenApiAny(5).Node } }, options => options .IgnoringCyclicReferences() - .Excluding(x => x.Schema.Default.Node.Parent)); + .Excluding(x => x.Schema.Default.Parent)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs index ad1ca897f..595631e29 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiOperationTests.cs @@ -321,12 +321,12 @@ public void ParseOperationWithResponseExamplesShouldSucceed() Format = "float" } }, - Example = new OpenApiAny(new JsonArray() + Example = new JsonArray() { 5.0, 6.0, 7.0 - }) + } }, ["application/xml"] = new OpenApiMediaType() { @@ -344,12 +344,12 @@ public void ParseOperationWithResponseExamplesShouldSucceed() }} } }, options => options.IgnoringCyclicReferences() - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[0].Parent) - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[0].Root) - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[1].Parent) - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[1].Root) - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[2].Parent) - .Excluding(o => o.Responses["200"].Content["application/json"].Example.Node[2].Root)); + .Excluding(o => o.Responses["200"].Content["application/json"].Example[0].Parent) + .Excluding(o => o.Responses["200"].Content["application/json"].Example[0].Root) + .Excluding(o => o.Responses["200"].Content["application/json"].Example[1].Parent) + .Excluding(o => o.Responses["200"].Content["application/json"].Example[1].Root) + .Excluding(o => o.Responses["200"].Content["application/json"].Example[2].Parent) + .Excluding(o => o.Responses["200"].Content["application/json"].Example[2].Root)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs index 9324c5132..e9eeaa054 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiParameterTests.cs @@ -231,9 +231,9 @@ public void ParseParameterWithDefaultShouldSucceed() { Type = "number", Format = "float", - Default = new OpenApiAny(5) + Default = new OpenApiAny(5).Node } - }, options => options.IgnoringCyclicReferences().Excluding(x => x.Schema.Default.Node.Parent)); + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Schema.Default.Parent)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs index a9b646040..4c66a67f8 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiSchemaTests.cs @@ -37,8 +37,8 @@ public void ParseSchemaWithDefaultShouldSucceed() { Type = "number", Format = "float", - Default = new OpenApiAny(5) - }, options => options.IgnoringCyclicReferences().Excluding(x => x.Default.Node.Parent)); + Default = 5 + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Default.Parent)); } [Fact] @@ -60,8 +60,8 @@ public void ParseSchemaWithExampleShouldSucceed() { Type = "number", Format = "float", - Example = new OpenApiAny(5) - }, options => options.IgnoringCyclicReferences().Excluding(x => x.Example.Node.Parent)); + Example = 5 + }, options => options.IgnoringCyclicReferences().Excluding(x => x.Example.Parent)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index bd72ff78a..fa58fa5bc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -1141,14 +1141,14 @@ public void HeaderParameterShouldAllowExample() AllowReserved = true, Style = ParameterStyle.Simple, Explode = true, - Example = new OpenApiAny("99391c7e-ad88-49ec-a2ad-99ddcb1f7721"), + Example = "99391c7e-ad88-49ec-a2ad-99ddcb1f7721", Schema = new() { Type = "string", Format = "uuid" }, }, options => options.IgnoringCyclicReferences() - .Excluding(e => e.Example.Node.Parent) + .Excluding(e => e.Example.Parent) .Excluding(x => x.Reference)); var examplesHeader = result.OpenApiDocument.Components?.Headers?["examples-header"]; @@ -1167,12 +1167,12 @@ public void HeaderParameterShouldAllowExample() { { "uuid1", new OpenApiExample() { - Value = new OpenApiAny("99391c7e-ad88-49ec-a2ad-99ddcb1f7721") + Value = "99391c7e-ad88-49ec-a2ad-99ddcb1f7721" } }, { "uuid2", new OpenApiExample() { - Value = new OpenApiAny("99391c7e-ad88-49ec-a2ad-99ddcb1f7721") + Value = "99391c7e-ad88-49ec-a2ad-99ddcb1f7721" } } }, @@ -1182,8 +1182,8 @@ public void HeaderParameterShouldAllowExample() Format = "uuid" }, }, options => options.IgnoringCyclicReferences() - .Excluding(e => e.Examples["uuid1"].Value.Node.Parent) - .Excluding(e => e.Examples["uuid2"].Value.Node.Parent)); + .Excluding(e => e.Examples["uuid1"].Value.Parent) + .Excluding(e => e.Examples["uuid2"].Value.Parent)); } [Fact] @@ -1270,7 +1270,7 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() { Type = "integer", Format = "int32", - Default = new OpenApiAny(10) + Default = 10 }, Reference = new OpenApiReference { @@ -1298,7 +1298,7 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() { Type = "integer", Format = "int32", - Default = new OpenApiAny(10) + Default = 10 }, } } @@ -1339,7 +1339,8 @@ public void ParseDocWithRefsUsingProxyReferencesSucceeds() // Assert actualParam.Should().BeEquivalentTo(expectedParam, options => options .Excluding(x => x.Reference.HostDocument) - .Excluding(x => x.Schema.Default.Node.Parent) + .Excluding(x => x.Schema.Default.Parent) + .Excluding(x => x.Schema.Default.Options) .IgnoringCyclicReferences()); outputDoc.Should().BeEquivalentTo(expectedSerializedDoc.MakeLineBreaksEnvironmentNeutral()); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs index f8b0d1f1f..84f028f6b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System.IO; @@ -27,7 +27,7 @@ public void ParseAdvancedExampleShouldSucceed() var example = OpenApiModelFactory.Load(Path.Combine(SampleFolderPath, "advancedExample.yaml"), OpenApiSpecVersion.OpenApi3_0, out var diagnostic); var expected = new OpenApiExample { - Value = new OpenApiAny(new JsonObject + Value = new JsonObject { ["versions"] = new JsonArray { @@ -59,23 +59,23 @@ public void ParseAdvancedExampleShouldSucceed() } } } - }) + } }; - var actualRoot = example.Value.Node["versions"][0]["status"].Root; - var expectedRoot = expected.Value.Node["versions"][0]["status"].Root; + var actualRoot = example.Value["versions"][0]["status"].Root; + var expectedRoot = expected.Value["versions"][0]["status"].Root; diagnostic.Errors.Should().BeEmpty(); example.Should().BeEquivalentTo(expected, options => options.IgnoringCyclicReferences() - .Excluding(e => e.Value.Node["versions"][0]["status"].Root) - .Excluding(e => e.Value.Node["versions"][0]["id"].Root) - .Excluding(e => e.Value.Node["versions"][0]["links"][0]["href"].Root) - .Excluding(e => e.Value.Node["versions"][0]["links"][0]["rel"].Root) - .Excluding(e => e.Value.Node["versions"][1]["status"].Root) - .Excluding(e => e.Value.Node["versions"][1]["id"].Root) - .Excluding(e => e.Value.Node["versions"][1]["links"][0]["href"].Root) - .Excluding(e => e.Value.Node["versions"][1]["links"][0]["rel"].Root)); + .Excluding(e => e.Value["versions"][0]["status"].Root) + .Excluding(e => e.Value["versions"][0]["id"].Root) + .Excluding(e => e.Value["versions"][0]["links"][0]["href"].Root) + .Excluding(e => e.Value["versions"][0]["links"][0]["rel"].Root) + .Excluding(e => e.Value["versions"][1]["status"].Root) + .Excluding(e => e.Value["versions"][1]["id"].Root) + .Excluding(e => e.Value["versions"][1]["links"][0]["href"].Root) + .Excluding(e => e.Value["versions"][1]["links"][0]["rel"].Root)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index 90c797723..f7102b338 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -30,14 +30,14 @@ public void ParseMediaTypeWithExampleShouldSucceed() mediaType.Should().BeEquivalentTo( new OpenApiMediaType { - Example = new OpenApiAny(5), + Example = 5, Schema = new() { Type = "number", Format = "float" } }, options => options.IgnoringCyclicReferences() - .Excluding(m => m.Example.Node.Parent) + .Excluding(m => m.Example.Parent) ); } @@ -55,11 +55,11 @@ public void ParseMediaTypeWithExamplesShouldSucceed() { ["example1"] = new() { - Value = new OpenApiAny(5) + Value = 5 }, ["example2"] = new() { - Value = new OpenApiAny(7.5) + Value = 7.5 } }, Schema = new() @@ -68,8 +68,8 @@ public void ParseMediaTypeWithExamplesShouldSucceed() Format = "float" } }, options => options.IgnoringCyclicReferences() - .Excluding(m => m.Examples["example1"].Value.Node.Parent) - .Excluding(m => m.Examples["example2"].Value.Node.Parent)); + .Excluding(m => m.Examples["example1"].Value.Parent) + .Excluding(m => m.Examples["example2"].Value.Parent)); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index 1a6cb9aa9..2ff60b388 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -254,13 +254,13 @@ public void ParseParameterWithExampleShouldSucceed() Name = "username", Description = "username to fetch", Required = true, - Example = new OpenApiAny((float)5.0), + Example = (float)5.0, Schema = new() { Type = "number", Format = "float" } - }, options => options.IgnoringCyclicReferences().Excluding(p => p.Example.Node.Parent)); + }, options => options.IgnoringCyclicReferences().Excluding(p => p.Example.Parent)); } [Fact] @@ -281,11 +281,11 @@ public void ParseParameterWithExamplesShouldSucceed() { ["example1"] = new() { - Value = new OpenApiAny(5.0) + Value = 5.0 }, ["example2"] = new() { - Value = new OpenApiAny((float)7.5) + Value = (float) 7.5 } }, Schema = new() @@ -294,8 +294,8 @@ public void ParseParameterWithExamplesShouldSucceed() Format = "float" } }, options => options.IgnoringCyclicReferences() - .Excluding(p => p.Examples["example1"].Value.Node.Parent) - .Excluding(p => p.Examples["example2"].Value.Node.Parent)); + .Excluding(p => p.Examples["example1"].Value.Parent) + .Excluding(p => p.Examples["example2"].Value.Parent)); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 52e879aca..06a7f80f9 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -216,11 +216,11 @@ public void ParseBasicSchemaWithExampleShouldSucceed() { "name" }, - Example = new OpenApiAny(new JsonObject + Example = new JsonObject { ["name"] = new OpenApiAny("Puma").Node, ["id"] = new OpenApiAny(1).Node - }) + } }, options => options .IgnoringCyclicReferences() .Excluding((IMemberInfo memberInfo) => @@ -378,7 +378,7 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Type = "integer", Format = "int32", Description = "the size of the pack the dog is from", - Default = new OpenApiAny(0), + Default = 0, Minimum = 0 } } diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs index 99a27d358..6849e5e9c 100644 --- a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs +++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiDeprecationExtensionTests.cs @@ -80,7 +80,7 @@ public void Parses() { "version", new OpenApiAny("v1.0").Node}, { "description", new OpenApiAny("removing").Node} }; - var value = OpenApiDeprecationExtension.Parse(new OpenApiAny(oaiValue)); + var value = OpenApiDeprecationExtension.Parse(oaiValue); Assert.NotNull(value); Assert.Equal("v1.0", value.Version); Assert.Equal("removing", value.Description); diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs index 3451f8c52..3d084908c 100644 --- a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs +++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPagingExtensionsTests.cs @@ -83,7 +83,7 @@ public void ParsesPagingInfo() }; // Act - var extension = OpenApiPagingExtension.Parse(new OpenApiAny(obj)); + var extension = OpenApiPagingExtension.Parse(obj); // Assert Assert.Equal("@odata.nextLink", extension.NextLinkName); diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs index 10bd9d400..f7256f8e6 100644 --- a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs +++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiPrimaryErrorMessageExtensionTests.cs @@ -47,7 +47,7 @@ public void WritesValue() public void ParsesValue() { // Arrange - var value = new OpenApiAny(true); + var value = true; // Act var extension = MicrosoftExtensions.OpenApiPrimaryErrorMessageExtension.Parse(value); diff --git a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs index 6bd14a9fb..4972f3230 100644 --- a/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs +++ b/test/Microsoft.OpenApi.Tests/MicrosoftExtensions/OpenApiReservedParameterExtensionTests.cs @@ -13,7 +13,7 @@ public class OpenApiReservedParameterExtensionTests [Fact] public void Parses() { - var oaiValue = new OpenApiAny(true); + var oaiValue = true; var value = OpenApiReservedParameterExtension.Parse(oaiValue); Assert.NotNull(value); Assert.True(value.IsReserved); diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs index bec6f6b23..ef9786272 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs @@ -22,7 +22,7 @@ public class OpenApiExampleTests { public static OpenApiExample AdvancedExample = new() { - Value = new OpenApiAny(new JsonObject + Value = new JsonObject { ["versions"] = new JsonArray { @@ -55,13 +55,13 @@ public class OpenApiExampleTests } } } - }) + } }; public static OpenApiExampleReference OpenApiExampleReference = new(ReferencedExample, "example1"); public static OpenApiExample ReferencedExample = new() { - Value = new OpenApiAny(new JsonObject + Value = new JsonObject { ["versions"] = new JsonArray { @@ -94,7 +94,7 @@ public class OpenApiExampleTests } }, ["aDate"] = JsonSerializer.Serialize(DateTime.Parse("12/12/2022 00:00:00").ToString("yyyy-MM-dd")) - }) + } }; [Theory] diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs index 4468ed201..d4e7f95f4 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs @@ -30,10 +30,10 @@ public class OpenApiLinkTests }, RequestBody = new() { - Any = new OpenApiAny(new JsonObject + Any = new JsonObject { ["property1"] = true - }) + } }, Description = "description1", Server = new() @@ -60,10 +60,10 @@ public class OpenApiLinkTests }, RequestBody = new() { - Any = new OpenApiAny(new JsonObject + Any = new JsonObject { ["property1"] = true - }) + } }, Description = "description1", Server = new() diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs index ea9612c4f..e00799567 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs @@ -18,8 +18,8 @@ public class OpenApiMediaTypeTests public static OpenApiMediaType BasicMediaType = new(); public static OpenApiMediaType AdvanceMediaType = new() - { - Example = new OpenApiAny(42), + { + Example = 42, Encoding = new Dictionary { {"testEncoding", OpenApiEncodingTests.AdvanceEncoding} @@ -28,7 +28,7 @@ public class OpenApiMediaTypeTests public static OpenApiMediaType MediaTypeWithObjectExample = new() { - Example = new OpenApiAny(new JsonObject + Example = new JsonObject { ["versions"] = new JsonArray { @@ -60,7 +60,7 @@ public class OpenApiMediaTypeTests } } } - }), + }, Encoding = new Dictionary { {"testEncoding", OpenApiEncodingTests.AdvanceEncoding} @@ -69,7 +69,7 @@ public class OpenApiMediaTypeTests public static OpenApiMediaType MediaTypeWithXmlExample = new() { - Example = new OpenApiAny("123"), + Example = "123", Encoding = new Dictionary { {"testEncoding", OpenApiEncodingTests.AdvanceEncoding} @@ -81,7 +81,7 @@ public class OpenApiMediaTypeTests Examples = { ["object1"] = new() { - Value = new OpenApiAny(new JsonObject + Value = new JsonObject { ["versions"] = new JsonArray { @@ -113,7 +113,7 @@ public class OpenApiMediaTypeTests } } } - }) + } } }, Encoding = new Dictionary diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index 14a29a907..631490a38 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -35,11 +35,11 @@ public class OpenApiResponseTests Type = "array", Items = new OpenApiSchemaReference("customType", null) }, - Example = new OpenApiAny("Blabla"), + Example = "Blabla", Extensions = new Dictionary { ["myextension"] = new OpenApiAny("myextensionvalue"), - }, + }, } }, Headers = @@ -74,7 +74,7 @@ public class OpenApiResponseTests Type = "array", Items = new OpenApiSchemaReference("customType", null) }, - Example = new OpenApiAny("Blabla"), + Example = "Blabla", Extensions = new Dictionary { ["myextension"] = new OpenApiAny("myextensionvalue"), diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs index a10fba5ff..4ea8cdef9 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiExampleReferenceTests.cs @@ -136,7 +136,7 @@ public void ExampleReferenceResolutionWorks() { // Assert Assert.NotNull(_localExampleReference.Value); - Assert.Equal("[{\"id\":1,\"name\":\"John Doe\"}]", _localExampleReference.Value.Node.ToJsonString()); + Assert.Equal("[{\"id\":1,\"name\":\"John Doe\"}]", _localExampleReference.Value.ToJsonString()); Assert.Equal("Example of a local user", _localExampleReference.Summary); Assert.Equal("This is an example of a local user", _localExampleReference.Description); diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index f15f19bff..0e8f3e22e 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -275,7 +275,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public string Version { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiDeprecationExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiDeprecationExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } public class OpenApiEnumFlagsExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension { @@ -283,7 +283,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public bool IsFlags { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumFlagsExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumFlagsExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } public class OpenApiEnumValuesDescriptionExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension { @@ -292,7 +292,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public System.Collections.Generic.List ValuesDescriptions { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumValuesDescriptionExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiEnumValuesDescriptionExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } public class OpenApiPagingExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension { @@ -302,7 +302,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public string OperationName { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPagingExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPagingExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } public class OpenApiPrimaryErrorMessageExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension { @@ -310,7 +310,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public bool IsPrimaryErrorMessage { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPrimaryErrorMessageExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiPrimaryErrorMessageExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } public class OpenApiReservedParameterExtension : Microsoft.OpenApi.Interfaces.IOpenApiExtension { @@ -318,7 +318,7 @@ namespace Microsoft.OpenApi.MicrosoftExtensions public bool? IsReserved { get; set; } public static string Name { get; } public void Write(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } - public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiReservedParameterExtension Parse(Microsoft.OpenApi.Any.OpenApiAny source) { } + public static Microsoft.OpenApi.MicrosoftExtensions.OpenApiReservedParameterExtension Parse(System.Text.Json.Nodes.JsonNode source) { } } } namespace Microsoft.OpenApi.Models @@ -597,7 +597,7 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public virtual string Summary { get; set; } public virtual bool UnresolvedReference { get; set; } - public virtual Microsoft.OpenApi.Any.OpenApiAny Value { get; set; } + public virtual System.Text.Json.Nodes.JsonNode Value { get; set; } public void Serialize(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -637,7 +637,7 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IDictionary Content { get; set; } public virtual bool Deprecated { get; set; } public virtual string Description { get; set; } - public virtual Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } @@ -705,7 +705,7 @@ namespace Microsoft.OpenApi.Models public OpenApiMediaType() { } public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } public System.Collections.Generic.IDictionary Encoding { get; set; } - public Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public System.Text.Json.Nodes.JsonNode Example { get; set; } public System.Collections.Generic.IDictionary Examples { get; set; } public System.Collections.Generic.IDictionary Extensions { get; set; } public virtual Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } @@ -771,7 +771,7 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IDictionary Content { get; set; } public virtual bool Deprecated { get; set; } public virtual string Description { get; set; } - public virtual Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } public virtual System.Collections.Generic.IDictionary Examples { get; set; } public virtual bool Explode { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } @@ -881,7 +881,7 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IList AllOf { get; set; } public virtual System.Collections.Generic.IList AnyOf { get; set; } public virtual string Comment { get; set; } - public virtual Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public virtual System.Text.Json.Nodes.JsonNode Default { get; set; } public virtual System.Collections.Generic.IDictionary Definitions { get; set; } public virtual bool Deprecated { get; set; } public virtual string Description { get; set; } @@ -889,7 +889,7 @@ namespace Microsoft.OpenApi.Models public virtual string DynamicAnchor { get; set; } public virtual string DynamicRef { get; set; } public virtual System.Collections.Generic.IList Enum { get; set; } - public virtual Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public virtual System.Text.Json.Nodes.JsonNode Example { get; set; } public virtual System.Collections.Generic.IList Examples { get; set; } public virtual bool? ExclusiveMaximum { get; set; } public virtual bool? ExclusiveMinimum { get; set; } @@ -1098,7 +1098,7 @@ namespace Microsoft.OpenApi.Models { public RuntimeExpressionAnyWrapper() { } public RuntimeExpressionAnyWrapper(Microsoft.OpenApi.Models.RuntimeExpressionAnyWrapper runtimeExpressionAnyWrapper) { } - public Microsoft.OpenApi.Any.OpenApiAny Any { get; set; } + public System.Text.Json.Nodes.JsonNode Any { get; set; } public Microsoft.OpenApi.Expressions.RuntimeExpression Expression { get; set; } public void WriteValue(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -1131,7 +1131,7 @@ namespace Microsoft.OpenApi.Models.References public override System.Collections.Generic.IDictionary Extensions { get; set; } public override string ExternalValue { get; set; } public override string Summary { get; set; } - public override Microsoft.OpenApi.Any.OpenApiAny Value { get; set; } + public override System.Text.Json.Nodes.JsonNode Value { get; set; } public override void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public override void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -1143,7 +1143,7 @@ namespace Microsoft.OpenApi.Models.References public override System.Collections.Generic.IDictionary Content { get; set; } public override bool Deprecated { get; set; } public override string Description { get; set; } - public override Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public override System.Text.Json.Nodes.JsonNode Example { get; set; } public override System.Collections.Generic.IDictionary Examples { get; set; } public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1175,7 +1175,7 @@ namespace Microsoft.OpenApi.Models.References public override System.Collections.Generic.IDictionary Content { get; set; } public override bool Deprecated { get; set; } public override string Description { get; set; } - public override Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public override System.Text.Json.Nodes.JsonNode Example { get; set; } public override System.Collections.Generic.IDictionary Examples { get; set; } public override bool Explode { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1229,7 +1229,7 @@ namespace Microsoft.OpenApi.Models.References public override System.Collections.Generic.IList AllOf { get; set; } public override System.Collections.Generic.IList AnyOf { get; set; } public override string Comment { get; set; } - public override Microsoft.OpenApi.Any.OpenApiAny Default { get; set; } + public override System.Text.Json.Nodes.JsonNode Default { get; set; } public override System.Collections.Generic.IDictionary Definitions { get; set; } public override bool Deprecated { get; set; } public override string Description { get; set; } @@ -1237,7 +1237,7 @@ namespace Microsoft.OpenApi.Models.References public override string DynamicAnchor { get; set; } public override string DynamicRef { get; set; } public override System.Collections.Generic.IList Enum { get; set; } - public override Microsoft.OpenApi.Any.OpenApiAny Example { get; set; } + public override System.Text.Json.Nodes.JsonNode Example { get; set; } public override System.Collections.Generic.IList Examples { get; set; } public override bool? ExclusiveMaximum { get; set; } public override bool? ExclusiveMinimum { get; set; } @@ -1359,7 +1359,7 @@ namespace Microsoft.OpenApi.Reader public System.Uri BaseUrl { get; set; } public Microsoft.OpenApi.Interfaces.IStreamLoader CustomExternalLoader { get; set; } public System.Collections.Generic.List DefaultContentType { get; set; } - public System.Collections.Generic.Dictionary> ExtensionParsers { get; set; } + public System.Collections.Generic.Dictionary> ExtensionParsers { get; set; } public bool LeaveStreamOpen { get; set; } public bool LoadExternalRefs { get; set; } public Microsoft.OpenApi.Reader.ReferenceResolutionSetting ReferenceResolution { get; set; } @@ -1378,7 +1378,7 @@ namespace Microsoft.OpenApi.Reader public System.Uri BaseUrl { get; set; } public System.Collections.Generic.List DefaultContentType { get; set; } public Microsoft.OpenApi.Reader.OpenApiDiagnostic Diagnostic { get; } - public System.Collections.Generic.Dictionary> ExtensionParsers { get; set; } + public System.Collections.Generic.Dictionary> ExtensionParsers { get; set; } public void EndObject() { } public T GetFromTempStorage(string key, object scope = null) { } public string GetLocation() { } @@ -1818,7 +1818,7 @@ namespace Microsoft.OpenApi.Writers } public static class OpenApiWriterAnyExtensions { - public static void WriteAny(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.Any.OpenApiAny any) { } + public static void WriteAny(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Text.Json.Nodes.JsonNode node) { } public static void WriteExtensions(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, System.Collections.Generic.IDictionary extensions, Microsoft.OpenApi.OpenApiSpecVersion specVersion) { } } public abstract class OpenApiWriterBase : Microsoft.OpenApi.Writers.IOpenApiWriter diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs index a189a3575..bbc9dfe35 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiHeaderValidationTests.cs @@ -23,7 +23,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() var header = new OpenApiHeader { Required = true, - Example = new OpenApiAny(55), + Example = 55, Schema = new OpenApiSchema { Type = "string" @@ -72,29 +72,28 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() { ["example0"] = new() { - Value = new OpenApiAny("1"), + Value = "1", }, ["example1"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 2, ["y"] = "20", ["z"] = "200" - }) + } }, ["example2"] = new() { - Value =new OpenApiAny( - new JsonArray(){3}) + Value = new JsonArray(){3} }, ["example3"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 4, ["y"] = 40 - }) + } }, } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs index d735e87d2..9f42cb21b 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiMediaTypeValidationTests.cs @@ -22,7 +22,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() IEnumerable warnings; var mediaType = new OpenApiMediaType { - Example = new OpenApiAny(55), + Example = 55, Schema = new() { Type = "string", @@ -70,29 +70,28 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() { ["example0"] = new() { - Value = new OpenApiAny("1"), + Value = "1", }, ["example1"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 2, ["y"] = "20", ["z"] = "200" - }) + } }, ["example2"] = new() { - Value =new OpenApiAny( - new JsonArray(){3}) + Value = new JsonArray(){3} }, ["example3"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 4, ["y"] = 40 - }) + } }, } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs index 197d0dbb7..beac66d74 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiParameterValidationTests.cs @@ -71,7 +71,7 @@ public void ValidateExampleShouldNotHaveDataTypeMismatchForSimpleSchema() Name = "parameter1", In = ParameterLocation.Path, Required = true, - Example = new OpenApiAny(55), + Example = 55, Schema = new() { Type = "string", @@ -122,28 +122,28 @@ public void ValidateExamplesShouldNotHaveDataTypeMismatchForSimpleSchema() { ["example0"] = new() { - Value = new OpenApiAny("1"), + Value = "1", }, ["example1"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 2, ["y"] = "20", ["z"] = "200" - }) + } }, ["example2"] = new() { - Value = new OpenApiAny(new JsonArray(){3}) + Value = new JsonArray(){3} }, ["example3"] = new() { - Value = new OpenApiAny(new JsonObject() + Value = new JsonObject() { ["x"] = 4, ["y"] = 40 - }) + } }, } }; diff --git a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs index 3144955b3..5885377ed 100644 --- a/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Validations/OpenApiSchemaValidationTests.cs @@ -26,7 +26,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForSimpleSchema() IEnumerable warnings; var schema = new OpenApiSchema { - Default = new OpenApiAny(55), + Default = 55, Type = "string", }; @@ -57,8 +57,8 @@ public void ValidateExampleAndDefaultShouldNotHaveDataTypeMismatchForSimpleSchem IEnumerable warnings; var schema = new OpenApiSchema { - Example = new OpenApiAny(55), - Default = new OpenApiAny("1234"), + Example = 55, + Default = "1234", Type = "string", }; @@ -180,7 +180,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() Type = "string" } }, - Default = new OpenApiAny(new JsonObject() + Default = new JsonObject() { ["property1"] = new JsonArray() { @@ -200,7 +200,7 @@ public void ValidateDefaultShouldNotHaveDataTypeMismatchForComplexSchema() }, ["property3"] = "123", ["property4"] = DateTime.UtcNow - }) + } }; // Act diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs index 6e1a883c4..96e8027a0 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; @@ -263,7 +263,7 @@ private static string WriteAsJson(JsonNode any, bool produceTerseOutput = false) new StreamWriter(stream), new() { Terse = produceTerseOutput }); - writer.WriteAny(new OpenApiAny(any)); + writer.WriteAny(any); writer.Flush(); stream.Position = 0; From 38bd152777e08bd62400b140da031152aba14540 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 13:08:16 +0300 Subject: [PATCH 34/44] Fix codeQL warnings --- src/Microsoft.OpenApi/Models/OpenApiComponents.cs | 3 --- src/Microsoft.OpenApi/Models/OpenApiDocument.cs | 7 ++----- src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs | 7 ++----- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 8d2f36883..4ba4aaf19 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -339,9 +339,6 @@ private void RenderComponents(IOpenApiWriter writer, Action schemas)) { - var openApiSchemas = schemas.Cast().Distinct().ToList() - .ToDictionary(k => k.Reference.Id); - writer.WriteOptionalMap(OpenApiConstants.Schemas, Schemas, callback); } writer.WriteEndObject(); diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 5762223c3..291aac1a6 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -667,12 +667,9 @@ public override void Visit(IOpenApiReferenceable referenceable) public override void Visit(OpenApiSchema schema) { // This is needed to handle schemas used in Responses in components - if (schema.Reference != null) + if (schema.Reference != null && !Schemas.ContainsKey(schema.Reference.Id)) { - if (!Schemas.ContainsKey(schema.Reference.Id)) - { - Schemas.Add(schema.Reference.Id, schema); - } + Schemas.Add(schema.Reference.Id, schema); } base.Visit(schema); } diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index 471c79d5c..9902360ec 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -61,12 +61,9 @@ public static void ValidateDataTypeMismatch( // Before checking the type, check first if the schema allows null. // If so and the data given is also null, this is allowed for any type. - if (nullable) + if (nullable && jsonElement.ValueKind is JsonValueKind.Null) { - if (jsonElement.ValueKind is JsonValueKind.Null) - { - return; - } + return; } if (type == "object") From af42af25abd294683ea5aa0fbb7fbb0dee5e537c Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 15:54:07 +0300 Subject: [PATCH 35/44] Avoid virtual calls in constructors --- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 3 +- .../Models/OpenApiMediaType.cs | 3 +- .../Models/OpenApiParameter.cs | 2 +- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 31 ++++++++++++++----- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 315382a4d..6e9df4255 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; @@ -114,7 +113,7 @@ public OpenApiHeader(OpenApiHeader header) Style = header?.Style ?? Style; Explode = header?.Explode ?? Explode; AllowReserved = header?.AllowReserved ?? AllowReserved; - Schema = header?.Schema != null ? new(header.Schema) : null; + _schema = header?.Schema != null ? new(header.Schema) : null; Example = header?.Example != null ? JsonNodeCloneHelper.Clone(header.Example) : null; Examples = header?.Examples != null ? new Dictionary(header.Examples) : null; Content = header?.Content != null ? new Dictionary(header.Content) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 806632bda..7183d5808 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -62,7 +61,7 @@ public OpenApiMediaType() { } /// public OpenApiMediaType(OpenApiMediaType mediaType) { - Schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; + _schema = mediaType?.Schema != null ? new(mediaType.Schema) : null; Example = mediaType?.Example != null ? JsonNodeCloneHelper.Clone(mediaType.Example) : null; Examples = mediaType?.Examples != null ? new Dictionary(mediaType.Examples) : null; Encoding = mediaType?.Encoding != null ? new Dictionary(mediaType.Encoding) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 1b1514733..2cbbeb631 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -168,7 +168,7 @@ public OpenApiParameter(OpenApiParameter parameter) Style = parameter?.Style ?? Style; Explode = parameter?.Explode ?? Explode; AllowReserved = parameter?.AllowReserved ?? AllowReserved; - Schema = parameter?.Schema != null ? new(parameter.Schema) : null; + _schema = parameter?.Schema != null ? new(parameter.Schema) : null; Examples = parameter?.Examples != null ? new Dictionary(parameter.Examples) : null; Example = parameter?.Example != null ? JsonNodeCloneHelper.Clone(parameter.Example) : null; Content = parameter?.Content != null ? new Dictionary(parameter.Content) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 90b3f9126..376936af3 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Helpers; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -17,6 +16,10 @@ namespace Microsoft.OpenApi.Models /// public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApiSerializable { + private JsonNode _example; + private JsonNode _default; + private IList _examples; + /// /// Follow JSON Schema definition. Short text providing information about the data. /// @@ -149,7 +152,11 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. /// For example, if type is string, then default can be "foo" but cannot be 1. /// - public virtual JsonNode Default { get; set; } + public virtual JsonNode Default + { + get => _default; + set => _default = value; + } /// /// Relevant only for Schema "properties" definitions. Declares the property as "read only". @@ -270,14 +277,22 @@ public class OpenApiSchema : IOpenApiExtensible, IOpenApiReferenceable, IOpenApi /// To represent examples that cannot be naturally represented in JSON or YAML, /// a string value can be used to contain the example with escaping where necessary. /// - public virtual JsonNode Example { get; set; } + public virtual JsonNode Example + { + get => _example; + set => _example = value; + } /// /// A free-form property to include examples of an instance for this schema. /// To represent examples that cannot be naturally represented in JSON or YAML, /// a list of values can be used to contain the examples with escaping where necessary. /// - public virtual IList Examples { get; set; } + public virtual IList Examples + { + get => _examples; + set => _examples = value; + } /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 @@ -360,7 +375,7 @@ public OpenApiSchema(OpenApiSchema schema) MinLength = schema?.MinLength ?? MinLength; Pattern = schema?.Pattern ?? Pattern; MultipleOf = schema?.MultipleOf ?? MultipleOf; - Default = schema?.Default != null ? JsonNodeCloneHelper.Clone(schema?.Default) : null; + _default = schema?.Default != null ? JsonNodeCloneHelper.Clone(schema?.Default) : null; ReadOnly = schema?.ReadOnly ?? ReadOnly; WriteOnly = schema?.WriteOnly ?? WriteOnly; AllOf = schema?.AllOf != null ? new List(schema.AllOf) : null; @@ -379,8 +394,8 @@ public OpenApiSchema(OpenApiSchema schema) AdditionalPropertiesAllowed = schema?.AdditionalPropertiesAllowed ?? AdditionalPropertiesAllowed; AdditionalProperties = schema?.AdditionalProperties != null ? new(schema?.AdditionalProperties) : null; Discriminator = schema?.Discriminator != null ? new(schema?.Discriminator) : null; - Example = schema?.Example != null ? JsonNodeCloneHelper.Clone(schema?.Example) : null; - Examples = schema?.Examples != null ? new List(schema.Examples) : null; + _example = schema?.Example != null ? JsonNodeCloneHelper.Clone(schema?.Example) : null; + _examples = schema?.Examples != null ? new List(schema.Examples) : null; Enum = schema?.Enum != null ? new List(schema.Enum) : null; Nullable = schema?.Nullable ?? Nullable; ExternalDocs = schema?.ExternalDocs != null ? new(schema?.ExternalDocs) : null; @@ -606,7 +621,7 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum); writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum); writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false); - writer.WriteOptionalCollection(OpenApiConstants.Examples, Examples, (nodeWriter, s) => nodeWriter.WriteAny(s)); + writer.WriteOptionalCollection(OpenApiConstants.Examples, _examples, (nodeWriter, s) => nodeWriter.WriteAny(s)); writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } From 4cd04c6708745a8602cf527ce3588289b85c95c4 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 15:54:36 +0300 Subject: [PATCH 36/44] Clean up tests; add test for schema examples --- .../V31Tests/OpenApiSchemaTests.cs | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index a534d3dd1..2d5776005 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -2,17 +2,12 @@ // Licensed under the MIT license. using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Text.Json.Nodes; using FluentAssertions; using FluentAssertions.Equivalency; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; -using Microsoft.OpenApi.Reader.ParseNodes; -using Microsoft.OpenApi.Reader.V31; -using SharpYaml.Serialization; using Xunit; namespace Microsoft.OpenApi.Readers.Tests.V31Tests @@ -21,6 +16,11 @@ public class OpenApiSchemaTests { private const string SampleFolderPath = "V31Tests/Samples/OpenApiSchema/"; + public OpenApiSchemaTests() + { + OpenApiReaderRegistry.RegisterReader("yaml", new OpenApiYamlReader()); + } + [Fact] public void ParseBasicV31SchemaShouldSucceed() { @@ -74,7 +74,7 @@ public void ParseBasicV31SchemaShouldSucceed() // Act var schema = OpenApiModelFactory.Load( - Path.Combine(SampleFolderPath, "jsonSchema.json"), OpenApiSpecVersion.OpenApi3_1, out _); + System.IO.Path.Combine(SampleFolderPath, "jsonSchema.json"), OpenApiSpecVersion.OpenApi3_1, out _); // Assert schema.Should().BeEquivalentTo(expectedObject); @@ -144,19 +144,10 @@ public void TestSchemaCopyConstructorWithTypeArrayWorks() [Fact] public void ParseV31SchemaShouldSucceed() { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "schema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); + var path = System.IO.Path.Combine(SampleFolderPath, "schema.yaml"); // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); + var schema = OpenApiModelFactory.Load(path, OpenApiSpecVersion.OpenApi3_1, out _); var expectedSchema = new OpenApiSchema { Type = "object", @@ -177,19 +168,9 @@ public void ParseV31SchemaShouldSucceed() [Fact] public void ParseAdvancedV31SchemaShouldSucceed() { - using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedSchema.yaml")); - var yamlStream = new YamlStream(); - yamlStream.Load(new StreamReader(stream)); - var yamlNode = yamlStream.Documents.First().RootNode; - - var diagnostic = new OpenApiDiagnostic(); - var context = new ParsingContext(diagnostic); - - var asJsonNode = yamlNode.ToJsonNode(); - var node = new MapNode(context, asJsonNode); - - // Act - var schema = OpenApiV31Deserializer.LoadSchema(node); + // Arrange and Act + var path = System.IO.Path.Combine(SampleFolderPath, "advancedSchema.yaml"); + var schema = OpenApiModelFactory.Load(path, OpenApiSpecVersion.OpenApi3_1, out _); var expectedSchema = new OpenApiSchema { @@ -268,5 +249,22 @@ public void ParseAdvancedV31SchemaShouldSucceed() .Excluding((IMemberInfo memberInfo) => memberInfo.Path.EndsWith("Parent"))); } + + [Fact] + public void ParseSchemaWithExamplesShouldSucceed() + { + // Arrange + var input = @" +type: string +examples: + - fedora + - ubuntu +"; + // Act + var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, out _, "yaml"); + + // Assert + schema.Examples.Should().HaveCount(2); + } } } From 887748e1248c82dceb805a20eac74de4ac790de6 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 17:53:15 +0300 Subject: [PATCH 37/44] Cleanup and add test for cloning examples --- .../V31Tests/OpenApiSchemaTests.cs | 25 ++++++++++++++++++- .../V3Tests/OpenApiSchemaTests.cs | 8 +++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index 2d5776005..af11245d4 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -203,7 +203,7 @@ public void ParseAdvancedV31SchemaShouldSucceed() Type = "string", Examples = new List { - new OpenApiAny("exampleValue").Node + "exampleValue" } }, ["six"] = new() @@ -266,5 +266,28 @@ public void ParseSchemaWithExamplesShouldSucceed() // Assert schema.Examples.Should().HaveCount(2); } + + [Fact] + public void CloningSchemaWithExamplesAndEnumsShouldSucceed() + { + // Arrange + var schema = new OpenApiSchema + { + Type = "int", + Default = 5, + Examples = [2, 3], + Enum = [1, 2, 3] + }; + + var clone = new OpenApiSchema(schema); + clone.Examples.Add(4); + clone.Enum.Add(4); + clone.Default = 6; + + // Assert + clone.Enum.Should().NotBeEquivalentTo(schema.Enum); + clone.Examples.Should().NotBeEquivalentTo(schema.Examples); + clone.Default.Should().NotBeEquivalentTo(schema.Default); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 06a7f80f9..dfd28ded3 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -351,10 +351,10 @@ public void ParseAdvancedSchemaWithReferenceShouldSucceed() Description = "The measured skill for hunting", Enum = { - new OpenApiAny("clueless").Node, - new OpenApiAny("lazy").Node, - new OpenApiAny("adventurous").Node, - new OpenApiAny("aggressive").Node + "clueless", + "lazy", + "adventurous", + "aggressive" } } } From 5901f492d0dbacfa826582b8770e0e9861ccc8ca Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Thu, 22 Aug 2024 19:46:53 +0300 Subject: [PATCH 38/44] Add test to bump up test coverage --- .../Models/OpenApiMediaTypeTests.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs index e00799567..d4eecf7ee 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiMediaTypeTests.cs @@ -6,6 +6,7 @@ using FluentAssertions; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Xunit; using Xunit.Abstractions; @@ -426,5 +427,21 @@ public void SerializeMediaTypeWithObjectExamplesAsV3JsonWorks() expected = expected.MakeLineBreaksEnvironmentNeutral(); actual.Should().Be(expected); } + + [Fact] + public void MediaTypeCopyConstructorWorks() + { + var clone = new OpenApiMediaType(MediaTypeWithObjectExamples) + { + Example = 42, + Examples = new Dictionary(), + Encoding = new Dictionary(), + Extensions = new Dictionary() + }; + + // Assert + MediaTypeWithObjectExamples.Examples.Should().NotBeEquivalentTo(clone.Examples); + MediaTypeWithObjectExamples.Example.Should().Be(null); + } } } From 8fd03c90037b842246f29fafe7b9abe3cf51ed29 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:36:34 +0300 Subject: [PATCH 39/44] Clean up serializers --- .../Interfaces/IOpenApiReferenceable.cs | 16 ---- .../Models/OpenApiCallback.cs | 51 +--------- .../Models/OpenApiComponents.cs | 67 +++++-------- .../Models/OpenApiDocument.cs | 48 ++++------ .../Models/OpenApiExample.cs | 52 ++-------- src/Microsoft.OpenApi/Models/OpenApiHeader.cs | 48 ++-------- src/Microsoft.OpenApi/Models/OpenApiLink.cs | 41 +------- .../Models/OpenApiParameter.cs | 52 ++-------- .../Models/OpenApiPathItem.cs | 54 ++--------- .../Models/OpenApiRequestBody.cs | 45 +-------- .../Models/OpenApiResponse.cs | 50 ++-------- src/Microsoft.OpenApi/Models/OpenApiSchema.cs | 94 ++++--------------- .../Models/OpenApiSecurityScheme.cs | 45 ++------- .../References/OpenApiCallbackReference.cs | 4 +- .../References/OpenApiExampleReference.cs | 4 +- .../References/OpenApiHeaderReference.cs | 6 +- .../Models/References/OpenApiLinkReference.cs | 4 +- .../References/OpenApiParameterReference.cs | 6 +- .../References/OpenApiPathItemReference.cs | 2 +- .../References/OpenApiRequestBodyReference.cs | 4 +- .../References/OpenApiResponseReference.cs | 6 +- .../References/OpenApiSchemaReference.cs | 23 ++++- .../OpenApiSecuritySchemeReference.cs | 10 +- 23 files changed, 153 insertions(+), 579 deletions(-) diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs index ceb5e1b7d..0920fb1ef 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReferenceable.cs @@ -20,21 +20,5 @@ public interface IOpenApiReferenceable : IOpenApiSerializable /// Reference object. /// OpenApiReference Reference { get; set; } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - void SerializeAsV31WithoutReference(IOpenApiWriter writer); - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - void SerializeAsV3WithoutReference(IOpenApiWriter writer); - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - void SerializeAsV2WithoutReference(IOpenApiWriter writer); - } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs index ce8342d67..f538d90c0 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiCallback.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiCallback.cs @@ -73,8 +73,7 @@ public void AddPathItem(RuntimeExpression expression, OpenApiPathItem pathItem) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, referenceElement) => referenceElement.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -82,47 +81,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, referenceElement) => referenceElement.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - /// - /// Serialize - /// - /// - /// - /// - private void SerializeInternal(IOpenApiWriter writer, - Action callback, - Action action) + internal void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, + Action callback) { Utils.CheckArgumentNull(writer); - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); - } - - internal void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, - Action callback) - { writer.WriteStartObject(); // path items @@ -144,14 +110,5 @@ public void SerializeAsV2(IOpenApiWriter writer) { // Callback object does not exist in V2. } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { - // Callback object does not exist in V2. - } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 4ba4aaf19..5079e9915 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Writers; @@ -120,11 +121,9 @@ public void SerializeAsV31(IOpenApiWriter writer) PathItems, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Schema && - component.Reference.Id == key) + if (component is OpenApiPathItemReference reference) { - component.SerializeAsV31WithoutReference(w); + reference.SerializeAsV31(w); } else { @@ -133,7 +132,7 @@ public void SerializeAsV31(IOpenApiWriter writer) }); SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer), - (writer, referenceElement) => referenceElement.SerializeAsV31WithoutReference(writer)); + (writer, referenceElement) => referenceElement.SerializeAsV31(writer)); } /// @@ -154,7 +153,7 @@ public void SerializeAsV3(IOpenApiWriter writer) writer.WriteStartObject(); SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer), - (writer, referenceElement) => referenceElement.SerializeAsV3WithoutReference(writer)); + (writer, referenceElement) => referenceElement.SerializeAsV3(writer)); } /// @@ -172,14 +171,13 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Schemas, (w, key, component) => { - if (component.Reference is { Type: ReferenceType.Schema } && - component.Reference.Id == key) + if (component is OpenApiSchemaReference reference) { - component.SerializeAsV3WithoutReference(w); + action(w, reference); } else { - component.SerializeAsV3(w); + callback(w, component); } }); @@ -189,11 +187,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Responses, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Response && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiResponseReference reference) { - action(w, component); + action(w, reference); } else { @@ -207,11 +203,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Parameters, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Parameter && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiParameterReference reference) { - action(w, component); + action(w, reference); } else { @@ -225,11 +219,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Examples, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Example && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiExampleReference reference) { - action(writer, component); + action(w, reference); } else { @@ -243,12 +235,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version RequestBodies, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.RequestBody && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) - + if (component is OpenApiRequestBodyReference reference) { - action(w, component); + action(w, reference); } else { @@ -262,11 +251,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Headers, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Header && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiHeaderReference reference) { - action(w, component); + action(w, reference); } else { @@ -280,11 +267,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version SecuritySchemes, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.SecurityScheme && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiSecuritySchemeReference reference) { - action(w, component); + action(w, reference); } else { @@ -298,11 +283,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Links, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Link && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiLinkReference reference) { - action(w, component); + action(w, reference); } else { @@ -316,11 +299,9 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version Callbacks, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Callback && - string.Equals(component.Reference.Id, key, StringComparison.OrdinalIgnoreCase)) + if (component is OpenApiCallbackReference reference) { - action(w, component); + action(w, reference); } else { diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 291aac1a6..5fee30ac2 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Microsoft.OpenApi.Extensions; using Microsoft.OpenApi.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Reader; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; @@ -133,8 +134,7 @@ public void SerializeAsV31(IOpenApiWriter writer) // jsonSchemaDialect writer.WriteProperty(OpenApiConstants.JsonSchemaDialect, JsonSchemaDialect); - SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (w, element) => element.SerializeAsV31(w), - (w, element) => element.SerializeAsV31WithoutReference(w)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (w, element) => element.SerializeAsV31(w)); // webhooks writer.WriteOptionalMap( @@ -142,11 +142,9 @@ public void SerializeAsV31(IOpenApiWriter writer) Webhooks, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.PathItem && - component.Reference.Id == key) + if (component is OpenApiPathItemReference reference) { - component.SerializeAsV31WithoutReference(w); + reference.SerializeAsV31(w); } else { @@ -168,8 +166,7 @@ public void SerializeAsV3(IOpenApiWriter writer) // openapi writer.WriteProperty(OpenApiConstants.OpenApi, "3.0.1"); - SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (w, element) => element.SerializeAsV3(w), - (w, element) => element.SerializeAsV3WithoutReference(w)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (w, element) => element.SerializeAsV3(w)); writer.WriteEndObject(); } @@ -179,10 +176,8 @@ public void SerializeAsV3(IOpenApiWriter writer) /// /// /// - /// private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, - Action callback, - Action action) + Action callback) { // info writer.WriteRequiredObject(OpenApiConstants.Info, Info, callback); @@ -190,7 +185,7 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version // servers writer.WriteOptionalCollection(OpenApiConstants.Servers, Servers, callback); - // paths + // paths writer.WriteRequiredObject(OpenApiConstants.Paths, Paths, callback); // components @@ -203,7 +198,7 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version callback); // tags - writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => action(w, t)); + writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => callback(w, t)); // external docs writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, callback); @@ -252,7 +247,7 @@ public void SerializeAsV2(IOpenApiWriter writer) writer.WriteOptionalMap( OpenApiConstants.Definitions, openApiSchemas, - (w, _, component) => component.SerializeAsV2WithoutReference(w)); + (w, _, component) => component.SerializeAsV2(w)); } } else @@ -265,10 +260,9 @@ public void SerializeAsV2(IOpenApiWriter writer) Components?.Schemas, (w, key, component) => { - if (component.Reference is { Type: ReferenceType.Schema } && - component.Reference.Id == key) + if (component is OpenApiSchemaReference reference) { - component.SerializeAsV2WithoutReference(w); + reference.SerializeAsV2(w); } else { @@ -293,11 +287,9 @@ public void SerializeAsV2(IOpenApiWriter writer) parameters, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Parameter && - component.Reference.Id == key) + if (component is OpenApiParameterReference reference) { - component.SerializeAsV2WithoutReference(w); + reference.SerializeAsV2(w); } else { @@ -311,11 +303,9 @@ public void SerializeAsV2(IOpenApiWriter writer) Components?.Responses, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.Response && - component.Reference.Id == key) + if (component is OpenApiResponseReference reference) { - component.SerializeAsV2WithoutReference(w); + reference.SerializeAsV2(w); } else { @@ -329,11 +319,9 @@ public void SerializeAsV2(IOpenApiWriter writer) Components?.SecuritySchemes, (w, key, component) => { - if (component.Reference != null && - component.Reference.Type == ReferenceType.SecurityScheme && - component.Reference.Id == key) + if (component is OpenApiSecuritySchemeReference reference) { - component.SerializeAsV2WithoutReference(w); + reference.SerializeAsV2(w); } else { @@ -348,7 +336,7 @@ public void SerializeAsV2(IOpenApiWriter writer) (w, s) => s.SerializeAsV2(w)); // tags - writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.SerializeAsV2WithoutReference(w)); + writer.WriteOptionalCollection(OpenApiConstants.Tags, Tags, (w, t) => t.SerializeAsV2(w)); // externalDocs writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, e) => e.SerializeAsV2(w)); diff --git a/src/Microsoft.OpenApi/Models/OpenApiExample.cs b/src/Microsoft.OpenApi/Models/OpenApiExample.cs index 785477c9d..ef8a64b7a 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiExample.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiExample.cs @@ -82,8 +82,7 @@ public OpenApiExample(OpenApiExample example) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1); } /// @@ -92,38 +91,7 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); - } - - internal virtual void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer); - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V31 example without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1); - } - - /// - /// Serialize to OpenAPI V3 example without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0); - } - - internal void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version) - { - Serialize(writer, OpenApiSpecVersion.OpenApi3_0); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0); } /// @@ -131,8 +99,10 @@ internal void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSp /// /// /// - public void Serialize(IOpenApiWriter writer, OpenApiSpecVersion version) + public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // summary @@ -156,17 +126,7 @@ public void Serialize(IOpenApiWriter writer, OpenApiSpecVersion version) /// /// Serialize to Open Api v2.0 /// - public void SerializeAsV2(IOpenApiWriter writer) - { - // Example object of this form does not exist in V2. - // V2 Example object requires knowledge of media type and exists only - // in Response object, so it will be serialized as a part of the Response object. - } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) + public virtual void SerializeAsV2(IOpenApiWriter writer) { // Example object of this form does not exist in V2. // V2 Example object requires knowledge of media type and exists only diff --git a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs index 6e9df4255..b1e633dd9 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiHeader.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiHeader.cs @@ -125,8 +125,7 @@ public OpenApiHeader(OpenApiHeader header) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -134,40 +133,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); - } - - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // description @@ -210,21 +183,12 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O } /// - /// Serialize to Open Api v2.0 + /// Serialize to OpenAPI V2 document without using reference. /// public virtual void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); - var target = this; - target.SerializeAsV2WithoutReference(writer); - } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { writer.WriteStartObject(); // description diff --git a/src/Microsoft.OpenApi/Models/OpenApiLink.cs b/src/Microsoft.OpenApi/Models/OpenApiLink.cs index d9c9e343c..715826c67 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiLink.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiLink.cs @@ -87,8 +87,7 @@ public OpenApiLink(OpenApiLink link) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -96,37 +95,13 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); - } - - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer); - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, (writer, element) => element.SerializeAsV31(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) + internal virtual void SerializeInternal(IOpenApiWriter writer, Action callback) { - SerializeInternalWithoutReference(writer, (writer, element) => element.SerializeAsV3(writer)); - } + Utils.CheckArgumentNull(writer); - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, Action callback) - { writer.WriteStartObject(); // operationRef @@ -160,13 +135,5 @@ public void SerializeAsV2(IOpenApiWriter writer) { // Link object does not exist in V2. } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { - // Link object does not exist in V2. - } } } diff --git a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs index 2cbbeb631..121292f1e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiParameter.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiParameter.cs @@ -182,8 +182,7 @@ public OpenApiParameter(OpenApiParameter parameter) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -191,40 +190,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); - } - - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // name @@ -276,21 +249,12 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O } /// - /// Serialize to Open Api v2.0 + /// Serialize to OpenAPI V2 document without using reference. /// public virtual void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; + Utils.CheckArgumentNull(writer); - var target = this; - target.SerializeAsV2WithoutReference(writer); - } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { writer.WriteStartObject(); // in @@ -395,7 +359,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) foreach (var example in Examples) { writer.WritePropertyName(example.Key); - example.Value.Serialize(writer, OpenApiSpecVersion.OpenApi2_0); + example.Value.SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); } writer.WriteEndObject(); } diff --git a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs index fa2db1705..ea7d628ea 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiPathItem.cs @@ -91,8 +91,7 @@ public OpenApiPathItem(OpenApiPathItem pathItem) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -100,38 +99,17 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); - } - - /// - /// Serialize to Open Api v3.0 - /// - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - var target = this; - action(writer, target); - } - - /// - /// Serialize to Open Api v2.0 - /// - public virtual void SerializeAsV2(IOpenApiWriter writer) - { - Utils.CheckArgumentNull(writer);; - - var target = this; - target.SerializeAsV2WithoutReference(writer); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } /// /// Serialize inline PathItem in OpenAPI V2 /// /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) + public void SerializeAsV2(IOpenApiWriter writer) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // operations except "trace" @@ -163,28 +141,10 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) writer.WriteEndObject(); } - /// - /// Serialize inline PathItem in OpenAPI V31 - /// - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize inline PathItem in OpenAPI V3 - /// - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); - - } - - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); writer.WriteStartObject(); diff --git a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs index e937ad565..b35619a2c 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiRequestBody.cs @@ -70,8 +70,7 @@ public OpenApiRequestBody(OpenApiRequestBody requestBody) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -79,40 +78,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); - } - - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // description @@ -138,14 +111,6 @@ public void SerializeAsV2(IOpenApiWriter writer) // RequestBody object does not exist in V2. } - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { - // RequestBody object does not exist in V2. - } - internal OpenApiBodyParameter ConvertToBodyParameter() { var bodyParameter = new OpenApiBodyParameter diff --git a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs index 83f3e19e3..2fab33fd5 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiResponse.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiResponse.cs @@ -76,8 +76,7 @@ public OpenApiResponse(OpenApiResponse response) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -85,40 +84,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); - } - - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // description @@ -140,21 +113,12 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O } /// - /// Serialize to Open Api v2.0. + /// Serialize to OpenAPI V2 document without using reference. /// public virtual void SerializeAsV2(IOpenApiWriter writer) { Utils.CheckArgumentNull(writer); - var target = this; - target.SerializeAsV2WithoutReference(writer); - } - - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { writer.WriteStartObject(); // description @@ -198,7 +162,7 @@ public void SerializeAsV2WithoutReference(IOpenApiWriter writer) .SelectMany(mediaTypePair => mediaTypePair.Value.Examples)) { writer.WritePropertyName(example.Key); - example.Value.Serialize(writer, OpenApiSpecVersion.OpenApi2_0); + example.Value.SerializeInternal(writer, OpenApiSpecVersion.OpenApi2_0); } writer.WriteEndObject(); diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index 376936af3..25352086f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -411,8 +411,7 @@ public OpenApiSchema(OpenApiSchema schema) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), - (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -420,39 +419,12 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), - (writer, element) => element.SerializeAsV3WithoutReference(writer)); - } - - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer); - var target = this; - action(writer, target); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } /// - public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { writer.WriteStartObject(); @@ -590,16 +562,6 @@ public void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpec writer.WriteEndObject(); } -/// - - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { - SerializeAsV2WithoutReference( - writer: writer, - parentRequiredProperties: new HashSet(), - propertyName: null); - } - /// public virtual void SerializeAsV2(IOpenApiWriter writer) @@ -625,41 +587,6 @@ internal void WriteV31Properties(IOpenApiWriter writer) writer.WriteOptionalMap(OpenApiConstants.PatternProperties, PatternProperties, (w, s) => s.SerializeAsV31(w)); } - /// - /// Serialize to Open Api v2.0 and handles not marking the provided property - /// as readonly if its included in the provided list of required properties of parent schema. - /// - /// The open api writer. - /// The list of required properties in parent schema. - /// The property name that will be serialized. - internal void SerializeAsV2( - IOpenApiWriter writer, - ISet parentRequiredProperties, - string propertyName) - { - var target = this; - parentRequiredProperties ??= new HashSet(); - - target.SerializeAsV2WithoutReference(writer, parentRequiredProperties, propertyName); - } - - /// - /// Serialize to OpenAPI V2 document without using reference and handles not marking the provided property - /// as readonly if its included in the provided list of required properties of parent schema. - /// - /// The open api writer. - /// The list of required properties in parent schema. - /// The property name that will be serialized. - internal void SerializeAsV2WithoutReference( - IOpenApiWriter writer, - ISet parentRequiredProperties, - string propertyName) - { - writer.WriteStartObject(); - WriteAsSchemaProperties(writer, parentRequiredProperties, propertyName); - writer.WriteEndObject(); - } - internal void WriteAsItemsProperties(IOpenApiWriter writer) { // type @@ -726,11 +653,22 @@ internal void WriteAsItemsProperties(IOpenApiWriter writer) writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi2_0); } - internal void WriteAsSchemaProperties( + /// + /// Serialize to Open Api v2.0 and handles not marking the provided property + /// as readonly if its included in the provided list of required properties of parent schema. + /// + /// The open api writer. + /// The list of required properties in parent schema. + /// The property name that will be serialized. + internal void SerializeAsV2( IOpenApiWriter writer, ISet parentRequiredProperties, string propertyName) { + parentRequiredProperties ??= new HashSet(); + + writer.WriteStartObject(); + // type writer.WriteProperty(OpenApiConstants.Type, (string)Type); @@ -857,6 +795,8 @@ internal void WriteAsSchemaProperties( // extensions writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi2_0); + + writer.WriteEndObject(); } private object DeepCloneType(object type) diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs index 964c9dc3c..33a07beda 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs @@ -100,7 +100,7 @@ public OpenApiSecurityScheme(OpenApiSecurityScheme securityScheme) /// public virtual void SerializeAsV31(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer), SerializeAsV31WithoutReference); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_1, (writer, element) => element.SerializeAsV31(writer)); } /// @@ -108,40 +108,14 @@ public virtual void SerializeAsV31(IOpenApiWriter writer) /// public virtual void SerializeAsV3(IOpenApiWriter writer) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer), SerializeAsV3WithoutReference); + SerializeInternal(writer, OpenApiSpecVersion.OpenApi3_0, (writer, element) => element.SerializeAsV3(writer)); } - /// - /// Serialize to Open Api v3.0 - /// - private void SerializeInternal(IOpenApiWriter writer, Action callback, - Action action) - { - Utils.CheckArgumentNull(writer);; - action(writer); - } - - /// - /// Serialize to OpenAPI V31 document without using reference. - /// - public virtual void SerializeAsV31WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_1, - (writer, element) => element.SerializeAsV31(writer)); - } - - /// - /// Serialize to OpenAPI V3 document without using reference. - /// - public virtual void SerializeAsV3WithoutReference(IOpenApiWriter writer) - { - SerializeInternalWithoutReference(writer, OpenApiSpecVersion.OpenApi3_0, - (writer, element) => element.SerializeAsV3(writer)); - } - - internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, OpenApiSpecVersion version, + internal virtual void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version, Action callback) { + Utils.CheckArgumentNull(writer); + writer.WriteStartObject(); // type @@ -189,15 +163,8 @@ internal virtual void SerializeInternalWithoutReference(IOpenApiWriter writer, O /// public virtual void SerializeAsV2(IOpenApiWriter writer) { - Utils.CheckArgumentNull(writer);; - SerializeAsV2WithoutReference(writer); - } + Utils.CheckArgumentNull(writer); - /// - /// Serialize to OpenAPI V2 document without using reference. - /// - public void SerializeAsV2WithoutReference(IOpenApiWriter writer) - { if (Type == SecuritySchemeType.Http && Scheme != OpenApiConstants.Basic) { // Bail because V2 does not support non-basic HTTP scheme diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs index 834e6aa3b..88ac484b3 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiCallbackReference.cs @@ -81,7 +81,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -95,7 +95,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs index feea24cea..7f4170e83 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiExampleReference.cs @@ -104,7 +104,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV3(writer)); } } @@ -118,7 +118,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, referenceElement) => referenceElement.SerializeAsV31(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs index 49f566966..e27734e08 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiHeaderReference.cs @@ -119,7 +119,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } @@ -133,7 +133,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -147,7 +147,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs index ffc7f3532..57fa90f0b 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiLinkReference.cs @@ -102,7 +102,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -116,7 +116,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs index f677ea0a1..a4601dc89 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiParameterReference.cs @@ -135,7 +135,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -149,7 +149,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } @@ -163,7 +163,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs index 21979093c..212bf72da 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiPathItemReference.cs @@ -105,7 +105,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs index be6399c9f..1588cfd81 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiRequestBodyReference.cs @@ -93,7 +93,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -107,7 +107,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs index cf5d06bb5..ed6a0b3cc 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiResponseReference.cs @@ -98,7 +98,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -112,7 +112,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } @@ -126,7 +126,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index b4b2b639e..4ee1c3fbd 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -6,6 +6,7 @@ using Microsoft.OpenApi.Writers; using System; using System.Collections.Generic; +using System.Runtime; using System.Text.Json.Nodes; namespace Microsoft.OpenApi.Models.References @@ -186,10 +187,16 @@ public override void SerializeAsV31(IOpenApiWriter writer) _reference.SerializeAsV31(writer); return; } - else + // If Loop is detected then just Serialize as a reference. + else if (!writer.GetSettings().LoopDetector.PushLoop(this)) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV31WithoutReference(writer)); + writer.GetSettings().LoopDetector.SaveLoop(this); + _reference.SerializeAsV31(writer); + return; } + + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); + writer.GetSettings().LoopDetector.PopLoop(); } /// @@ -200,10 +207,16 @@ public override void SerializeAsV3(IOpenApiWriter writer) _reference.SerializeAsV3(writer); return; } - else + // If Loop is detected then just Serialize as a reference. + else if (!writer.GetSettings().LoopDetector.PushLoop(this)) { - SerializeInternal(writer, (writer, element) => element.SerializeAsV3WithoutReference(writer)); + writer.GetSettings().LoopDetector.SaveLoop(this); + _reference.SerializeAsV3(writer); + return; } + + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); + writer.GetSettings().LoopDetector.PopLoop(); } /// @@ -216,7 +229,7 @@ public override void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, (writer, element) => element.SerializeAsV2WithoutReference(writer)); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs index 74a6828d7..43fa7423f 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs @@ -104,7 +104,7 @@ public override void SerializeAsV3(IOpenApiWriter writer) } else { - SerializeInternal(writer, SerializeAsV3WithoutReference); + SerializeInternal(writer, (writer, element) => element.SerializeAsV3(writer)); } } @@ -118,7 +118,7 @@ public override void SerializeAsV31(IOpenApiWriter writer) } else { - SerializeInternal(writer, SerializeAsV31WithoutReference); + SerializeInternal(writer, (writer, element) => element.SerializeAsV31(writer)); } } @@ -132,16 +132,16 @@ public override void SerializeAsV2(IOpenApiWriter writer) } else { - SerializeInternal(writer, SerializeAsV2WithoutReference); + SerializeInternal(writer, (writer, element) => element.SerializeAsV2(writer)); } } /// private void SerializeInternal(IOpenApiWriter writer, - Action action) + Action action) { Utils.CheckArgumentNull(writer);; - action(writer); + action(writer, Target); } } } From a9803f71ebd7ffa6829e82ec230e97d20da6a25b Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:39:07 +0300 Subject: [PATCH 40/44] clean up tests --- .../V31Tests/OpenApiDocumentTests.cs | 23 ++++--------------- .../V3Tests/OpenApiDocumentTests.cs | 2 +- .../Models/OpenApiCallbackTests.cs | 2 +- .../Models/OpenApiExampleTests.cs | 2 +- .../Models/OpenApiHeaderTests.cs | 4 ++-- .../Models/OpenApiLinkTests.cs | 2 +- .../Models/OpenApiParameterTests.cs | 8 +++---- .../Models/OpenApiRequestBodyTests.cs | 2 +- .../Models/OpenApiResponseTests.cs | 4 ++-- .../Models/OpenApiSecuritySchemeTests.cs | 2 +- .../Writers/OpenApiYamlWriterTests.cs | 1 - 11 files changed, 19 insertions(+), 33 deletions(-) diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index b22e428f2..2ada8e4bd 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -22,24 +22,6 @@ public OpenApiDocumentTests() OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); } - public static T Clone(T element) where T : IOpenApiSerializable - { - using var stream = new MemoryStream(); - IOpenApiWriter writer; - var streamWriter = new FormattingStreamWriter(stream, CultureInfo.InvariantCulture); - writer = new OpenApiJsonWriter(streamWriter, new OpenApiJsonWriterSettings() - { - InlineLocalReferences = true - }); - element.SerializeAsV31(writer); - writer.Flush(); - stream.Position = 0; - - using var streamReader = new StreamReader(stream); - var result = streamReader.ReadToEnd(); - return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_1, out OpenApiDiagnostic diagnostic4); - } - [Fact] public void ParseDocumentWithWebhooksShouldSucceed() { @@ -408,6 +390,11 @@ public void ParseDocumentsWithReusablePathItemInWebhooksSucceeds() .Excluding(y => y.BaseUri)); actual.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 }); + + var outputWriter = new StringWriter(CultureInfo.InvariantCulture); + var writer = new OpenApiJsonWriter(outputWriter, new() { InlineLocalReferences = true } ); + actual.OpenApiDocument.SerializeAsV31(writer); + var serialized = outputWriter.ToString(); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index fa58fa5bc..1e69c6818 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -63,7 +63,7 @@ public OpenApiSecurityScheme CloneSecurityScheme(OpenApiSecurityScheme element) { InlineLocalReferences = true }); - element.SerializeAsV3WithoutReference(writer); + element.SerializeAsV3(writer); writer.Flush(); stream.Position = 0; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs index 083b89ffc..c871c50c3 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiCallbackTests.cs @@ -138,7 +138,7 @@ public async Task SerializeReferencedCallbackAsV3JsonWithoutReferenceWorks(bool var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedCallback.SerializeAsV3WithoutReference(writer); + ReferencedCallback.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs index ef9786272..266761f70 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiExampleTests.cs @@ -141,7 +141,7 @@ public async Task SerializeReferencedExampleAsV3JsonWithoutReferenceWorks(bool p var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedExample.SerializeAsV3WithoutReference(writer); + ReferencedExample.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs index de569bb49..014092e93 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiHeaderTests.cs @@ -81,7 +81,7 @@ public async Task SerializeReferencedHeaderAsV3JsonWithoutReferenceWorks(bool pr var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedHeader.SerializeAsV3WithoutReference(writer); + ReferencedHeader.SerializeAsV3(writer); writer.Flush(); // Assert @@ -132,7 +132,7 @@ public async Task SerializeReferencedHeaderAsV2JsonWithoutReferenceWorks(bool pr var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedHeader.SerializeAsV2WithoutReference(writer); + ReferencedHeader.SerializeAsV2(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs index d4e7f95f4..194d909b1 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiLinkTests.cs @@ -116,7 +116,7 @@ public async Task SerializeReferencedLinkAsV3JsonWithoutReferenceWorksAsync(bool var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedLink.SerializeAsV3WithoutReference(writer); + ReferencedLink.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs index f40913dd4..6893fe692 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiParameterTests.cs @@ -352,7 +352,7 @@ public async Task SerializeReferencedParameterAsV3JsonWithoutReferenceWorksAsync var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedParameter.SerializeAsV3WithoutReference(writer); + ReferencedParameter.SerializeAsV3(writer); writer.Flush(); // Assert @@ -386,7 +386,7 @@ public async Task SerializeReferencedParameterAsV2JsonWithoutReferenceWorksAsync var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedParameter.SerializeAsV2WithoutReference(writer); + ReferencedParameter.SerializeAsV2(writer); writer.Flush(); // Assert @@ -420,7 +420,7 @@ public async Task SerializeParameterWithFormStyleAndExplodeFalseWorksAsync(bool var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ParameterWithFormStyleAndExplodeFalse.SerializeAsV3WithoutReference(writer); + ParameterWithFormStyleAndExplodeFalse.SerializeAsV3(writer); writer.Flush(); // Assert @@ -437,7 +437,7 @@ public async Task SerializeParameterWithFormStyleAndExplodeTrueWorksAsync(bool p var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ParameterWithFormStyleAndExplodeTrue.SerializeAsV3WithoutReference(writer); + ParameterWithFormStyleAndExplodeTrue.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs index 5101bb22b..d6bd2cc69 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiRequestBodyTests.cs @@ -92,7 +92,7 @@ public async Task SerializeReferencedRequestBodyAsV3JsonWithoutReferenceWorksAsy var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedRequestBody.SerializeAsV3WithoutReference(writer); + ReferencedRequestBody.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs index 631490a38..2de154306 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiResponseTests.cs @@ -374,7 +374,7 @@ public async Task SerializeReferencedResponseAsV3JsonWithoutReferenceWorksAsync( var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput }); // Act - ReferencedV3Response.SerializeAsV3WithoutReference(writer); + ReferencedV3Response.SerializeAsV3(writer); writer.Flush(); // Assert @@ -408,7 +408,7 @@ public async Task SerializeReferencedResponseAsV2JsonWithoutReferenceWorksAsync( var writer = new OpenApiJsonWriter(outputStringWriter, new OpenApiJsonWriterSettings { Terse = produceTerseOutput }); // Act - ReferencedV2Response.SerializeAsV2WithoutReference(writer); + ReferencedV2Response.SerializeAsV2(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs index 49a5dcbfd..68b5867ea 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs @@ -333,7 +333,7 @@ public async Task SerializeReferencedSecuritySchemeAsV3JsonWithoutReferenceWorks var writer = new OpenApiJsonWriter(outputStringWriter, new() { Terse = produceTerseOutput }); // Act - ReferencedSecurityScheme.SerializeAsV3WithoutReference(writer); + ReferencedSecurityScheme.SerializeAsV3(writer); writer.Flush(); // Assert diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index 56b8fd83c..977247f7a 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -390,7 +390,6 @@ public void WriteInlineSchema() // Act doc.SerializeAsV3(writer); var mediaType = doc.Paths["/"].Operations[OperationType.Get].Responses["200"].Content["application/json"]; - //mediaType.SerializeAsV3(writer); var actual = outputString.GetStringBuilder().ToString(); // Assert From e4b0adf9eac8d0dde1d4e6e0c3fc9719b713477d Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:39:49 +0300 Subject: [PATCH 41/44] Add tests and samples --- .../OpenApiSchema/schemaWithExamples.yaml | 4 +++ .../Models/OpenApiDocumentTests.cs | 28 ++++++++++++++++++- .../Samples/docWithReusableWebhooks.yaml | 26 +++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithExamples.yaml create mode 100644 test/Microsoft.OpenApi.Tests/Models/Samples/docWithReusableWebhooks.yaml diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithExamples.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithExamples.yaml new file mode 100644 index 000000000..56bcb1e4c --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithExamples.yaml @@ -0,0 +1,4 @@ +type: string +examples: + - fedora + - ubuntu \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs index d0b6f8904..c6927fcfb 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiDocumentTests.cs @@ -1614,7 +1614,33 @@ public void SerializeDocumentWithRootJsonSchemaDialectPropertyWorks() var actual = doc.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_1); // Assert - Assert.Equal(expected.MakeLineBreaksEnvironmentNeutral(), actual.MakeLineBreaksEnvironmentNeutral()); + actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral()); + } + + [Fact] + public void SerializeV31DocumentWithRefsInWebhooksWorks() + { + var expected = @"description: Returns all pets from the system that the user has access to +operationId: findPets +responses: + '200': + description: pet response + content: + application/json: + schema: + type: array + items: + type: object"; + + var doc = OpenApiDocument.Load("Models/Samples/docWithReusableWebhooks.yaml").OpenApiDocument; + + var stringWriter = new StringWriter(); + var writer = new OpenApiYamlWriter(stringWriter, new OpenApiWriterSettings { InlineLocalReferences = true }); + var webhooks = doc.Webhooks["pets"].Operations; + + webhooks[OperationType.Get].SerializeAsV31(writer); + var actual = stringWriter.ToString(); + actual.MakeLineBreaksEnvironmentNeutral().Should().BeEquivalentTo(expected.MakeLineBreaksEnvironmentNeutral()); } } } diff --git a/test/Microsoft.OpenApi.Tests/Models/Samples/docWithReusableWebhooks.yaml b/test/Microsoft.OpenApi.Tests/Models/Samples/docWithReusableWebhooks.yaml new file mode 100644 index 000000000..6d3af550e --- /dev/null +++ b/test/Microsoft.OpenApi.Tests/Models/Samples/docWithReusableWebhooks.yaml @@ -0,0 +1,26 @@ +openapi : 3.1.0 +info: + title: Webhook Example + version: 1.0.0 +jsonSchemaDialect: "http://json-schema.org/draft-07/schema#" +webhooks: + pets: + $ref: '#/components/pathItems/pets' +components: + schemas: + petSchema: + type: object + pathItems: + pets: + get: + description: Returns all pets from the system that the user has access to + operationId: findPets + responses: + '200': + description: pet response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/petSchema' \ No newline at end of file From 97a13db503a646bf250206614f844f0c651f8f0c Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:39:59 +0300 Subject: [PATCH 42/44] Bump test coverage --- .../Extensions/OpenApiTypeMapperTests.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs index ee6d6e658..bb42a9c2a 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs @@ -15,17 +15,36 @@ public class OpenApiTypeMapperTests public static IEnumerable PrimitiveTypeData => new List { new object[] { typeof(int), new OpenApiSchema { Type = "integer", Format = "int32" } }, + new object[] { typeof(decimal), new OpenApiSchema { Type = "number", Format = "double" } }, + new object[] { typeof(bool?), new OpenApiSchema { Type = "boolean", Nullable = true } }, + new object[] { typeof(Guid), new OpenApiSchema { Type = "string", Format = "uuid" } }, + new object[] { typeof(uint), new OpenApiSchema { Type = "integer", Format = "int32" } }, + new object[] { typeof(long), new OpenApiSchema { Type = "integer", Format = "int64" } }, + new object[] { typeof(ulong), new OpenApiSchema { Type = "integer", Format = "int64" } }, new object[] { typeof(string), new OpenApiSchema { Type = "string" } }, new object[] { typeof(double), new OpenApiSchema { Type = "number", Format = "double" } }, new object[] { typeof(float?), new OpenApiSchema { Type = "number", Format = "float", Nullable = true } }, + new object[] { typeof(byte?), new OpenApiSchema { Type = "string", Format = "byte", Nullable = true } }, + new object[] { typeof(int?), new OpenApiSchema { Type = "integer", Format = "int32", Nullable = true } }, + new object[] { typeof(uint?), new OpenApiSchema { Type = "integer", Format = "int32", Nullable = true } }, + new object[] { typeof(DateTimeOffset?), new OpenApiSchema { Type = "string", Format = "date-time", Nullable = true } }, + new object[] { typeof(double?), new OpenApiSchema { Type = "number", Format = "double", Nullable = true } }, + new object[] { typeof(char?), new OpenApiSchema { Type = "string", Nullable = true } }, new object[] { typeof(DateTimeOffset), new OpenApiSchema { Type = "string", Format = "date-time" } } }; public static IEnumerable OpenApiDataTypes => new List { new object[] { new OpenApiSchema { Type = "integer", Format = "int32"}, typeof(int) }, + new object[] { new OpenApiSchema { Type = "number", Format = "decimal"}, typeof(decimal) }, + new object[] { new OpenApiSchema { Type = "number", Format = null, Nullable = false}, typeof(double) }, new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = false}, typeof(int) }, new object[] { new OpenApiSchema { Type = "integer", Format = null, Nullable = true}, typeof(int?) }, + new object[] { new OpenApiSchema { Type = "number", Format = "decimal", Nullable = true}, typeof(decimal?) }, + new object[] { new OpenApiSchema { Type = "number", Format = "double", Nullable = true}, typeof(double?) }, + new object[] { new OpenApiSchema { Type = "string", Format = "date-time", Nullable = true}, typeof(DateTimeOffset?) }, + new object[] { new OpenApiSchema { Type = "string", Format = "char", Nullable = true}, typeof(char?) }, + new object[] { new OpenApiSchema { Type = "string", Format = "uuid", Nullable = true}, typeof(Guid?) }, new object[] { new OpenApiSchema { Type = "string" }, typeof(string) }, new object[] { new OpenApiSchema { Type = "number", Format = "double" }, typeof(double) }, new object[] { new OpenApiSchema { Type = "number", Format = "float", Nullable = true }, typeof(float?) }, From 9f118b90b06eaca2afc9e7205906256b669d52cb Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:41:06 +0300 Subject: [PATCH 43/44] Update public API --- .../PublicApi/PublicApi.approved.txt | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 0e8f3e22e..7eb01a70c 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -219,9 +219,6 @@ namespace Microsoft.OpenApi.Interfaces { Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } bool UnresolvedReference { get; set; } - void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer); - void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer); - void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer); } public interface IOpenApiSerializable : Microsoft.OpenApi.Interfaces.IOpenApiElement { @@ -333,11 +330,8 @@ namespace Microsoft.OpenApi.Models public virtual bool UnresolvedReference { get; set; } public void AddPathItem(Microsoft.OpenApi.Expressions.RuntimeExpression expression, Microsoft.OpenApi.Models.OpenApiPathItem pathItem) { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiComponents : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -598,13 +592,10 @@ namespace Microsoft.OpenApi.Models public virtual string Summary { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual System.Text.Json.Nodes.JsonNode Value { get; set; } - public void Serialize(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version) { } - public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeInternal(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version) { } } public abstract class OpenApiExtensibleDictionary : System.Collections.Generic.Dictionary, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable where T : Microsoft.OpenApi.Interfaces.IOpenApiSerializable @@ -646,11 +637,8 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiInfo : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -694,11 +682,8 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.OpenApiServer Server { get; set; } public virtual bool UnresolvedReference { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiMediaType : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -782,11 +767,8 @@ namespace Microsoft.OpenApi.Models public virtual Microsoft.OpenApi.Models.ParameterStyle? Style { get; set; } public virtual bool UnresolvedReference { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPathItem : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -801,12 +783,9 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IList Servers { get; set; } public virtual string Summary { get; set; } public void AddOperation(Microsoft.OpenApi.Models.OperationType operationType, Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } + public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiPaths : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary { @@ -843,11 +822,8 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IDictionary Extensions { get; set; } public virtual bool Required { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiResponse : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -861,11 +837,8 @@ namespace Microsoft.OpenApi.Models public virtual System.Collections.Generic.IDictionary Headers { get; set; } public virtual System.Collections.Generic.IDictionary Links { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiResponses : Microsoft.OpenApi.Models.OpenApiExtensibleDictionary { @@ -931,12 +904,9 @@ namespace Microsoft.OpenApi.Models public virtual bool WriteOnly { get; set; } public virtual Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeInternalWithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version, System.Action callback) { } + public void SerializeInternal(Microsoft.OpenApi.Writers.IOpenApiWriter writer, Microsoft.OpenApi.OpenApiSpecVersion version, System.Action callback) { } } public class OpenApiSecurityRequirement : System.Collections.Generic.Dictionary>, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { @@ -961,11 +931,8 @@ namespace Microsoft.OpenApi.Models public virtual string Scheme { get; set; } public virtual Microsoft.OpenApi.Models.SecuritySchemeType Type { get; set; } public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public void SerializeAsV2WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public virtual void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV31WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } - public virtual void SerializeAsV3WithoutReference(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } public class OpenApiServer : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { From 264f9100aa9397248a413ef9684ae56db7678703 Mon Sep 17 00:00:00 2001 From: Maggiekimani1 Date: Tue, 27 Aug 2024 14:46:52 +0300 Subject: [PATCH 44/44] copy file to output directory --- test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj index a0cf97f87..81991fd63 100644 --- a/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj +++ b/test/Microsoft.OpenApi.Tests/Microsoft.OpenApi.Tests.csproj @@ -1,4 +1,4 @@ - + net8.0 false @@ -42,6 +42,10 @@ OpenApiCallbackReferenceTests.cs + + PreserveNewest + +