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

feat: allow to have equality between null and empty array #20

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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 @@ -6,32 +6,24 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CompositeJsonMatcher implements JsonMatcher {
private final PartialJsonMatcher<ArrayNode> jsonArrayPartialMatcher;
private final PartialJsonMatcher<ObjectNode> jsonObjectPartialMatcher;
private final PartialJsonMatcher<ValueNode> primitivePartialMatcher;
private final List<PartialJsonMatcher<JsonNode>> matchers;

public CompositeJsonMatcher(
PartialJsonMatcher<ArrayNode> jsonArrayPartialMatcher,
PartialJsonMatcher<ObjectNode> jsonObjectPartialMatcher,
PartialJsonMatcher<ValueNode> primitivePartialMatcher
) {
this.jsonArrayPartialMatcher = jsonArrayPartialMatcher;
this.jsonObjectPartialMatcher = jsonObjectPartialMatcher;
this.primitivePartialMatcher = primitivePartialMatcher;
public CompositeJsonMatcher(PartialJsonMatcher<?> ...jsonArrayPartialMatcher) {
this.matchers = new ArrayList<>();
Arrays.stream(jsonArrayPartialMatcher).forEach(it -> this.matchers.add((PartialJsonMatcher<JsonNode>) it));
}

@Override
public JsonDiff diff(Path path, JsonNode expected, JsonNode received) {
if (expected instanceof ObjectNode && received instanceof ObjectNode) {
return this.jsonObjectPartialMatcher.jsonDiff(path, (ObjectNode) expected, (ObjectNode) received, this);
} else if (expected instanceof ArrayNode && received instanceof ArrayNode) {
return this.jsonArrayPartialMatcher.jsonDiff(path, (ArrayNode) expected, (ArrayNode) received, this);
} else if (expected instanceof ValueNode && received instanceof ValueNode){
return this.primitivePartialMatcher.jsonDiff(path, (ValueNode) expected, (ValueNode) received, this);
} else {
return new UnMatchedPrimaryDiff(path, expected, received);
}
return this.matchers.stream()
.filter(matcher -> matcher.manage(expected, received))
.findFirst()
.map(matcher -> matcher.jsonDiff(path, expected, received, this))
.orElseGet(() -> new UnMatchedPrimaryDiff(path, expected, received));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@
public interface JsonMatcher {

JsonDiff diff(Path path, JsonNode expected, JsonNode received);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.deblock.jsondiff.diff.JsonArrayDiff;
import com.deblock.jsondiff.diff.JsonDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

import java.util.*;
Expand Down Expand Up @@ -51,6 +52,11 @@ public JsonDiff jsonDiff(Path path, ArrayNode expectedValues, ArrayNode received
return diff;
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isArray() && received.isArray();
}

private double maxSimilarityRate(Map.Entry<Integer, Map<Integer, JsonDiff>> entry) {
return entry.getValue().values().stream().mapToDouble(JsonDiff::similarityRate).max().orElse(0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.deblock.jsondiff.diff.JsonDiff;
import com.deblock.jsondiff.diff.JsonObjectDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class LenientJsonObjectPartialMatcher implements PartialJsonMatcher<ObjectNode> {
Expand All @@ -26,4 +27,9 @@ public JsonDiff jsonDiff(Path path, ObjectNode expectedJson, ObjectNode received

return jsonDiff;
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isObject() && received.isObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.deblock.jsondiff.diff.JsonDiff;
import com.deblock.jsondiff.diff.MatchedPrimaryDiff;
import com.deblock.jsondiff.diff.UnMatchedPrimaryDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NumericNode;
import com.fasterxml.jackson.databind.node.ValueNode;

Expand Down Expand Up @@ -30,4 +31,9 @@ public JsonDiff jsonDiff(Path path, ValueNode expectedValue, ValueNode receivedV

return delegated.jsonDiff(path, expectedValue, receivedValue, jsonMatcher);
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isValueNode() && received.isValueNode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.deblock.jsondiff.matcher;

import com.deblock.jsondiff.diff.JsonDiff;
import com.deblock.jsondiff.diff.MatchedPrimaryDiff;
import com.deblock.jsondiff.diff.UnMatchedPrimaryDiff;
import com.fasterxml.jackson.databind.JsonNode;

public class NullEqualsEmptyArrayMatcher implements PartialJsonMatcher<JsonNode> {

@Override
public JsonDiff jsonDiff(Path path, JsonNode expectedJson, JsonNode receivedJson, JsonMatcher jsonMatcher) {
if (
(expectedJson.isNull() && receivedJson.isEmpty())
|| (receivedJson.isNull() && expectedJson.isEmpty())
) {
return new MatchedPrimaryDiff(path, expectedJson);
}
return new UnMatchedPrimaryDiff(path, expectedJson, receivedJson);
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return (expected.isNull() && received.isArray())
|| (received.isNull() && expected.isArray());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@

public interface PartialJsonMatcher<T extends JsonNode> {
JsonDiff jsonDiff(Path path, T expectedJson, T receivedJson, JsonMatcher jsonMatcher);

boolean manage(JsonNode expected, JsonNode received);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.deblock.jsondiff.diff.JsonArrayDiff;
import com.deblock.jsondiff.diff.JsonDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

import java.util.Comparator;
Expand Down Expand Up @@ -35,4 +36,9 @@ public JsonDiff jsonDiff(Path path, ArrayNode expectedValues, ArrayNode received
}
return diff;
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isArray() && received.isArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.deblock.jsondiff.diff.JsonDiff;
import com.deblock.jsondiff.diff.JsonObjectDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.util.stream.Collectors;
Expand Down Expand Up @@ -43,4 +44,9 @@ public JsonDiff jsonDiff(Path path, ObjectNode expectedJson, ObjectNode received

return jsonDiff;
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isObject() && received.isObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.deblock.jsondiff.diff.JsonDiff;
import com.deblock.jsondiff.diff.MatchedPrimaryDiff;
import com.deblock.jsondiff.diff.UnMatchedPrimaryDiff;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ValueNode;

import java.util.Objects;
Expand All @@ -17,4 +18,9 @@ public JsonDiff jsonDiff(Path path, ValueNode expectedValue, ValueNode receivedV
return new UnMatchedPrimaryDiff(path, expectedValue, receivedValue);
}
}

@Override
public boolean manage(JsonNode expected, JsonNode received) {
return expected.isValueNode() && received.isValueNode();
}
}
5 changes: 3 additions & 2 deletions src/test/java/com/deblock/jsondiff/Sample.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

public class Sample {
public static void main(String[] args) {
final var expectedJson = "{\"array\": [{\"b\": [1]}, {\"a\": [1, 5]}]}";
final var receivedJson = "{\"array\": [{\"a\": [1]}]}";
final var expectedJson = "{\"array\": []}";
final var receivedJson = "{}";

// define your matcher
// CompositeJsonMatcher use other matcher to perform matching on objects, list or primitive
final var jsonMatcher = new CompositeJsonMatcher(
new NullEqualsEmptyArrayMatcher(),
new LenientJsonArrayPartialMatcher(), // comparing array using lenient mode (ignore array order and extra items)
new LenientJsonObjectPartialMatcher(), // comparing object using lenient mode (ignoring extra properties)
new LenientNumberPrimitivePartialMatcher(new StrictPrimitivePartialMatcher()) // comparing primitive types and manage numbers (100.00 == 100)
Expand Down
Loading