diff --git a/core/src/main/java/org/openapitools/openapidiff/core/compare/schemadiffresult/SchemaDiffResult.java b/core/src/main/java/org/openapitools/openapidiff/core/compare/schemadiffresult/SchemaDiffResult.java index dd3c8ab3..67d976a3 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/compare/schemadiffresult/SchemaDiffResult.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/compare/schemadiffresult/SchemaDiffResult.java @@ -66,6 +66,7 @@ public , X> DeferredChanged diff( .setReadOnly(new ChangedReadOnly(left.getReadOnly(), right.getReadOnly(), context)) .setWriteOnly(new ChangedWriteOnly(left.getWriteOnly(), right.getWriteOnly(), context)) .setMaxLength(new ChangedMaxLength(left.getMaxLength(), right.getMaxLength(), context)) + .setMinLength(new ChangedMinLength(left.getMinLength(), right.getMinLength(), context)) .setNumericRange( new ChangedNumericRange( left.getMinimum(), 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 f2180b34..b3da97ca 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 @@ -14,6 +14,7 @@ public enum BackwardIncompatibleProp { REQUEST_CONTENT_DECREASED("incompatible.request.content.decreased", true), REQUEST_ENUM_DECREASED("incompatible.request.enum.decreased", true), REQUEST_MAX_LENGTH_DECREASED("incompatible.request.max.length.decreased", true), + REQUEST_MIN_LENGTH_INCREASED("incompatible.request.min.length.increased", false), REQUEST_NUMERIC_RANGE_DECREASED("incompatible.request.numeric.range.decreased", true), REQUEST_ONEOF_DECREASED("incompatible.request.oneof.decreased", true), REQUEST_PARAM_ALLOWEMPTY_DECREASED("incompatible.request.param.allowempty.decreased", true), @@ -31,6 +32,7 @@ public enum BackwardIncompatibleProp { RESPONSE_HEADER_REQUIRED_INCREASED("incompatible.response.header.required.increased", true), RESPONSE_HEADERS_DECREASED("incompatible.response.headers.decreased", true), RESPONSE_MAX_LENGTH_INCREASED("incompatible.response.max.length.increased", true), + RESPONSE_MIN_LENGTH_INCREASED("incompatible.response.min.length.increased", false), RESPONSE_NUMERIC_RANGE_INCREASED("incompatible.response.numeric.range.increased", false), RESPONSE_ONEOF_INCREASED("incompatible.response.oneof.increased", true), RESPONSE_REQUIRED_DECREASED("incompatible.response.required.decreased", true), diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/ChangedSchema.java b/core/src/main/java/org/openapitools/openapidiff/core/model/ChangedSchema.java index 1896783a..30d126fb 100644 --- a/core/src/main/java/org/openapitools/openapidiff/core/model/ChangedSchema.java +++ b/core/src/main/java/org/openapitools/openapidiff/core/model/ChangedSchema.java @@ -17,6 +17,7 @@ import org.openapitools.openapidiff.core.model.schema.ChangedMaxLength; import org.openapitools.openapidiff.core.model.schema.ChangedMaxProperties; import org.openapitools.openapidiff.core.model.schema.ChangedMinItems; +import org.openapitools.openapidiff.core.model.schema.ChangedMinLength; import org.openapitools.openapidiff.core.model.schema.ChangedMinProperties; import org.openapitools.openapidiff.core.model.schema.ChangedMultipleOf; import org.openapitools.openapidiff.core.model.schema.ChangedNullable; @@ -49,6 +50,7 @@ public class ChangedSchema implements ComposedChanged { protected ChangedWriteOnly writeOnly; protected boolean changedType; protected ChangedMaxLength maxLength; + protected ChangedMinLength minLength; protected ChangedNumericRange numericRange; protected ChangedMultipleOf multipleOf; protected ChangedMaxItems maxItems; @@ -139,6 +141,7 @@ public List getChangedElements() { enumeration, required, maxLength, + minLength, numericRange, multipleOf, maxItems, @@ -303,6 +306,10 @@ public ChangedMaxLength getMaxLength() { return this.maxLength; } + public ChangedMinLength getMinLength() { + return this.minLength; + } + public ChangedNumericRange getNumericRange() { return this.numericRange; } @@ -475,6 +482,12 @@ public ChangedSchema setMaxLength(final ChangedMaxLength maxLength) { return this; } + public ChangedSchema setMinLength(final ChangedMinLength minLength) { + clearChangedCache(); + this.minLength = minLength; + return this; + } + public ChangedSchema setNumericRange(final ChangedNumericRange numericRange) { clearChangedCache(); this.numericRange = numericRange; @@ -585,6 +598,7 @@ public boolean equals(Object o) { && Objects.equals(readOnly, that.readOnly) && Objects.equals(writeOnly, that.writeOnly) && Objects.equals(maxLength, that.maxLength) + && Objects.equals(minLength, that.minLength) && Objects.equals(numericRange, that.numericRange) && Objects.equals(multipleOf, that.multipleOf) && Objects.equals(maxItems, that.maxItems) @@ -623,6 +637,7 @@ public int hashCode() { writeOnly, changedType, maxLength, + minLength, numericRange, multipleOf, maxItems, @@ -681,6 +696,8 @@ public java.lang.String toString() { + this.isChangedType() + ", maxLength=" + this.getMaxLength() + + ", minLength=" + + this.getMinLength() + ", numericRange=" + this.getNumericRange() + ", multipleOf=" diff --git a/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinLength.java b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinLength.java new file mode 100644 index 00000000..a964f4a1 --- /dev/null +++ b/core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinLength.java @@ -0,0 +1,78 @@ +package org.openapitools.openapidiff.core.model.schema; + +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.REQUEST_MIN_LENGTH_INCREASED; +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_MIN_LENGTH_INCREASED; + +import java.util.Objects; +import org.openapitools.openapidiff.core.model.Changed; +import org.openapitools.openapidiff.core.model.DiffContext; +import org.openapitools.openapidiff.core.model.DiffResult; + +public final class ChangedMinLength implements Changed { + private final Integer oldValue; + private final Integer newValue; + private final DiffContext context; + + @Override + public DiffResult isChanged() { + if (Objects.equals(oldValue, newValue)) { + return DiffResult.NO_CHANGES; + } + if (context.isRequest() && (newValue != null && (oldValue == null || newValue > oldValue))) { + if (REQUEST_MIN_LENGTH_INCREASED.enabled(context)) { + return DiffResult.INCOMPATIBLE; + } + } + if (context.isResponse() && (newValue != null && (oldValue == null || newValue > oldValue))) { + if (RESPONSE_MIN_LENGTH_INCREASED.enabled(context)) { + return DiffResult.INCOMPATIBLE; + } + } + return DiffResult.COMPATIBLE; + } + + public ChangedMinLength( + final Integer oldValue, final Integer newValue, final DiffContext context) { + this.oldValue = oldValue; + this.newValue = newValue; + this.context = context; + } + + public Integer getOldValue() { + return this.oldValue; + } + + public Integer getNewValue() { + return this.newValue; + } + + public DiffContext getContext() { + return this.context; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChangedMinLength that = (ChangedMinLength) o; + return Objects.equals(oldValue, that.oldValue) + && Objects.equals(newValue, that.newValue) + && Objects.equals(context, that.context); + } + + @Override + public int hashCode() { + return Objects.hash(oldValue, newValue, context); + } + + @Override + public String toString() { + return "ChangedMinLength(oldValue=" + + this.getOldValue() + + ", newValue=" + + this.getNewValue() + + ", context=" + + this.getContext() + + ")"; + } +} diff --git a/core/src/test/java/org/openapitools/openapidiff/core/backcompat/MinLengthBCTest.java b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/MinLengthBCTest.java new file mode 100644 index 00000000..fbc792b6 --- /dev/null +++ b/core/src/test/java/org/openapitools/openapidiff/core/backcompat/MinLengthBCTest.java @@ -0,0 +1,41 @@ +package org.openapitools.openapidiff.core.backcompat; + +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.REQUEST_MIN_LENGTH_INCREASED; +import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_MIN_LENGTH_INCREASED; + +import org.junit.jupiter.api.Test; +import org.openapitools.openapidiff.core.model.BackwardIncompatibleProp; + +public class MinLengthBCTest { + private final String BASE = "bc_minlength_base.yaml"; + + @Test + public void minLengthUnchanged() { + assertSpecUnchanged(BASE, BASE); + } + + @Test + public void requestMinLengthIncreased() { + BackwardIncompatibleProp prop = REQUEST_MIN_LENGTH_INCREASED; + assertSpecIncompatible(BASE, "bc_request_minlength_increased.yaml", prop); + } + + @Test + public void requestMinLengthDecreasedButCompatible() { + assertSpecChangedButCompatible(BASE, "bc_request_minlength_changed_but_compatible.yaml"); + } + + @Test + public void responseMinLengthIncreased() { + BackwardIncompatibleProp prop = RESPONSE_MIN_LENGTH_INCREASED; + assertSpecIncompatible(BASE, "bc_response_minlength_increased.yaml", prop); + } + + @Test + public void responseMinLengthDecreasedButCompatible() { + assertSpecChangedButCompatible(BASE, "bc_response_minlength_changed_but_compatible.yaml"); + } +} diff --git a/core/src/test/resources/bc_minlength_base.yaml b/core/src/test/resources/bc_minlength_base.yaml new file mode 100644 index 00000000..3e61e691 --- /dev/null +++ b/core/src/test/resources/bc_minlength_base.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + diff --git a/core/src/test/resources/bc_request_minlength_changed_but_compatible.yaml b/core/src/test/resources/bc_request_minlength_changed_but_compatible.yaml new file mode 100644 index 00000000..663ee7c0 --- /dev/null +++ b/core/src/test/resources/bc_request_minlength_changed_but_compatible.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + type: string + minLength: 3 + application/xml: + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + diff --git a/core/src/test/resources/bc_request_minlength_increased.yaml b/core/src/test/resources/bc_request_minlength_increased.yaml new file mode 100644 index 00000000..f7760ba6 --- /dev/null +++ b/core/src/test/resources/bc_request_minlength_increased.yaml @@ -0,0 +1,31 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + type: string + minLength: 10 + application/xml: + schema: + type: string + minLength: 10 + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + diff --git a/core/src/test/resources/bc_response_minlength_changed_but_compatible.yaml b/core/src/test/resources/bc_response_minlength_changed_but_compatible.yaml new file mode 100644 index 00000000..a965540a --- /dev/null +++ b/core/src/test/resources/bc_response_minlength_changed_but_compatible.yaml @@ -0,0 +1,31 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string + minLength: 3 + application/xml: + schema: + type: string + minLength: 3 + diff --git a/core/src/test/resources/bc_response_minlength_increased.yaml b/core/src/test/resources/bc_response_minlength_increased.yaml new file mode 100644 index 00000000..06197c03 --- /dev/null +++ b/core/src/test/resources/bc_response_minlength_increased.yaml @@ -0,0 +1,31 @@ +openapi: 3.0.0 +info: + description: myDesc + title: myTitle + version: 1.0.0 +paths: + /widgets: + post: + operationId: widgetCreate + requestBody: + content: + application/json: + schema: + type: string + minLength: 5 + application/xml: + schema: + type: string + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: string + minLength: 10 + application/xml: + schema: + type: string + minLength: 10 +