Skip to content

Commit 746fe68

Browse files
Merge pull request #1195 from dldl-cmd/openapioperation-copy-constructor-preserve-null
OpenApiOperation constructor preserve null
2 parents db02b95 + d479ec3 commit 746fe68

6 files changed

+61
-7
lines changed

src/Microsoft.OpenApi/Models/OpenApiOperation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ public OpenApiOperation() {}
116116
/// </summary>
117117
public OpenApiOperation(OpenApiOperation operation)
118118
{
119-
Tags = new List<OpenApiTag>(operation?.Tags);
119+
Tags = operation?.Tags != null ? new List<OpenApiTag>(operation?.Tags) : null;
120120
Summary = operation?.Summary ?? Summary;
121121
Description = operation?.Description ?? Description;
122122
ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null;
123123
OperationId = operation?.OperationId ?? OperationId;
124124
Parameters = operation?.Parameters != null ? new List<OpenApiParameter>(operation.Parameters) : null;
125-
RequestBody = new(operation?.RequestBody);
125+
RequestBody = operation?.RequestBody != null ? new(operation?.RequestBody) : null;
126126
Responses = operation?.Responses != null ? new(operation?.Responses) : null;
127127
Callbacks = operation?.Callbacks != null ? new Dictionary<string, OpenApiCallback>(operation.Callbacks) : null;
128128
Deprecated = operation?.Deprecated ?? Deprecated;

src/Microsoft.OpenApi/Models/OpenApiParameter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,11 +243,11 @@ public void SerializeAsV3WithoutReference(IOpenApiWriter writer)
243243
// style
244244
if (_style.HasValue)
245245
{
246-
writer.WriteProperty(OpenApiConstants.Style, Style.Value.GetDisplayName());
246+
writer.WriteProperty(OpenApiConstants.Style, _style.Value.GetDisplayName());
247247
}
248248

249249
// explode
250-
writer.WriteProperty(OpenApiConstants.Explode, Explode, Style.HasValue && Style.Value == ParameterStyle.Form);
250+
writer.WriteProperty(OpenApiConstants.Explode, _explode, _style.HasValue && _style.Value == ParameterStyle.Form);
251251

252252
// allowReserved
253253
writer.WriteProperty(OpenApiConstants.AllowReserved, AllowReserved, false);
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","style":"form","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","style":"form","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/newPet"}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"style":"simple","schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"style":"simple","schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}
1+
{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","termsOfService":"http://helloreverb.com/terms/","contact":{"name":"Swagger API team","url":"http://swagger.io","email":"[email protected]"},"license":{"name":"MIT","url":"http://opensource.org/licenses/MIT"},"version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/pets":{"get":{"description":"Returns all pets from the system that the user has access to","operationId":"findPets","parameters":[{"name":"tags","in":"query","description":"tags to filter by","schema":{"type":"array","items":{"type":"string"}}},{"name":"limit","in":"query","description":"maximum number of results to return","schema":{"type":"integer","format":"int32"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}},"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/pet"}}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"post":{"description":"Creates a new pet in the store. Duplicates are allowed","operationId":"addPet","requestBody":{"description":"Pet to add to the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/newPet"}}},"required":true},"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}},"/pets/{id}":{"get":{"description":"Returns a user based on a single ID, if the user does not have access to the pet","operationId":"findPetById","parameters":[{"name":"id","in":"path","description":"ID of pet to fetch","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/pet"}}}},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}},"delete":{"description":"deletes a single pet based on the ID supplied","operationId":"deletePet","parameters":[{"name":"id","in":"path","description":"ID of pet to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"204":{"description":"pet deleted"},"4XX":{"description":"unexpected client error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}},"5XX":{"description":"unexpected server error","content":{"text/html":{"schema":{"$ref":"#/components/schemas/errorModel"}}}}}}}},"components":{"schemas":{"pet":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"newPet":{"required":["name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"errorModel":{"required":["code","message"],"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}}}}}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","parameters":[{"name":"operand1","in":"path","description":"The first operand","required":true,"style":"simple","schema":{"type":"integer","my-extension":4},"my-extension":4},{"name":"operand2","in":"path","description":"The second operand","required":true,"style":"simple","schema":{"type":"integer","my-extension":4},"my-extension":4}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}}}}
1+
{"openapi":"3.0.1","info":{"title":"Swagger Petstore (Simple)","description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification","version":"1.0.0"},"servers":[{"url":"http://petstore.swagger.io/api"}],"paths":{"/add/{operand1}/{operand2}":{"get":{"operationId":"addByOperand1AndByOperand2","parameters":[{"name":"operand1","in":"path","description":"The first operand","required":true,"schema":{"type":"integer","my-extension":4},"my-extension":4},{"name":"operand2","in":"path","description":"The second operand","required":true,"schema":{"type":"integer","my-extension":4},"my-extension":4}],"responses":{"200":{"description":"pet response","content":{"application/json":{"schema":{"type":"array","items":{"required":["id","name"],"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}}}}}}}}}}}

test/Microsoft.OpenApi.Tests/Models/OpenApiOperationTests.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using FluentAssertions;
77
using Microsoft.OpenApi.Extensions;
88
using Microsoft.OpenApi.Models;
9+
using NuGet.Frameworks;
910
using Xunit;
1011
using Xunit.Abstractions;
1112

@@ -793,5 +794,58 @@ public void EnsureOpenApiOperationCopyConstructorCopiesResponsesObject()
793794
Assert.NotNull(operation.Responses);
794795
Assert.Equal(2, operation.Responses.Count);
795796
}
797+
798+
[Fact]
799+
public void EnsureOpenApiOperationCopyConstructorCopiesNull()
800+
{
801+
// Arrange
802+
_basicOperation.Parameters = null;
803+
_basicOperation.Tags = null;
804+
_basicOperation.Responses = null;
805+
_basicOperation.Callbacks = null;
806+
_basicOperation.Security = null;
807+
_basicOperation.Servers = null;
808+
_basicOperation.Extensions = null;
809+
810+
// Act
811+
var operation = new OpenApiOperation(_basicOperation);
812+
813+
// Assert
814+
Assert.Null(operation.Tags);
815+
Assert.Null(operation.Summary);
816+
Assert.Null(operation.Description);
817+
Assert.Null(operation.ExternalDocs);
818+
Assert.Null(operation.OperationId);
819+
Assert.Null(operation.Parameters);
820+
Assert.Null(operation.RequestBody);
821+
Assert.Null(operation.Responses);
822+
Assert.Null(operation.Callbacks);
823+
Assert.Null(operation.Security);
824+
Assert.Null(operation.Servers);
825+
Assert.Null(operation.Extensions);
826+
}
827+
828+
[Fact]
829+
public void EnsureOpenApiOperationCopyConstructor_SerializationResultsInSame()
830+
{
831+
var operations = new[]
832+
{
833+
_basicOperation,
834+
_operationWithBody,
835+
_operationWithFormData,
836+
_advancedOperationWithTagsAndSecurity
837+
};
838+
839+
foreach (var operation in operations)
840+
{
841+
// Act
842+
var expected = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
843+
var openApiOperation = new OpenApiOperation(operation);
844+
var actual = openApiOperation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
845+
846+
// Assert
847+
actual.Should().Be(expected);
848+
}
849+
}
796850
}
797851
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"name":"name1","in":"path","style":"simple"}
1+
{"name":"name1","in":"path"}

0 commit comments

Comments
 (0)