Skip to content

Commit 42c17be

Browse files
authored
Change of 'multipleof' is not detected (#746)
1 parent 3afafef commit 42c17be

File tree

7 files changed

+224
-14
lines changed

7 files changed

+224
-14
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
@@ -71,6 +71,7 @@ public <V extends Schema<X>, X> DeferredChanged<ChangedSchema> diff(
7171
left.getExclusiveMaximum(),
7272
right.getExclusiveMaximum(),
7373
context))
74+
.setMultipleOf(new ChangedMultipleOf(left.getMultipleOf(), right.getMultipleOf()))
7475
.setExamples(new ChangedExamples(left.getExamples(), right.getExamples()))
7576
.setExample(new ChangedExample(left.getExample(), right.getExample()));
7677
builder

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.stream.Stream;
1111
import org.openapitools.openapidiff.core.model.schema.ChangedEnum;
1212
import org.openapitools.openapidiff.core.model.schema.ChangedMaxLength;
13+
import org.openapitools.openapidiff.core.model.schema.ChangedMultipleOf;
1314
import org.openapitools.openapidiff.core.model.schema.ChangedNumericRange;
1415
import org.openapitools.openapidiff.core.model.schema.ChangedReadOnly;
1516
import org.openapitools.openapidiff.core.model.schema.ChangedRequired;
@@ -37,6 +38,7 @@ public class ChangedSchema implements ComposedChanged {
3738
protected boolean changedType;
3839
protected ChangedMaxLength maxLength;
3940
protected ChangedNumericRange numericRange;
41+
protected ChangedMultipleOf multipleOf;
4042
protected boolean discriminatorPropertyChanged;
4143
protected ChangedSchema items;
4244
protected ChangedOneOfSchema oneOfSchema;
@@ -119,6 +121,7 @@ public List<Changed> getChangedElements() {
119121
required,
120122
maxLength,
121123
numericRange,
124+
multipleOf,
122125
extensions))
123126
.collect(Collectors.toList());
124127
}
@@ -274,6 +277,14 @@ public ChangedMaxLength getMaxLength() {
274277
return this.maxLength;
275278
}
276279

280+
public ChangedNumericRange getNumericRange() {
281+
return this.numericRange;
282+
}
283+
284+
public ChangedMultipleOf getMultipleOf() {
285+
return this.multipleOf;
286+
}
287+
277288
public boolean isDiscriminatorPropertyChanged() {
278289
return this.discriminatorPropertyChanged;
279290
}
@@ -416,6 +427,12 @@ public ChangedSchema setNumericRange(final ChangedNumericRange numericRange) {
416427
return this;
417428
}
418429

430+
public ChangedSchema setMultipleOf(final ChangedMultipleOf multipleOf) {
431+
clearChangedCache();
432+
this.multipleOf = multipleOf;
433+
return this;
434+
}
435+
419436
public ChangedSchema setDiscriminatorPropertyChanged(final boolean discriminatorPropertyChanged) {
420437
clearChangedCache();
421438
this.discriminatorPropertyChanged = discriminatorPropertyChanged;
@@ -473,6 +490,7 @@ public boolean equals(Object o) {
473490
&& Objects.equals(writeOnly, that.writeOnly)
474491
&& Objects.equals(maxLength, that.maxLength)
475492
&& Objects.equals(numericRange, that.numericRange)
493+
&& Objects.equals(multipleOf, that.multipleOf)
476494
&& Objects.equals(items, that.items)
477495
&& Objects.equals(oneOfSchema, that.oneOfSchema)
478496
&& Objects.equals(addProp, that.addProp)
@@ -503,6 +521,7 @@ public int hashCode() {
503521
changedType,
504522
maxLength,
505523
numericRange,
524+
multipleOf,
506525
discriminatorPropertyChanged,
507526
items,
508527
oneOfSchema,
@@ -552,6 +571,10 @@ public java.lang.String toString() {
552571
+ this.isChangedType()
553572
+ ", maxLength="
554573
+ this.getMaxLength()
574+
+ ", numericRange="
575+
+ this.getNumericRange()
576+
+ ", multipleOf="
577+
+ this.getMultipleOf()
555578
+ ", discriminatorPropertyChanged="
556579
+ this.isDiscriminatorPropertyChanged()
557580
+ ", items="
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.openapitools.openapidiff.core.model.schema;
2+
3+
import java.math.BigDecimal;
4+
import java.util.Objects;
5+
import org.openapitools.openapidiff.core.model.Changed;
6+
import org.openapitools.openapidiff.core.model.DiffResult;
7+
8+
public class ChangedMultipleOf implements Changed {
9+
10+
private final BigDecimal left;
11+
private final BigDecimal right;
12+
13+
public ChangedMultipleOf(BigDecimal leftMultipleOf, BigDecimal rightMultipleOf) {
14+
this.left = leftMultipleOf;
15+
this.right = rightMultipleOf;
16+
}
17+
18+
@Override
19+
public DiffResult isChanged() {
20+
if (Objects.equals(left, right)) {
21+
return DiffResult.NO_CHANGES;
22+
}
23+
24+
// multipleof removed -> compatible
25+
if (right == null) {
26+
return DiffResult.COMPATIBLE;
27+
}
28+
29+
return DiffResult.INCOMPATIBLE;
30+
}
31+
32+
public BigDecimal getLeft() {
33+
return left;
34+
}
35+
36+
public BigDecimal getRight() {
37+
return right;
38+
}
39+
40+
@Override
41+
public String toString() {
42+
return "ChangedMultipleOf [left=" + left + ", right=" + right + "]";
43+
}
44+
45+
@Override
46+
public boolean equals(Object o) {
47+
if (this == o) return true;
48+
if (o == null || getClass() != o.getClass()) return false;
49+
ChangedMultipleOf that = (ChangedMultipleOf) o;
50+
return Objects.equals(left, that.getLeft()) && Objects.equals(right, that.getRight());
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return Objects.hash(left, right);
56+
}
57+
}

core/src/test/java/org/openapitools/openapidiff/core/ChangesResolver.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717

1818
public class ChangesResolver {
1919

20+
/**
21+
* Get the ChangedOperation for the given method and path.
22+
*
23+
* @param changedOpenApi the ChangedOpenApi object
24+
* @param method the HTTP method
25+
* @param path the path
26+
* @return the ChangedOperation object
27+
*/
2028
@Nullable
2129
public static ChangedOperation getChangedOperation(
2230
ChangedOpenApi changedOpenApi, HttpMethod method, String path) {
@@ -28,6 +36,15 @@ public static ChangedOperation getChangedOperation(
2836
.orElse(null);
2937
}
3038

39+
/**
40+
* Get the ChangedParameter for the given method, path, and parameter name.
41+
*
42+
* @param changedOpenApi the ChangedOpenApi object
43+
* @param method the HTTP method
44+
* @param path the path
45+
* @param parameterName the parameter name
46+
* @return the ChangedParameter object
47+
*/
3148
@Nullable
3249
public static ChangedParameter getChangedParameter(
3350
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String parameterName) {
@@ -47,6 +64,15 @@ public static ChangedParameter getChangedParameter(
4764
.orElse(null);
4865
}
4966

67+
/**
68+
* Get the ChangedHeaders for the given method, path, and response code.
69+
*
70+
* @param changedOpenApi the ChangedOpenApi object
71+
* @param method the HTTP method
72+
* @param path the path
73+
* @param responseCode the response code
74+
* @return the ChangedHeaders object
75+
*/
5076
@Nullable
5177
public static ChangedHeaders getChangedResponseHeaders(
5278
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String responseCode) {
@@ -58,9 +84,24 @@ public static ChangedHeaders getChangedResponseHeaders(
5884
.orElse(null);
5985
}
6086

87+
/**
88+
* Get the ChangedSchema for the given method, path, and media type.
89+
*
90+
* @param changedOpenApi the ChangedOpenApi object
91+
* @param method the HTTP method
92+
* @param path the path
93+
* @param mediaType the media type
94+
* @return the ChangedSchema object
95+
*/
6196
@Nullable
6297
public static ChangedSchema getRequestBodyChangedSchema(
63-
ChangedOperation changedOperation, String mediaType) {
98+
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String mediaType) {
99+
ChangedOperation changedOperation = getChangedOperation(changedOpenApi, method, path);
100+
101+
if (changedOperation == null) {
102+
return null;
103+
}
104+
64105
return Optional.ofNullable(changedOperation)
65106
.map(ChangedOperation::getRequestBody)
66107
.map(ChangedRequestBody::getContent)

core/src/test/java/org/openapitools/openapidiff/core/SchemaDiffTest.java

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
package org.openapitools.openapidiff.core;
22

3+
import static io.swagger.v3.oas.models.PathItem.HttpMethod.POST;
34
import static org.assertj.core.api.Assertions.assertThat;
45
import static org.junit.jupiter.api.Assertions.assertEquals;
56
import static org.junit.jupiter.api.Assertions.assertNotNull;
67
import static org.junit.jupiter.api.Assertions.assertTrue;
7-
import static org.openapitools.openapidiff.core.ChangesResolver.getChangedOperation;
88
import static org.openapitools.openapidiff.core.ChangesResolver.getRequestBodyChangedSchema;
99
import static org.openapitools.openapidiff.core.TestUtils.assertOpenApiBackwardCompatible;
1010

11-
import io.swagger.v3.oas.models.PathItem.HttpMethod;
1211
import java.io.ByteArrayOutputStream;
1312
import java.io.OutputStreamWriter;
13+
import java.math.BigDecimal;
14+
import java.util.Map;
1415
import org.junit.jupiter.api.Test;
1516
import org.openapitools.openapidiff.core.model.ChangedOpenApi;
16-
import org.openapitools.openapidiff.core.model.ChangedOperation;
1717
import org.openapitools.openapidiff.core.model.ChangedSchema;
1818
import org.openapitools.openapidiff.core.output.ConsoleRender;
1919

@@ -49,11 +49,9 @@ public void schemaBecomesDeprecatedTest() {
4949
"schemaDiff/schema-deprecated-handling-1.yaml",
5050
"schemaDiff/schema-deprecated-handling-2.yaml");
5151

52-
ChangedOperation operation =
53-
getChangedOperation(changedOpenApi, HttpMethod.POST, "/schema-diff/deprecated/added");
54-
assertNotNull(operation);
55-
56-
ChangedSchema requestBodySchema = getRequestBodyChangedSchema(operation, "application/json");
52+
ChangedSchema requestBodySchema =
53+
getRequestBodyChangedSchema(
54+
changedOpenApi, POST, "/schema-diff/deprecated/added", "application/json");
5755
assertNotNull(requestBodySchema);
5856
assertTrue(requestBodySchema.isChangeDeprecated());
5957
}
@@ -65,11 +63,9 @@ public void schemaBecomesNotDeprecatedTest() {
6563
"schemaDiff/schema-deprecated-handling-1.yaml",
6664
"schemaDiff/schema-deprecated-handling-2.yaml");
6765

68-
ChangedOperation operation =
69-
getChangedOperation(changedOpenApi, HttpMethod.POST, "/schema-diff/deprecated/removed");
70-
assertNotNull(operation);
71-
72-
ChangedSchema requestBodySchema = getRequestBodyChangedSchema(operation, "application/json");
66+
ChangedSchema requestBodySchema =
67+
getRequestBodyChangedSchema(
68+
changedOpenApi, POST, "/schema-diff/deprecated/removed", "application/json");
7369
assertNotNull(requestBodySchema);
7470
assertTrue(requestBodySchema.isChangeDeprecated());
7571
}
@@ -104,4 +100,38 @@ public void addPropertyInPutApiIsCompatible() {
104100
assertThat(changedOpenApi.isDifferent()).isTrue();
105101
assertThat(changedOpenApi.isCompatible()).isTrue();
106102
}
103+
104+
@Test // issues #483 #463
105+
public void changeMultipleOfHandling() {
106+
ChangedOpenApi changedOpenApi =
107+
OpenApiCompare.fromLocations(
108+
"schemaDiff/schema-multiple-of-diff-1.yaml",
109+
"schemaDiff/schema-multiple-of-diff-2.yaml");
110+
ChangedSchema changedSchema =
111+
getRequestBodyChangedSchema(
112+
changedOpenApi, POST, "/schema/numeric/multiple-of", "application/json");
113+
114+
assertThat(changedSchema).isNotNull();
115+
Map<String, ChangedSchema> props = changedSchema.getChangedProperties();
116+
assertThat(props).isNotEmpty();
117+
118+
// Check changes in multipleOf
119+
assertThat(props.get("field1").getMultipleOf().isIncompatible()).isTrue();
120+
assertThat(props.get("field1").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(10));
121+
assertThat(props.get("field1").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(20));
122+
123+
assertThat(props.get("field2").getMultipleOf().isIncompatible()).isTrue();
124+
assertThat(props.get("field2").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(0.01));
125+
assertThat(props.get("field2").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(0.1));
126+
127+
// Check addition of multipleOf
128+
assertThat(props.get("field3").getMultipleOf().isIncompatible()).isTrue();
129+
assertThat(props.get("field3").getMultipleOf().getLeft()).isNull();
130+
assertThat(props.get("field3").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(10));
131+
132+
// Check deletion of multipleOf
133+
assertThat(props.get("field4").getMultipleOf().isCompatible()).isTrue();
134+
assertThat(props.get("field4").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(10));
135+
assertThat(props.get("field4").getMultipleOf().getRight()).isNull();
136+
}
107137
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
openapi: 3.1.0
2+
info:
3+
description: Schema diff
4+
title: schema diff
5+
version: 1.0.0
6+
paths:
7+
/schema/numeric/multiple-of:
8+
post:
9+
requestBody:
10+
content:
11+
application/json:
12+
schema:
13+
$ref: '#/components/schemas/TestDTO'
14+
components:
15+
schemas:
16+
TestDTO:
17+
type: object
18+
properties:
19+
field1:
20+
type: integer
21+
multipleOf: 10
22+
field2:
23+
type: integer
24+
multipleOf: 0.01
25+
field3:
26+
type: integer
27+
field4:
28+
type: integer
29+
multipleOf: 10
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
openapi: 3.1.0
2+
info:
3+
description: Schema diff
4+
title: schema diff
5+
version: 1.0.0
6+
paths:
7+
/schema/numeric/multiple-of:
8+
post:
9+
requestBody:
10+
content:
11+
application/json:
12+
schema:
13+
$ref: '#/components/schemas/TestDTO'
14+
components:
15+
schemas:
16+
TestDTO:
17+
type: object
18+
properties:
19+
field1:
20+
type: integer
21+
multipleOf: 20
22+
field2:
23+
type: integer
24+
multipleOf: 0.1
25+
field3:
26+
type: integer
27+
multipleOf: 10
28+
field4:
29+
type: integer

0 commit comments

Comments
 (0)