Skip to content

Commit eae9122

Browse files
fix(#852): Proposed solution to disable BC on min and max properties change (#853)
1 parent 2ec4089 commit eae9122

File tree

9 files changed

+564
-9
lines changed

9 files changed

+564
-9
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ public enum BackwardIncompatibleProp {
5252
SECURITY_SCHEME_SCHEME_CHANGED("incompatible.security.scheme.scheme.changed", true),
5353
SECURITY_SCHEME_SCOPES_INCREASED("incompatible.security.scheme.scopes.increased", true),
5454
SCHEMA_DISCRIMINATOR_CHANGED("incompatible.schema.discriminator.changed", true),
55-
SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true),
5655
SCHEMA_PATTERN_CHANGED("incompatible.schema.pattern.changed", true),
56+
SCHEMA_MIN_PROPERTIES_CHANGED("incompatible.schema.min-properties.changed", true),
57+
SCHEMA_MAX_PROPERTIES_CHANGED("incompatible.schema.max-properties.changed", true),
58+
SCHEMA_TYPE_CHANGED("incompatible.schema.type.changed", true),
5759
;
5860

5961
private final String propertyName;

core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMaxProperties.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.openapitools.openapidiff.core.model.schema;
22

3+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MAX_PROPERTIES_CHANGED;
4+
35
import org.openapitools.openapidiff.core.model.Changed;
46
import org.openapitools.openapidiff.core.model.DiffContext;
57
import org.openapitools.openapidiff.core.model.DiffResult;
@@ -30,15 +32,23 @@ public DiffResult isChanged() {
3032
}
3133

3234
if (oldValue == null) {
33-
return DiffResult.INCOMPATIBLE;
35+
if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context)) {
36+
return DiffResult.INCOMPATIBLE;
37+
} else {
38+
return DiffResult.COMPATIBLE;
39+
}
3440
}
3541

3642
if (newValue == null) {
3743
return DiffResult.COMPATIBLE;
3844
}
3945

4046
if (!oldValue.equals(newValue)) {
41-
return oldValue > newValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE;
47+
if (SCHEMA_MAX_PROPERTIES_CHANGED.enabled(context) && oldValue > newValue) {
48+
return DiffResult.INCOMPATIBLE;
49+
} else {
50+
return DiffResult.COMPATIBLE;
51+
}
4252
}
4353

4454
return DiffResult.NO_CHANGES;

core/src/main/java/org/openapitools/openapidiff/core/model/schema/ChangedMinProperties.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.openapitools.openapidiff.core.model.schema;
22

3+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_MIN_PROPERTIES_CHANGED;
4+
35
import org.openapitools.openapidiff.core.model.Changed;
46
import org.openapitools.openapidiff.core.model.DiffContext;
57
import org.openapitools.openapidiff.core.model.DiffResult;
@@ -30,15 +32,23 @@ public DiffResult isChanged() {
3032
}
3133

3234
if (oldValue == null) {
33-
return DiffResult.INCOMPATIBLE;
35+
if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context)) {
36+
return DiffResult.INCOMPATIBLE;
37+
} else {
38+
return DiffResult.COMPATIBLE;
39+
}
3440
}
3541

3642
if (newValue == null) {
3743
return DiffResult.COMPATIBLE;
3844
}
3945

4046
if (!oldValue.equals(newValue)) {
41-
return newValue > oldValue ? DiffResult.INCOMPATIBLE : DiffResult.COMPATIBLE;
47+
if (SCHEMA_MIN_PROPERTIES_CHANGED.enabled(context) && newValue > oldValue) {
48+
return DiffResult.INCOMPATIBLE;
49+
} else {
50+
return DiffResult.COMPATIBLE;
51+
}
4252
}
4353

4454
return DiffResult.NO_CHANGES;

core/src/test/java/org/openapitools/openapidiff/core/backcompat/SchemaBCTest.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import static org.openapitools.openapidiff.core.TestUtils.assertSpecChangedButCompatible;
55
import static org.openapitools.openapidiff.core.TestUtils.assertSpecIncompatible;
66
import static org.openapitools.openapidiff.core.TestUtils.assertSpecUnchanged;
7-
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.RESPONSE_REQUIRED_DECREASED;
8-
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_DISCRIMINATOR_CHANGED;
9-
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_PATTERN_CHANGED;
10-
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.SCHEMA_TYPE_CHANGED;
7+
import static org.openapitools.openapidiff.core.model.BackwardIncompatibleProp.*;
118

129
import org.junit.jupiter.api.Test;
1310
import org.openapitools.openapidiff.core.model.BackwardIncompatibleProp;
@@ -76,4 +73,28 @@ public void patternChanged() {
7673
BackwardIncompatibleProp prop = SCHEMA_PATTERN_CHANGED;
7774
assertSpecIncompatible(BASE, "bc_schema_pattern_changed.yaml", prop);
7875
}
76+
77+
@Test
78+
public void minPropertiesIncreased() {
79+
BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED;
80+
assertSpecIncompatible(BASE, "bc_schema_min_properties_increased.yaml", prop);
81+
}
82+
83+
@Test
84+
public void minPropertiesAdded() {
85+
BackwardIncompatibleProp prop = SCHEMA_MIN_PROPERTIES_CHANGED;
86+
assertSpecIncompatible(BASE, "bc_schema_min_properties_added.yaml", prop);
87+
}
88+
89+
@Test
90+
public void maxPropertiesDecreased() {
91+
BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED;
92+
assertSpecIncompatible(BASE, "bc_schema_max_properties_decreased.yaml", prop);
93+
}
94+
95+
@Test
96+
public void maxPropertiesAdded() {
97+
BackwardIncompatibleProp prop = SCHEMA_MAX_PROPERTIES_CHANGED;
98+
assertSpecIncompatible(BASE, "bc_schema_max_properties_added.yaml", prop);
99+
}
79100
}

core/src/test/resources/bc_schema_base.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,16 @@ components:
8686
type: integer
8787
format: int32
8888
deprecated: true
89+
stuffUnbounded:
90+
type: object
91+
additionalProperties:
92+
type: string
93+
stuffBounded:
94+
type: object
95+
minProperties: 1
96+
maxProperties: 10
97+
additionalProperties:
98+
type: string
8999
required:
90100
- '@type'
91101
- prop1
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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+
$ref: '#/components/schemas/WidgetCreateRequest'
15+
responses:
16+
'200':
17+
description: successful operation
18+
content:
19+
application/json:
20+
schema:
21+
$ref: '#/components/schemas/WidgetCreateResponse'
22+
put:
23+
operationId: widgetUpdate
24+
requestBody:
25+
content:
26+
application/json:
27+
schema:
28+
type: object
29+
properties:
30+
put_prop1:
31+
type: string
32+
put_prop2:
33+
type: string
34+
responses:
35+
'200':
36+
description: successful operation
37+
content:
38+
application/json:
39+
schema:
40+
type: string
41+
components:
42+
schemas:
43+
WidgetCreateRequest:
44+
type: object
45+
properties:
46+
to_create:
47+
$ref: '#/components/schemas/Widget_Polymorphic'
48+
request_prop1:
49+
type: integer
50+
format: int32
51+
request_prop2:
52+
type: integer
53+
format: int64
54+
required:
55+
- to_create
56+
- request_prop1
57+
WidgetCreateResponse:
58+
type: object
59+
properties:
60+
created:
61+
$ref: '#/components/schemas/Widget_Polymorphic'
62+
response_prop1:
63+
type: integer
64+
format: int32
65+
response_prop2:
66+
type: integer
67+
format: int64
68+
required:
69+
- created
70+
- response_prop1
71+
Widget_Polymorphic:
72+
type: object
73+
oneOf:
74+
- $ref: '#/components/schemas/Doodad'
75+
- $ref: '#/components/schemas/Gadget'
76+
discriminator:
77+
propertyName: '@type'
78+
Widget:
79+
type: object
80+
properties:
81+
'@type':
82+
type: string
83+
prop1:
84+
type: string
85+
prop2:
86+
type: integer
87+
format: int32
88+
deprecated: true
89+
stuffUnbounded:
90+
type: object
91+
maxProperties: 5
92+
additionalProperties:
93+
type: string
94+
stuffBounded:
95+
type: object
96+
minProperties: 1
97+
maxProperties: 10
98+
additionalProperties:
99+
type: string
100+
required:
101+
- '@type'
102+
- prop1
103+
Doodad:
104+
type: object
105+
allOf:
106+
- $ref: '#/components/schemas/Widget'
107+
- type: object
108+
properties:
109+
doodad_prop1:
110+
type: string
111+
Gadget:
112+
type: object
113+
allOf:
114+
- $ref: '#/components/schemas/Widget'
115+
- type: object
116+
properties:
117+
gadget_prop1:
118+
type: string
119+
Gizmo:
120+
type: object
121+
allOf:
122+
- $ref: '#/components/schemas/Widget'
123+
- type: object
124+
properties:
125+
gizmo_prop1:
126+
type: string
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
$ref: '#/components/schemas/WidgetCreateRequest'
15+
responses:
16+
'200':
17+
description: successful operation
18+
content:
19+
application/json:
20+
schema:
21+
$ref: '#/components/schemas/WidgetCreateResponse'
22+
put:
23+
operationId: widgetUpdate
24+
requestBody:
25+
content:
26+
application/json:
27+
schema:
28+
type: object
29+
properties:
30+
put_prop1:
31+
type: string
32+
put_prop2:
33+
type: string
34+
responses:
35+
'200':
36+
description: successful operation
37+
content:
38+
application/json:
39+
schema:
40+
type: string
41+
components:
42+
schemas:
43+
WidgetCreateRequest:
44+
type: object
45+
properties:
46+
to_create:
47+
$ref: '#/components/schemas/Widget_Polymorphic'
48+
request_prop1:
49+
type: integer
50+
format: int32
51+
request_prop2:
52+
type: integer
53+
format: int64
54+
required:
55+
- to_create
56+
- request_prop1
57+
WidgetCreateResponse:
58+
type: object
59+
properties:
60+
created:
61+
$ref: '#/components/schemas/Widget_Polymorphic'
62+
response_prop1:
63+
type: integer
64+
format: int32
65+
response_prop2:
66+
type: integer
67+
format: int64
68+
required:
69+
- created
70+
- response_prop1
71+
Widget_Polymorphic:
72+
type: object
73+
oneOf:
74+
- $ref: '#/components/schemas/Doodad'
75+
- $ref: '#/components/schemas/Gadget'
76+
discriminator:
77+
propertyName: '@type'
78+
Widget:
79+
type: object
80+
properties:
81+
'@type':
82+
type: string
83+
prop1:
84+
type: string
85+
prop2:
86+
type: integer
87+
format: int32
88+
deprecated: true
89+
stuffUnbounded:
90+
type: object
91+
additionalProperties:
92+
type: string
93+
stuffBounded:
94+
type: object
95+
minProperties: 1
96+
maxProperties: 5
97+
additionalProperties:
98+
type: string
99+
required:
100+
- '@type'
101+
- prop1
102+
Doodad:
103+
type: object
104+
allOf:
105+
- $ref: '#/components/schemas/Widget'
106+
- type: object
107+
properties:
108+
doodad_prop1:
109+
type: string
110+
Gadget:
111+
type: object
112+
allOf:
113+
- $ref: '#/components/schemas/Widget'
114+
- type: object
115+
properties:
116+
gadget_prop1:
117+
type: string
118+
Gizmo:
119+
type: object
120+
allOf:
121+
- $ref: '#/components/schemas/Widget'
122+
- type: object
123+
properties:
124+
gizmo_prop1:
125+
type: string

0 commit comments

Comments
 (0)