Skip to content

Commit 42dd7b8

Browse files
authored
fix #461: add minlength breaking change detection (#863)
1 parent 33c40f4 commit 42dd7b8

File tree

10 files changed

+292
-0
lines changed

10 files changed

+292
-0
lines changed

core/src/main/java/org/openapitools/openapidiff/core/compare/schemadiffresult/SchemaDiffResult.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public <V extends Schema<X>, X> DeferredChanged<ChangedSchema> diff(
6666
.setReadOnly(new ChangedReadOnly(left.getReadOnly(), right.getReadOnly(), context))
6767
.setWriteOnly(new ChangedWriteOnly(left.getWriteOnly(), right.getWriteOnly(), context))
6868
.setMaxLength(new ChangedMaxLength(left.getMaxLength(), right.getMaxLength(), context))
69+
.setMinLength(new ChangedMinLength(left.getMinLength(), right.getMinLength(), context))
6970
.setNumericRange(
7071
new ChangedNumericRange(
7172
left.getMinimum(),

core/src/main/java/org/openapitools/openapidiff/core/model/BackwardIncompatibleProp.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public enum BackwardIncompatibleProp {
1414
REQUEST_CONTENT_DECREASED("incompatible.request.content.decreased", true),
1515
REQUEST_ENUM_DECREASED("incompatible.request.enum.decreased", true),
1616
REQUEST_MAX_LENGTH_DECREASED("incompatible.request.max.length.decreased", true),
17+
REQUEST_MIN_LENGTH_INCREASED("incompatible.request.min.length.increased", false),
1718
REQUEST_NUMERIC_RANGE_DECREASED("incompatible.request.numeric.range.decreased", true),
1819
REQUEST_ONEOF_DECREASED("incompatible.request.oneof.decreased", true),
1920
REQUEST_PARAM_ALLOWEMPTY_DECREASED("incompatible.request.param.allowempty.decreased", true),
@@ -31,6 +32,7 @@ public enum BackwardIncompatibleProp {
3132
RESPONSE_HEADER_REQUIRED_INCREASED("incompatible.response.header.required.increased", true),
3233
RESPONSE_HEADERS_DECREASED("incompatible.response.headers.decreased", true),
3334
RESPONSE_MAX_LENGTH_INCREASED("incompatible.response.max.length.increased", true),
35+
RESPONSE_MIN_LENGTH_INCREASED("incompatible.response.min.length.increased", false),
3436
RESPONSE_NUMERIC_RANGE_INCREASED("incompatible.response.numeric.range.increased", false),
3537
RESPONSE_ONEOF_INCREASED("incompatible.response.oneof.increased", true),
3638
RESPONSE_REQUIRED_DECREASED("incompatible.response.required.decreased", true),

core/src/main/java/org/openapitools/openapidiff/core/model/ChangedSchema.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.openapitools.openapidiff.core.model.schema.ChangedMaxLength;
1818
import org.openapitools.openapidiff.core.model.schema.ChangedMaxProperties;
1919
import org.openapitools.openapidiff.core.model.schema.ChangedMinItems;
20+
import org.openapitools.openapidiff.core.model.schema.ChangedMinLength;
2021
import org.openapitools.openapidiff.core.model.schema.ChangedMinProperties;
2122
import org.openapitools.openapidiff.core.model.schema.ChangedMultipleOf;
2223
import org.openapitools.openapidiff.core.model.schema.ChangedNullable;
@@ -49,6 +50,7 @@ public class ChangedSchema implements ComposedChanged {
4950
protected ChangedWriteOnly writeOnly;
5051
protected boolean changedType;
5152
protected ChangedMaxLength maxLength;
53+
protected ChangedMinLength minLength;
5254
protected ChangedNumericRange numericRange;
5355
protected ChangedMultipleOf multipleOf;
5456
protected ChangedMaxItems maxItems;
@@ -139,6 +141,7 @@ public List<Changed> getChangedElements() {
139141
enumeration,
140142
required,
141143
maxLength,
144+
minLength,
142145
numericRange,
143146
multipleOf,
144147
maxItems,
@@ -303,6 +306,10 @@ public ChangedMaxLength getMaxLength() {
303306
return this.maxLength;
304307
}
305308

309+
public ChangedMinLength getMinLength() {
310+
return this.minLength;
311+
}
312+
306313
public ChangedNumericRange getNumericRange() {
307314
return this.numericRange;
308315
}
@@ -475,6 +482,12 @@ public ChangedSchema setMaxLength(final ChangedMaxLength maxLength) {
475482
return this;
476483
}
477484

485+
public ChangedSchema setMinLength(final ChangedMinLength minLength) {
486+
clearChangedCache();
487+
this.minLength = minLength;
488+
return this;
489+
}
490+
478491
public ChangedSchema setNumericRange(final ChangedNumericRange numericRange) {
479492
clearChangedCache();
480493
this.numericRange = numericRange;
@@ -585,6 +598,7 @@ public boolean equals(Object o) {
585598
&& Objects.equals(readOnly, that.readOnly)
586599
&& Objects.equals(writeOnly, that.writeOnly)
587600
&& Objects.equals(maxLength, that.maxLength)
601+
&& Objects.equals(minLength, that.minLength)
588602
&& Objects.equals(numericRange, that.numericRange)
589603
&& Objects.equals(multipleOf, that.multipleOf)
590604
&& Objects.equals(maxItems, that.maxItems)
@@ -623,6 +637,7 @@ public int hashCode() {
623637
writeOnly,
624638
changedType,
625639
maxLength,
640+
minLength,
626641
numericRange,
627642
multipleOf,
628643
maxItems,
@@ -681,6 +696,8 @@ public java.lang.String toString() {
681696
+ this.isChangedType()
682697
+ ", maxLength="
683698
+ this.getMaxLength()
699+
+ ", minLength="
700+
+ this.getMinLength()
684701
+ ", numericRange="
685702
+ this.getNumericRange()
686703
+ ", multipleOf="
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.openapitools.openapidiff.core.model.schema;
2+
3+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.REQUEST_MIN_LENGTH_INCREASED;
4+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_MIN_LENGTH_INCREASED;
5+
6+
import java.util.Objects;
7+
import org.openapitools.openapidiff.core.model.Changed;
8+
import org.openapitools.openapidiff.core.model.DiffContext;
9+
import org.openapitools.openapidiff.core.model.DiffResult;
10+
11+
public final class ChangedMinLength implements Changed {
12+
private final Integer oldValue;
13+
private final Integer newValue;
14+
private final DiffContext context;
15+
16+
@Override
17+
public DiffResult isChanged() {
18+
if (Objects.equals(oldValue, newValue)) {
19+
return DiffResult.NO_CHANGES;
20+
}
21+
if (context.isRequest() && (newValue != null && (oldValue == null || newValue > oldValue))) {
22+
if (REQUEST_MIN_LENGTH_INCREASED.enabled(context)) {
23+
return DiffResult.INCOMPATIBLE;
24+
}
25+
}
26+
if (context.isResponse() && (newValue != null && (oldValue == null || newValue > oldValue))) {
27+
if (RESPONSE_MIN_LENGTH_INCREASED.enabled(context)) {
28+
return DiffResult.INCOMPATIBLE;
29+
}
30+
}
31+
return DiffResult.COMPATIBLE;
32+
}
33+
34+
public ChangedMinLength(
35+
final Integer oldValue, final Integer newValue, final DiffContext context) {
36+
this.oldValue = oldValue;
37+
this.newValue = newValue;
38+
this.context = context;
39+
}
40+
41+
public Integer getOldValue() {
42+
return this.oldValue;
43+
}
44+
45+
public Integer getNewValue() {
46+
return this.newValue;
47+
}
48+
49+
public DiffContext getContext() {
50+
return this.context;
51+
}
52+
53+
@Override
54+
public boolean equals(Object o) {
55+
if (this == o) return true;
56+
if (o == null || getClass() != o.getClass()) return false;
57+
ChangedMinLength that = (ChangedMinLength) o;
58+
return Objects.equals(oldValue, that.oldValue)
59+
&& Objects.equals(newValue, that.newValue)
60+
&& Objects.equals(context, that.context);
61+
}
62+
63+
@Override
64+
public int hashCode() {
65+
return Objects.hash(oldValue, newValue, context);
66+
}
67+
68+
@Override
69+
public String toString() {
70+
return "ChangedMinLength(oldValue="
71+
+ this.getOldValue()
72+
+ ", newValue="
73+
+ this.getNewValue()
74+
+ ", context="
75+
+ this.getContext()
76+
+ ")";
77+
}
78+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.openapitools.openapidiff.core.backcompat;
2+
3+
import static org.openapitools.openapidiff.core.TestUtils.assertSpecChangedButCompatible;
4+
import static org.openapitools.openapidiff.core.TestUtils.assertSpecIncompatible;
5+
import static org.openapitools.openapidiff.core.TestUtils.assertSpecUnchanged;
6+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.REQUEST_MIN_LENGTH_INCREASED;
7+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_MIN_LENGTH_INCREASED;
8+
9+
import org.junit.jupiter.api.Test;
10+
import org.openapitools.openapidiff.core.model.BackwardIncompatibleProp;
11+
12+
public class MinLengthBCTest {
13+
private final String BASE = "bc_minlength_base.yaml";
14+
15+
@Test
16+
public void minLengthUnchanged() {
17+
assertSpecUnchanged(BASE, BASE);
18+
}
19+
20+
@Test
21+
public void requestMinLengthIncreased() {
22+
BackwardIncompatibleProp prop = REQUEST_MIN_LENGTH_INCREASED;
23+
assertSpecIncompatible(BASE, "bc_request_minlength_increased.yaml", prop);
24+
}
25+
26+
@Test
27+
public void requestMinLengthDecreasedButCompatible() {
28+
assertSpecChangedButCompatible(BASE, "bc_request_minlength_changed_but_compatible.yaml");
29+
}
30+
31+
@Test
32+
public void responseMinLengthIncreased() {
33+
BackwardIncompatibleProp prop = RESPONSE_MIN_LENGTH_INCREASED;
34+
assertSpecIncompatible(BASE, "bc_response_minlength_increased.yaml", prop);
35+
}
36+
37+
@Test
38+
public void responseMinLengthDecreasedButCompatible() {
39+
assertSpecChangedButCompatible(BASE, "bc_response_minlength_changed_but_compatible.yaml");
40+
}
41+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
openapi: 3.0.0
2+
info:
3+
description: myDesc
4+
title: myTitle
5+
version: 1.0.0
6+
paths:
7+
/widgets:
8+
post:
9+
operationId: widgetCreate
10+
requestBody:
11+
content:
12+
application/json:
13+
schema:
14+
type: string
15+
minLength: 5
16+
application/xml:
17+
schema:
18+
type: string
19+
responses:
20+
'200':
21+
description: successful operation
22+
content:
23+
application/json:
24+
schema:
25+
type: string
26+
minLength: 5
27+
application/xml:
28+
schema:
29+
type: string
30+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
openapi: 3.0.0
2+
info:
3+
description: myDesc
4+
title: myTitle
5+
version: 1.0.0
6+
paths:
7+
/widgets:
8+
post:
9+
operationId: widgetCreate
10+
requestBody:
11+
content:
12+
application/json:
13+
schema:
14+
type: string
15+
minLength: 3
16+
application/xml:
17+
schema:
18+
type: string
19+
responses:
20+
'200':
21+
description: successful operation
22+
content:
23+
application/json:
24+
schema:
25+
type: string
26+
minLength: 5
27+
application/xml:
28+
schema:
29+
type: string
30+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
openapi: 3.0.0
2+
info:
3+
description: myDesc
4+
title: myTitle
5+
version: 1.0.0
6+
paths:
7+
/widgets:
8+
post:
9+
operationId: widgetCreate
10+
requestBody:
11+
content:
12+
application/json:
13+
schema:
14+
type: string
15+
minLength: 10
16+
application/xml:
17+
schema:
18+
type: string
19+
minLength: 10
20+
responses:
21+
'200':
22+
description: successful operation
23+
content:
24+
application/json:
25+
schema:
26+
type: string
27+
minLength: 5
28+
application/xml:
29+
schema:
30+
type: string
31+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
openapi: 3.0.0
2+
info:
3+
description: myDesc
4+
title: myTitle
5+
version: 1.0.0
6+
paths:
7+
/widgets:
8+
post:
9+
operationId: widgetCreate
10+
requestBody:
11+
content:
12+
application/json:
13+
schema:
14+
type: string
15+
minLength: 5
16+
application/xml:
17+
schema:
18+
type: string
19+
responses:
20+
'200':
21+
description: successful operation
22+
content:
23+
application/json:
24+
schema:
25+
type: string
26+
minLength: 3
27+
application/xml:
28+
schema:
29+
type: string
30+
minLength: 3
31+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
openapi: 3.0.0
2+
info:
3+
description: myDesc
4+
title: myTitle
5+
version: 1.0.0
6+
paths:
7+
/widgets:
8+
post:
9+
operationId: widgetCreate
10+
requestBody:
11+
content:
12+
application/json:
13+
schema:
14+
type: string
15+
minLength: 5
16+
application/xml:
17+
schema:
18+
type: string
19+
responses:
20+
'200':
21+
description: successful operation
22+
content:
23+
application/json:
24+
schema:
25+
type: string
26+
minLength: 10
27+
application/xml:
28+
schema:
29+
type: string
30+
minLength: 10
31+

0 commit comments

Comments
 (0)