Skip to content

Add support for 'uniqueItems' schema diff detection #758

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

Merged
merged 1 commit into from
Mar 18, 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 @@ -75,6 +75,7 @@ public <V extends Schema<X>, X> DeferredChanged<ChangedSchema> diff(
context))
.setMultipleOf(new ChangedMultipleOf(left.getMultipleOf(), right.getMultipleOf()))
.setNullable(new ChangedNullable(left.getNullable(), right.getNullable()))
.setUniqueItems(new ChangedUniqueItems(left.getUniqueItems(), right.getUniqueItems()))
.setExamples(new ChangedExamples(left.getExamples(), right.getExamples()))
.setExample(new ChangedExample(left.getExample(), right.getExample()))
.setMaxItems(new ChangedMaxItems(left.getMaxItems(), right.getMaxItems(), context))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.openapitools.openapidiff.core.model.schema.ChangedOneOfSchema;
import org.openapitools.openapidiff.core.model.schema.ChangedReadOnly;
import org.openapitools.openapidiff.core.model.schema.ChangedRequired;
import org.openapitools.openapidiff.core.model.schema.ChangedUniqueItems;
import org.openapitools.openapidiff.core.model.schema.ChangedWriteOnly;

public class ChangedSchema implements ComposedChanged {
Expand Down Expand Up @@ -50,6 +51,7 @@ public class ChangedSchema implements ComposedChanged {
protected ChangedMaxProperties maxProperties;
protected ChangedMinProperties minProperties;
protected ChangedNullable nullable;
protected ChangedUniqueItems uniqueItems;
protected boolean discriminatorPropertyChanged;
protected ChangedSchema items;
protected ChangedOneOfSchema oneOfSchema;
Expand Down Expand Up @@ -138,6 +140,7 @@ public List<Changed> getChangedElements() {
maxProperties,
minProperties,
nullable,
uniqueItems,
extensions))
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -313,6 +316,10 @@ public ChangedNullable getNullable() {
return this.nullable;
}

public ChangedUniqueItems getUniqueItems() {
return uniqueItems;
}

public boolean isDiscriminatorPropertyChanged() {
return this.discriminatorPropertyChanged;
}
Expand Down Expand Up @@ -487,6 +494,12 @@ public ChangedSchema setNullable(final ChangedNullable nullable) {
return this;
}

public ChangedSchema setUniqueItems(ChangedUniqueItems uniqueItems) {
clearChangedCache();
this.uniqueItems = uniqueItems;
return this;
}

public ChangedSchema setDiscriminatorPropertyChanged(final boolean discriminatorPropertyChanged) {
clearChangedCache();
this.discriminatorPropertyChanged = discriminatorPropertyChanged;
Expand Down Expand Up @@ -560,6 +573,7 @@ public boolean equals(Object o) {
&& Objects.equals(maxItems, that.maxItems)
&& Objects.equals(minItems, that.minItems)
&& Objects.equals(nullable, that.nullable)
&& Objects.equals(uniqueItems, that.uniqueItems)
&& Objects.equals(items, that.items)
&& Objects.equals(oneOfSchema, that.oneOfSchema)
&& Objects.equals(addProp, that.addProp)
Expand Down Expand Up @@ -596,6 +610,7 @@ public int hashCode() {
maxItems,
minItems,
nullable,
uniqueItems,
discriminatorPropertyChanged,
items,
oneOfSchema,
Expand Down Expand Up @@ -657,6 +672,8 @@ public java.lang.String toString() {
+ this.getMinItems()
+ ", nullable="
+ this.getNullable()
+ ", uniqueItems="
+ this.getUniqueItems()
+ ", discriminatorPropertyChanged="
+ this.isDiscriminatorPropertyChanged()
+ ", items="
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.openapitools.openapidiff.core.model.schema;

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

public class ChangedUniqueItems implements Changed {

private final Boolean left;
private final Boolean right;

public ChangedUniqueItems(Boolean leftNullable, Boolean rightNullable) {
this.left = leftNullable;
this.right = rightNullable;
}

@Override
public DiffResult isChanged() {
boolean leftValue = left != null && left;
boolean rightValue = right != null && right;

if (leftValue == false && rightValue == true) {
return DiffResult.INCOMPATIBLE;
}

if (leftValue == true && rightValue == false) {
return DiffResult.COMPATIBLE;
}

return DiffResult.NO_CHANGES;
}

public Boolean getLeft() {
return left;
}

public Boolean getRight() {
return right;
}

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

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChangedNullable that = (ChangedNullable) 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 @@ -171,7 +171,7 @@ public void changeMinMaxItemsHandling() {
}

@Test // issue #482
public void changeNullabeHandling() {
public void changeNullableHandling() {
ChangedOpenApi changedOpenApi =
OpenApiCompare.fromLocations(
"schemaDiff/schema-nullable-diff-1.yaml", "schemaDiff/schema-nullable-diff-2.yaml");
Expand Down Expand Up @@ -201,6 +201,44 @@ public void changeNullabeHandling() {
assertThat(props.get("field3").getNullable().getRight()).isTrue();
}

@Test // issue #478
public void changeUniqueItemsHandling() {
ChangedOpenApi changedOpenApi =
OpenApiCompare.fromLocations(
"schemaDiff/schema-uniqueItems-diff-1.yaml",
"schemaDiff/schema-uniqueItems-diff-2.yaml");
ChangedSchema changedSchema =
getRequestBodyChangedSchema(
changedOpenApi, POST, "/schema/uniqueItems", "application/json");

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

// Check no changes in uniqueItems
assertThat(props.get("field0")).isNull();

// Check changes true -> false
assertThat(props.get("field1").getUniqueItems().isCompatible()).isTrue();
assertThat(props.get("field1").getUniqueItems().getLeft()).isTrue();
assertThat(props.get("field1").getUniqueItems().getRight()).isFalse();

// Check changes false -> true
assertThat(props.get("field2").getUniqueItems().isIncompatible()).isTrue();
assertThat(props.get("field2").getUniqueItems().getLeft()).isFalse();
assertThat(props.get("field2").getUniqueItems().getRight()).isTrue();

// Check deletion of uniqueItems
assertThat(props.get("field3").getUniqueItems().isCompatible()).isTrue();
assertThat(props.get("field3").getUniqueItems().getLeft()).isTrue();
assertThat(props.get("field3").getUniqueItems().getRight()).isNull();

// Check addition of uniqueItems
assertThat(props.get("field4").getUniqueItems().isIncompatible()).isTrue();
assertThat(props.get("field4").getUniqueItems().getLeft()).isNull();
assertThat(props.get("field4").getUniqueItems().getRight()).isTrue();
}

@Test // issue #479
public void changeMinMaxPropertiesHandling() {
ChangedOpenApi changedOpenApi =
Expand Down
31 changes: 31 additions & 0 deletions core/src/test/resources/schemaDiff/schema-uniqueItems-diff-1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
openapi: 3.0.1
info:
description: Schema diff uniqueItems
title: schema diff uniqueItems
version: 1.0.0
paths:
/schema/uniqueItems:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TestDTO'
components:
schemas:
TestDTO:
type: object
properties:
field0:
type: integer
field1:
type: integer
uniqueItems: true
field2:
type: integer
uniqueItems: false
field3:
type: integer
uniqueItems: true
field4:
type: integer
31 changes: 31 additions & 0 deletions core/src/test/resources/schemaDiff/schema-uniqueItems-diff-2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
openapi: 3.0.1
info:
description: Schema diff uniqueItems
title: schema diff uniqueItems
version: 1.0.0
paths:
/schema/uniqueItems:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TestDTO'
components:
schemas:
TestDTO:
type: object
properties:
field0:
type: integer
field1:
type: integer
uniqueItems: false
field2:
type: integer
uniqueItems: true
field3:
type: integer
field4:
type: integer
uniqueItems: true