From bc605f738d026415adb798ebe8bdf4e02fad36c0 Mon Sep 17 00:00:00 2001 From: kalle Date: Fri, 4 Feb 2011 12:40:39 +0100 Subject: [PATCH] added some hamcrest matchers --- .../com/jayway/jsonassert/JsonAssert.java | 22 +++++++ .../jsonassert/impl/JsonAsserterImpl.java | 7 ++- .../impl/matcher/CollectionMatcher.java | 17 ++++++ .../impl/matcher/IsCollectionWithSize.java | 50 ++++++++++++++++ .../impl/matcher/IsEmptyCollection.java | 30 ++++++++++ .../impl/matcher/IsMapContainingKey.java | 41 +++++++++++++ .../impl/matcher/IsMapContainingValue.java | 40 +++++++++++++ .../impl/matcher/MapTypeSafeMatcher.java | 14 +++++ .../com/jayway/jsonassert/JsonAssertTest.java | 58 +++++-------------- pom.xml | 1 - 10 files changed, 233 insertions(+), 47 deletions(-) create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/CollectionMatcher.java create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java create mode 100644 json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/MapTypeSafeMatcher.java diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAssert.java b/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAssert.java index d55eb299..19999fe8 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAssert.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAssert.java @@ -2,6 +2,8 @@ package com.jayway.jsonassert; import com.jayway.jsonassert.impl.JsonAsserterImpl; +import com.jayway.jsonassert.impl.matcher.*; +import org.hamcrest.Matcher; import org.json.simple.parser.JSONParser; import java.io.IOException; @@ -9,6 +11,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.text.ParseException; +import java.util.Collection; +import java.util.Map; /** * User: kalle stenflo @@ -63,4 +67,22 @@ public class JsonAssert { return with(reader); } + //Matchers + + public static CollectionMatcher collectionWithSize(Matcher sizeMatcher) { + return new IsCollectionWithSize(sizeMatcher); + } + + public static Matcher> mapContainingKey(Matcher keyMatcher) { + return new IsMapContainingKey(keyMatcher); + } + + public static Matcher> mapContainingValue(Matcher valueMatcher) { + return new IsMapContainingValue(valueMatcher); + } + + public static Matcher> emptyCollection() { + return new IsEmptyCollection(); + } + } diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java index 111bd247..aa5073c2 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java @@ -4,6 +4,7 @@ package com.jayway.jsonassert.impl; import com.jayway.jsonassert.JsonAsserter; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.PathUtil; +import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; @@ -41,11 +42,13 @@ public class JsonAsserterImpl implements JsonAsserter { @SuppressWarnings("unchecked") public JsonAsserter assertThat(String path, Matcher matcher) { + String reason = "When processing json path: " + path; + if(PathUtil.isPathDefinite(path)){ - MatcherAssert.assertThat(JsonPath.readOne(jsonObject, path), matcher); + MatcherAssert.assertThat(reason, JsonPath.readOne(jsonObject, path), matcher); } else { - MatcherAssert.assertThat((T) JsonPath.read(jsonObject, path), matcher); + MatcherAssert.assertThat(reason, (T) JsonPath.read(jsonObject, path), matcher); } return this; } diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/CollectionMatcher.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/CollectionMatcher.java new file mode 100644 index 00000000..cfb30549 --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/CollectionMatcher.java @@ -0,0 +1,17 @@ +package com.jayway.jsonassert.impl.matcher; + +import org.hamcrest.BaseMatcher; + +import java.util.Collection; + +public abstract class CollectionMatcher> extends BaseMatcher { + @SuppressWarnings("unchecked") + public boolean matches(Object item) { + if (!(item instanceof Collection)) { + return false; + } + return matchesSafely((C)item); + } + + protected abstract boolean matchesSafely(C collection); +} \ No newline at end of file diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java new file mode 100644 index 00000000..23c10cd5 --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java @@ -0,0 +1,50 @@ +package com.jayway.jsonassert.impl.matcher; + +import static org.hamcrest.core.IsEqual.equalTo; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +import java.util.Collection; + +/** + * Matches if collection size satisfies a nested matcher. + */ +public class IsCollectionWithSize extends CollectionMatcher> { + private final Matcher sizeMatcher; + + public IsCollectionWithSize(Matcher sizeMatcher) { + this.sizeMatcher = sizeMatcher; + } + + @Override + public boolean matchesSafely(Collection item) { + return sizeMatcher.matches(item.size()); + } + + public void describeTo(Description description) { + description.appendText("a collection with size ") + .appendDescriptionOf(sizeMatcher); + } + + /** + * Does collection size satisfy a given matcher? + */ + @Factory + public static Matcher> hasSize(Matcher size) { + return new IsCollectionWithSize(size); + } + + /** + * This is a shortcut to the frequently used hasSize(equalTo(x)). + * + * For example, assertThat(hasSize(equal_to(x))) + * vs. assertThat(hasSize(x)) + */ + @Factory + public static Matcher> hasSize(int size) { + Matcher matcher = equalTo(size); + return IsCollectionWithSize.hasSize(matcher); + } +} \ No newline at end of file diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java new file mode 100644 index 00000000..0ee7edc6 --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java @@ -0,0 +1,30 @@ +package com.jayway.jsonassert.impl.matcher; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; + +import java.util.Collection; + +/** + * Tests if collection is empty. + */ +public class IsEmptyCollection extends CollectionMatcher> { + + @Override + public boolean matchesSafely(Collection item) { + return item.isEmpty(); + } + + public void describeTo(Description description) { + description.appendText("an empty collection"); + } + + /** + * Matches an empty collection. + */ + @Factory + public static Matcher> empty() { + return new IsEmptyCollection(); + } +} \ No newline at end of file diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java new file mode 100644 index 00000000..abe3bd25 --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java @@ -0,0 +1,41 @@ +package com.jayway.jsonassert.impl.matcher; + +import java.util.Map; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import static org.hamcrest.core.IsEqual.equalTo; + +public class IsMapContainingKey extends MapTypeSafeMatcher> { + private final Matcher keyMatcher; + + public IsMapContainingKey(Matcher keyMatcher) { + this.keyMatcher = keyMatcher; + } + + @Override + public boolean matchesSafely(Map item) { + for (K key : item.keySet()) { + if (keyMatcher.matches(key)) { + return true; + } + } + return false; + } + + public void describeTo(Description description) { + description.appendText("map with key ") + .appendDescriptionOf(keyMatcher); + } + + @Factory + public static Matcher> hasKey(K key) { + return hasKey(equalTo(key)); + } + + @Factory + public static Matcher> hasKey(Matcher keyMatcher) { + return new IsMapContainingKey(keyMatcher); + } +} diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java new file mode 100644 index 00000000..4fd99495 --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java @@ -0,0 +1,40 @@ +package com.jayway.jsonassert.impl.matcher; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import static org.hamcrest.core.IsEqual.equalTo; +import java.util.Map; + +public class IsMapContainingValue extends MapTypeSafeMatcher>{ + private final Matcher valueMatcher; + + public IsMapContainingValue(Matcher valueMatcher) { + this.valueMatcher = valueMatcher; + } + + @Override + public boolean matchesSafely(Map item) { + for (V value : item.values()) { + if (valueMatcher.matches(value)) { + return true; + } + } + return false; + } + + public void describeTo(Description description) { + description.appendText("map with value ") + .appendDescriptionOf(valueMatcher); + } + + @Factory + public static Matcher> hasValue(V value) { + return IsMapContainingValue.hasValue(equalTo(value)); + } + + @Factory + public static Matcher> hasValue(Matcher valueMatcher) { + return new IsMapContainingValue(valueMatcher); + } +} diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/MapTypeSafeMatcher.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/MapTypeSafeMatcher.java new file mode 100644 index 00000000..83a6652b --- /dev/null +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/MapTypeSafeMatcher.java @@ -0,0 +1,14 @@ +package com.jayway.jsonassert.impl.matcher; + +import org.hamcrest.BaseMatcher; + +import java.util.Map; + +public abstract class MapTypeSafeMatcher> extends BaseMatcher { + @SuppressWarnings("unchecked") + public boolean matches(Object item) { + return item instanceof Map && matchesSafely((M) item); + } + + protected abstract boolean matchesSafely(M map); +} \ No newline at end of file diff --git a/json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java b/json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java index fbd6e50e..4b803f62 100644 --- a/json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java +++ b/json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java @@ -2,7 +2,7 @@ package com.jayway.jsonassert; import org.junit.Test; -import static com.jayway.jsonassert.JsonAssert.with; +import static com.jayway.jsonassert.JsonAssert.*; import static org.hamcrest.Matchers.*; /** @@ -57,7 +57,8 @@ public class JsonAssertTest { with(JSON).assertThat("$..book[*].author", hasItems("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien")); - with(JSON).assertThat("$..author", hasItems("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien")); + with(JSON).assertThat("$..author", hasItems("Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien")) + .assertThat("$..author", is(collectionWithSize(equalTo(4)))); } @Test @@ -69,56 +70,25 @@ public class JsonAssertTest { public void map_content_can_be_asserted_with_matcher() throws Exception { with(JSON).assertThat("$.store.book[0]", hasEntry("category", "reference")) - .assertThat("$.store.book[0]", hasEntry("title", "Sayings of the Century")); - - with(JSON).assertThat("$..book[0]", hasItems(hasEntry("category", "reference"))); - } - - @Test - public void a_path_can_be_asserted_equal_to() throws Exception { - - with(JSON).assertEquals("$.store.book[0].title", "Sayings of the Century") - .assertThat("$.store.book[0].title", equalTo("Sayings of the Century")); + .assertThat("$.store.book[0]", hasEntry("title", "Sayings of the Century")) + .and() + .assertThat("$..book[0]", hasItems(hasEntry("category", "reference"))) + .and() + .assertThat("$.store.book[0]", mapContainingKey(equalTo("category"))) + .and() + .assertThat("$.store.book[0]", mapContainingValue(equalTo("reference"))); } - - /* @Test - public void a_sub_document_can_asserted_on__by_path() throws Exception { - JsonAssert.with(TEST_DOCUMENT).assertThat("subDocument.subField", is(equalTo("sub-field"))); + public void an_empty_collection() throws Exception { + with(JSON).assertThat("$.store.book[?(@.category = 'x')]", emptyCollection()); } @Test public void a_path_can_be_asserted_equal_to() throws Exception { - JsonAssert.with(TEST_DOCUMENT).assertEquals("stringField", "string-field"); - } - - @Test - public void a_path_can_be_asserted_is_null() throws Exception { - - JsonAssert.with(TEST_DOCUMENT).assertNull("nullField"); - } - - @Test(expected = AssertionError.class) - public void failed_assert_throws() throws Exception { - - JsonAssert.with(TEST_DOCUMENT).assertThat("stringField", equalTo("SOME CRAP")); - } - - @Test - public void multiple_asserts_can_be_chained() throws Exception { - - JsonAssert.with(TEST_DOCUMENT) - .assertThat("stringField", equalTo("string-field")) - .assertThat("numberField", is(notNullValue())) - .and() - .assertNull("nullField") - .and() - .assertEquals("stringField", "string-field"); - + with(JSON).assertEquals("$.store.book[0].title", "Sayings of the Century") + .assertThat("$.store.book[0].title", equalTo("Sayings of the Century")); } - */ - } diff --git a/pom.xml b/pom.xml index 16410c22..1e18c696 100644 --- a/pom.xml +++ b/pom.xml @@ -72,7 +72,6 @@ json-path - examples json-path-assert