From 7c86a42805e3a0094b3f6ec7e06c93b74df6d9ea Mon Sep 17 00:00:00 2001 From: Damian Wieczorek Date: Thu, 30 May 2019 21:48:02 -0700 Subject: [PATCH 1/2] improve allOf merging for composite schemas --- .../openapi/diff/compare/SchemaDiff.java | 182 +++++++++++++++++- .../qdesrame/openapi/test/AllOfDiffTest.java | 12 +- src/test/resources/allOf_diff_1.yaml | 4 +- src/test/resources/allOf_diff_2.yaml | 1 + src/test/resources/allOf_diff_3.yaml | 4 +- src/test/resources/allOf_diff_4.yaml | 129 +++++++++++++ 6 files changed, 320 insertions(+), 12 deletions(-) create mode 100644 src/test/resources/allOf_diff_4.yaml diff --git a/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java b/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java index 9d8b774da..7dfdabf6d 100644 --- a/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java +++ b/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java @@ -1,7 +1,5 @@ package com.qdesrame.openapi.diff.compare; -import static java.util.Optional.ofNullable; - import com.qdesrame.openapi.diff.compare.schemadiffresult.ArraySchemaDiffResult; import com.qdesrame.openapi.diff.compare.schemadiffresult.ComposedSchemaDiffResult; import com.qdesrame.openapi.diff.compare.schemadiffresult.SchemaDiffResult; @@ -9,11 +7,24 @@ import com.qdesrame.openapi.diff.model.DiffContext; import com.qdesrame.openapi.diff.utils.RefPointer; import com.qdesrame.openapi.diff.utils.RefType; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Discriminator; import io.swagger.v3.oas.models.media.Schema; -import java.util.*; +import io.swagger.v3.oas.models.media.XML; + +import static java.util.Optional.ofNullable; public class SchemaDiff extends ReferenceDiffCache { @@ -87,10 +98,9 @@ protected static Schema resolveComposedSchema(Components components, Schema sche protected static Schema addSchema(Schema schema, Schema fromSchema) { if (fromSchema.getProperties() != null) { if (schema.getProperties() == null) { - schema.setProperties(fromSchema.getProperties()); - } else { - schema.getProperties().putAll(fromSchema.getProperties()); + schema.setProperties(new LinkedHashMap<>()); } + schema.getProperties().putAll(fromSchema.getProperties()); } if (fromSchema.getRequired() != null) { @@ -100,7 +110,165 @@ protected static Schema addSchema(Schema schema, Schema fromSchema) { schema.getRequired().addAll(fromSchema.getRequired()); } } - // TODO copy other things from fromSchema + + if (fromSchema.getReadOnly() != null) { + schema.setReadOnly(fromSchema.getReadOnly()); + } + if (fromSchema.getWriteOnly() != null) { + schema.setWriteOnly(fromSchema.getWriteOnly()); + } + if (fromSchema.getDeprecated() != null) { + schema.setDeprecated(fromSchema.getDeprecated()); + } + if (fromSchema.getExclusiveMaximum() != null) { + schema.setExclusiveMaximum(fromSchema.getExclusiveMaximum()); + } + if (fromSchema.getExclusiveMinimum() != null) { + schema.setExclusiveMinimum(fromSchema.getExclusiveMinimum()); + } + if (fromSchema.getNullable() != null) { + schema.setNullable(fromSchema.getNullable()); + } + if (fromSchema.getUniqueItems() != null) { + schema.setUniqueItems(fromSchema.getUniqueItems()); + } + if (fromSchema.getDescription() != null) { + schema.setDescription(fromSchema.getDescription()); + } + if (fromSchema.getFormat() != null) { + schema.setFormat(fromSchema.getFormat()); + } + if (fromSchema.getType() != null) { + schema.setType(fromSchema.getType()); + } + if (fromSchema.getEnum() != null) { + if (schema.getEnum() == null) { + schema.setEnum(new ArrayList<>()); + } + //noinspection unchecked + schema.getEnum().addAll((List) fromSchema.getEnum()); + } + if (fromSchema.getExtensions() != null) { + if (schema.getExtensions() == null) { + schema.setExtensions(new LinkedHashMap<>()); + } + schema.getExtensions().putAll(fromSchema.getExtensions()); + } + if (fromSchema.getDiscriminator() != null) { + if (schema.getDiscriminator() == null) { + schema.setDiscriminator(new Discriminator()); + } + final Discriminator discriminator = schema.getDiscriminator(); + final Discriminator fromDiscriminator = fromSchema.getDiscriminator(); + if (fromDiscriminator.getPropertyName() != null) { + discriminator.setPropertyName(fromDiscriminator.getPropertyName()); + } + if (fromDiscriminator.getMapping() != null) { + if (discriminator.getMapping() == null) { + discriminator.setMapping(new LinkedHashMap<>()); + } + discriminator.getMapping().putAll(fromDiscriminator.getMapping()); + } + } + if (fromSchema.getTitle() != null) { + schema.setTitle(fromSchema.getTitle()); + } + if (fromSchema.getName() != null) { + schema.setName(fromSchema.getName()); + } + if (fromSchema.getAdditionalProperties() != null) { + schema.setAdditionalProperties(fromSchema.getAdditionalProperties()); + } + if (fromSchema.getDefault() != null) { + schema.setDefault(fromSchema.getDefault()); + } + if (fromSchema.getExample() != null) { + schema.setExample(fromSchema.getExample()); + } + if (fromSchema.getExternalDocs() != null) { + if (schema.getExternalDocs() == null) { + schema.setExternalDocs(new ExternalDocumentation()); + } + final ExternalDocumentation externalDocs = schema.getExternalDocs(); + final ExternalDocumentation fromExternalDocs = fromSchema.getExternalDocs(); + if (fromExternalDocs.getDescription() != null) { + externalDocs.setDescription(fromExternalDocs.getDescription()); + } + if (fromExternalDocs.getExtensions() != null) { + if (externalDocs.getExtensions() == null) { + externalDocs.setExtensions(new LinkedHashMap<>()); + } + externalDocs.getExtensions().putAll(fromExternalDocs.getExtensions()); + } + if (fromExternalDocs.getUrl() != null) { + externalDocs.setUrl(fromExternalDocs.getUrl()); + } + } + if (fromSchema.getMaximum() != null) { + schema.setMaximum(fromSchema.getMaximum()); + } + if (fromSchema.getMinimum() != null) { + schema.setMinimum(fromSchema.getMinimum()); + } + if (fromSchema.getMaxItems() != null) { + schema.setMaxItems(fromSchema.getMaxItems()); + } + if (fromSchema.getMinItems() != null) { + schema.setMinItems(fromSchema.getMinItems()); + } + if (fromSchema.getMaxProperties() != null) { + schema.setMaxProperties(fromSchema.getMaxProperties()); + } + if (fromSchema.getMinProperties() != null) { + schema.setMinProperties(fromSchema.getMinProperties()); + } + if (fromSchema.getMaxLength() != null) { + schema.setMaxLength(fromSchema.getMaxLength()); + } + if (fromSchema.getMinLength() != null) { + schema.setMinLength(fromSchema.getMinLength()); + } + if (fromSchema.getMultipleOf() != null) { + schema.setMultipleOf(fromSchema.getMultipleOf()); + } + if (fromSchema.getNot() != null) { + if (schema.getNot() == null) { + schema.setNot(addSchema(new Schema(), fromSchema.getNot())); + } else { + addSchema(schema.getNot(), fromSchema.getNot()); + } + } + if (fromSchema.getPattern() != null) { + schema.setPattern(fromSchema.getPattern()); + } + if (fromSchema.getXml() != null) { + if (schema.getXml() == null) { + schema.setXml(new XML()); + } + final XML xml = schema.getXml(); + final XML fromXml = fromSchema.getXml(); + if (fromXml.getAttribute() != null) { + xml.setAttribute(fromXml.getAttribute()); + } + if (fromXml.getName() != null) { + xml.setName(fromXml.getName()); + } + if (fromXml.getNamespace() != null) { + xml.setNamespace(fromXml.getNamespace()); + } + if (fromXml.getExtensions() != null) { + if (xml.getExtensions() == null) { + xml.setExtensions(new LinkedHashMap<>()); + } + xml.getExtensions().putAll(fromXml.getExtensions()); + } + if (fromXml.getPrefix() != null) { + xml.setPrefix(fromXml.getPrefix()); + } + if (fromXml.getWrapped() != null) { + xml.setWrapped(fromXml.getWrapped()); + } + } return schema; } diff --git a/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java b/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java index b72e60dd2..49f336ee7 100644 --- a/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java +++ b/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java @@ -1,16 +1,17 @@ package com.qdesrame.openapi.test; +import org.junit.jupiter.api.Test; + import static com.qdesrame.openapi.test.TestUtils.assertOpenApiAreEquals; import static com.qdesrame.openapi.test.TestUtils.assertOpenApiChangedEndpoints; -import org.junit.jupiter.api.Test; - /** Created by adarsh.sharma on 19/12/17. */ public class AllOfDiffTest { private final String OPENAPI_DOC1 = "allOf_diff_1.yaml"; private final String OPENAPI_DOC2 = "allOf_diff_2.yaml"; private final String OPENAPI_DOC3 = "allOf_diff_3.yaml"; + private final String OPENAPI_DOC4 = "allOf_diff_4.yaml"; @Test public void testDiffSame() { @@ -23,7 +24,12 @@ public void testDiffSameWithAllOf() { } @Test - public void testDiffDifferent() { + public void testDiffDifferent1() { assertOpenApiChangedEndpoints(OPENAPI_DOC1, OPENAPI_DOC3); } + + @Test + public void testDiffDifferent2() { + assertOpenApiChangedEndpoints(OPENAPI_DOC1, OPENAPI_DOC4); + } } diff --git a/src/test/resources/allOf_diff_1.yaml b/src/test/resources/allOf_diff_1.yaml index 522657e0e..2d1cc4060 100644 --- a/src/test/resources/allOf_diff_1.yaml +++ b/src/test/resources/allOf_diff_1.yaml @@ -108,7 +108,9 @@ components: - pet_type properties: pet_type: - type: string + nullable: false + allOf: + - type: string Cat: description: Cat class allOf: diff --git a/src/test/resources/allOf_diff_2.yaml b/src/test/resources/allOf_diff_2.yaml index a0d4cc933..fef87ee57 100644 --- a/src/test/resources/allOf_diff_2.yaml +++ b/src/test/resources/allOf_diff_2.yaml @@ -101,6 +101,7 @@ components: - pet_type properties: pet_type: + nullable: false type: string Cat: description: Cat class diff --git a/src/test/resources/allOf_diff_3.yaml b/src/test/resources/allOf_diff_3.yaml index da0ddc304..759c1d59f 100644 --- a/src/test/resources/allOf_diff_3.yaml +++ b/src/test/resources/allOf_diff_3.yaml @@ -105,7 +105,9 @@ components: - pet_type properties: pet_type: - type: string + nullable: false + allOf: + - type: number Cat: description: Cat class allOf: diff --git a/src/test/resources/allOf_diff_4.yaml b/src/test/resources/allOf_diff_4.yaml new file mode 100644 index 000000000..38fcbb1e8 --- /dev/null +++ b/src/test/resources/allOf_diff_4.yaml @@ -0,0 +1,129 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. You can find out more about + Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, + #swagger](http://swagger.io/irc/). For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +paths: + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + explode: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + properties: + pets: + type: array + items: + $ref: '#/components/schemas/Cat' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + BasePet: + type: object + properties: + pet_color: + type: string + Pet: + allOf: + - $ref: '#/components/schemas/BasePet' + type: object + required: + - pet_type + properties: + pet_type: + nullable: false + allOf: + - type: number + Cat: + description: Cat class + allOf: + - $ref: '#/components/schemas/Pet' + type: object + properties: + name: + type: string + Dog: + description: Dog class + allOf: + - $ref: '#/components/schemas/Pet' + type: object + properties: + bark: + type: string From 2765aaa060ce0216ee76b1b1cc24ccddfe07c28c Mon Sep 17 00:00:00 2001 From: Damian Wieczorek Date: Fri, 31 May 2019 14:07:29 -0700 Subject: [PATCH 2/2] fix incorrect type in diff_3 --- .../openapi/diff/compare/SchemaDiff.java | 20 +++++++++---------- .../qdesrame/openapi/test/AllOfDiffTest.java | 4 ++-- src/test/resources/allOf_diff_3.yaml | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java b/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java index 7dfdabf6d..8642c91f6 100644 --- a/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java +++ b/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java @@ -1,5 +1,7 @@ package com.qdesrame.openapi.diff.compare; +import static java.util.Optional.ofNullable; + import com.qdesrame.openapi.diff.compare.schemadiffresult.ArraySchemaDiffResult; import com.qdesrame.openapi.diff.compare.schemadiffresult.ComposedSchemaDiffResult; import com.qdesrame.openapi.diff.compare.schemadiffresult.SchemaDiffResult; @@ -7,15 +9,6 @@ import com.qdesrame.openapi.diff.model.DiffContext; import com.qdesrame.openapi.diff.utils.RefPointer; import com.qdesrame.openapi.diff.utils.RefType; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.ExternalDocumentation; import io.swagger.v3.oas.models.media.ArraySchema; @@ -23,8 +16,13 @@ import io.swagger.v3.oas.models.media.Discriminator; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.XML; - -import static java.util.Optional.ofNullable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; public class SchemaDiff extends ReferenceDiffCache { diff --git a/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java b/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java index 49f336ee7..5255f34d3 100644 --- a/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java +++ b/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java @@ -1,10 +1,10 @@ package com.qdesrame.openapi.test; -import org.junit.jupiter.api.Test; - import static com.qdesrame.openapi.test.TestUtils.assertOpenApiAreEquals; import static com.qdesrame.openapi.test.TestUtils.assertOpenApiChangedEndpoints; +import org.junit.jupiter.api.Test; + /** Created by adarsh.sharma on 19/12/17. */ public class AllOfDiffTest { diff --git a/src/test/resources/allOf_diff_3.yaml b/src/test/resources/allOf_diff_3.yaml index 759c1d59f..c5fd84803 100644 --- a/src/test/resources/allOf_diff_3.yaml +++ b/src/test/resources/allOf_diff_3.yaml @@ -107,7 +107,7 @@ components: pet_type: nullable: false allOf: - - type: number + - type: string Cat: description: Cat class allOf: