diff --git a/src/Microsoft.OpenApi.YamlReader/OpenApiYamlReader.cs b/src/Microsoft.OpenApi.YamlReader/OpenApiYamlReader.cs index a2000327d..171c3cc38 100644 --- a/src/Microsoft.OpenApi.YamlReader/OpenApiYamlReader.cs +++ b/src/Microsoft.OpenApi.YamlReader/OpenApiYamlReader.cs @@ -31,14 +31,14 @@ public async Task ReadAsync(Stream input, if (input is null) throw new ArgumentNullException(nameof(input)); if (input is MemoryStream memoryStream) { - return Read(memoryStream, location, settings); + return UpdateFormat(Read(memoryStream, location, settings)); } else { using var preparedStream = new MemoryStream(); await input.CopyToAsync(preparedStream, copyBufferSize, cancellationToken).ConfigureAwait(false); preparedStream.Position = 0; - return Read(preparedStream, location, settings); + return UpdateFormat(Read(preparedStream, location, settings)); } } @@ -67,20 +67,27 @@ public ReadResult Read(MemoryStream input, { var diagnostic = new OpenApiDiagnostic(); diagnostic.Errors.Add(new($"#line={ex.LineNumber}", ex.Message)); + diagnostic.Format = OpenApiConstants.Yaml; return new() { Document = null, - Diagnostic = diagnostic + Diagnostic = diagnostic, }; } - return Read(jsonNode, location, settings); + return UpdateFormat(Read(jsonNode, location, settings)); + } + private static ReadResult UpdateFormat(ReadResult result) + { + result.Diagnostic ??= new OpenApiDiagnostic(); + result.Diagnostic.Format = OpenApiConstants.Yaml; + return result; } /// public static ReadResult Read(JsonNode jsonNode, Uri location, OpenApiReaderSettings settings) { - return _jsonReader.Read(jsonNode, location, settings); + return UpdateFormat(_jsonReader.Read(jsonNode, location, settings)); } /// diff --git a/src/Microsoft.OpenApi/Reader/OpenApiDiagnostic.cs b/src/Microsoft.OpenApi/Reader/OpenApiDiagnostic.cs index c66df68eb..2a6143fbf 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiDiagnostic.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiDiagnostic.cs @@ -25,6 +25,11 @@ public class OpenApiDiagnostic /// public OpenApiSpecVersion SpecificationVersion { get; set; } + /// + /// The format of the OpenAPI document (e.g., "json", "yaml"). + /// + public string? Format { get; set; } + /// /// Append another set of diagnostic Errors and Warnings to this one, this may be appended from another external /// document's parsing and we want to indicate which file it originated from. diff --git a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs index 0d29c6a6b..6b7a5fb9d 100644 --- a/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs +++ b/src/Microsoft.OpenApi/Reader/OpenApiJsonReader.cs @@ -42,10 +42,11 @@ public ReadResult Read(MemoryStream input, catch (JsonException ex) { diagnostic.Errors.Add(new OpenApiError($"#line={ex.LineNumber}", $"Please provide the correct format, {ex.Message}")); + diagnostic.Format = OpenApiConstants.Json; return new ReadResult { Document = null, - Diagnostic = diagnostic + Diagnostic = diagnostic, }; } @@ -102,11 +103,11 @@ public ReadResult Read(JsonNode jsonNode, } } } - + diagnostic.Format = OpenApiConstants.Json; return new() { Document = document, - Diagnostic = diagnostic + Diagnostic = diagnostic, }; } @@ -138,10 +139,11 @@ public async Task ReadAsync(Stream input, catch (JsonException ex) { diagnostic.Errors.Add(new OpenApiError($"#line={ex.LineNumber}", $"Please provide the correct format, {ex.Message}")); + diagnostic.Format = OpenApiConstants.Json; return new ReadResult { Document = null, - Diagnostic = diagnostic + Diagnostic = diagnostic, }; } diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiStreamReaderTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiStreamReaderTests.cs index 347611fce..d2da0d7a4 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiStreamReaderTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiStreamReaderTests.cs @@ -20,8 +20,9 @@ public async Task StreamShouldCloseIfLeaveStreamOpenSettingEqualsFalse() using var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "petStore.yaml")); var settings = new OpenApiReaderSettings { LeaveStreamOpen = false }; settings.AddYamlReader(); - _ = await OpenApiDocument.LoadAsync(stream, settings: settings); + (_, var diagnostic) = await OpenApiDocument.LoadAsync(stream, settings: settings); Assert.False(stream.CanRead); + Assert.Equal(OpenApiConstants.Yaml, diagnostic.Format); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs index 6df5d2853..f5f6078a2 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs @@ -314,7 +314,8 @@ public void InvalidHostShouldYieldError() { new OpenApiError("#/", "Invalid host") }, - SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi2_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs index ed8577b0d..46be108b6 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiDocumentTests.cs @@ -207,7 +207,7 @@ public async Task ParseDocumentWithWebhooksShouldSucceed() }; // Assert - Assert.Equivalent(new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 }, actual.Diagnostic); + Assert.Equivalent(new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1, Format = OpenApiConstants.Yaml }, actual.Diagnostic); actual.Document.Should().BeEquivalentTo(expected, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); } @@ -414,7 +414,7 @@ public async Task ParseDocumentsWithReusablePathItemInWebhooksSucceeds() .Excluding(x => x.Workspace) .Excluding(y => y.BaseUri)); Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1 }, actual.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_1, Format = OpenApiConstants.Yaml }, actual.Diagnostic); } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs index 52cfdbde0..1dee79059 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs @@ -71,7 +71,7 @@ public async Task ParseCallbackWithReferenceShouldSucceed() var callback = subscribeOperation.Callbacks["simpleHook"]; Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, result.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, Format = OpenApiConstants.Yaml }, result.Diagnostic); Assert.Equivalent( new OpenApiCallbackReference("simpleHook", result.Document) @@ -120,7 +120,7 @@ public async Task ParseMultipleCallbacksWithReferenceShouldSucceed() var subscribeOperation = path.Operations[HttpMethod.Post]; Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, result.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, Format = OpenApiConstants.Yaml }, result.Diagnostic); var callback1 = subscribeOperation.Callbacks["simpleHook"]; diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 370743141..10e4c4e0e 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -69,7 +69,8 @@ public void ParseDocumentFromInlineStringShouldSucceed() Assert.Equivalent( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); } @@ -147,7 +148,8 @@ public async Task ParseBrokenMinimalDocumentShouldYieldExpectedDiagnostic() { new OpenApiValidatorError(nameof(OpenApiInfoRules.InfoRequiredFields),"#/info/title", "The field 'title' in 'info' object is REQUIRED.") }, - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); } @@ -170,7 +172,8 @@ public async Task ParseMinimalDocumentShouldSucceed() Assert.Equivalent( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); } @@ -557,7 +560,7 @@ public async Task ParseStandardPetStoreDocumentShouldSucceed() actual.Document.Should().BeEquivalentTo(expectedDoc, options => options.Excluding(x => x.Workspace).Excluding(y => y.BaseUri)); Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, actual.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, Format = OpenApiConstants.Yaml }, actual.Diagnostic); } [Fact] @@ -1031,7 +1034,7 @@ [new OpenApiSecuritySchemeReference("securitySchemeName2")] = .Excluding(y => y.BaseUri)); Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, actual.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, Format = OpenApiConstants.Yaml }, actual.Diagnostic); } [Fact] @@ -1042,7 +1045,7 @@ public async Task ParsePetStoreExpandedShouldSucceed() // TODO: Create the object in memory and compare with the one read from YAML file. Assert.Equivalent( - new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }, actual.Diagnostic); + new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, Format = OpenApiConstants.Yaml }, actual.Diagnostic); } [Fact] @@ -1444,9 +1447,10 @@ public void ParseBasicDocumentWithServerVariableShouldSucceed() }; Assert.Equivalent( - new OpenApiDiagnostic - { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + new OpenApiDiagnostic + { + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); result.Document.Should().BeEquivalentTo(expected, options => options.Excluding(x => x.BaseUri)); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index aea5d46a4..e16e40594 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -231,7 +231,8 @@ public async Task ParseBasicSchemaWithReferenceShouldSucceed() Assert.Equivalent( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); var expectedComponents = new OpenApiComponents @@ -394,7 +395,8 @@ public async Task ParseExternalReferenceSchemaShouldSucceed() Assert.Equivalent( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, + Format = OpenApiConstants.Yaml }, result.Diagnostic); var expectedComponents = new OpenApiComponents diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 29e7ddc74..408ddb15e 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -1934,6 +1934,7 @@ namespace Microsoft.OpenApi.Reader { public OpenApiDiagnostic() { } public System.Collections.Generic.IList Errors { get; set; } + public string? Format { get; set; } public Microsoft.OpenApi.OpenApiSpecVersion SpecificationVersion { get; set; } public System.Collections.Generic.IList Warnings { get; set; } public void AppendDiagnostic(Microsoft.OpenApi.Reader.OpenApiDiagnostic diagnosticToAdd, string? fileNameToAdd = null) { } diff --git a/test/Microsoft.OpenApi.Tests/Reader/OpenApiModelFactoryTests.cs b/test/Microsoft.OpenApi.Tests/Reader/OpenApiModelFactoryTests.cs index 5cbfa93b0..26bd6d472 100644 --- a/test/Microsoft.OpenApi.Tests/Reader/OpenApiModelFactoryTests.cs +++ b/test/Microsoft.OpenApi.Tests/Reader/OpenApiModelFactoryTests.cs @@ -114,6 +114,7 @@ await File.WriteAllTextAsync(tempFilePathReferrer, BaseUrl = baseUri, }; var readResult = await OpenApiDocument.LoadAsync(stream, settings: settings); + Assert.Equal(OpenApiConstants.Json, readResult.Diagnostic.Format); Assert.NotNull(readResult.Document); Assert.NotNull(readResult.Document.Components); Assert.Equal(baseUri, readResult.Document.BaseUri);