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..8642c91f6 100644 --- a/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java +++ b/src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java @@ -10,10 +10,19 @@ import com.qdesrame.openapi.diff.utils.RefPointer; import com.qdesrame.openapi.diff.utils.RefType; 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 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 { @@ -87,10 +96,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 +108,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..5255f34d3 100644 --- a/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java +++ b/src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java @@ -11,6 +11,7 @@ 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..c5fd84803 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: string 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