Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change of 'multipleof' is not detected #746

Merged
merged 5 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public <V extends Schema<X>, X> DeferredChanged<ChangedSchema> diff(
left.getExclusiveMaximum(),
right.getExclusiveMaximum(),
context))
.setMultipleOf(new ChangedMultipleOf(left.getMultipleOf(), right.getMultipleOf()))
.setExamples(new ChangedExamples(left.getExamples(), right.getExamples()))
.setExample(new ChangedExample(left.getExample(), right.getExample()));
builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.stream.Stream;
import org.openapitools.openapidiff.core.model.schema.ChangedEnum;
import org.openapitools.openapidiff.core.model.schema.ChangedMaxLength;
import org.openapitools.openapidiff.core.model.schema.ChangedMultipleOf;
import org.openapitools.openapidiff.core.model.schema.ChangedNumericRange;
import org.openapitools.openapidiff.core.model.schema.ChangedReadOnly;
import org.openapitools.openapidiff.core.model.schema.ChangedRequired;
Expand Down Expand Up @@ -37,6 +38,7 @@ public class ChangedSchema implements ComposedChanged {
protected boolean changedType;
protected ChangedMaxLength maxLength;
protected ChangedNumericRange numericRange;
protected ChangedMultipleOf multipleOf;
protected boolean discriminatorPropertyChanged;
protected ChangedSchema items;
protected ChangedOneOfSchema oneOfSchema;
Expand Down Expand Up @@ -119,6 +121,7 @@ public List<Changed> getChangedElements() {
required,
maxLength,
numericRange,
multipleOf,
extensions))
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -274,6 +277,14 @@ public ChangedMaxLength getMaxLength() {
return this.maxLength;
}

public ChangedNumericRange getNumericRange() {
return this.numericRange;
}

public ChangedMultipleOf getMultipleOf() {
return this.multipleOf;
}

public boolean isDiscriminatorPropertyChanged() {
return this.discriminatorPropertyChanged;
}
Expand Down Expand Up @@ -416,6 +427,12 @@ public ChangedSchema setNumericRange(final ChangedNumericRange numericRange) {
return this;
}

public ChangedSchema setMultipleOf(final ChangedMultipleOf multipleOf) {
clearChangedCache();
this.multipleOf = multipleOf;
return this;
}

public ChangedSchema setDiscriminatorPropertyChanged(final boolean discriminatorPropertyChanged) {
clearChangedCache();
this.discriminatorPropertyChanged = discriminatorPropertyChanged;
Expand Down Expand Up @@ -473,6 +490,7 @@ public boolean equals(Object o) {
&& Objects.equals(writeOnly, that.writeOnly)
&& Objects.equals(maxLength, that.maxLength)
&& Objects.equals(numericRange, that.numericRange)
&& Objects.equals(multipleOf, that.multipleOf)
&& Objects.equals(items, that.items)
&& Objects.equals(oneOfSchema, that.oneOfSchema)
&& Objects.equals(addProp, that.addProp)
Expand Down Expand Up @@ -503,6 +521,7 @@ public int hashCode() {
changedType,
maxLength,
numericRange,
multipleOf,
discriminatorPropertyChanged,
items,
oneOfSchema,
Expand Down Expand Up @@ -552,6 +571,10 @@ public java.lang.String toString() {
+ this.isChangedType()
+ ", maxLength="
+ this.getMaxLength()
+ ", numericRange="
+ this.getNumericRange()
+ ", multipleOf="
+ this.getMultipleOf()
+ ", discriminatorPropertyChanged="
+ this.isDiscriminatorPropertyChanged()
+ ", items="
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.openapitools.openapidiff.core.model.schema;

import java.math.BigDecimal;
import java.util.Objects;
import org.openapitools.openapidiff.core.model.Changed;
import org.openapitools.openapidiff.core.model.DiffResult;

public class ChangedMultipleOf implements Changed {

private final BigDecimal left;
private final BigDecimal right;

public ChangedMultipleOf(BigDecimal leftMultipleOf, BigDecimal rightMultipleOf) {
this.left = leftMultipleOf;
this.right = rightMultipleOf;
}

@Override
public DiffResult isChanged() {
if (Objects.equals(left, right)) {
return DiffResult.NO_CHANGES;
}

// multipleof removed -> compatible
if (right == null) {
return DiffResult.COMPATIBLE;
}

return DiffResult.INCOMPATIBLE;
}

public BigDecimal getLeft() {
return left;
}

public BigDecimal getRight() {
return right;
}

@Override
public String toString() {
return "ChangedMultipleOf [left=" + left + ", right=" + right + "]";
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChangedMultipleOf that = (ChangedMultipleOf) o;
return Objects.equals(left, that.getLeft()) && Objects.equals(right, that.getRight());
}

@Override
public int hashCode() {
return Objects.hash(left, right);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@

public class ChangesResolver {

/**
* Get the ChangedOperation for the given method and path.
*
* @param changedOpenApi the ChangedOpenApi object
* @param method the HTTP method
* @param path the path
* @return the ChangedOperation object
*/
@Nullable
public static ChangedOperation getChangedOperation(
ChangedOpenApi changedOpenApi, HttpMethod method, String path) {
Expand All @@ -28,6 +36,15 @@ public static ChangedOperation getChangedOperation(
.orElse(null);
}

/**
* Get the ChangedParameter for the given method, path, and parameter name.
*
* @param changedOpenApi the ChangedOpenApi object
* @param method the HTTP method
* @param path the path
* @param parameterName the parameter name
* @return the ChangedParameter object
*/
@Nullable
public static ChangedParameter getChangedParameter(
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String parameterName) {
Expand All @@ -47,6 +64,15 @@ public static ChangedParameter getChangedParameter(
.orElse(null);
}

/**
* Get the ChangedHeaders for the given method, path, and response code.
*
* @param changedOpenApi the ChangedOpenApi object
* @param method the HTTP method
* @param path the path
* @param responseCode the response code
* @return the ChangedHeaders object
*/
@Nullable
public static ChangedHeaders getChangedResponseHeaders(
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String responseCode) {
Expand All @@ -58,9 +84,24 @@ public static ChangedHeaders getChangedResponseHeaders(
.orElse(null);
}

/**
* Get the ChangedSchema for the given method, path, and media type.
*
* @param changedOpenApi the ChangedOpenApi object
* @param method the HTTP method
* @param path the path
* @param mediaType the media type
* @return the ChangedSchema object
*/
@Nullable
public static ChangedSchema getRequestBodyChangedSchema(
ChangedOperation changedOperation, String mediaType) {
ChangedOpenApi changedOpenApi, HttpMethod method, String path, String mediaType) {
ChangedOperation changedOperation = getChangedOperation(changedOpenApi, method, path);

if (changedOperation == null) {
return null;
}

return Optional.ofNullable(changedOperation)
.map(ChangedOperation::getRequestBody)
.map(ChangedRequestBody::getContent)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package org.openapitools.openapidiff.core;

import static io.swagger.v3.oas.models.PathItem.HttpMethod.POST;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.openapitools.openapidiff.core.ChangesResolver.getChangedOperation;
import static org.openapitools.openapidiff.core.ChangesResolver.getRequestBodyChangedSchema;
import static org.openapitools.openapidiff.core.TestUtils.assertOpenApiBackwardCompatible;

import io.swagger.v3.oas.models.PathItem.HttpMethod;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.openapitools.openapidiff.core.model.ChangedOpenApi;
import org.openapitools.openapidiff.core.model.ChangedOperation;
import org.openapitools.openapidiff.core.model.ChangedSchema;
import org.openapitools.openapidiff.core.output.ConsoleRender;

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

ChangedOperation operation =
getChangedOperation(changedOpenApi, HttpMethod.POST, "/schema-diff/deprecated/added");
assertNotNull(operation);

ChangedSchema requestBodySchema = getRequestBodyChangedSchema(operation, "application/json");
ChangedSchema requestBodySchema =
getRequestBodyChangedSchema(
changedOpenApi, POST, "/schema-diff/deprecated/added", "application/json");
assertNotNull(requestBodySchema);
assertTrue(requestBodySchema.isChangeDeprecated());
}
Expand All @@ -65,11 +63,9 @@ public void schemaBecomesNotDeprecatedTest() {
"schemaDiff/schema-deprecated-handling-1.yaml",
"schemaDiff/schema-deprecated-handling-2.yaml");

ChangedOperation operation =
getChangedOperation(changedOpenApi, HttpMethod.POST, "/schema-diff/deprecated/removed");
assertNotNull(operation);

ChangedSchema requestBodySchema = getRequestBodyChangedSchema(operation, "application/json");
ChangedSchema requestBodySchema =
getRequestBodyChangedSchema(
changedOpenApi, POST, "/schema-diff/deprecated/removed", "application/json");
assertNotNull(requestBodySchema);
assertTrue(requestBodySchema.isChangeDeprecated());
}
Expand Down Expand Up @@ -104,4 +100,38 @@ public void addPropertyInPutApiIsCompatible() {
assertThat(changedOpenApi.isDifferent()).isTrue();
assertThat(changedOpenApi.isCompatible()).isTrue();
}

@Test // issues #483 #463
public void changeMultipleOfHandling() {
ChangedOpenApi changedOpenApi =
OpenApiCompare.fromLocations(
"schemaDiff/schema-multiple-of-diff-1.yaml",
"schemaDiff/schema-multiple-of-diff-2.yaml");
ChangedSchema changedSchema =
getRequestBodyChangedSchema(
changedOpenApi, POST, "/schema/numeric/multiple-of", "application/json");

assertThat(changedSchema).isNotNull();
Map<String, ChangedSchema> props = changedSchema.getChangedProperties();
assertThat(props).isNotEmpty();

// Check changes in multipleOf
assertThat(props.get("field1").getMultipleOf().isIncompatible()).isTrue();
assertThat(props.get("field1").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(10));
assertThat(props.get("field1").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(20));

assertThat(props.get("field2").getMultipleOf().isIncompatible()).isTrue();
assertThat(props.get("field2").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(0.01));
assertThat(props.get("field2").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(0.1));

// Check addition of multipleOf
assertThat(props.get("field3").getMultipleOf().isIncompatible()).isTrue();
assertThat(props.get("field3").getMultipleOf().getLeft()).isNull();
assertThat(props.get("field3").getMultipleOf().getRight()).isEqualTo(BigDecimal.valueOf(10));

// Check deletion of multipleOf
assertThat(props.get("field4").getMultipleOf().isCompatible()).isTrue();
assertThat(props.get("field4").getMultipleOf().getLeft()).isEqualTo(BigDecimal.valueOf(10));
assertThat(props.get("field4").getMultipleOf().getRight()).isNull();
}
}
29 changes: 29 additions & 0 deletions core/src/test/resources/schemaDiff/schema-multiple-of-diff-1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
openapi: 3.1.0
info:
description: Schema diff
title: schema diff
version: 1.0.0
paths:
/schema/numeric/multiple-of:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TestDTO'
components:
schemas:
TestDTO:
type: object
properties:
field1:
type: integer
multipleOf: 10
field2:
type: integer
multipleOf: 0.01
field3:
type: integer
field4:
type: integer
multipleOf: 10
29 changes: 29 additions & 0 deletions core/src/test/resources/schemaDiff/schema-multiple-of-diff-2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
openapi: 3.1.0
info:
description: Schema diff
title: schema diff
version: 1.0.0
paths:
/schema/numeric/multiple-of:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TestDTO'
components:
schemas:
TestDTO:
type: object
properties:
field1:
type: integer
multipleOf: 20
field2:
type: integer
multipleOf: 0.1
field3:
type: integer
multipleOf: 10
field4:
type: integer