diff --git a/json-path-assert/README.md b/json-path-assert/README.md index 9a9667cb..8847deb4 100644 --- a/json-path-assert/README.md +++ b/json-path-assert/README.md @@ -15,45 +15,66 @@ This library is available at the Central Maven Repository. Maven users add this ``` -# Usage +# Usage guide Statically import the library entry point: import static com.jayway.jsonpath.matchers.JsonPathMatchers.*; -Example usage: +NOTE: The actual evaluation of JsonPath will depend on the current configuration: - // NOTE: The actual evaluation will depend on the current JsonPath configuration Configuration.setDefaults(...); - // The json to be examined could be represented as a String... +The matchers can be used to inspect different representations of JSON: + + // As a String... String json = ...; - // a file... + // or a file... File json = ...; // or an already parsed json object... Object json = Configuration.defaultConfiguration().jsonProvider().parse(content); +Usage examples: + // Verify validity of JSON assertThat(json, isJson()); - // Verify existence of JSON path + // Verify existence (or non-existence) of JSON path assertThat(json, hasJsonPath("$.message")); - + assertThat(json, hasNoJsonPath("$.message")); + // Verify evaluation of JSON path assertThat(json, hasJsonPath("$.message", equalTo("Hi there"))); assertThat(json, hasJsonPath("$.quantity", equalTo(5))); assertThat(json, hasJsonPath("$.price", equalTo(34.56))); assertThat(json, hasJsonPath("$.store.book[*].author", hasSize(4))); assertThat(json, hasJsonPath("$.store.book[*].author", hasItem("Evelyn Waugh"))); + +Combine matchers for greater expressiveness - // Combine several JSON path evaluations + // This will separate the JSON parsing from the path evaluation + assertThat(json, isJson(withoutJsonPath("..."))); + assertThat(json, isJson(withJsonPath("...", equalTo(3)))); + + // Combine several JSON path evaluations into a single statement + // (This will parse the JSON only once) assertThat(json, isJson(allOf( withJsonPath("$.store.name", equalTo("Little Shop")), + withoutJsonPath("$.expensive"), withJsonPath("$..title", hasSize(4))))); + +Match on pre-compiled complex JSON path expressions + + Filter cheapFictionFilter = filter( + where("category").is("fiction").and("price").lte(10D)); + JsonPath cheapFiction = JsonPath.compile("$.store.book[?]", cheapFictionFilter); + String json = ...; + assertThat(json, isJson(withJsonPath(cheapFiction))); - // Use typed matchers for increased clarity +Use typed matchers for specific JSON representations, if needed + String json = ... assertThat(json, isJsonString(withJsonPath("$..author"))); diff --git a/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/JsonPathMatchers.java b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/JsonPathMatchers.java index 5103e699..c89c42cc 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/JsonPathMatchers.java +++ b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/JsonPathMatchers.java @@ -16,13 +16,19 @@ public class JsonPathMatchers { } public static Matcher hasJsonPath(String jsonPath) { - return hasJsonPath(jsonPath, not(anyOf(nullValue(), empty()))); + return describedAs("has json path %0", + hasJsonPath(jsonPath, not(anyOf(nullValue(), empty()))), + jsonPath); } public static Matcher hasJsonPath(final String jsonPath, final Matcher resultMatcher) { return isJson(withJsonPath(jsonPath, resultMatcher)); } + public static Matcher hasNoJsonPath(String jsonPath) { + return isJson(withoutJsonPath(jsonPath)); + } + public static Matcher isJson() { return isJson(withJsonPath("$..*")); } @@ -44,7 +50,17 @@ public class JsonPathMatchers { } public static Matcher withJsonPath(JsonPath jsonPath) { - return withJsonPath(jsonPath, not(anyOf(nullValue(), empty()))); + return describedAs("with json path %0", + withJsonPath(jsonPath, not(anyOf(nullValue(), empty()))), + jsonPath.getPath()); + } + + public static Matcher withoutJsonPath(String jsonPath, Predicate... filters) { + return withoutJsonPath(JsonPath.compile(jsonPath, filters)); + } + + public static Matcher withoutJsonPath(JsonPath jsonPath) { + return new WithoutJsonPath(jsonPath); } public static Matcher withJsonPath(String jsonPath, Matcher resultMatcher) { diff --git a/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithoutJsonPath.java b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithoutJsonPath.java new file mode 100644 index 00000000..b339d5df --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithoutJsonPath.java @@ -0,0 +1,36 @@ +package com.jayway.jsonpath.matchers; + +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.JsonPathException; +import com.jayway.jsonpath.ReadContext; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import static org.hamcrest.Matchers.empty; + +public class WithoutJsonPath extends TypeSafeDiagnosingMatcher { + private final JsonPath jsonPath; + + public WithoutJsonPath(JsonPath jsonPath) { + this.jsonPath = jsonPath; + } + + @Override + protected boolean matchesSafely(ReadContext actual, Description mismatchDescription) { + try { + Object value = actual.read(jsonPath); + mismatchDescription + .appendText(jsonPath.getPath()) + .appendText(" was evaluated to ") + .appendValue(value); + return value == null || empty().matches(value); + } catch (JsonPathException e) { + return true; + } + } + + @Override + public void describeTo(Description description) { + description.appendText("without json path ").appendValue(jsonPath.getPath()); + } +} diff --git a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/DemoTest.java b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/DemoTest.java index 8dfe8c07..1709e195 100644 --- a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/DemoTest.java +++ b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/DemoTest.java @@ -60,4 +60,22 @@ public class DemoTest { File json = resourceAsFile("invalid.json"); assertThat(json, isJsonFile(withJsonPath("$.store.name", equalTo("The Shop")))); } + + @Test + public void shouldFailOnNonExistingJsonPath() { + String json = resource("books.json"); + assertThat(json, hasJsonPath("$.not-here")); + } + + @Test + public void shouldFailOnExistingJsonPath() { + String json = resource("books.json"); + assertThat(json, hasNoJsonPath("$.store.name")); + } + + @Test + public void shouldFailOnExistingJsonPathAlternative() { + String json = resource("books.json"); + assertThat(json, isJson(withoutJsonPath("$.store.name"))); + } } diff --git a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/JsonPathMatchersTest.java b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/JsonPathMatchersTest.java index 90ceac01..f52edafd 100644 --- a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/JsonPathMatchersTest.java +++ b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/JsonPathMatchersTest.java @@ -131,4 +131,14 @@ public class JsonPathMatchersTest { Object json = Configuration.defaultConfiguration().jsonProvider().parse(BOOKS_JSON); assertThat(json, hasJsonPath("$.store.name", equalTo("Little Shop"))); } + + @Test + public void shouldMatchMissingJsonPath() { + assertThat(BOOKS_JSON, hasNoJsonPath("$.not_there")); + } + + @Test + public void shouldNotMatchExistingJsonPath() { + assertThat(BOOKS_JSON, not(hasNoJsonPath("$.store.name"))); + } } diff --git a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/WithJsonPathTest.java b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/WithJsonPathTest.java index 7815d154..6b26cd0c 100644 --- a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/WithJsonPathTest.java +++ b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/WithJsonPathTest.java @@ -12,6 +12,7 @@ import java.util.Collection; import static com.jayway.jsonpath.JsonPath.compile; import static com.jayway.jsonpath.matchers.JsonPathMatchers.withJsonPath; +import static com.jayway.jsonpath.matchers.JsonPathMatchers.withoutJsonPath; import static com.jayway.jsonpath.matchers.helpers.ResourceHelpers.resource; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; @@ -49,6 +50,26 @@ public class WithJsonPathTest { assertThat(BOOKS_JSON, not(withJsonPath("$.store.book[*].not_there"))); } + @Test + public void shouldMatchNonExistingJsonPath() { + assertThat(BOOKS_JSON, withoutJsonPath(compile("$.not_there"))); + } + + @Test + public void shouldMatchNonExistingStringJsonPath() { + assertThat(BOOKS_JSON, withoutJsonPath("$.not_there")); + } + + @Test + public void shouldNotMatchExistingCompiledJsonPath() { + assertThat(BOOKS_JSON, not(withoutJsonPath(compile("$.store.name")))); + } + + @Test + public void shouldNotMatchExistingStringJsonPath() { + assertThat(BOOKS_JSON, not(withoutJsonPath("$.store.name"))); + } + @Test public void shouldMatchJsonPathEvaluatedToStringValue() { assertThat(BOOKS_JSON, withJsonPath(compile("$.store.bicycle.color"), equalTo("red")));