diff --git a/src/Microsoft.OpenApi/Reader/ParsingContext.cs b/src/Microsoft.OpenApi/Reader/ParsingContext.cs index aae60da9d..7a8b07244 100644 --- a/src/Microsoft.OpenApi/Reader/ParsingContext.cs +++ b/src/Microsoft.OpenApi/Reader/ParsingContext.cs @@ -271,9 +271,9 @@ public void PopLoop(string loopid) private void ValidateRequiredFields(OpenApiDocument doc, string version) { - if ((version.is2_0() || version.is3_0()) && (doc.Paths == null || !doc.Paths.Any())) + if ((version.is2_0() || version.is3_0()) && (doc.Paths == null)) { - // paths is a required field in OpenAPI 3.0 but optional in 3.1 + // paths is a required field in OpenAPI 2.0 and 3.0 but optional in 3.1 RootNode.Context.Diagnostic.Errors.Add(new OpenApiError("", $"Paths is a REQUIRED field at {RootNode.Context.GetLocation()}")); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs index 5ecd58071..c99cc6fa9 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/OpenApiReaderTests/OpenApiDiagnosticTests.cs @@ -56,10 +56,7 @@ public async Task DiagnosticReportMergedForExternalReferenceAsync() Assert.NotNull(result); Assert.NotNull(result.OpenApiDocument.Workspace); - result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List - { - new OpenApiError("", "[File: ./TodoReference.yaml] Paths is a REQUIRED field at #/") - }); + result.OpenApiDiagnostic.Errors.Should().BeEmpty(); } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/ParseNodeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/ParseNodeTests.cs index 3f7c669b0..7c43ed124 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/ParseNodeTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/ParseNodeTests.cs @@ -34,8 +34,7 @@ public void BrokenSimpleList() var result = OpenApiDocument.Parse(input, "yaml"); result.OpenApiDiagnostic.Errors.Should().BeEquivalentTo(new List() { - new OpenApiError(new OpenApiReaderException("Expected a value.")), - new OpenApiError("", "Paths is a REQUIRED field at #/") + new OpenApiError(new OpenApiReaderException("Expected a value.")) }); } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs index 596269644..c97fd1aee 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiDocumentTests.cs @@ -96,16 +96,7 @@ public void ParseDocumentWithDifferentCultureShouldSucceed(string culture) .Excluding((IMemberInfo memberInfo) => memberInfo.Path.EndsWith("Parent")) .Excluding((IMemberInfo memberInfo) => - memberInfo.Path.EndsWith("Root"))); - - result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic { - SpecificationVersion = OpenApiSpecVersion.OpenApi2_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } - }); + memberInfo.Path.EndsWith("Root")));; } [Fact] diff --git a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs index 2e5779adb..775145794 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V2Tests/OpenApiServerTests.cs @@ -310,8 +310,7 @@ public void InvalidHostShouldYieldError() { Errors = { - new OpenApiError("#/", "Invalid host"), - new OpenApiError("", "Paths is a REQUIRED field at #/") + new OpenApiError("#/", "Invalid host") }, SpecificationVersion = OpenApiSpecVersion.OpenApi2_0 }); diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs index 1382d0248..2d3b02820 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs @@ -101,11 +101,7 @@ public void ParseDocumentFromInlineStringShouldSucceed() result.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); } @@ -115,16 +111,7 @@ public void ParseBasicDocumentWithMultipleServersShouldSucceed() var path = System.IO.Path.Combine(SampleFolderPath, "basicDocumentWithMultipleServers.yaml"); var result = OpenApiDocument.Load(path); - result.OpenApiDiagnostic.Should().BeEquivalentTo( - new OpenApiDiagnostic() - { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } - }); - + result.OpenApiDiagnostic.Errors.Should().BeEmpty(); result.OpenApiDocument.Should().BeEquivalentTo( new OpenApiDocument { @@ -170,7 +157,6 @@ public void ParseBrokenMinimalDocumentShouldYieldExpectedDiagnostic() { Errors = { - new OpenApiError("", "Paths is a REQUIRED field at #/"), new OpenApiValidatorError(nameof(OpenApiInfoRules.InfoRequiredFields),"#/info/title", "The field 'title' in 'info' object is REQUIRED.") }, SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 @@ -196,11 +182,7 @@ public void ParseMinimalDocumentShouldSucceed() result.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); } @@ -1388,11 +1370,7 @@ public void ParseBasicDocumentWithServerVariableShouldSucceed() result.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); result.OpenApiDocument.Should().BeEquivalentTo(expected, options => options.Excluding(x => x.BaseUri)); @@ -1417,5 +1395,12 @@ public void ParseBasicDocumentWithServerVariableAndNoDefaultShouldFail() result.OpenApiDiagnostic.Errors.Should().NotBeEmpty(); } + + [Fact] + public void ParseDocumentWithEmptyPathsSucceeds() + { + var result = OpenApiDocument.Load(System.IO.Path.Combine(SampleFolderPath, "docWithEmptyPaths.yaml")); + result.OpenApiDiagnostic.Errors.Should().BeEmpty(); + } } } diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs index 81cb4376b..6c1370626 100644 --- a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiSchemaTests.cs @@ -241,11 +241,7 @@ public void ParseBasicSchemaWithReferenceShouldSucceed() result.OpenApiDiagnostic.Should().BeEquivalentTo( new OpenApiDiagnostic() { - SpecificationVersion = OpenApiSpecVersion.OpenApi3_0, - Errors = new List() - { - new OpenApiError("", "Paths is a REQUIRED field at #/") - } + SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 }); var expectedComponents = new OpenApiComponents diff --git a/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithEmptyPaths.yaml b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithEmptyPaths.yaml new file mode 100644 index 000000000..a325ad743 --- /dev/null +++ b/test/Microsoft.OpenApi.Readers.Tests/V3Tests/Samples/OpenApiDocument/docWithEmptyPaths.yaml @@ -0,0 +1,5 @@ +openapi: 3.0.0 +info: + title: Sample API + version: 1.0.0 +paths: {} \ No newline at end of file