From 878593b7a7e6ff1f2adc6965608c46e5f8ce8f38 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 31 Dec 2024 15:16:16 -0500 Subject: [PATCH 1/2] fix: side effects in tag references Signed-off-by: Vincent Biret --- .../OpenApiYamlReader.cs | 7 +- .../Interfaces/IOpenApiReader.cs | 4 +- .../Interfaces/IOpenApiVersionService.cs | 2 +- .../Models/OpenApiDocument.cs | 15 -- .../Models/OpenApiOperation.cs | 4 +- src/Microsoft.OpenApi/Models/OpenApiTag.cs | 8 +- .../Models/References/OpenApiTagReference.cs | 70 +++---- .../Reader/OpenApiJsonReader.cs | 9 +- .../Reader/OpenApiModelFactory.cs | 21 +- .../Reader/ParseNodes/ListNode.cs | 5 +- .../Reader/ParseNodes/ParseNode.cs | 3 +- .../Reader/ParsingContext.cs | 9 +- .../Reader/V2/OpenApiDocumentDeserializer.cs | 12 +- .../Reader/V2/OpenApiOperationDeserializer.cs | 14 +- .../Reader/V2/OpenApiSchemaDeserializer.cs | 2 +- .../OpenApiSecurityRequirementDeserializer.cs | 4 +- .../Reader/V3/OpenApiDocumentDeserializer.cs | 11 +- .../Reader/V3/OpenApiOperationDeserializer.cs | 6 +- .../Reader/V3/OpenApiSchemaDeserializer.cs | 2 +- .../OpenApiSecurityRequirementDeserializer.cs | 4 +- .../V3/OpenApiServerVariableDeserializer.cs | 2 +- .../Reader/V31/OpenApiDocumentDeserializer.cs | 11 +- .../V31/OpenApiOperationDeserializer.cs | 4 +- .../Reader/V31/OpenApiSchemaDeserializer.cs | 6 +- .../OpenApiSecurityRequirementDeserializer.cs | 4 +- .../V31/OpenApiServerVariableDeserializer.cs | 4 +- .../Services/OpenApiVisitorBase.cs | 15 ++ .../Services/OpenApiWalker.cs | 39 +++- .../UtilityFiles/OpenApiDocumentMock.cs | 198 ++++++++---------- .../V2Tests/OpenApiContactTests.cs | 2 +- .../V31Tests/OpenApiSchemaTests.cs | 28 +-- .../V3Tests/OpenApiCallbackTests.cs | 2 +- .../V3Tests/OpenApiContactTests.cs | 2 +- .../V3Tests/OpenApiDiscriminatorTests.cs | 2 +- .../V3Tests/OpenApiDocumentTests.cs | 51 ++--- .../V3Tests/OpenApiEncodingTests.cs | 4 +- .../V3Tests/OpenApiExampleTests.cs | 2 +- .../V3Tests/OpenApiInfoTests.cs | 6 +- .../V3Tests/OpenApiMediaTypeTests.cs | 4 +- .../V3Tests/OpenApiOperationTests.cs | 15 +- .../V3Tests/OpenApiParameterTests.cs | 20 +- .../V3Tests/OpenApiSchemaTests.cs | 6 +- .../V3Tests/OpenApiSecuritySchemeTests.cs | 10 +- .../V3Tests/OpenApiXmlTests.cs | 2 +- .../petStoreWithTagAndSecurity.yaml | 2 + .../Models/OpenApiOperationTests.cs | 4 +- .../References/OpenApiTagReferenceTest.cs | 9 +- .../PublicApi/PublicApi.approved.txt | 28 +-- .../Walkers/WalkerLocationTests.cs | 4 + .../Workspaces/OpenApiReferencableTests.cs | 3 - 50 files changed, 342 insertions(+), 359 deletions(-) diff --git a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs index 217db91b3..488f497c9 100644 --- a/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs +++ b/src/Microsoft.OpenApi.Readers/OpenApiYamlReader.cs @@ -86,6 +86,7 @@ public static ReadResult Read(JsonNode jsonNode, OpenApiReaderSettings settings, /// public T ReadFragment(MemoryStream input, OpenApiSpecVersion version, + OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement { @@ -105,13 +106,13 @@ public T ReadFragment(MemoryStream input, return default; } - return ReadFragment(jsonNode, version, out diagnostic, settings); + return ReadFragment(jsonNode, version, openApiDocument, out diagnostic, settings); } /// - public static T ReadFragment(JsonNode input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement + public static T ReadFragment(JsonNode input, OpenApiSpecVersion version, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement { - return _jsonReader.ReadFragment(input, version, out diagnostic, settings); + return _jsonReader.ReadFragment(input, version, openApiDocument, out diagnostic, settings); } /// diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs index 9398551dd..82a064478 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiReader.cs @@ -5,6 +5,7 @@ using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; +using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Reader; namespace Microsoft.OpenApi.Interfaces @@ -36,9 +37,10 @@ public interface IOpenApiReader /// /// Memory stream containing OpenAPI description to parse. /// Version of the OpenAPI specification that the fragment conforms to. + /// The OpenApiDocument object to which the fragment belongs, used to lookup references. /// Returns diagnostic object containing errors detected during parsing. /// The OpenApiReader settings. /// Instance of newly created IOpenApiElement. - T ReadFragment(MemoryStream input, OpenApiSpecVersion version, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement; + T ReadFragment(MemoryStream input, OpenApiSpecVersion version, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement; } } diff --git a/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs b/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs index 97d1d3c9b..073962a35 100644 --- a/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs +++ b/src/Microsoft.OpenApi/Interfaces/IOpenApiVersionService.cs @@ -28,7 +28,7 @@ internal interface IOpenApiVersionService /// document fragment node /// A host document instance. /// Instance of OpenAPIElement - T LoadElement(ParseNode node, OpenApiDocument doc = null) where T : IOpenApiElement; + T LoadElement(ParseNode node, OpenApiDocument doc) where T : IOpenApiElement; /// /// Converts a generic RootNode instance into a strongly typed OpenApiDocument diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 268007141..42409db8e 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -503,21 +503,6 @@ private static string ConvertByteArrayToString(byte[] hash) throw new ArgumentException(Properties.SRResource.LocalReferenceRequiresType); } - // Special case for Tag - if (reference.Type == ReferenceType.Tag) - { - foreach (var tag in this.Tags ?? Enumerable.Empty()) - { - if (tag.Name == reference.Id) - { - tag.Reference = reference; - return tag; - } - } - - return null; - } - string uriLocation; if (reference.Id.Contains("/")) // this means its a URL reference { diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 6e54cd894..4906d1f76 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -26,7 +26,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible, IOpenA /// A list of tags for API documentation control. /// Tags can be used for logical grouping of operations by resources or any other qualifier. /// - public IList? Tags { get; set; } = new List(); + public IList? Tags { get; set; } = []; /// /// A short summary of what the operation does. @@ -121,7 +121,7 @@ public OpenApiOperation() { } /// public OpenApiOperation(OpenApiOperation? operation) { - Tags = operation?.Tags != null ? new List(operation.Tags) : null; + Tags = operation?.Tags != null ? new List(operation.Tags) : null; Summary = operation?.Summary ?? Summary; Description = operation?.Description ?? Description; ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiTag.cs b/src/Microsoft.OpenApi/Models/OpenApiTag.cs index 8e9321fe8..58fa99694 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiTag.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiTag.cs @@ -11,7 +11,7 @@ namespace Microsoft.OpenApi.Models /// /// Tag Object. /// - public class OpenApiTag : IOpenApiReferenceable, IOpenApiExtensible + public class OpenApiTag : IOpenApiSerializable, IOpenApiExtensible { /// /// The name of the tag. @@ -38,11 +38,6 @@ public class OpenApiTag : IOpenApiReferenceable, IOpenApiExtensible /// public bool UnresolvedReference { get; set; } - /// - /// Reference. - /// - public OpenApiReference Reference { get; set; } - /// /// Parameterless constructor /// @@ -58,7 +53,6 @@ public OpenApiTag(OpenApiTag tag) ExternalDocs = tag?.ExternalDocs != null ? new(tag.ExternalDocs) : null; Extensions = tag?.Extensions != null ? new Dictionary(tag.Extensions) : null; UnresolvedReference = tag?.UnresolvedReference ?? UnresolvedReference; - Reference = tag?.Reference != null ? new(tag.Reference) : null; } /// diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index 664f784f3..50017c4f9 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections.Generic; +using System.Linq; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; @@ -10,21 +12,24 @@ namespace Microsoft.OpenApi.Models.References /// /// Tag Object Reference /// - public class OpenApiTagReference : OpenApiTag + public class OpenApiTagReference : OpenApiTag, IOpenApiReferenceable { internal OpenApiTag _target; - private readonly OpenApiReference _reference; - private string _description; - private OpenApiTag Target + /// + /// Reference. + /// + public OpenApiReference Reference { get; set; } + + /// + /// Resolved target of the reference. + /// + public OpenApiTag Target { get { - _target ??= Reference.HostDocument?.ResolveReferenceTo(_reference); - _target ??= new OpenApiTag() { Name = _reference.Id }; - OpenApiTag resolved = new OpenApiTag(_target); - if (!string.IsNullOrEmpty(_description)) resolved.Description = _description; - return resolved; + _target ??= Reference.HostDocument?.Tags.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, Reference.Id)); + return _target; } } @@ -37,50 +42,43 @@ public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument) { Utils.CheckArgumentNullOrEmpty(referenceId); - _reference = new OpenApiReference() + Reference = new OpenApiReference() { Id = referenceId, HostDocument = hostDocument, Type = ReferenceType.Tag }; - - Reference = _reference; } - internal OpenApiTagReference(OpenApiTag target, string referenceId) + /// + /// Copy Constructor + /// + /// The source to copy information from. + public OpenApiTagReference(OpenApiTagReference source):base() { - _target = target; - - _reference = new OpenApiReference() - { - Id = referenceId, - Type = ReferenceType.Tag, - }; + Reference = source?.Reference != null ? new(source.Reference) : null; + _target = source._target; } + private const string ReferenceErrorMessage = "Setting the value from the reference is not supported, use the target property instead."; /// - public override string Description - { - get => string.IsNullOrEmpty(_description) ? Target?.Description : _description; - set => _description = value; - } + public override string Description { get => Target.Description; set => throw new InvalidOperationException(ReferenceErrorMessage); } /// - public override OpenApiExternalDocs ExternalDocs { get => Target?.ExternalDocs; set => Target.ExternalDocs = value; } + public override OpenApiExternalDocs ExternalDocs { get => Target.ExternalDocs; set => throw new InvalidOperationException(ReferenceErrorMessage); } /// - public override IDictionary Extensions { get => Target?.Extensions; set => Target.Extensions = value; } + public override IDictionary Extensions { get => Target.Extensions; set => throw new InvalidOperationException(ReferenceErrorMessage); } /// - public override string Name { get => Target?.Name; set => Target.Name = value; } + public override string Name { get => Target.Name; set => throw new InvalidOperationException(ReferenceErrorMessage); } /// public override void SerializeAsV3(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV3(writer); - return; + Reference.SerializeAsV3(writer); } else { @@ -91,10 +89,9 @@ public override void SerializeAsV3(IOpenApiWriter writer) /// public override void SerializeAsV31(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV31(writer); - return; + Reference.SerializeAsV31(writer); } else { @@ -105,10 +102,9 @@ public override void SerializeAsV31(IOpenApiWriter writer) /// public override void SerializeAsV2(IOpenApiWriter writer) { - if (!writer.GetSettings().ShouldInlineReference(_reference)) + if (!writer.GetSettings().ShouldInlineReference(Reference)) { - _reference.SerializeAsV2(writer); - return; + Reference.SerializeAsV2(writer); } else { diff --git a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs index 71cf3f8c3..4aad45278 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs @@ -148,10 +148,12 @@ public async Task ReadAsync(Stream input, /// public T ReadFragment(MemoryStream input, OpenApiSpecVersion version, + OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement { - if (input is null) throw new ArgumentNullException(nameof(input)); + Utils.CheckArgumentNull(input); + Utils.CheckArgumentNull(openApiDocument); JsonNode jsonNode; @@ -167,12 +169,13 @@ public T ReadFragment(MemoryStream input, return default; } - return ReadFragment(jsonNode, version, out diagnostic); + return ReadFragment(jsonNode, version, openApiDocument, out diagnostic); } /// public T ReadFragment(JsonNode input, OpenApiSpecVersion version, + OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement { @@ -187,7 +190,7 @@ public T ReadFragment(JsonNode input, try { // Parse the OpenAPI element - element = context.ParseFragment(input, version); + element = context.ParseFragment(input, version, openApiDocument); } catch (OpenApiException ex) { diff --git a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs index 31b939548..0d7960f92 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiModelFactory.cs @@ -61,14 +61,15 @@ public static ReadResult Load(MemoryStream stream, /// Stream containing OpenAPI description to parse. /// Version of the OpenAPI specification that the fragment conforms to. /// + /// The OpenApiDocument object to which the fragment belongs, used to lookup references. /// Returns diagnostic object containing errors detected during parsing. /// The OpenApiReader settings. /// Instance of newly created IOpenApiElement. /// The OpenAPI element. - public static T Load(MemoryStream input, OpenApiSpecVersion version, string format, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement + public static T Load(MemoryStream input, OpenApiSpecVersion version, string format, OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, OpenApiReaderSettings settings = null) where T : IOpenApiElement { format ??= InspectStreamFormat(input); - return OpenApiReaderRegistry.GetReader(format).ReadFragment(input, version, out diagnostic, settings); + return OpenApiReaderRegistry.GetReader(format).ReadFragment(input, version, openApiDocument, out diagnostic, settings); } /// @@ -91,13 +92,14 @@ public static async Task LoadAsync(string url, OpenApiReaderSettings /// The path to the OpenAPI file /// Version of the OpenAPI specification that the fragment conforms to. /// The OpenApiReader settings. + /// The OpenApiDocument object to which the fragment belongs, used to lookup references. /// /// Instance of newly created IOpenApiElement. /// The OpenAPI element. - public static async Task LoadAsync(string url, OpenApiSpecVersion version, OpenApiReaderSettings settings = null, CancellationToken token = default) where T : IOpenApiElement + public static async Task LoadAsync(string url, OpenApiSpecVersion version, OpenApiDocument openApiDocument, OpenApiReaderSettings settings = null, CancellationToken token = default) where T : IOpenApiElement { var (stream, format) = await RetrieveStreamAndFormatAsync(url, token).ConfigureAwait(false); - return await LoadAsync(stream, version, format, settings, token); + return await LoadAsync(stream, version, openApiDocument, format, settings, token); } /// @@ -141,27 +143,30 @@ public static async Task LoadAsync(Stream input, string format = nul /// /// /// + /// The document used to lookup tag or schema references. /// /// /// /// public static async Task LoadAsync(Stream input, OpenApiSpecVersion version, + OpenApiDocument openApiDocument, string format = null, OpenApiReaderSettings settings = null, CancellationToken token = default) where T : IOpenApiElement { + Utils.CheckArgumentNull(openApiDocument); if (input is null) throw new ArgumentNullException(nameof(input)); if (input is MemoryStream memoryStream) { - return Load(memoryStream, version, format, out var _, settings); + return Load(memoryStream, version, format, openApiDocument, out var _, settings); } else { memoryStream = new MemoryStream(); await input.CopyToAsync(memoryStream, 81920, token).ConfigureAwait(false); memoryStream.Position = 0; - return Load(memoryStream, version, format, out var _, settings); + return Load(memoryStream, version, format, openApiDocument, out var _, settings); } } @@ -191,12 +196,14 @@ public static ReadResult Parse(string input, /// /// The input string. /// + /// The OpenApiDocument object to which the fragment belongs, used to lookup references. /// The diagnostic entity containing information from the reading process. /// The Open API format /// The OpenApi reader settings. /// An OpenAPI document instance. public static T Parse(string input, OpenApiSpecVersion version, + OpenApiDocument openApiDocument, out OpenApiDiagnostic diagnostic, string format = null, OpenApiReaderSettings settings = null) where T : IOpenApiElement @@ -205,7 +212,7 @@ public static T Parse(string input, format ??= InspectInputFormat(input); settings ??= new OpenApiReaderSettings(); using var stream = new MemoryStream(Encoding.UTF8.GetBytes(input)); - return Load(stream, version, format, out diagnostic, settings); + return Load(stream, version, format, openApiDocument, out diagnostic, settings); } private static readonly OpenApiReaderSettings DefaultReaderSettings = new(); diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs index 6654344cd..f07d93745 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ListNode.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; @@ -44,14 +43,14 @@ public override List CreateListOfAny() return list; } - public override List CreateSimpleList(Func map) + public override List CreateSimpleList(Func map, OpenApiDocument openApiDocument) { if (_nodeList == null) { throw new OpenApiReaderException($"Expected list while parsing {typeof(T).Name}", _nodeList); } - return _nodeList.Select(n => map(new(Context, n), null)).ToList(); + return _nodeList.Select(n => map(new(Context, n), openApiDocument)).ToList(); } public IEnumerator GetEnumerator() diff --git a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs index 44d626f35..4b2523901 100644 --- a/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs +++ b/src/Microsoft.OpenApi/Reader/ParseNodes/ParseNode.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Text.Json.Nodes; -using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Exceptions; using Microsoft.OpenApi.Models; @@ -57,7 +56,7 @@ public virtual Dictionary CreateMap(Func CreateSimpleList(Func map) + public virtual List CreateSimpleList(Func map, OpenApiDocument openApiDocument) { throw new OpenApiReaderException("Cannot create simple list from this type of node.", Context); } diff --git a/src/Microsoft.OpenApi/Reader/ParsingContext.cs b/src/Microsoft.OpenApi/Reader/ParsingContext.cs index 7a8b07244..184760c17 100644 --- a/src/Microsoft.OpenApi/Reader/ParsingContext.cs +++ b/src/Microsoft.OpenApi/Reader/ParsingContext.cs @@ -105,8 +105,9 @@ public OpenApiDocument Parse(JsonNode jsonNode) /// /// /// OpenAPI version of the fragment + /// The OpenApiDocument object to which the fragment belongs, used to lookup references. /// An OpenApiDocument populated based on the passed yamlDocument - public T ParseFragment(JsonNode jsonNode, OpenApiSpecVersion version) where T : IOpenApiElement + public T ParseFragment(JsonNode jsonNode, OpenApiSpecVersion version, OpenApiDocument openApiDocument) where T : IOpenApiElement { var node = ParseNode.Create(this, jsonNode); @@ -116,16 +117,16 @@ public T ParseFragment(JsonNode jsonNode, OpenApiSpecVersion version) where T { case OpenApiSpecVersion.OpenApi2_0: VersionService = new OpenApiV2VersionService(Diagnostic); - element = this.VersionService.LoadElement(node); + element = this.VersionService.LoadElement(node, openApiDocument); break; case OpenApiSpecVersion.OpenApi3_0: this.VersionService = new OpenApiV3VersionService(Diagnostic); - element = this.VersionService.LoadElement(node); + element = this.VersionService.LoadElement(node, openApiDocument); break; case OpenApiSpecVersion.OpenApi3_1: this.VersionService = new OpenApiV31VersionService(Diagnostic); - element = this.VersionService.LoadElement(node); + element = this.VersionService.LoadElement(node, openApiDocument); break; } diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs index f33d98465..95d26845d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiDocumentDeserializer.cs @@ -28,16 +28,16 @@ internal static partial class OpenApiV2Deserializer {"host", (_, n, _) => n.Context.SetTempStorage("host", n.GetScalarValue())}, {"basePath", (_, n, _) => n.Context.SetTempStorage("basePath", n.GetScalarValue())}, { - "schemes", (_, n, _) => n.Context.SetTempStorage( + "schemes", (_, n, doc) => n.Context.SetTempStorage( "schemes", n.CreateSimpleList( - (s, p) => s.GetScalarValue())) + (s, p) => s.GetScalarValue(), doc)) }, { "consumes", - (_, n, _) => + (_, n, doc) => { - var consumes = n.CreateSimpleList((s, p) => s.GetScalarValue()); + var consumes = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc); if (consumes.Count > 0) { n.Context.SetTempStorage(TempStorageKeys.GlobalConsumes, consumes); @@ -45,8 +45,8 @@ internal static partial class OpenApiV2Deserializer } }, { - "produces", (_, n, _) => { - var produces = n.CreateSimpleList((s, p) => s.GetScalarValue()); + "produces", (_, n, doc) => { + var produces = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc); if (produces.Count > 0) { n.Context.SetTempStorage(TempStorageKeys.GlobalProduces, produces); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs index d65f7a16b..d1f894407 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiOperationDeserializer.cs @@ -24,8 +24,7 @@ internal static partial class OpenApiV2Deserializer "tags", (o, n, doc) => o.Tags = n.CreateSimpleList( (valueNode, doc) => LoadTagByReference( - valueNode.Context, - valueNode.GetScalarValue(), doc)) + valueNode.GetScalarValue(), doc), doc) }, { "summary", @@ -48,16 +47,16 @@ internal static partial class OpenApiV2Deserializer (o, n, t) => o.Parameters = n.CreateList(LoadParameter, t) }, { - "consumes", (_, n, _) => { - var consumes = n.CreateSimpleList((s, p) => s.GetScalarValue()); + "consumes", (_, n, doc) => { + var consumes = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc); if (consumes.Count > 0) { n.Context.SetTempStorage(TempStorageKeys.OperationConsumes,consumes); } } }, { - "produces", (_, n, _) => { - var produces = n.CreateSimpleList((s, p) => s.GetScalarValue()); + "produces", (_, n, doc) => { + var produces = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc); if (produces.Count > 0) { n.Context.SetTempStorage(TempStorageKeys.OperationProduces, produces); } @@ -205,8 +204,7 @@ internal static OpenApiRequestBody CreateRequestBody( return requestBody; } - private static OpenApiTag LoadTagByReference( - ParsingContext context, + private static OpenApiTagReference LoadTagByReference( string tagName, OpenApiDocument hostDocument = null) { return new OpenApiTagReference(tagName, hostDocument); diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs index 53208fd40..7c5ab3d2d 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSchemaDeserializer.cs @@ -76,7 +76,7 @@ internal static partial class OpenApiV2Deserializer }, { "required", - (o, n, _) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue())) + (o, n, doc) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue(), doc)) }, { "enum", diff --git a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs index 5e430206c..4dfdbba16 100644 --- a/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V2/OpenApiSecurityRequirementDeserializer.cs @@ -12,7 +12,7 @@ namespace Microsoft.OpenApi.Reader.V2 /// internal static partial class OpenApiV2Deserializer { - public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("security"); @@ -24,7 +24,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, mapNode.Context, property.Name); - var scopes = property.Value.CreateSimpleList((n2, p) => n2.GetScalarValue()); + var scopes = property.Value.CreateSimpleList((n2, p) => n2.GetScalarValue(), hostDocument); if (scheme != null) { diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs index 3fcdb9af7..f349250b6 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiDocumentDeserializer.cs @@ -26,16 +26,7 @@ internal static partial class OpenApiV3Deserializer {"servers", (o, n, _) => o.Servers = n.CreateList(LoadServer, o)}, {"paths", (o, n, _) => o.Paths = LoadPaths(n, o)}, {"components", (o, n, _) => o.Components = LoadComponents(n, o)}, - {"tags", (o, n, _) => {o.Tags = n.CreateList(LoadTag, o); - foreach (var tag in o.Tags) - { - tag.Reference = new() - { - Id = tag.Name, - Type = ReferenceType.Tag - }; - } - } }, + {"tags", (o, n, _) => o.Tags = n.CreateList(LoadTag, o) }, {"externalDocs", (o, n, _) => o.ExternalDocs = LoadExternalDocs(n, o)}, {"security", (o, n, _) => o.SecurityRequirements = n.CreateList(LoadSecurityRequirement, o)} }; diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs index 33aadc141..72ce13d58 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiOperationDeserializer.cs @@ -21,8 +21,7 @@ internal static partial class OpenApiV3Deserializer "tags", (o, n, doc) => o.Tags = n.CreateSimpleList( (valueNode, doc) => LoadTagByReference( - valueNode.Context, - valueNode.GetScalarValue(), doc)) + valueNode.GetScalarValue(), doc), doc) }, { "summary", @@ -87,8 +86,7 @@ internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument h return operation; } - private static OpenApiTag LoadTagByReference( - ParsingContext context, + private static OpenApiTagReference LoadTagByReference( string tagName, OpenApiDocument hostDocument) { return new OpenApiTagReference(tagName, hostDocument); diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index f3c02a6c8..9faafca12 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -76,7 +76,7 @@ internal static partial class OpenApiV3Deserializer }, { "required", - (o, n, _) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue())) + (o, n, doc) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue(), doc)) }, { "enum", diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs index e1d4ddc2f..73610713c 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSecurityRequirementDeserializer.cs @@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.Reader.V3 /// internal static partial class OpenApiV3Deserializer { - public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("security"); @@ -23,7 +23,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, { var scheme = LoadSecuritySchemeByReference(mapNode.Context, property.Name); - var scopes = property.Value.CreateSimpleList((value, p) => value.GetScalarValue()); + var scopes = property.Value.CreateSimpleList((value, p) => value.GetScalarValue(), hostDocument); if (scheme != null) { diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs index 1bfa4fe04..dc04b9e4a 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiServerVariableDeserializer.cs @@ -18,7 +18,7 @@ internal static partial class OpenApiV3Deserializer { { "enum", - (o, n, _) => o.Enum = n.CreateSimpleList((s, p) => s.GetScalarValue()) + (o, n, doc) => o.Enum = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc) }, { "default", diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs index 8137fb460..2ce56486e 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs @@ -25,16 +25,7 @@ internal static partial class OpenApiV31Deserializer {"paths", (o, n, _) => o.Paths = LoadPaths(n, o)}, {"webhooks", (o, n, _) => o.Webhooks = n.CreateMap(LoadPathItem, o)}, {"components", (o, n, _) => o.Components = LoadComponents(n, o)}, - {"tags", (o, n, _) => {o.Tags = n.CreateList(LoadTag, o); - foreach (var tag in o.Tags) - { - tag.Reference = new OpenApiReference() - { - Id = tag.Name, - Type = ReferenceType.Tag - }; - } - } }, + {"tags", (o, n, _) => o.Tags = n.CreateList(LoadTag, o) }, {"externalDocs", (o, n, _) => o.ExternalDocs = LoadExternalDocs(n, o)}, {"security", (o, n, _) => o.SecurityRequirements = n.CreateList(LoadSecurityRequirement, o)} }; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs index fb143e4c6..b2946fab5 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiOperationDeserializer.cs @@ -17,7 +17,7 @@ internal static partial class OpenApiV31Deserializer { "tags", (o, n, doc) => o.Tags = n.CreateSimpleList( (valueNode, doc) => - LoadTagByReference(valueNode.GetScalarValue(), doc)) + LoadTagByReference(valueNode.GetScalarValue(), doc), doc) }, { "summary", (o, n, _) => @@ -104,7 +104,7 @@ internal static OpenApiOperation LoadOperation(ParseNode node, OpenApiDocument h return operation; } - private static OpenApiTag LoadTagByReference(string tagName, OpenApiDocument hostDocument = null) + private static OpenApiTagReference LoadTagByReference(string tagName, OpenApiDocument hostDocument = null) { var tagObject = new OpenApiTagReference(tagName, hostDocument); return tagObject; diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs index ad943dce4..83be6f773 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs @@ -106,7 +106,7 @@ internal static partial class OpenApiV31Deserializer }, { "required", - (o, n, _) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue())) + (o, n, doc) => o.Required = new HashSet(n.CreateSimpleList((n2, p) => n2.GetScalarValue(), doc)) }, { "enum", @@ -114,7 +114,7 @@ internal static partial class OpenApiV31Deserializer }, { "type", - (o, n, _) => + (o, n, doc) => { if (n is ValueNode) { @@ -122,7 +122,7 @@ internal static partial class OpenApiV31Deserializer } else { - var list = n.CreateSimpleList((n2, p) => n2.GetScalarValue()); + var list = n.CreateSimpleList((n2, p) => n2.GetScalarValue(), doc); JsonSchemaType combinedType = 0; foreach(var type in list) { diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs index 94753dafa..b204c83d4 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSecurityRequirementDeserializer.cs @@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.Reader.V31 /// internal static partial class OpenApiV31Deserializer { - public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument = null) + public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, OpenApiDocument hostDocument) { var mapNode = node.CheckMapNode("security"); @@ -23,7 +23,7 @@ public static OpenApiSecurityRequirement LoadSecurityRequirement(ParseNode node, { var scheme = LoadSecuritySchemeByReference(property.Name, hostDocument); - var scopes = property.Value.CreateSimpleList((value, p) => value.GetScalarValue()); + var scopes = property.Value.CreateSimpleList((value, p) => value.GetScalarValue(), hostDocument); if (scheme != null) { diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs index e5344554d..74dc1c504 100644 --- a/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiServerVariableDeserializer.cs @@ -17,9 +17,9 @@ internal static partial class OpenApiV31Deserializer new() { { - "enum", (o, n, _) => + "enum", (o, n, doc) => { - o.Enum = n.CreateSimpleList((s, p) => s.GetScalarValue()); + o.Enum = n.CreateSimpleList((s, p) => s.GetScalarValue(), doc); } }, { diff --git a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs index c731d4d8b..a889628b3 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiVisitorBase.cs @@ -7,6 +7,7 @@ using System.Text.Json.Nodes; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Services { @@ -262,6 +263,13 @@ public virtual void Visit(OpenApiTag tag) { } + /// + /// Visits + /// + public virtual void Visit(OpenApiTagReference tag) + { + } + /// /// Visits /// @@ -304,6 +312,13 @@ public virtual void Visit(IList openApiTags) { } + /// + /// Visits list of + /// + public virtual void Visit(IList openApiTags) + { + } + /// /// Visits list of /// diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 2dd882ce7..9321b3b17 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -80,6 +80,28 @@ internal void Walk(IList tags) } } + /// + /// Visits list of and child objects + /// + internal void Walk(IList tags) + { + if (tags == null) + { + return; + } + + _visitor.Visit(tags); + + // Visit tags + if (tags != null) + { + for (var i = 0; i < tags.Count; i++) + { + Walk(i.ToString(), () => Walk(tags[i])); + } + } + } + /// /// Visits and child objects /// @@ -424,15 +446,22 @@ internal void Walk(OpenApiTag tag) return; } - if (tag is OpenApiTagReference) + _visitor.Visit(tag); + _visitor.Visit(tag.ExternalDocs); + _visitor.Visit(tag as IOpenApiExtensible); + } + + /// + /// Visits and child objects + /// + internal void Walk(OpenApiTagReference tag) + { + if (tag == null) { - Walk(tag as IOpenApiReferenceable); return; } - _visitor.Visit(tag); - _visitor.Visit(tag.ExternalDocs); - _visitor.Visit(tag as IOpenApiExtensible); + Walk(tag as IOpenApiReferenceable); } /// diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index 91dd59919..edbf143fe 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -4,6 +4,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; namespace Microsoft.OpenApi.Tests.UtilityFiles { @@ -19,6 +20,17 @@ public static class OpenApiDocumentMock public static OpenApiDocument CreateOpenApiDocument() { var applicationJsonMediaType = "application/json"; + const string getTeamsActivityByPeriodPath = "/reports/microsoft.graph.getTeamsUserActivityCounts(period={period})"; + const string getTeamsActivityByDatePath = "/reports/microsoft.graph.getTeamsUserActivityUserDetail(date={date})"; + const string usersPath = "/users"; + const string usersByIdPath = "/users/{user-id}"; + const string messagesByIdPath = "/users/{user-id}/messages/{message-id}"; + const string administrativeUnitRestorePath = "/administrativeUnits/{administrativeUnit-id}/microsoft.graph.restore"; + const string logoPath = "/applications/{application-id}/logo"; + const string securityProfilesPath = "/security/hostSecurityProfiles"; + const string communicationsCallsKeepAlivePath = "/communications/calls/{call-id}/microsoft.graph.keepAlive"; + const string eventsDeltaPath = "/groups/{group-id}/events/{event-id}/calendar/events/microsoft.graph.delta"; + const string refPath = "/applications/{application-id}/createdOnBehalfOf/$ref"; var document = new OpenApiDocument { @@ -57,22 +69,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/reports/microsoft.graph.getTeamsUserActivityCounts(period={period})"] = new() + [getTeamsActivityByPeriodPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "reports.Functions" - } - } - }, OperationId = "reports.getTeamsUserActivityCounts", Summary = "Invoke function getTeamsUserActivityUserCounts", Parameters = new List @@ -131,22 +134,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/reports/microsoft.graph.getTeamsUserActivityUserDetail(date={date})"] = new() + [getTeamsActivityByDatePath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "reports.Functions" - } - } - }, OperationId = "reports.getTeamsUserActivityUserDetail-a3f1", Summary = "Invoke function getTeamsUserActivityUserDetail", Parameters = new List @@ -203,22 +197,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/users"] = new() + [usersPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "users.user" - } - } - }, OperationId = "users.user.ListUser", Summary = "Get entities from users", Responses = new() @@ -266,22 +251,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/users/{user-id}"] = new() + [usersByIdPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "users.user" - } - } - }, OperationId = "users.user.GetUser", Summary = "Get entity from users by key", Responses = new() @@ -315,15 +291,6 @@ public static OpenApiDocument CreateOpenApiDocument() { OperationType.Patch, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "users.user" - } - } - }, OperationId = "users.user.UpdateUser", Summary = "Update entity in users", Responses = new() @@ -339,22 +306,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/users/{user-id}/messages/{message-id}"] = new() + [messagesByIdPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "users.message" - } - } - }, OperationId = "users.GetMessages", Summary = "Get messages from users", Description = "The messages in a mailbox or folder. Read-only. Nullable.", @@ -403,22 +361,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/administrativeUnits/{administrativeUnit-id}/microsoft.graph.restore"] = new() + [administrativeUnitRestorePath] = new() { Operations = new Dictionary { { OperationType.Post, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "administrativeUnits.Actions" - } - } - }, OperationId = "administrativeUnits.restore", Summary = "Invoke action restore", Parameters = new List @@ -470,22 +419,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/applications/{application-id}/logo"] = new() + [logoPath] = new() { Operations = new Dictionary { { OperationType.Put, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "applications.application" - } - } - }, OperationId = "applications.application.UpdateLogo", Summary = "Update media content for application in applications", Responses = new() @@ -501,22 +441,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/security/hostSecurityProfiles"] = new() + [securityProfilesPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "security.hostSecurityProfile" - } - } - }, OperationId = "security.ListHostSecurityProfiles", Summary = "Get hostSecurityProfiles from security", Responses = new() @@ -564,22 +495,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/communications/calls/{call-id}/microsoft.graph.keepAlive"] = new() + [communicationsCallsKeepAlivePath] = new() { Operations = new Dictionary { { OperationType.Post, new OpenApiOperation { - Tags = new List - { - { - new() - { - Name = "communications.Actions" - } - } - }, OperationId = "communications.calls.call.keepAlive", Summary = "Invoke action keepAlive", Parameters = new List @@ -621,20 +543,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/groups/{group-id}/events/{event-id}/calendar/events/microsoft.graph.delta"] = new() + [eventsDeltaPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - new() - { - Name = "groups.Functions" - } - }, OperationId = "groups.group.events.event.calendar.events.delta", Summary = "Invoke function delta", Parameters = new List @@ -711,20 +626,13 @@ public static OpenApiDocument CreateOpenApiDocument() } } }, - ["/applications/{application-id}/createdOnBehalfOf/$ref"] = new() + [refPath] = new() { Operations = new Dictionary { { OperationType.Get, new OpenApiOperation { - Tags = new List - { - new() - { - Name = "applications.directoryObject" - } - }, OperationId = "applications.GetRefCreatedOnBehalfOf", Summary = "Get ref of createdOnBehalfOf from applications" } @@ -755,8 +663,68 @@ public static OpenApiDocument CreateOpenApiDocument() } } } + }, + Tags = new List + { + new() + { + Name = "reports.Functions", + Description = "The reports.Functions operations" + }, + new() + { + Name = "users.user", + Description = "The users.user operations" + }, + new() + { + Name = "users.message", + Description = "The users.message operations" + }, + new() + { + Name = "administrativeUnits.Actions", + Description = "The administrativeUnits.Actions operations" + }, + new() + { + Name = "applications.application", + Description = "The applications.application operations" + }, + new() + { + Name = "security.hostSecurityProfile", + Description = "The security.hostSecurityProfile operations" + }, + new() + { + Name = "communications.Actions", + Description = "The communications.Actions operations" + }, + new() + { + Name = "groups.Functions", + Description = "The groups.Functions operations" + }, + new() + { + Name = "applications.directoryObject", + Description = "The applications.directoryObject operations" + } } }; + document.Paths[getTeamsActivityByPeriodPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("reports.Functions", document)); + document.Paths[getTeamsActivityByDatePath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("reports.Functions", document)); + document.Paths[usersPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("users.user", document)); + document.Paths[usersByIdPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("users.user", document)); + document.Paths[usersByIdPath].Operations[OperationType.Patch].Tags!.Add(new OpenApiTagReference("users.user", document)); + document.Paths[messagesByIdPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("users.message", document)); + document.Paths[administrativeUnitRestorePath].Operations[OperationType.Post].Tags!.Add(new OpenApiTagReference("administrativeUnits.Actions", document)); + document.Paths[logoPath].Operations[OperationType.Put].Tags!.Add(new OpenApiTagReference("applications.application", document)); + document.Paths[securityProfilesPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("security.hostSecurityProfile", document)); + document.Paths[communicationsCallsKeepAlivePath].Operations[OperationType.Post].Tags!.Add(new OpenApiTagReference("communications.Actions", document)); + document.Paths[eventsDeltaPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("groups.Functions", document)); + document.Paths[refPath].Operations[OperationType.Get].Tags!.Add(new OpenApiTagReference("applications.directoryObject", document)); return document; } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiContactTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiContactTests.cs index 413d3ee7b..8bbc7ffdb 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiContactTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiContactTests.cs @@ -23,7 +23,7 @@ public void ParseStringContactFragmentShouldSucceed() """; // Act - var contact = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi2_0, out var diagnostic); + var contact = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi2_0, new(), out var diagnostic); // Assert diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs index 312353ba8..e01c8645d 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs @@ -86,7 +86,7 @@ public async Task ParseBasicV31SchemaShouldSucceed() // Act var schema = await OpenApiModelFactory.LoadAsync( - System.IO.Path.Combine(SampleFolderPath, "jsonSchema.json"), OpenApiSpecVersion.OpenApi3_1); + Path.Combine(SampleFolderPath, "jsonSchema.json"), OpenApiSpecVersion.OpenApi3_1, new()); // Assert schema.Should().BeEquivalentTo(expectedObject); @@ -112,7 +112,7 @@ public void ParseSchemaWithTypeArrayWorks() }; // Act - var actual = OpenApiModelFactory.Parse(schema, OpenApiSpecVersion.OpenApi3_1, out _); + var actual = OpenApiModelFactory.Parse(schema, OpenApiSpecVersion.OpenApi3_1, new(), out _); // Assert actual.Should().BeEquivalentTo(expected); @@ -161,7 +161,7 @@ public async Task ParseV31SchemaShouldSucceed() var path = Path.Combine(SampleFolderPath, "schema.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); var expectedSchema = new OpenApiSchema { Type = JsonSchemaType.Object, @@ -184,7 +184,7 @@ public async Task ParseAdvancedV31SchemaShouldSucceed() { // Arrange and Act var path = Path.Combine(SampleFolderPath, "advancedSchema.yaml"); - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); var expectedSchema = new OpenApiSchema { @@ -275,7 +275,7 @@ public void ParseSchemaWithExamplesShouldSucceed() - ubuntu "; // Act - var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, out _, "yaml"); + var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, new(), out _, "yaml"); // Assert schema.Examples.Should().HaveCount(2); @@ -314,7 +314,7 @@ public async Task SerializeV31SchemaWithMultipleTypesAsV3Works() var path = Path.Combine(SampleFolderPath, "schemaWithTypeArray.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); var writer = new StringWriter(); schema.SerializeAsV3(new OpenApiYamlWriter(writer)); @@ -333,7 +333,7 @@ public async Task SerializeV31SchemaWithMultipleTypesAsV2Works() var path = Path.Combine(SampleFolderPath, "schemaWithTypeArray.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); var writer = new StringWriter(); schema.SerializeAsV2(new OpenApiYamlWriter(writer)); @@ -353,7 +353,7 @@ public async Task SerializeV3SchemaWithNullableAsV31Works() var path = Path.Combine(SampleFolderPath, "schemaWithNullable.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_0); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_0, new()); var writer = new StringWriter(); schema.SerializeAsV31(new OpenApiYamlWriter(writer)); @@ -374,7 +374,7 @@ public async Task SerializeV2SchemaWithNullableExtensionAsV31Works() var path = Path.Combine(SampleFolderPath, "schemaWithNullableExtension.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi2_0); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi2_0, new()); var writer = new StringWriter(); schema.SerializeAsV31(new OpenApiYamlWriter(writer)); @@ -393,7 +393,7 @@ public void SerializeSchemaWithTypeArrayAndNullableDoesntEmitType() var expected = @"{ }"; - var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, out _, "yaml"); + var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, new(), out _, "yaml"); var writer = new StringWriter(); schema.SerializeAsV2(new OpenApiYamlWriter(writer)); @@ -411,7 +411,7 @@ public async Task LoadSchemaWithNullableExtensionAsV31Works(string filePath) var path = Path.Combine(SampleFolderPath, filePath); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); // Assert schema.Type.Should().Be(JsonSchemaType.String | JsonSchemaType.Null); @@ -451,7 +451,7 @@ public async Task SerializeSchemaWithJsonSchemaKeywordsWorks() var path = Path.Combine(SampleFolderPath, "schemaWithJsonSchemaKeywords.yaml"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); // serialization var writer = new StringWriter(); @@ -495,7 +495,7 @@ public async Task ParseSchemaWithConstWorks() var path = Path.Combine(SampleFolderPath, "schemaWithConst.json"); // Act - var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1); + var schema = await OpenApiModelFactory.LoadAsync(path, OpenApiSpecVersion.OpenApi3_1, new()); schema.Properties["status"].Const.Should().Be("active"); schema.Properties["user"].Properties["role"].Const.Should().Be("admin"); @@ -517,7 +517,7 @@ public void ParseSchemaWithUnrecognizedKeywordsWorks() ""x-test"": ""test"" } "; - var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, out _, "json"); + var schema = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_1, new(), out _, "json"); schema.UnrecognizedKeywords.Should().HaveCount(2); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 1e50ca6e0..d7ed66049 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -25,7 +25,7 @@ public OpenApiCallbackTests() public async Task ParseBasicCallbackShouldSucceed() { // Act - var callback = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicCallback.yaml"), OpenApiSpecVersion.OpenApi3_0); + var callback = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicCallback.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert callback.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiContactTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiContactTests.cs index d6d0422c4..d230d33d2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiContactTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiContactTests.cs @@ -23,7 +23,7 @@ public void ParseStringContactFragmentShouldSucceed() """; // Act - var contact = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out var diagnostic, OpenApiConstants.Json); + var contact = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, new(), out var diagnostic, OpenApiConstants.Json); // Assert diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs index ba62c7f33..78196ee87 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDiscriminatorTests.cs @@ -31,7 +31,7 @@ public async Task ParseBasicDiscriminatorShouldSucceed() memoryStream.Position = 0; // Act - var discriminator = OpenApiModelFactory.Load(memoryStream, OpenApiSpecVersion.OpenApi3_0, OpenApiConstants.Yaml, out var diagnostic); + var discriminator = OpenApiModelFactory.Load(memoryStream, OpenApiSpecVersion.OpenApi3_0, OpenApiConstants.Yaml, new(), out var diagnostic); // Assert discriminator.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index c281206e3..dba7b73d0 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -46,7 +46,7 @@ private static T Clone(T element) where T : IOpenApiSerializable using var streamReader = new StreamReader(stream); var result = streamReader.ReadToEnd(); - return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, out var _); + return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, new(), out var _); } private static OpenApiSecurityScheme CloneSecurityScheme(OpenApiSecurityScheme element) @@ -63,7 +63,7 @@ private static OpenApiSecurityScheme CloneSecurityScheme(OpenApiSecurityScheme e using var streamReader = new StreamReader(stream); var result = streamReader.ReadToEnd(); - return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, out var _); + return OpenApiModelFactory.Parse(result, OpenApiSpecVersion.OpenApi3_0, new(), out var _); } [Fact] @@ -707,27 +707,9 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() HostDocument = actual.Document }; - var tag1 = new OpenApiTag - { - Name = "tagName1", - Description = "tagDescription1", - Reference = new OpenApiReference - { - Id = "tagName1", - Type = ReferenceType.Tag - } - }; + var tagReference1 = new OpenApiTagReference("tagName1", null); - - var tag2 = new OpenApiTag - { - Name = "tagName2", - Reference = new OpenApiReference - { - Id = "tagName2", - Type = ReferenceType.Tag - } - }; + var tagReference2 = new OpenApiTagReference("tagName2", null); var securityScheme1 = CloneSecurityScheme(components.SecuritySchemes["securitySchemeName1"]); @@ -781,10 +763,10 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { [OperationType.Get] = new OpenApiOperation { - Tags = new List + Tags = new List { - tag1, - tag2 + tagReference1, + tagReference2 }, Description = "Returns all pets from the system that the user has access to", OperationId = "findPets", @@ -869,10 +851,10 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() }, [OperationType.Post] = new OpenApiOperation { - Tags = new List + Tags = new List { - tag1, - tag2 + tagReference1, + tagReference2 }, Description = "Creates a new pet in the store. Duplicates are allowed", OperationId = "addPet", @@ -1063,6 +1045,11 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() { Name = "tagName1", Description = "tagDescription1" + }, + new OpenApiTag + { + Name = "tagName2", + Description = "tagDescription2" } }, SecurityRequirements = new List @@ -1080,14 +1067,20 @@ public async Task ParseModifiedPetStoreDocumentWithTagAndSecurityShouldSucceed() } }; + tagReference1.Reference.HostDocument = expected; + tagReference2.Reference.HostDocument = expected; + actual.Document.Should().BeEquivalentTo(expected, options => options .Excluding(x => x.HashCode) - .Excluding(m => m.Tags[0].Reference) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Reference.HostDocument) + .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[0].Target) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[0].Reference.HostDocument) + .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[0].Target) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[1].Reference.HostDocument) + .Excluding(x => x.Paths["/pets"].Operations[OperationType.Get].Tags[1].Target) .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[1].Reference.HostDocument) + .Excluding(x => x.Paths["/pets"].Operations[OperationType.Post].Tags[1].Target) .Excluding(x => x.Workspace) .Excluding(y => y.BaseUri)); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs index 91e428c49..8a9f2fe4f 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiEncodingTests.cs @@ -24,7 +24,7 @@ public OpenApiEncodingTests() public async Task ParseBasicEncodingShouldSucceed() { // Act - var encoding = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicEncoding.yaml"), OpenApiSpecVersion.OpenApi3_0); + var encoding = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicEncoding.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert encoding.Should().BeEquivalentTo( @@ -40,7 +40,7 @@ public async Task ParseAdvancedEncodingShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedEncoding.yaml")); // Act - var encoding = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var encoding = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert encoding.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs index 633a0f688..5bb83a9fc 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiExampleTests.cs @@ -25,7 +25,7 @@ public OpenApiExampleTests() [Fact] public async Task ParseAdvancedExampleShouldSucceed() { - var example = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "advancedExample.yaml"), OpenApiSpecVersion.OpenApi3_0); + var example = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "advancedExample.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); var expected = new OpenApiExample { Value = new JsonObject diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiInfoTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiInfoTests.cs index fdd5ae8ee..db59dad32 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiInfoTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiInfoTests.cs @@ -27,7 +27,7 @@ public OpenApiInfoTests() public async Task ParseAdvancedInfoShouldSucceed() { // Act - var openApiInfo = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "advancedInfo.yaml"), OpenApiSpecVersion.OpenApi3_0); + var openApiInfo = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "advancedInfo.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert openApiInfo.Should().BeEquivalentTo( @@ -84,7 +84,7 @@ public async Task ParseAdvancedInfoShouldSucceed() public async Task ParseBasicInfoShouldSucceed() { // Act - var openApiInfo = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicInfo.yaml"), OpenApiSpecVersion.OpenApi3_0); + var openApiInfo = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "basicInfo.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert openApiInfo.Should().BeEquivalentTo( @@ -114,7 +114,7 @@ public async Task ParseMinimalInfoShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "minimalInfo.yaml")); // Act - var openApiInfo = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var openApiInfo = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert openApiInfo.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs index 6197cca71..36710f6ca 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiMediaTypeTests.cs @@ -28,7 +28,7 @@ public OpenApiMediaTypeTests() public async Task ParseMediaTypeWithExampleShouldSucceed() { // Act - var mediaType = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "mediaTypeWithExample.yaml"), OpenApiSpecVersion.OpenApi3_0); + var mediaType = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "mediaTypeWithExample.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert mediaType.Should().BeEquivalentTo( @@ -49,7 +49,7 @@ public async Task ParseMediaTypeWithExampleShouldSucceed() public async Task ParseMediaTypeWithExamplesShouldSucceed() { // Act - var mediaType = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "mediaTypeWithExamples.yaml"), OpenApiSpecVersion.OpenApi3_0); + var mediaType = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "mediaTypeWithExamples.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert mediaType.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs index 7dcb5e28a..22167e0ee 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiOperationTests.cs @@ -34,13 +34,17 @@ public async Task OperationWithSecurityRequirementShouldReferenceSecurityScheme( [Fact] public async Task ParseOperationWithParameterWithNoLocationShouldSucceed() { + var openApiDocument = new OpenApiDocument + { + Tags = { new OpenApiTag() { Name = "user" } } + }; // Act - var operation = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "operationWithParameterWithNoLocation.json"), OpenApiSpecVersion.OpenApi3_0); + var operation = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "operationWithParameterWithNoLocation.json"), OpenApiSpecVersion.OpenApi3_0, openApiDocument); var expectedOp = new OpenApiOperation { Tags = { - new OpenApiTagReference("user", null) + new OpenApiTagReference("user", openApiDocument) }, Summary = "Logs user into the system", Description = "", @@ -73,8 +77,11 @@ public async Task ParseOperationWithParameterWithNoLocationShouldSucceed() // Assert expectedOp.Should().BeEquivalentTo(operation, - options => options.Excluding(x => x.Tags[0].Reference.HostDocument) - .Excluding(x => x.Tags[0].Extensions)); + options => + options.Excluding(x => x.Tags[0].Reference.HostDocument) + .Excluding(x => x.Tags[0].Reference) + .Excluding(x => x.Tags[0].Target) + .Excluding(x => x.Tags[0].Extensions)); } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs index a40cb4144..a2c127728 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiParameterTests.cs @@ -32,7 +32,7 @@ public async Task ParsePathParameterShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "pathParameter.yaml")); // Act - var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -53,7 +53,7 @@ public async Task ParsePathParameterShouldSucceed() public async Task ParseQueryParameterShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "queryParameter.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "queryParameter.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -80,7 +80,7 @@ public async Task ParseQueryParameterShouldSucceed() public async Task ParseQueryParameterWithObjectTypeShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "queryParameterWithObjectType.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "queryParameterWithObjectType.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -107,7 +107,7 @@ public async Task ParseQueryParameterWithObjectTypeAndContentShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "queryParameterWithObjectTypeAndContent.yaml")); // Act - var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -148,7 +148,7 @@ public async Task ParseQueryParameterWithObjectTypeAndContentShouldSucceed() public async Task ParseHeaderParameterShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "headerParameter.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "headerParameter.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -176,7 +176,7 @@ public async Task ParseHeaderParameterShouldSucceed() public async Task ParseParameterWithNullLocationShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithNullLocation.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithNullLocation.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -200,7 +200,7 @@ public async Task ParseParameterWithNoLocationShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "parameterWithNoLocation.yaml")); // Act - var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -224,7 +224,7 @@ public async Task ParseParameterWithUnknownLocationShouldSucceed() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "parameterWithUnknownLocation.yaml")); // Act - var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(stream, OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -245,7 +245,7 @@ public async Task ParseParameterWithUnknownLocationShouldSucceed() public async Task ParseParameterWithExampleShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithExample.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithExample.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( @@ -268,7 +268,7 @@ public async Task ParseParameterWithExampleShouldSucceed() public async Task ParseParameterWithExamplesShouldSucceed() { // Act - var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithExamples.yaml"), OpenApiSpecVersion.OpenApi3_0); + var parameter = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "parameterWithExamples.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert parameter.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 8e52ad6aa..5a1f2b70b 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -68,7 +68,7 @@ public void ParseExampleStringFragmentShouldSucceed() }"; // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out var diagnostic); + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, new(), out var diagnostic); // Assert diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); @@ -91,7 +91,7 @@ public void ParseEnumFragmentShouldSucceed() ]"; // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out var diagnostic); + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, new(), out var diagnostic); // Assert diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); @@ -116,7 +116,7 @@ public void ParsePathFragmentShouldSucceed() "; // Act - var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, out var diagnostic, "yaml"); + var openApiAny = OpenApiModelFactory.Parse(input, OpenApiSpecVersion.OpenApi3_0, new(), out var diagnostic, "yaml"); // Assert diagnostic.Should().BeEquivalentTo(new OpenApiDiagnostic()); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs index 3f99bb2c5..5ff92fb0a 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSecuritySchemeTests.cs @@ -24,7 +24,7 @@ public OpenApiSecuritySchemeTests() public async Task ParseHttpSecuritySchemeShouldSucceed() { // Act - var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "httpSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0); + var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "httpSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert securityScheme.Should().BeEquivalentTo( @@ -39,7 +39,7 @@ public async Task ParseHttpSecuritySchemeShouldSucceed() public async Task ParseApiKeySecuritySchemeShouldSucceed() { // Act - var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "apiKeySecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0); + var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "apiKeySecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert securityScheme.Should().BeEquivalentTo( @@ -55,7 +55,7 @@ public async Task ParseApiKeySecuritySchemeShouldSucceed() public async Task ParseBearerSecuritySchemeShouldSucceed() { // Act - var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "bearerSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0); + var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "bearerSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert securityScheme.Should().BeEquivalentTo( @@ -71,7 +71,7 @@ public async Task ParseBearerSecuritySchemeShouldSucceed() public async Task ParseOAuth2SecuritySchemeShouldSucceed() { // Act - var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "oauth2SecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0); + var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "oauth2SecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert securityScheme.Should().BeEquivalentTo( @@ -97,7 +97,7 @@ public async Task ParseOAuth2SecuritySchemeShouldSucceed() public async Task ParseOpenIdConnectSecuritySchemeShouldSucceed() { // Act - var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "openIdConnectSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0); + var securityScheme = await OpenApiModelFactory.LoadAsync(Path.Combine(SampleFolderPath, "openIdConnectSecurityScheme.yaml"), OpenApiSpecVersion.OpenApi3_0, new()); // Assert securityScheme.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiXmlTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiXmlTests.cs index fc23865ba..c9864642d 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiXmlTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiXmlTests.cs @@ -25,7 +25,7 @@ public OpenApiXmlTests() public async Task ParseBasicXmlShouldSucceed() { // Act - var xml = await OpenApiModelFactory.LoadAsync(Resources.GetStream(Path.Combine(SampleFolderPath, "basicXml.yaml")), OpenApiSpecVersion.OpenApi3_0); + var xml = await OpenApiModelFactory.LoadAsync(Resources.GetStream(Path.Combine(SampleFolderPath, "basicXml.yaml")), OpenApiSpecVersion.OpenApi3_0, new()); // Assert xml.Should().BeEquivalentTo( diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/petStoreWithTagAndSecurity.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/petStoreWithTagAndSecurity.yaml index 528804491..78a85fae6 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/petStoreWithTagAndSecurity.yaml +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/petStoreWithTagAndSecurity.yaml @@ -210,6 +210,8 @@ components: tags: - name: tagName1 description: tagDescription1 + - name: tagName2 + description: tagDescription2 security: - securitySchemeName1: [] securitySchemeName2: diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs index 5f6b5f4e7..01b79ec02 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs @@ -87,9 +87,9 @@ public class OpenApiOperationTests private static readonly OpenApiOperation _advancedOperationWithTagsAndSecurity = new() { - Tags = new List + Tags = new List { - new OpenApiTagReference("tagId1", null) + new OpenApiTagReference("tagId1", new OpenApiDocument{ Tags = new List() { new OpenApiTag{Name = "tagId1"}} }) }, Summary = "summary1", Description = "operationDescription", diff --git a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs index 8ec0e1373..edf28f9f2 100644 --- a/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs +++ b/test/Microsoft.OpenApi.Tests/Models/References/OpenApiTagReferenceTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Globalization; using System.IO; using System.Threading.Tasks; @@ -64,10 +65,7 @@ public OpenApiTagReferenceTest() { OpenApiReaderRegistry.RegisterReader(OpenApiConstants.Yaml, new OpenApiYamlReader()); var result = OpenApiDocument.Parse(OpenApi, "yaml"); - _openApiTagReference = new("user", result.Document) - { - Description = "Users operations" - }; + _openApiTagReference = new("user", result.Document); } [Fact] @@ -75,7 +73,8 @@ public void TagReferenceResolutionWorks() { // Assert Assert.Equal("user", _openApiTagReference.Name); - Assert.Equal("Users operations", _openApiTagReference.Description); + Assert.Equal("Operations about users.", _openApiTagReference.Description); + Assert.Throws(() => _openApiTagReference.Description = "New Description"); } [Theory] diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 642dd0b82..2373b65c9 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -221,7 +221,7 @@ namespace Microsoft.OpenApi.Interfaces { Microsoft.OpenApi.Reader.ReadResult Read(System.IO.MemoryStream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings); System.Threading.Tasks.Task ReadAsync(System.IO.Stream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings, System.Threading.CancellationToken cancellationToken = default); - T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) + T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement; } public interface IOpenApiReferenceable : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiSerializable @@ -765,7 +765,7 @@ namespace Microsoft.OpenApi.Models public System.Collections.Generic.IList? Security { get; set; } public System.Collections.Generic.IList? Servers { get; set; } public string? Summary { get; set; } - public System.Collections.Generic.IList? Tags { get; set; } + public System.Collections.Generic.IList? Tags { 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) { } @@ -983,11 +983,10 @@ namespace Microsoft.OpenApi.Models public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV31(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } - public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable + public class OpenApiTag : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiTag() { } public OpenApiTag(Microsoft.OpenApi.Models.OpenApiTag tag) { } - public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } public bool UnresolvedReference { get; set; } public virtual string Description { get; set; } public virtual System.Collections.Generic.IDictionary Extensions { get; set; } @@ -1284,9 +1283,12 @@ 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 OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag + public class OpenApiTagReference : Microsoft.OpenApi.Models.OpenApiTag, Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiReferenceable, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { + public OpenApiTagReference(Microsoft.OpenApi.Models.References.OpenApiTagReference source) { } public OpenApiTagReference(string referenceId, Microsoft.OpenApi.Models.OpenApiDocument hostDocument) { } + public Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; } + public Microsoft.OpenApi.Models.OpenApiTag Target { get; } public override string Description { get; set; } public override System.Collections.Generic.IDictionary Extensions { get; set; } public override Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } @@ -1312,24 +1314,24 @@ namespace Microsoft.OpenApi.Reader public Microsoft.OpenApi.Reader.ReadResult Read(System.IO.MemoryStream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings) { } public Microsoft.OpenApi.Reader.ReadResult Read(System.Text.Json.Nodes.JsonNode jsonNode, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings, string format = null) { } public System.Threading.Tasks.Task ReadAsync(System.IO.Stream input, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings, System.Threading.CancellationToken cancellationToken = default) { } - public T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) + public T ReadFragment(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public T ReadFragment(System.Text.Json.Nodes.JsonNode input, Microsoft.OpenApi.OpenApiSpecVersion version, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) + public T ReadFragment(System.Text.Json.Nodes.JsonNode input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } } public static class OpenApiModelFactory { public static Microsoft.OpenApi.Reader.ReadResult Load(System.IO.MemoryStream stream, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static T Load(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, string format, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) + public static T Load(System.IO.MemoryStream input, Microsoft.OpenApi.OpenApiSpecVersion version, string format, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static System.Threading.Tasks.Task LoadAsync(string url, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken token = default) { } public static System.Threading.Tasks.Task LoadAsync(System.IO.Stream input, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken cancellationToken = default) { } - public static System.Threading.Tasks.Task LoadAsync(string url, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken token = default) + public static System.Threading.Tasks.Task LoadAsync(string url, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken token = default) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public static System.Threading.Tasks.Task LoadAsync(System.IO.Stream input, Microsoft.OpenApi.OpenApiSpecVersion version, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken token = default) + public static System.Threading.Tasks.Task LoadAsync(System.IO.Stream input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null, System.Threading.CancellationToken token = default) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static Microsoft.OpenApi.Reader.ReadResult Parse(string input, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) { } - public static T Parse(string input, Microsoft.OpenApi.OpenApiSpecVersion version, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) + public static T Parse(string input, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument, out Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnostic, string format = null, Microsoft.OpenApi.Reader.OpenApiReaderSettings settings = null) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } } public static class OpenApiReaderRegistry @@ -1368,7 +1370,7 @@ namespace Microsoft.OpenApi.Reader public T GetFromTempStorage(string key, object scope = null) { } public string GetLocation() { } public Microsoft.OpenApi.Models.OpenApiDocument Parse(System.Text.Json.Nodes.JsonNode jsonNode) { } - public T ParseFragment(System.Text.Json.Nodes.JsonNode jsonNode, Microsoft.OpenApi.OpenApiSpecVersion version) + public T ParseFragment(System.Text.Json.Nodes.JsonNode jsonNode, Microsoft.OpenApi.OpenApiSpecVersion version, Microsoft.OpenApi.Models.OpenApiDocument openApiDocument) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public void PopLoop(string loopid) { } public bool PushLoop(string loopId, string key) { } @@ -1501,6 +1503,7 @@ namespace Microsoft.OpenApi.Services public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServer server) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiServerVariable serverVariable) { } public virtual void Visit(Microsoft.OpenApi.Models.OpenApiTag tag) { } + public virtual void Visit(Microsoft.OpenApi.Models.References.OpenApiTagReference tag) { } public virtual void Visit(System.Collections.Generic.IDictionary operations) { } public virtual void Visit(System.Collections.Generic.IDictionary callbacks) { } public virtual void Visit(System.Collections.Generic.IDictionary encodings) { } @@ -1515,6 +1518,7 @@ 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.IList openApiTags) { } public virtual void Visit(System.Text.Json.Nodes.JsonNode node) { } } public class OpenApiWalker diff --git a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs index bec1f3602..7e12ad766 100644 --- a/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs +++ b/test/Microsoft.OpenApi.Tests/Walkers/WalkerLocationTests.cs @@ -328,5 +328,9 @@ public override void Visit(OpenApiServer server) { Locations.Add(this.PathString); } + public override void Visit(IList openApiTags) + { + Locations.Add(this.PathString); + } } } diff --git a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs index e015da4f4..3712b0662 100644 --- a/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs +++ b/test/Microsoft.OpenApi.Tests/Workspaces/OpenApiReferencableTests.cs @@ -47,8 +47,6 @@ public class OpenApiReferencableTests }; private static readonly OpenApiSchema _schemaFragment = new OpenApiSchema(); private static readonly OpenApiSecurityScheme _securitySchemeFragment = new OpenApiSecurityScheme(); - private static readonly OpenApiTag _tagFragment = new OpenApiTag(); - public static IEnumerable ResolveReferenceCanResolveValidJsonPointersTestData => new List { @@ -64,7 +62,6 @@ public class OpenApiReferencableTests new object[] { _responseFragment, "/headers/header1", _responseFragment.Headers["header1"] }, new object[] { _responseFragment, "/links/link1", _responseFragment.Links["link1"] }, new object[] { _securitySchemeFragment, "/", _securitySchemeFragment}, - new object[] { _tagFragment, "/", _tagFragment} }; [Theory] From 9db6e2d3ce9043ff6b702060eda75290aa37b401 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 31 Dec 2024 15:22:58 -0500 Subject: [PATCH 2/2] fix: potential NRT Signed-off-by: Vincent Biret --- src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs index 50017c4f9..1fcaf62f3 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiTagReference.cs @@ -57,7 +57,7 @@ public OpenApiTagReference(string referenceId, OpenApiDocument hostDocument) public OpenApiTagReference(OpenApiTagReference source):base() { Reference = source?.Reference != null ? new(source.Reference) : null; - _target = source._target; + _target = source?._target; } private const string ReferenceErrorMessage = "Setting the value from the reference is not supported, use the target property instead.";