Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Company>Microsoft</Company>
<Product>Microsoft.OpenApi.Readers</Product>
<PackageId>Microsoft.OpenApi.Readers</PackageId>
<Version>1.0.0-beta006</Version>
<Version>1.0.0-beta007</Version>
<Description>OpenAPI.NET Readers for JSON and YAML documents</Description>
<AssemblyName>Microsoft.OpenApi.Readers</AssemblyName>
<RootNamespace>Microsoft.OpenApi.Readers</RootNamespace>
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Microsoft.OpenApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Company>Microsoft</Company>
<Product>Microsoft.OpenApi</Product>
<PackageId>Microsoft.OpenApi</PackageId>
<Version>1.0.0-beta006</Version>
<Version>1.0.0-beta007</Version>
<Description>.NET models and JSON/YAML writers for OpenAPI specification</Description>
<AssemblyName>Microsoft.OpenApi</AssemblyName>
<RootNamespace>Microsoft.OpenApi</RootNamespace>
Expand Down
2 changes: 2 additions & 0 deletions src/Microsoft.OpenApi/Writers/OpenApiJsonWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ public override void WriteValue(string value)
/// </summary>
public override void WriteNull()
{
WriteValueSeparator();

Writer.Write("null");
}

Expand Down
18 changes: 16 additions & 2 deletions src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,14 @@ private static void WriteCollectionInternal<T>(
{
foreach (var item in elements)
{
action(writer, item);
if (item != null)
{
action(writer, item);
}
else
{
writer.WriteNull();
}
}
}

Expand All @@ -325,7 +332,14 @@ private static void WriteMapInternal<T>(
foreach (var item in elements)
{
writer.WritePropertyName(item.Key);
action(writer, item.Value);
if (item.Value != null)
{
action(writer, item.Value);
}
else
{
writer.WriteNull();
}
}
}

Expand Down
271 changes: 269 additions & 2 deletions test/Microsoft.OpenApi.Tests/Models/OpenApiComponentsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, OpenApiSchema>
{
["schema1"] = new OpenApiSchema
{
Properties = new Dictionary<string, OpenApiSchema>
{
["property2"] = new OpenApiSchema
{
Type = "integer"
},
["property3"] = new OpenApiSchema
{
Type = "string",
MaxLength = 15
}
},
},
},
SecuritySchemes = new Dictionary<string, OpenApiSecurityScheme>
{
["securityScheme1"] = new OpenApiSecurityScheme
{
Description = "description1",
Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
Scopes = new Dictionary<string, string>
{
["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<string, OpenApiSchema>
{
["schema1"] = new OpenApiSchema
{
Type = "string"
},
["schema2"] = null,
["schema3"] = null,
["schema4"] = new OpenApiSchema
{
Type = "string",
AllOf = new List<OpenApiSchema>()
{
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);
}
}
}
}