diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java b/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java index 0772eace..f2180b34 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java @@ -52,8 +52,10 @@ public enum BackwardIncompatibleProp { SECURITY_SCHEME_SCHEME_CHANGED("incompatible.security.scheme.scheme.changed", true), SECURITY_SCHEME_SCOPES_INCREASED("incompatible.security.scheme.scopes.increased", true), SCHEMA_DISCRIMINATOR_CHANGED("incompatible.schema.discriminator.changed", true), - SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true), SCHEMA_PATTERN_CHANGED("incompatible.schema.pattern.changed", true), + SCHEMA_MIN_PROPERTIES_CHANGED("incompatible.schema.min-properties.changed", true), + SCHEMA_MAX_PROPERTIES_CHANGED("incompatible.schema.max-properties.changed", true), + SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true), ; private final String propertyName; diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java index c4c56af3..8c5dce25 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java @@ -1,5 +1,7 @@ package org.openapitools.openapidiff.core.model.schema; +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MAX_PROPERTIES_CHANGED; + import org.openapitools.openapidiff.core.model.Changed; import org.openapitools.openapidiff.core.model.DiffContext; import org.openapitools.openapidiff.core.model.DiffResult; @@ -30,7 +32,11 @@ public DiffResult isChanged() { } if (oldValue == null) { - return DiffResult.INCOMPATIBLE; + if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context)) { + return DiffResult.INCOMPATIBLE; + } else { + return DiffResult.COMPATIBLE; + } } if (newValue == null) { @@ -38,7 +44,11 @@ public DiffResult isChanged() { } if (!oldValue.equals(newValue)) { - return oldValue > newValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE; + if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context) && oldValue > newValue) { + return DiffResult.INCOMPATIBLE; + } else { + return DiffResult.COMPATIBLE; + } } return DiffResult.NO_CHANGES; diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java index f574b5c8..16059593 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java @@ -1,5 +1,7 @@ package org.openapitools.openapidiff.core.model.schema; +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MIN_PROPERTIES_CHANGED; + import org.openapitools.openapidiff.core.model.Changed; import org.openapitools.openapidiff.core.model.DiffContext; import org.openapitools.openapidiff.core.model.DiffResult; @@ -30,7 +32,11 @@ public DiffResult isChanged() { } if (oldValue == null) { - return DiffResult.INCOMPATIBLE; + if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context)) { + return DiffResult.INCOMPATIBLE; + } else { + return DiffResult.COMPATIBLE; + } } if (newValue == null) { @@ -38,7 +44,11 @@ public DiffResult isChanged() { } if (!oldValue.equals(newValue)) { - return newValue > oldValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE; + if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context) && newValue > oldValue) { + return DiffResult.INCOMPATIBLE; + } else { + return DiffResult.COMPATIBLE; + } } return DiffResult.NO_CHANGES; diff --git a/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java index 28d6d398..f4d624b6 100644 --- a/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java +++ b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java @@ -4,10 +4,7 @@ import static org.openapitools.openapidiff.core.TestUtils.assertSpecChangedButCompatible; import static org.openapitools.openapidiff.core.TestUtils.assertSpecIncompatible; import static org.openapitools.openapidiff.core.TestUtils.assertSpecUnchanged; -import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_REQUIRED_DECREASED; -import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_DISCRIMINATOR_CHANGED; -import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_PATTERN_CHANGED; -import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_TYPE_CHANGED; +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.*; import org.junit.jupiter.api.Test; import org.openapitools.openapidiff.core.model.BackwardIncompatibleProp; @@ -76,4 +73,28 @@ public void patternChanged() { BackwardIncompatibleProp prop = SCHEMA_PATTERN_CHANGED; assertSpecIncompatible(BASE, "bc_schema_pattern_changed.yaml", prop); } + + @Test + public void minPropertiesIncreased() { + BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED; + assertSpecIncompatible(BASE, "bc_schema_min_properties_increased.yaml", prop); + } + + @Test + public void minPropertiesAdded() { + BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED; + assertSpecIncompatible(BASE, "bc_schema_min_properties_added.yaml", prop); + } + + @Test + public void maxPropertiesDecreased() { + BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED; + assertSpecIncompatible(BASE, "bc_schema_max_properties_decreased.yaml", prop); + } + + @Test + public void maxPropertiesAdded() { + BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED; + assertSpecIncompatible(BASE, "bc_schema_max_properties_added.yaml", prop); + } } diff --git a/core/src/test/resources/bc_schema_base.yaml b/core/src/test/resources/bc_schema_base.yaml index 28d8800d..79c9aa69 100644 --- a/core/src/test/resources/bc_schema_base.yaml +++ b/core/src/test/resources/bc_schema_base.yaml @@ -86,6 +86,16 @@ components: type: integer format: int32 deprecated: true + stuffUnbounded: + type: object + additionalProperties: + type: string + stuffBounded: + type: object + minProperties: 1 + maxProperties: 10 + additionalProperties: + type: string required: - '@type' - prop1 diff --git a/core/src/test/resources/bc_schema_max_properties_added.yaml b/core/src/test/resources/bc_schema_max_properties_added.yaml new file mode 100644 index 00000000..670f5afe --- /dev/null +++ b/core/src/test/resources/bc_schema_max_properties_added.yaml @@ -0,0 +1,126 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateRequest' + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateResponse' + put: + operationId: widgetUpdate + requestBody: + content: + application/json: + schema: + type: object + properties: + put_prop1: + type: string + put_prop2: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string +components: + schemas: + WidgetCreateRequest: + type: object + properties: + to_create: + $ref: '#/components/schemas/Widget_Polymorphic' + request_prop1: + type: integer + format: int32 + request_prop2: + type: integer + format: int64 + required: + - to_create + - request_prop1 + WidgetCreateResponse: + type: object + properties: + created: + $ref: '#/components/schemas/Widget_Polymorphic' + response_prop1: + type: integer + format: int32 + response_prop2: + type: integer + format: int64 + required: + - created + - response_prop1 + Widget_Polymorphic: + type: object + oneOf: + - $ref: '#/components/schemas/Doodad' + - $ref: '#/components/schemas/Gadget' + discriminator: + propertyName: '@type' + Widget: + type: object + properties: + '@type': + type: string + prop1: + type: string + prop2: + type: integer + format: int32 + deprecated: true + stuffUnbounded: + type: object + maxProperties: 5 + additionalProperties: + type: string + stuffBounded: + type: object + minProperties: 1 + maxProperties: 10 + additionalProperties: + type: string + required: + - '@type' + - prop1 + Doodad: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + doodad_prop1: + type: string + Gadget: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gadget_prop1: + type: string + Gizmo: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gizmo_prop1: + type: string diff --git a/core/src/test/resources/bc_schema_max_properties_decreased.yaml b/core/src/test/resources/bc_schema_max_properties_decreased.yaml new file mode 100644 index 00000000..a4b86071 --- /dev/null +++ b/core/src/test/resources/bc_schema_max_properties_decreased.yaml @@ -0,0 +1,125 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateRequest' + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateResponse' + put: + operationId: widgetUpdate + requestBody: + content: + application/json: + schema: + type: object + properties: + put_prop1: + type: string + put_prop2: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string +components: + schemas: + WidgetCreateRequest: + type: object + properties: + to_create: + $ref: '#/components/schemas/Widget_Polymorphic' + request_prop1: + type: integer + format: int32 + request_prop2: + type: integer + format: int64 + required: + - to_create + - request_prop1 + WidgetCreateResponse: + type: object + properties: + created: + $ref: '#/components/schemas/Widget_Polymorphic' + response_prop1: + type: integer + format: int32 + response_prop2: + type: integer + format: int64 + required: + - created + - response_prop1 + Widget_Polymorphic: + type: object + oneOf: + - $ref: '#/components/schemas/Doodad' + - $ref: '#/components/schemas/Gadget' + discriminator: + propertyName: '@type' + Widget: + type: object + properties: + '@type': + type: string + prop1: + type: string + prop2: + type: integer + format: int32 + deprecated: true + stuffUnbounded: + type: object + additionalProperties: + type: string + stuffBounded: + type: object + minProperties: 1 + maxProperties: 5 + additionalProperties: + type: string + required: + - '@type' + - prop1 + Doodad: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + doodad_prop1: + type: string + Gadget: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gadget_prop1: + type: string + Gizmo: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gizmo_prop1: + type: string diff --git a/core/src/test/resources/bc_schema_min_properties_added.yaml b/core/src/test/resources/bc_schema_min_properties_added.yaml new file mode 100644 index 00000000..5398280c --- /dev/null +++ b/core/src/test/resources/bc_schema_min_properties_added.yaml @@ -0,0 +1,126 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateRequest' + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateResponse' + put: + operationId: widgetUpdate + requestBody: + content: + application/json: + schema: + type: object + properties: + put_prop1: + type: string + put_prop2: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string +components: + schemas: + WidgetCreateRequest: + type: object + properties: + to_create: + $ref: '#/components/schemas/Widget_Polymorphic' + request_prop1: + type: integer + format: int32 + request_prop2: + type: integer + format: int64 + required: + - to_create + - request_prop1 + WidgetCreateResponse: + type: object + properties: + created: + $ref: '#/components/schemas/Widget_Polymorphic' + response_prop1: + type: integer + format: int32 + response_prop2: + type: integer + format: int64 + required: + - created + - response_prop1 + Widget_Polymorphic: + type: object + oneOf: + - $ref: '#/components/schemas/Doodad' + - $ref: '#/components/schemas/Gadget' + discriminator: + propertyName: '@type' + Widget: + type: object + properties: + '@type': + type: string + prop1: + type: string + prop2: + type: integer + format: int32 + deprecated: true + stuffUnbounded: + type: object + minProperties: 5 + additionalProperties: + type: string + stuffBounded: + type: object + minProperties: 1 + maxProperties: 10 + additionalProperties: + type: string + required: + - '@type' + - prop1 + Doodad: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + doodad_prop1: + type: string + Gadget: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gadget_prop1: + type: string + Gizmo: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gizmo_prop1: + type: string diff --git a/core/src/test/resources/bc_schema_min_properties_increased.yaml b/core/src/test/resources/bc_schema_min_properties_increased.yaml new file mode 100644 index 00000000..0236a1b1 --- /dev/null +++ b/core/src/test/resources/bc_schema_min_properties_increased.yaml @@ -0,0 +1,125 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateRequest' + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateResponse' + put: + operationId: widgetUpdate + requestBody: + content: + application/json: + schema: + type: object + properties: + put_prop1: + type: string + put_prop2: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string +components: + schemas: + WidgetCreateRequest: + type: object + properties: + to_create: + $ref: '#/components/schemas/Widget_Polymorphic' + request_prop1: + type: integer + format: int32 + request_prop2: + type: integer + format: int64 + required: + - to_create + - request_prop1 + WidgetCreateResponse: + type: object + properties: + created: + $ref: '#/components/schemas/Widget_Polymorphic' + response_prop1: + type: integer + format: int32 + response_prop2: + type: integer + format: int64 + required: + - created + - response_prop1 + Widget_Polymorphic: + type: object + oneOf: + - $ref: '#/components/schemas/Doodad' + - $ref: '#/components/schemas/Gadget' + discriminator: + propertyName: '@type' + Widget: + type: object + properties: + '@type': + type: string + prop1: + type: string + prop2: + type: integer + format: int32 + deprecated: true + stuffUnbounded: + type: object + additionalProperties: + type: string + stuffBounded: + type: object + minProperties: 5 + maxProperties: 10 + additionalProperties: + type: string + required: + - '@type' + - prop1 + Doodad: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + doodad_prop1: + type: string + Gadget: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gadget_prop1: + type: string + Gizmo: + type: object + allOf: + - $ref: '#/components/schemas/Widget' + - type: object + properties: + gizmo_prop1: + type: string