Skip to content

Commit

Permalink
Absent in paths
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-krecan committed Jan 26, 2021
1 parent 086cf67 commit 047ada3
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@
*/
package net.javacrumbs.jsonunit.core.internal;

import java.util.List;

/**
* For internal use only!!! Wraps JSON source and its description
*/
interface JsonSource {
public interface JsonSource {
Object getJson();

String getPathPrefix();

List<String> getMatchingPaths();
}


Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
import net.javacrumbs.jsonunit.core.Option;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import static java.util.Collections.emptyList;

/**
* Internal utility class to parse JSON values.
*/
Expand Down Expand Up @@ -109,26 +112,20 @@ public static boolean nodeAbsent(Object json, Path path, Configuration configura
return nodeAbsent(json, path, configuration.getOptions().contains(Option.TREATING_NULL_AS_ABSENT));
}

public static Object jsonSource(final Object json, final String pathPrefix) {
return new JsonSource() {
@Override
public Object getJson() {
return json;
}
public static Object jsonSource(Object json, String pathPrefix) {
return jsonSource(json, pathPrefix, emptyList());
}

@Override
public String getPathPrefix() {
return pathPrefix;
}
};
public static Object jsonSource(Object json, String pathPrefix, List<String> matchingPaths) {
return new DefaultJsonSource(json, pathPrefix, matchingPaths);
}

public static String getPathPrefix(Object json) {
if (json instanceof JsonSource) {
return ((JsonSource) json).getPathPrefix();
} else {
return "";
}
return ((JsonSource) json).getPathPrefix();
} else {
return "";
}
}

/**
Expand Down Expand Up @@ -238,4 +235,30 @@ private static Object quoteString(Object value) {
return value instanceof String ? "\"" + value + "\"" : value;
}

private static class DefaultJsonSource implements JsonSource {
private final Object json;
private final String pathPrefix;
private final List<String> matchingPaths;

public DefaultJsonSource(Object json, String pathPrefix, List<String> matchingPaths) {
this.json = json;
this.pathPrefix = pathPrefix;
this.matchingPaths = matchingPaths;
}

@Override
public Object getJson() {
return json;
}

@Override
public String getPathPrefix() {
return pathPrefix;
}

@Override
public List<String> getMatchingPaths() {
return matchingPaths;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import net.javacrumbs.jsonunit.core.ConfigurationWhen.PathsParam;
import net.javacrumbs.jsonunit.core.Option;
import net.javacrumbs.jsonunit.core.internal.Diff;
import net.javacrumbs.jsonunit.core.internal.JsonSource;
import net.javacrumbs.jsonunit.core.internal.Node;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.listener.DifferenceListener;
Expand All @@ -32,6 +33,7 @@
import java.util.Iterator;
import java.util.List;

import static java.util.Collections.singletonList;
import static net.javacrumbs.jsonunit.core.Option.COMPARING_ONLY_STRUCTURE;
import static net.javacrumbs.jsonunit.core.internal.Diff.create;
import static net.javacrumbs.jsonunit.core.internal.Diff.quoteTextValue;
Expand Down Expand Up @@ -162,21 +164,32 @@ public void isEqualTo(@Nullable Object expected) {
*/
public void isStringEqualTo(@Nullable String expected) {
isString();
Node node = getNode(actual, path);
Node node = getActualNode();
if (!node.asText().equals(expected)) {
failOnDifference(quoteTextValue(expected), quoteTextValue(node.asText()));
}
}

private void failOnDifference(@Nullable Object expected, @NotNull Object actual) {
failWithMessage(String.format("Different value found in node \"%s\", expected: <%s> but was: <%s>.", path, expected, actual));
failOnDifference(expected, actual, singletonList(path.toString()));
}

private void failOnDifference(@Nullable Object expected, @NotNull Object actual, @NotNull List<String> paths) {
String path;
String node;
if (paths.size() == 1) {
path = paths.get(0);
node = "node";
} else {
path = paths.toString();
node = "nodes";
}
failWithMessage(String.format("Different value found in %s \"%s\", expected: <%s> but was: <%s>.", node, path, expected, actual));
}

/**
* Fails if compared documents are equal. The expected object is converted to JSON
* before comparison. Ignores order of sibling nodes and whitespaces.
*
* @param expected
*/
public void isNotEqualTo(@Nullable Object expected) {
Diff diff = createDiff(expected, configuration);
Expand Down Expand Up @@ -231,8 +244,22 @@ private void failWithMessage(@NotNull String message) {
*/
public void isAbsent() {
if (!nodeAbsent(actual, path, configuration)) {
failOnDifference("node to be absent", quoteTextValue(getNode(actual, path)));
List<String> matchingPaths = getMatchingPaths();
failOnDifference("node to be absent", quoteTextValue(getActualNode()), matchingPaths);
}
}

/**
* Extracts data from JsonPath matches
*/
private List<String> getMatchingPaths() {
if (actual instanceof JsonSource) {
JsonSource jsonSource = (JsonSource) actual;
if (!jsonSource.getMatchingPaths().isEmpty()) {
return jsonSource.getMatchingPaths();
}
}
return singletonList(path.toString());
}

/**
Expand Down Expand Up @@ -260,7 +287,7 @@ public ArrayMatcher isArray() {
@NotNull
public Node assertType(@NotNull Node.NodeType type) {
isPresent(type.getDescription());
Node node = getNode(actual, path);
Node node = getActualNode();
if (node.getNodeType() != type) {
failOnType(node, type);
}
Expand Down Expand Up @@ -292,20 +319,24 @@ public void isString() {

public void isNull() {
isPresent();
Node node = getNode(actual, path);
Node node = getActualNode();
if (node.getNodeType() != NULL) {
failOnType(node, "a null");
}
}

public void isNotNull() {
isPresent("not null");
Node node = getNode(actual, path);
Node node = getActualNode();
if (node.getNodeType() == NULL) {
failOnType(node, "not null");
}
}

private Node getActualNode() {
return getNode(actual, path);
}

private void failOnType(@NotNull Node node, @NotNull Node.NodeType expectedType) {
failOnType(node, expectedType.getDescription());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@
*/
package net.javacrumbs.jsonunit.jsonpath;

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.EvaluationListener;
import com.jayway.jsonpath.PathNotFoundException;
import org.jetbrains.annotations.NotNull;

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

import static com.jayway.jsonpath.Configuration.defaultConfiguration;
import static net.javacrumbs.jsonunit.core.internal.JsonUtils.jsonSource;
import static net.javacrumbs.jsonunit.core.internal.JsonUtils.missingNode;
import static net.javacrumbs.jsonunit.core.internal.JsonUtils.wrapDeserializedObject;
Expand All @@ -36,9 +40,25 @@ private JsonPathAdapter() {
public static Object inPath(@NotNull Object json, @NotNull String path) {
String normalizedPath = fromBracketNotation(path);
try {
return jsonSource(wrapDeserializedObject(readValue(Configuration.defaultConfiguration(), json, path)), normalizedPath);
MatchRecordingListener recordingListener = new MatchRecordingListener();
Object value = readValue(defaultConfiguration().addEvaluationListeners(recordingListener), json, path);
return jsonSource(wrapDeserializedObject(value), normalizedPath, recordingListener.getMatchingPaths());
} catch (PathNotFoundException e) {
return jsonSource(missingNode(), normalizedPath);
}
}

private static class MatchRecordingListener implements EvaluationListener {
private final List<String> matchingPaths = new ArrayList<>();

@Override
public EvaluationContinuation resultFound(FoundResult foundResult) {
matchingPaths.add(fromBracketNotation(foundResult.path()));
return EvaluationContinuation.CONTINUE;
}

public List<String> getMatchingPaths() {
return matchingPaths;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,27 @@ void shouldAssertObjectFailure() {
.hasMessage("Node \"\" has invalid type, expected: <object> but was: <true>.");
}


@Test
void absentInPathShouldFailOnSimpleJson() {
assertThatThrownBy(() -> assertThatJson("{\"a\":{\"b\": 1}}").inPath("$.a.b").isAbsent())
.hasMessage("Different value found in node \"$.a.b\", expected: <node to be absent> but was: <1>.");
}

@Test
void absentInPathShouldFailOnArray() {
assertThatThrownBy(() -> assertThatJson("[{\"b\": 1}, {\"c\": 1}]").inPath("[*].c").isAbsent())
.hasMessage("Different value found in node \"$[1].c\", expected: <node to be absent> but was: <[1]>.");
}


@Test
void absentInPathShouldFailOnMultipleMatches() {
assertThatThrownBy(() -> assertThatJson("[{\"c\": {\"x\": 2}}, {\"b\": {\"x\": 2}}, {\"c\": {\"x\": 2}}]")
.inPath("$.[*].c").isAbsent())
.hasMessage("Different value found in nodes \"[$[0].c, $[2].c]\", expected: <node to be absent> but was: <[{\"x\":2},{\"x\":2}]>.");
}

@Test
void shouldAssertNumber() {
assertThatJson("{\"a\":1}").node("a").isNumber().isEqualByComparingTo("1");
Expand Down

0 comments on commit 047ada3

Please sign in to comment.