Skip to content

Commit 2aea9df

Browse files
Thomas Deblockdeblockt
authored andcommitted
feat: update object similarity calculation
- now structure similarity is 60% of the result and value similarity is 40% of the result - the value similarity is now `number of value match / number of expected property` instead of `number of value match / number of matched keys`. This avoids to have a high ratio if only one key match the expected object.
1 parent 523bca2 commit 2aea9df

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

src/main/java/com/deblock/jsondiff/diff/JsonObjectDiff.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import java.util.Map;
99

1010
public class JsonObjectDiff implements JsonDiff {
11-
private static final int STRUCTURE_MAX_RATIO = 50;
12-
private static final int VALUE_MAX_RATIO = 50;
11+
private static final int STRUCTURE_MAX_RATIO = 60;
12+
private static final int VALUE_MAX_RATIO = 40;
1313

1414
private final Map<String, JsonDiff> propertiesDiff = new HashMap<>();
1515
private final Map<String, JsonNode> notFoundProperties = new HashMap<>();
@@ -46,7 +46,7 @@ public double similarityRate() {
4646
if (propertiesDiff.isEmpty()) {
4747
equalityRatio = 0;
4848
} else {
49-
equalityRatio = propertiesSimilarityRate * VALUE_MAX_RATIO / (propertiesDiff.size() * 100);
49+
equalityRatio = propertiesSimilarityRate * VALUE_MAX_RATIO / (totalPropertiesCount * 100);
5050
}
5151
return structureRatio + equalityRatio;
5252
}

src/test/java/com/deblock/jsondiff/matcher/JsonDiffAsserter.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class JsonDiffAsserter implements JsonDiffViewer {
1717
private final List<MatchingPropertyAsserter> matchingPropertyAsserters = new ArrayList<>();
1818
private final List<PrimaryNonMatchingAsserter> primaryNonMatchingAsserters = new ArrayList<>();
1919
private final List<PrimaryMatchingAsserter> primaryMatchingAsserters = new ArrayList<>();
20+
private Double expectedSimilarityRate = null;
2021

2122
@Override
2223
public void matchingProperty(Path path, JsonDiff diff) {
@@ -79,6 +80,14 @@ public void primaryMatching(Path path, JsonNode value) {
7980
}
8081

8182
public void validate(JsonDiff jsonDiff) {
83+
if (this.expectedSimilarityRate != null && this.expectedSimilarityRate != jsonDiff.similarityRate()) {
84+
throw new AssertionError(
85+
String.format(
86+
"The similarity rate should be equals to \"%s\" but actual value is \"%s\"",
87+
this.expectedSimilarityRate, jsonDiff.similarityRate()
88+
)
89+
);
90+
}
8291
jsonDiff.display(this);
8392

8493
final var allErrors = Stream.of(missingPropertyAsserters, nonMatchingPropertyAsserters, matchingPropertyAsserters, primaryNonMatchingAsserters, extraPropertyAsserters)
@@ -122,6 +131,11 @@ public JsonDiffAsserter assertExtraProperty(Path path) {
122131
return this;
123132
}
124133

134+
public JsonDiffAsserter assertSimilarityRate(double structural, double value) {
135+
this.expectedSimilarityRate = structural + value;
136+
return this;
137+
}
138+
125139
interface Asserter {
126140
boolean isDone();
127141
String getError();

src/test/java/com/deblock/jsondiff/matcher/LenientJsonObjectPartialMatcherTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ public void shouldReturnNonMachIfAllPropertiesAreNotFound() {
3636

3737
final var result = new LenientJsonObjectPartialMatcher().jsonDiff(path, object1, object2, null);
3838

39-
assertEquals(0, result.similarityRate());
4039
assertEquals(path, result.path());
4140
new JsonDiffAsserter()
41+
.assertSimilarityRate(0, 0)
4242
.assertMissingProperty(path.add(Path.PathItem.of("a")))
4343
.assertMissingProperty(path.add(Path.PathItem.of("b")))
4444
.validate(result);
@@ -60,11 +60,34 @@ public void shouldReturnNonMatchingPropertyIfAllPropertiesAreFoundWithoutMatch()
6060

6161
assertEquals(path, result.path());
6262
new JsonDiffAsserter()
63+
.assertSimilarityRate(60, 0)
6364
.assertNonMatchingProperty(path.add(Path.PathItem.of("a")))
6465
.assertNonMatchingProperty(path.add(Path.PathItem.of("b")))
6566
.validate(result);
6667
}
6768

69+
@Test
70+
public void shouldMixMatchingAndNotFoundPropertiesOnSameResult() {
71+
final var object1 = new ObjectNode(null, Map.of(
72+
"a", TextNode.valueOf("a"),
73+
"b", TextNode.valueOf("b")
74+
));
75+
final var object2 = new ObjectNode(null, Map.of(
76+
"a", TextNode.valueOf("a"),
77+
"c", TextNode.valueOf("b")
78+
));
79+
final var parentMatcher = Mockito.mock(JsonMatcher.class);
80+
Mockito.when(parentMatcher.diff(any(), any(), any())).thenAnswer((args) -> fullMatchJsonDiff(args.getArgument(0)));
81+
final var result = new LenientJsonObjectPartialMatcher().jsonDiff(path, object1, object2, parentMatcher);
82+
83+
assertEquals(path, result.path());
84+
new JsonDiffAsserter()
85+
.assertSimilarityRate(30, 20)
86+
.assertMatchingProperty(path.add(Path.PathItem.of("a")))
87+
.assertMissingProperty(path.add(Path.PathItem.of("b")))
88+
.validate(result);
89+
}
90+
6891
@Test
6992
public void shouldReturnFullMatchingPropertyAllPropertiesAreFoundAndMatch() {
7093
final var object1 = new ObjectNode(null, Map.of(
@@ -81,6 +104,7 @@ public void shouldReturnFullMatchingPropertyAllPropertiesAreFoundAndMatch() {
81104

82105
assertEquals(path, result.path());
83106
new JsonDiffAsserter()
107+
.assertSimilarityRate(60, 40)
84108
.assertMatchingProperty(path.add(Path.PathItem.of("a")))
85109
.assertMatchingProperty(path.add(Path.PathItem.of("b")))
86110
.validate(result);
@@ -102,6 +126,7 @@ public void shouldReturnSimilarityIfOnlyOneProperty() {
102126

103127
assertEquals(path, result.path());
104128
new JsonDiffAsserter()
129+
.assertSimilarityRate(20, 40.0 / 3.0)
105130
.assertMatchingProperty(path.add(Path.PathItem.of("a")))
106131
.assertMissingProperty(path.add(Path.PathItem.of("b")))
107132
.assertMissingProperty(path.add(Path.PathItem.of("c")))

0 commit comments

Comments
 (0)