diff --git a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
index 34f5a3491..2fe7cb4cf 100644
--- a/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
+++ b/src/Microsoft.OpenApi.Readers/Microsoft.OpenApi.Readers.csproj
@@ -6,7 +6,7 @@
Microsoft
Microsoft.OpenApi.Readers
Microsoft.OpenApi.Readers
- 1.0.0-beta006
+ 1.0.0-beta007
OpenAPI.NET Readers for JSON and YAML documents
Microsoft.OpenApi.Readers
Microsoft.OpenApi.Readers
diff --git a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
index bae43cf74..6545cf63c 100644
--- a/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
+++ b/src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
@@ -6,7 +6,7 @@
Microsoft
Microsoft.OpenApi
Microsoft.OpenApi
- 1.0.0-beta006
+ 1.0.0-beta007
.NET models and JSON/YAML writers for OpenAPI specification
Microsoft.OpenApi
Microsoft.OpenApi
diff --git a/src/Microsoft.OpenApi/Writers/OpenApiJsonWriter.cs b/src/Microsoft.OpenApi/Writers/OpenApiJsonWriter.cs
index d0425caf4..b7f6f3b99 100644
--- a/src/Microsoft.OpenApi/Writers/OpenApiJsonWriter.cs
+++ b/src/Microsoft.OpenApi/Writers/OpenApiJsonWriter.cs
@@ -178,6 +178,8 @@ public override void WriteValue(string value)
///
public override void WriteNull()
{
+ WriteValueSeparator();
+
Writer.Write("null");
}
diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
index 3598f5eea..42ed2ff0c 100644
--- a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
+++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
@@ -302,7 +302,14 @@ private static void WriteCollectionInternal(
{
foreach (var item in elements)
{
- action(writer, item);
+ if (item != null)
+ {
+ action(writer, item);
+ }
+ else
+ {
+ writer.WriteNull();
+ }
}
}
@@ -325,7 +332,14 @@ private static void WriteMapInternal(
foreach (var item in elements)
{
writer.WritePropertyName(item.Key);
- action(writer, item.Value);
+ if (item.Value != null)
+ {
+ action(writer, item.Value);
+ }
+ else
+ {
+ writer.WriteNull();
+ }
}
}
diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs
index 3ded738e3..5cb8345c4 100644
--- a/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs
@@ -3,12 +3,279 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
+using System;
+using System.Collections.Generic;
+using FluentAssertions;
+using Microsoft.OpenApi.Extensions;
using Microsoft.OpenApi.Models;
+using Xunit;
+using Xunit.Abstractions;
namespace Microsoft.OpenApi.Tests.Models
{
public class OpenApiComponentsTests
{
- public static OpenApiComponents basicComponents = new OpenApiComponents();
+ public static OpenApiComponents AdvancedComponents = new OpenApiComponents
+ {
+ Schemas = new Dictionary
+ {
+ ["schema1"] = new OpenApiSchema
+ {
+ Properties = new Dictionary
+ {
+ ["property2"] = new OpenApiSchema
+ {
+ Type = "integer"
+ },
+ ["property3"] = new OpenApiSchema
+ {
+ Type = "string",
+ MaxLength = 15
+ }
+ },
+ },
+ },
+ SecuritySchemes = new Dictionary
+ {
+ ["securityScheme1"] = new OpenApiSecurityScheme
+ {
+ Description = "description1",
+ Type = SecuritySchemeType.OAuth2,
+ Flows = new OpenApiOAuthFlows
+ {
+ Implicit = new OpenApiOAuthFlow
+ {
+ Scopes = new Dictionary
+ {
+ ["operation1:object1"] = "operation 1 on object 1",
+ ["operation2:object2"] = "operation 2 on object 2"
+ },
+ AuthorizationUrl = new Uri("https://example.com/api/oauth")
+ }
+ }
+ },
+ ["securityScheme2"] = new OpenApiSecurityScheme
+ {
+ Description = "description1",
+ Type = SecuritySchemeType.OpenIdConnect,
+ Scheme = "openIdConnectUrl",
+ OpenIdConnectUrl = new Uri("https://example.com/openIdConnect")
+ }
+ }
+ };
+
+ public static OpenApiComponents BasicComponents = new OpenApiComponents();
+
+ public static OpenApiComponents BrokenComponents = new OpenApiComponents
+ {
+ Schemas = new Dictionary
+ {
+ ["schema1"] = new OpenApiSchema
+ {
+ Type = "string"
+ },
+ ["schema2"] = null,
+ ["schema3"] = null,
+ ["schema4"] = new OpenApiSchema
+ {
+ Type = "string",
+ AllOf = new List()
+ {
+ null,
+ null,
+ new OpenApiSchema()
+ {
+ Type = "string"
+ },
+ null,
+ null
+ }
+ }
+ }
+ };
+
+ private readonly ITestOutputHelper _output;
+
+ public OpenApiComponentsTests(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
+ [Fact]
+ public void SerializeBasicComponentsAsJsonWorks()
+ {
+ // Arrange
+ var expected = @"{ }";
+
+ // Act
+ var actual = BasicComponents.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
+
+ [Fact]
+ public void SerializeBasicComponentsAsYamlWorks()
+ {
+ // Arrange
+ var expected = @"{ }";
+
+ // Act
+ var actual = BasicComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
+
+ [Fact]
+ public void SerializeAdvancedComponentsAsJsonWorks()
+ {
+ // Arrange
+ var expected = @"{
+ ""schemas"": {
+ ""schema1"": {
+ ""properties"": {
+ ""property2"": {
+ ""type"": ""integer""
+ },
+ ""property3"": {
+ ""maxLength"": 15,
+ ""type"": ""string""
+ }
+ }
+ }
+ },
+ ""securitySchemes"": {
+ ""securityScheme1"": {
+ ""type"": ""oauth2"",
+ ""description"": ""description1"",
+ ""flows"": {
+ ""implicit"": {
+ ""authorizationUrl"": ""https://example.com/api/oauth"",
+ ""scopes"": {
+ ""operation1:object1"": ""operation 1 on object 1"",
+ ""operation2:object2"": ""operation 2 on object 2""
+ }
+ }
+ }
+ },
+ ""securityScheme2"": {
+ ""type"": ""openIdConnect"",
+ ""description"": ""description1"",
+ ""openIdConnectUrl"": ""https://example.com/openIdConnect""
+ }
+ }
+}";
+
+ // Act
+ var actual = AdvancedComponents.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
+
+ [Fact]
+ public void SerializeAdvancedComponentsAsYamlWorks()
+ {
+ // Arrange
+ var expected = @"schemas:
+ schema1:
+ properties:
+ property2:
+ type: integer
+ property3:
+ maxLength: 15
+ type: string
+securitySchemes:
+ securityScheme1:
+ type: oauth2
+ description: description1
+ flows:
+ implicit:
+ authorizationUrl: https://example.com/api/oauth
+ scopes:
+ operation1:object1: operation 1 on object 1
+ operation2:object2: operation 2 on object 2
+ securityScheme2:
+ type: openIdConnect
+ description: description1
+ openIdConnectUrl: https://example.com/openIdConnect";
+
+ // Act
+ var actual = AdvancedComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
+
+ [Fact]
+ public void SerializeBrokenComponentsAsJsonWorks()
+ {
+ // Arrange
+ var expected = @"{
+ ""schemas"": {
+ ""schema1"": {
+ ""type"": ""string""
+ },
+ ""schema2"": null,
+ ""schema3"": null,
+ ""schema4"": {
+ ""type"": ""string"",
+ ""allOf"": [
+ null,
+ null,
+ {
+ ""type"": ""string""
+ },
+ null,
+ null
+ ]
+ }
+ }
+}";
+
+ // Act
+ var actual = BrokenComponents.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
+
+ [Fact]
+ public void SerializeBrokenComponentsAsYamlWorks()
+ {
+ // Arrange
+ var expected = @"schemas:
+ schema1:
+ type: string
+ schema2:
+ schema3:
+ schema4:
+ type: string
+ allOf:
+ -
+ -
+ - type: string
+ -
+ - ";
+
+ // Act
+ var actual = BrokenComponents.SerializeAsYaml(OpenApiSpecVersion.OpenApi3_0_0);
+
+ // Assert
+ actual = actual.MakeLineBreaksEnvironmentNeutral();
+ expected = expected.MakeLineBreaksEnvironmentNeutral();
+ actual.Should().Be(expected);
+ }
}
-}
+}
\ No newline at end of file