Skip to content

Commit

Permalink
Use JonPath instead of node in Spring
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-krecan committed Nov 29, 2024
1 parent 080411f commit 5b6d16a
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public static Object inPath(@Nullable Object json, @NotNull String path) {
try {
MatchRecordingListener recordingListener = new MatchRecordingListener();
Object value = readValue(defaultConfiguration().addEvaluationListeners(recordingListener), json, path);
return jsonSource(wrapDeserializedObject(value), concatJsonPaths(json, path), recordingListener.getMatchingPaths());
return jsonSource(
wrapDeserializedObject(value), concatJsonPaths(json, path), recordingListener.getMatchingPaths());
} catch (PathNotFoundException e) {
return jsonSource(missingNode(), concatJsonPaths(json, path));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,15 @@
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import org.jetbrains.annotations.NotNull;

import static net.javacrumbs.jsonunit.core.internal.JsonUtils.getPathPrefix;

abstract class AbstractSpringMatcher {
private final Path path;
private final Configuration configuration;
private final Consumer<InternalMatcher> matcher;
private final Function<Object, Object> jsonTransformer;

AbstractSpringMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
this.path = path;
this.configuration = configuration;
this.matcher = matcher;
this.jsonTransformer = jsonTransformer;
Expand All @@ -45,6 +40,7 @@ abstract class AbstractSpringMatcher {
void doMatch(Object actual) {
Object json = jsonTransformer.apply(actual);
String pathPrefix = JsonUtils.getPathPrefix(json);
matcher.accept(new InternalMatcher(json, pathPrefix.isEmpty() ? path : Path.create("", pathPrefix), "", configuration));
Path path = Path.create("", pathPrefix);
matcher.accept(new InternalMatcher(json, path, "", configuration));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.ConfigurationWhen;
import net.javacrumbs.jsonunit.core.Option;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import net.javacrumbs.jsonunit.core.listener.DifferenceListener;
import net.javacrumbs.jsonunit.jsonpath.JsonPathAdapter;
Expand All @@ -35,13 +34,10 @@
* @param <MATCHER> Type of the matcher
*/
abstract class AbstractSpringMatchers<ME, MATCHER> {
final Path path;
final Configuration configuration;
final Function<Object, Object> jsonTransformer;

AbstractSpringMatchers(
@NotNull Path path, @NotNull Configuration configuration, Function<Object, Object> jsonTransformer) {
this.path = path;
AbstractSpringMatchers(@NotNull Configuration configuration, Function<Object, Object> jsonTransformer) {
this.configuration = configuration;
this.jsonTransformer = jsonTransformer;
}
Expand All @@ -50,13 +46,10 @@ abstract class AbstractSpringMatchers<ME, MATCHER> {
abstract MATCHER matcher(@NotNull Consumer<InternalMatcher> matcher);

@NotNull
abstract ME matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer);
abstract ME matchers(@NotNull Configuration configuration, @NotNull Function<Object, Object> jsonTransformer);

protected ME matchers(@NotNull Path path, @NotNull Configuration configuration) {
return matchers(path, configuration, jsonTransformer);
protected ME matchers(@NotNull Configuration configuration) {
return matchers(configuration, jsonTransformer);
}

/**
Expand All @@ -70,16 +63,16 @@ protected ME matchers(@NotNull Path path, @NotNull Configuration configuration)
* @return object comparing only node given by path.
*/
@NotNull
public ME node(String newPath) {
return matchers(path.copy(newPath), configuration);
public ME node(String path) {
return inPath(path);
}

/**
* Uses JsonPath to extract values from the actual value.
*/
@NotNull
public ME inPath(String path) {
return matchers(this.path, configuration, json -> JsonPathAdapter.inPath(jsonTransformer.apply(json), path));
return matchers(configuration, json -> JsonPathAdapter.inPath(jsonTransformer.apply(json), path));
}

/**
Expand All @@ -88,7 +81,7 @@ public ME inPath(String path) {
*/
@NotNull
public ME ignoring(@NotNull String ignorePlaceholder) {
return matchers(path, configuration.withIgnorePlaceholder(ignorePlaceholder));
return matchers(configuration.withIgnorePlaceholder(ignorePlaceholder));
}

/**
Expand All @@ -105,7 +98,7 @@ public ME withTolerance(double tolerance) {
*/
@NotNull
public ME withMatcher(@NotNull String matcherName, @NotNull Matcher<?> matcher) {
return matchers(path, configuration.withMatcher(matcherName, matcher));
return matchers(configuration.withMatcher(matcherName, matcher));
}

/**
Expand All @@ -114,12 +107,12 @@ public ME withMatcher(@NotNull String matcherName, @NotNull Matcher<?> matcher)
*/
@NotNull
public ME withTolerance(@Nullable BigDecimal tolerance) {
return matchers(path, configuration.withTolerance(tolerance));
return matchers(configuration.withTolerance(tolerance));
}

@NotNull
public ME withDifferenceListener(@NotNull DifferenceListener differenceListener) {
return matchers(path, configuration.withDifferenceListener(differenceListener));
return matchers(configuration.withDifferenceListener(differenceListener));
}

/**
Expand All @@ -130,7 +123,7 @@ public ME withDifferenceListener(@NotNull DifferenceListener differenceListener)
*/
@NotNull
public ME when(@NotNull Option firstOption, @NotNull Option... otherOptions) {
return matchers(path, configuration.withOptions(firstOption, otherOptions));
return matchers(configuration.withOptions(firstOption, otherOptions));
}

/**
Expand All @@ -141,7 +134,7 @@ public ME when(@NotNull Option firstOption, @NotNull Option... otherOptions) {
@NotNull
public ME when(
@NotNull ConfigurationWhen.PathsParam object, @NotNull ConfigurationWhen.ApplicableForPath... actions) {
return matchers(path, configuration.when(object, actions));
return matchers(configuration.when(object, actions));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.client.ClientHttpRequest;
Expand All @@ -38,40 +37,37 @@
*/
public class JsonUnitRequestMatchers extends AbstractSpringMatchers<JsonUnitRequestMatchers, RequestMatcher> {

private JsonUnitRequestMatchers(Path path, Configuration configuration, Function<Object, Object> jsonTransformer) {
super(path, configuration, jsonTransformer);
private JsonUnitRequestMatchers(Configuration configuration, Function<Object, Object> jsonTransformer) {
super(configuration, jsonTransformer);
}

@NotNull
@Override
RequestMatcher matcher(@NotNull Consumer<InternalMatcher> matcher) {
return new JsonRequestMatcher(path, configuration, matcher, jsonTransformer);
return new JsonRequestMatcher(configuration, matcher, jsonTransformer);
}

@Override
@NotNull
JsonUnitRequestMatchers matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitRequestMatchers(path, configuration, jsonTransformer);
@NotNull Configuration configuration, @NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitRequestMatchers(configuration, jsonTransformer);
}

/**
* Creates JsonUnitResultMatchers to be used for JSON assertions.
*/
@NotNull
public static JsonUnitRequestMatchers json() {
return new JsonUnitRequestMatchers(Path.root(), Configuration.empty(), Function.identity());
return new JsonUnitRequestMatchers(Configuration.empty(), Function.identity());
}

private static class JsonRequestMatcher extends AbstractSpringMatcher implements RequestMatcher {
private JsonRequestMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
super(path, configuration, matcher, jsonTransformer);
super(configuration, matcher, jsonTransformer);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import org.jetbrains.annotations.NotNull;
import org.springframework.mock.web.MockHttpServletResponse;
Expand All @@ -37,39 +36,36 @@
* </code>
*/
public class JsonUnitResultMatchers extends AbstractSpringMatchers<JsonUnitResultMatchers, ResultMatcher> {
private JsonUnitResultMatchers(Path path, Configuration configuration, Function<Object, Object> jsonTransformer) {
super(path, configuration, jsonTransformer);
private JsonUnitResultMatchers(Configuration configuration, Function<Object, Object> jsonTransformer) {
super(configuration, jsonTransformer);
}

/**
* Creates JsonUnitResultMatchers to be used for JSON assertions.
*/
public static JsonUnitResultMatchers json() {
return new JsonUnitResultMatchers(Path.root(), Configuration.empty(), Function.identity());
return new JsonUnitResultMatchers(Configuration.empty(), Function.identity());
}

@Override
@NotNull
ResultMatcher matcher(@NotNull Consumer<InternalMatcher> matcher) {
return new JsonResultMatcher(path, configuration, matcher, jsonTransformer);
return new JsonResultMatcher(configuration, matcher, jsonTransformer);
}

@Override
@NotNull
JsonUnitResultMatchers matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitResultMatchers(path, configuration, jsonTransformer);
@NotNull Configuration configuration, @NotNull Function<Object, Object> jsonTransformer) {
return new JsonUnitResultMatchers(configuration, jsonTransformer);
}

private static class JsonResultMatcher extends AbstractSpringMatcher implements ResultMatcher {
private JsonResultMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
super(path, configuration, matcher, jsonTransformer);
super(configuration, matcher, jsonTransformer);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
import net.javacrumbs.jsonunit.core.Configuration;
import net.javacrumbs.jsonunit.core.internal.Path;
import net.javacrumbs.jsonunit.core.internal.matchers.InternalMatcher;
import org.jetbrains.annotations.NotNull;
import org.springframework.test.web.reactive.server.EntityExchangeResult;
Expand All @@ -22,37 +21,34 @@
*/
public class WebTestClientJsonMatcher
extends AbstractSpringMatchers<WebTestClientJsonMatcher, Consumer<EntityExchangeResult<byte[]>>> {
private WebTestClientJsonMatcher(Path path, Configuration configuration, Function<Object, Object> jsonTransformer) {
super(path, configuration, jsonTransformer);
private WebTestClientJsonMatcher(Configuration configuration, Function<Object, Object> jsonTransformer) {
super(configuration, jsonTransformer);
}

public static WebTestClientJsonMatcher json() {
return new WebTestClientJsonMatcher(Path.root(), Configuration.empty(), Function.identity());
return new WebTestClientJsonMatcher(Configuration.empty(), Function.identity());
}

@Override
@NotNull
Consumer<EntityExchangeResult<byte[]>> matcher(@NotNull Consumer<InternalMatcher> matcher) {
return new JsonUnitWebTestClientMatcher(path, configuration, matcher, jsonTransformer);
return new JsonUnitWebTestClientMatcher(configuration, matcher, jsonTransformer);
}

@Override
@NotNull
WebTestClientJsonMatcher matchers(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Function<Object, Object> jsonTransformer) {
return new WebTestClientJsonMatcher(path, configuration, jsonTransformer);
@NotNull Configuration configuration, @NotNull Function<Object, Object> jsonTransformer) {
return new WebTestClientJsonMatcher(configuration, jsonTransformer);
}

private static class JsonUnitWebTestClientMatcher extends AbstractSpringMatcher
implements Consumer<EntityExchangeResult<byte[]>> {
private JsonUnitWebTestClientMatcher(
@NotNull Path path,
@NotNull Configuration configuration,
@NotNull Consumer<InternalMatcher> matcher,
@NotNull Function<Object, Object> jsonTransformer) {
super(path, configuration, matcher, jsonTransformer);
super(configuration, matcher, jsonTransformer);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.List;
import net.javacrumbs.jsonunit.core.listener.Difference;
import net.javacrumbs.jsonunit.core.listener.DifferenceContext;
import net.javacrumbs.jsonunit.core.listener.DifferenceListener;
Expand All @@ -47,7 +48,6 @@
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.List;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {SpringConfig.class})
Expand Down Expand Up @@ -79,33 +79,38 @@ void shouldAllowOptionsOnPath() throws Exception {
void shouldSupportJsonPath() throws Exception {
exec("/sampleProduces").andExpect(json().inPath("$.result.array[1]").isEqualTo(2));
}

@Test
void shouldSupportJsonPathError() throws Exception {
assertThatThrownBy(() ->
exec("/sampleProduces").andExpect(json().inPath("$.result.array[1]").isEqualTo(3))
).hasMessage("""
assertThatThrownBy(() -> exec("/sampleProduces")
.andExpect(json().inPath("$.result.array[1]").isEqualTo(3)))
.hasMessage(
"""
JSON documents are different:
Different value found in node "$.result.array[1]", expected: <3> but was: <2>.
""");
}

@Test
void shouldSupportJsonPathChainedError() {
assertThatThrownBy(() ->
exec("/sampleProduces").andExpect(json().inPath("$.result").inPath("$.array[*]").isEqualTo(List.of(1, 3, 3)))
).hasMessage("""
assertThatThrownBy(() -> exec("/sampleProduces")
.andExpect(
json().inPath("$.result").inPath("$.array[*]").isEqualTo(List.of(1, 3, 3))))
.hasMessage(
"""
JSON documents are different:
Different value found in node "$.result.array[*][1]", expected: <3> but was: <2>.
""");
}

@Test
void shouldSupportJsonPathChainedWithNodeError() {
assertThatThrownBy(() ->
exec("/sampleProduces").andExpect(json().node("result").inPath("$.array[1]").isEqualTo(3))
).hasMessage("""
assertThatThrownBy(() -> exec("/sampleProduces")
.andExpect(json().node("result").inPath("$.array[1]").isEqualTo(3)))
.hasMessage(
"""
JSON documents are different:
Different value found in node "$.result.array[*][1]", expected: <3> but was: <2>.
Different value found in node "result.array[1]", expected: <3> but was: <2>.
""");
}

Expand Down Expand Up @@ -212,7 +217,7 @@ void isStringEqualToShouldPassIfEquals() throws Exception {
void isAbsentShouldFailIfNodeExists() {
assertThatThrownBy(() -> exec().andExpect(json().node("result.string").isAbsent()))
.hasMessage(
"Different value found in node \"result.string\", expected: <node to be absent> but was: <\"stringValue\">.");
"Different value found in node \"$.result.string\", expected: <node to be absent> but was: <\"stringValue\">.");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ void isStringEqualToShouldPassIfEquals() {
void isAbsentShouldFailIfNodeExists() {
assertThatThrownBy(() -> exec().consumeWith(json().node("result.string").isAbsent()))
.hasMessageStartingWith(
"Different value found in node \"result.string\", expected: <node to be absent> but was: <\"stringValue\">.");
"Different value found in node \"$.result.string\", expected: <node to be absent> but was: <\"stringValue\">.");
}

@Test
Expand Down

0 comments on commit 5b6d16a

Please sign in to comment.