diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java index 4b42b32263..a82b8a4035 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonPathExpectationsHelper.java @@ -25,7 +25,9 @@ import java.util.Map; import org.hamcrest.Matcher; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; import com.jayway.jsonpath.InvalidPathException; import com.jayway.jsonpath.JsonPath; @@ -135,8 +137,7 @@ public class JsonPathExpectationsHelper { */ public void assertValueIsString(String content) throws ParseException { Object value = assertExistsAndReturn(content); - String reason = "Expected a string at JSON path \"" + this.expression + "\" but found: " + value; - assertThat(reason, value, instanceOf(String.class)); + assertThat(failureReason("a string", value), value, instanceOf(String.class)); } /** @@ -147,8 +148,7 @@ public class JsonPathExpectationsHelper { */ public void assertValueIsBoolean(String content) throws ParseException { Object value = assertExistsAndReturn(content); - String reason = "Expected a boolean at JSON path \"" + this.expression + "\" but found: " + value; - assertThat(reason, value, instanceOf(Boolean.class)); + assertThat(failureReason("a boolean", value), value, instanceOf(Boolean.class)); } /** @@ -159,8 +159,7 @@ public class JsonPathExpectationsHelper { */ public void assertValueIsNumber(String content) throws ParseException { Object value = assertExistsAndReturn(content); - String reason = "Expected a number at JSON path \"" + this.expression + "\" but found: " + value; - assertThat(reason, value, instanceOf(Number.class)); + assertThat(failureReason("a number", value), value, instanceOf(Number.class)); } /** @@ -170,8 +169,7 @@ public class JsonPathExpectationsHelper { */ public void assertValueIsArray(String content) throws ParseException { Object value = assertExistsAndReturn(content); - String reason = "Expected an array at JSON path \"" + this.expression + "\" but found: " + value; - assertThat(reason, value, instanceOf(List.class)); + assertThat(failureReason("an array", value), value, instanceOf(List.class)); } /** @@ -182,8 +180,7 @@ public class JsonPathExpectationsHelper { */ public void assertValueIsMap(String content) throws ParseException { Object value = assertExistsAndReturn(content); - String reason = "Expected a map at JSON path \"" + this.expression + "\" but found: " + value; - assertThat(reason, value, instanceOf(Map.class)); + assertThat(failureReason("a map", value), value, instanceOf(Map.class)); } /** @@ -214,7 +211,7 @@ public class JsonPathExpectationsHelper { catch (AssertionError ex) { return; } - String reason = "Expected no value at JSON path \"" + this.expression + "\" but found: " + value; + String reason = failureReason("no value", value); if (pathIsIndefinite() && value instanceof List) { assertTrue(reason, ((List>) value).isEmpty()); } @@ -223,6 +220,35 @@ public class JsonPathExpectationsHelper { } } + /** + * Evaluate the JSON path expression against the supplied {@code content} + * and assert that an empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link ObjectUtils#isEmpty(Object)}. + * @param content the JSON content + */ + public void assertValueIsEmpty(String content) throws ParseException { + Object value = evaluateJsonPath(content); + assertTrue(failureReason("an empty value", value), ObjectUtils.isEmpty(value)); + } + + /** + * Evaluate the JSON path expression against the supplied {@code content} + * and assert that a non-empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link ObjectUtils#isEmpty(Object)}. + * @param content the JSON content + */ + public void assertValueIsNotEmpty(String content) throws ParseException { + Object value = evaluateJsonPath(content); + assertTrue(failureReason("a non-empty value", value), !ObjectUtils.isEmpty(value)); + } + + private String failureReason(String expectedDescription, Object value) { + return String.format("Expected %s at JSON path \"%s\" but found: %s", expectedDescription, this.expression, + ObjectUtils.nullSafeToString(StringUtils.quoteIfString(value))); + } + private Object evaluateJsonPath(String content) throws ParseException { String message = "No value at JSON path \"" + this.expression + "\", exception: "; try { diff --git a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java index 969d28263b..cccab60d93 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/match/JsonPathRequestMatchers.java @@ -115,6 +115,44 @@ public class JsonPathRequestMatchers { }; } + /** + * Evaluate the JSON path expression against the request content and + * assert that an empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. + * @since 4.2.1 + * @see #isNotEmpty() + * @see #exists() + * @see #doesNotExist() + */ + public RequestMatcher isEmpty() { + return new AbstractJsonPathRequestMatcher() { + @Override + public void matchInternal(MockClientHttpRequest request) throws IOException, ParseException { + JsonPathRequestMatchers.this.jsonPathHelper.assertValueIsEmpty(request.getBodyAsString()); + } + }; + } + + /** + * Evaluate the JSON path expression against the request content and + * assert that a non-empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. + * @since 4.2.1 + * @see #isEmpty() + * @see #exists() + * @see #doesNotExist() + */ + public RequestMatcher isNotEmpty() { + return new AbstractJsonPathRequestMatcher() { + @Override + public void matchInternal(MockClientHttpRequest request) throws IOException, ParseException { + JsonPathRequestMatchers.this.jsonPathHelper.assertValueIsNotEmpty(request.getBodyAsString()); + } + }; + } + /** * Evaluate the JSON path expression against the request content and * assert that the result is a {@link String}. diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java index 1a9a9a1a24..bbc3e1c015 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/result/JsonPathResultMatchers.java @@ -116,6 +116,46 @@ public class JsonPathResultMatchers { }; } + /** + * Evaluate the JSON path expression against the response content and + * assert that an empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. + * @since 4.2.1 + * @see #isNotEmpty() + * @see #exists() + * @see #doesNotExist() + */ + public ResultMatcher isEmpty() { + return new ResultMatcher() { + @Override + public void match(MvcResult result) throws Exception { + String content = result.getResponse().getContentAsString(); + JsonPathResultMatchers.this.jsonPathHelper.assertValueIsEmpty(content); + } + }; + } + + /** + * Evaluate the JSON path expression against the response content and + * assert that a non-empty value exists at the given path. + *
For the semantics of empty, consult the Javadoc for + * {@link org.springframework.util.ObjectUtils#isEmpty(Object)}. + * @since 4.2.1 + * @see #isEmpty() + * @see #exists() + * @see #doesNotExist() + */ + public ResultMatcher isNotEmpty() { + return new ResultMatcher() { + @Override + public void match(MvcResult result) throws Exception { + String content = result.getResponse().getContentAsString(); + JsonPathResultMatchers.this.jsonPathHelper.assertValueIsNotEmpty(content); + } + }; + } + /** * Evaluate the JSON path expression against the response content and * assert that the result is a {@link String}. diff --git a/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java b/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java index 8f5dc01d21..ba44e89487 100644 --- a/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java +++ b/spring-test/src/test/java/org/springframework/test/util/JsonPathExpectationsHelperTests.java @@ -32,13 +32,15 @@ import static org.hamcrest.CoreMatchers.*; public class JsonPathExpectationsHelperTests { private static final String CONTENT = "{" + // - "'str': 'foo', " + // - "'num': 5, " + // - "'bool': true, " + // - "'arr': [42], " + // - "'emptyArray': [], " + // - "'colorMap': {'red': 'rojo'}, " + // - "'emptyMap': {} " + // + "'str': 'foo', " + // + "'num': 5, " + // + "'bool': true, " + // + "'arr': [42], " + // + "'colorMap': {'red': 'rojo'}, " + // + "'whitespace': ' ', " + // + "'emptyString': '', " + // + "'emptyArray': [], " + // + "'emptyMap': {} " + // "}"; private static final String SIMPSONS = "{ 'familyMembers': [ " + // @@ -113,8 +115,106 @@ public class JsonPathExpectationsHelperTests { @Test public void doesNotExistForIndefinatePathWithEmptyResults() throws Exception { + new JsonPathExpectationsHelper("$.familyMembers[?(@.name == 'Dilbert')]").doesNotExist(SIMPSONS); + } + + @Test + public void assertValueIsEmptyForAnEmptyString() throws Exception { + new JsonPathExpectationsHelper("$.emptyString").assertValueIsEmpty(CONTENT); + } + + @Test + public void assertValueIsEmptyForAnEmptyArray() throws Exception { + new JsonPathExpectationsHelper("$.emptyArray").assertValueIsEmpty(CONTENT); + } + + @Test + public void assertValueIsEmptyForAnEmptyMap() throws Exception { + new JsonPathExpectationsHelper("$.emptyMap").assertValueIsEmpty(CONTENT); + } + + @Test + public void assertValueIsEmptyForIndefinatePathWithEmptyResults() throws Exception { + new JsonPathExpectationsHelper("$.familyMembers[?(@.name == 'Dilbert')]").assertValueIsEmpty(SIMPSONS); + } + + @Test + public void assertValueIsEmptyForIndefinatePathWithResults() throws Exception { + String expression = "$.familyMembers[?(@.name == 'Bart')]"; + exception.expect(AssertionError.class); + exception.expectMessage("Expected an empty value at JSON path \"" + expression + + "\" but found: [{\"name\":\"Bart\"}]"); + new JsonPathExpectationsHelper(expression).assertValueIsEmpty(SIMPSONS); + } + + @Test + public void assertValueIsEmptyForWhitespace() throws Exception { + String expression = "$.whitespace"; + exception.expect(AssertionError.class); + exception.expectMessage("Expected an empty value at JSON path \"" + expression + "\" but found: ' '"); + new JsonPathExpectationsHelper(expression).assertValueIsEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForString() throws Exception { + new JsonPathExpectationsHelper("$.str").assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForNumber() throws Exception { + new JsonPathExpectationsHelper("$.num").assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForBoolean() throws Exception { + new JsonPathExpectationsHelper("$.bool").assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForArray() throws Exception { + new JsonPathExpectationsHelper("$.arr").assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForMap() throws Exception { + new JsonPathExpectationsHelper("$.colorMap").assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForIndefinatePathWithResults() throws Exception { + new JsonPathExpectationsHelper("$.familyMembers[?(@.name == 'Bart')]").assertValueIsNotEmpty(SIMPSONS); + } + + @Test + public void assertValueIsNotEmptyForIndefinatePathWithEmptyResults() throws Exception { String expression = "$.familyMembers[?(@.name == 'Dilbert')]"; - new JsonPathExpectationsHelper(expression).doesNotExist(SIMPSONS); + exception.expect(AssertionError.class); + exception.expectMessage("Expected a non-empty value at JSON path \"" + expression + "\" but found: []"); + new JsonPathExpectationsHelper(expression).assertValueIsNotEmpty(SIMPSONS); + } + + @Test + public void assertValueIsNotEmptyForAnEmptyString() throws Exception { + String expression = "$.emptyString"; + exception.expect(AssertionError.class); + exception.expectMessage("Expected a non-empty value at JSON path \"" + expression + "\" but found: ''"); + new JsonPathExpectationsHelper(expression).assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForAnEmptyArray() throws Exception { + String expression = "$.emptyArray"; + exception.expect(AssertionError.class); + exception.expectMessage("Expected a non-empty value at JSON path \"" + expression + "\" but found: []"); + new JsonPathExpectationsHelper(expression).assertValueIsNotEmpty(CONTENT); + } + + @Test + public void assertValueIsNotEmptyForAnEmptyMap() throws Exception { + String expression = "$.emptyMap"; + exception.expect(AssertionError.class); + exception.expectMessage("Expected a non-empty value at JSON path \"" + expression + "\" but found: {}"); + new JsonPathExpectationsHelper(expression).assertValueIsNotEmpty(CONTENT); } @Test @@ -134,10 +234,17 @@ public class JsonPathExpectationsHelperTests { new JsonPathExpectationsHelper("$.str").assertValueIsString(CONTENT); } + @Test + public void assertValueIsStringForAnEmptyString() throws Exception { + new JsonPathExpectationsHelper("$.emptyString").assertValueIsString(CONTENT); + } + @Test public void assertValueIsStringForNonString() throws Exception { + String expression = "$.bool"; exception.expect(AssertionError.class); - new JsonPathExpectationsHelper("$.bool").assertValueIsString(CONTENT); + exception.expectMessage("Expected a string at JSON path \"" + expression + "\" but found: true"); + new JsonPathExpectationsHelper(expression).assertValueIsString(CONTENT); } @Test @@ -147,8 +254,10 @@ public class JsonPathExpectationsHelperTests { @Test public void assertValueIsNumberForNonNumber() throws Exception { + String expression = "$.bool"; exception.expect(AssertionError.class); - new JsonPathExpectationsHelper("$.bool").assertValueIsNumber(CONTENT); + exception.expectMessage("Expected a number at JSON path \"" + expression + "\" but found: true"); + new JsonPathExpectationsHelper(expression).assertValueIsNumber(CONTENT); } @Test @@ -158,8 +267,10 @@ public class JsonPathExpectationsHelperTests { @Test public void assertValueIsBooleanForNonBoolean() throws Exception { + String expression = "$.num"; exception.expect(AssertionError.class); - new JsonPathExpectationsHelper("$.num").assertValueIsBoolean(CONTENT); + exception.expectMessage("Expected a boolean at JSON path \"" + expression + "\" but found: 5"); + new JsonPathExpectationsHelper(expression).assertValueIsBoolean(CONTENT); } @Test @@ -174,8 +285,10 @@ public class JsonPathExpectationsHelperTests { @Test public void assertValueIsArrayForNonArray() throws Exception { + String expression = "$.str"; exception.expect(AssertionError.class); - new JsonPathExpectationsHelper("$.str").assertValueIsArray(CONTENT); + exception.expectMessage("Expected an array at JSON path \"" + expression + "\" but found: 'foo'"); + new JsonPathExpectationsHelper(expression).assertValueIsArray(CONTENT); } @Test @@ -190,8 +303,10 @@ public class JsonPathExpectationsHelperTests { @Test public void assertValueIsMapForNonMap() throws Exception { + String expression = "$.str"; exception.expect(AssertionError.class); - new JsonPathExpectationsHelper("$.str").assertValueIsMap(CONTENT); + exception.expectMessage("Expected a map at JSON path \"" + expression + "\" but found: 'foo'"); + new JsonPathExpectationsHelper(expression).assertValueIsMap(CONTENT); } } diff --git a/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java b/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java index 15e4915045..0b2069b19f 100644 --- a/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/client/match/JsonPathRequestMatchersTests.java @@ -33,13 +33,14 @@ import static org.hamcrest.CoreMatchers.*; public class JsonPathRequestMatchersTests { private static final String REQUEST_CONTENT = "{" + // - "'str': 'foo', " + // - "'num': 5, " + // - "'bool': true, " + // - "'arr': [42], " + // - "'emptyArray': [], " + // - "'colorMap': {'red': 'rojo'}, " + // - "'emptyMap': {} " + // + "'str': 'foo', " + // + "'num': 5, " + // + "'bool': true, " + // + "'arr': [42], " + // + "'colorMap': {'red': 'rojo'}, " + // + "'emptyString': '', " + // + "'emptyArray': [], " + // + "'emptyMap': {} " + // "}"; private static final MockClientHttpRequest request = new MockClientHttpRequest(); @@ -114,6 +115,61 @@ public class JsonPathRequestMatchersTests { new JsonPathRequestMatchers("$.emptyMap").doesNotExist().match(request); } + @Test + public void isEmptyForAnEmptyString() throws Exception { + new JsonPathRequestMatchers("$.emptyString").isEmpty().match(request); + } + + @Test + public void isEmptyForAnEmptyArray() throws Exception { + new JsonPathRequestMatchers("$.emptyArray").isEmpty().match(request); + } + + @Test + public void isEmptyForAnEmptyMap() throws Exception { + new JsonPathRequestMatchers("$.emptyMap").isEmpty().match(request); + } + + @Test + public void isNotEmptyForString() throws Exception { + new JsonPathRequestMatchers("$.str").isNotEmpty().match(request); + } + + @Test + public void isNotEmptyForNumber() throws Exception { + new JsonPathRequestMatchers("$.num").isNotEmpty().match(request); + } + + @Test + public void isNotEmptyForBoolean() throws Exception { + new JsonPathRequestMatchers("$.bool").isNotEmpty().match(request); + } + + @Test + public void isNotEmptyForArray() throws Exception { + new JsonPathRequestMatchers("$.arr").isNotEmpty().match(request); + } + + @Test + public void isNotEmptyForMap() throws Exception { + new JsonPathRequestMatchers("$.colorMap").isNotEmpty().match(request); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyString() throws Exception { + new JsonPathRequestMatchers("$.emptyString").isNotEmpty().match(request); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyArray() throws Exception { + new JsonPathRequestMatchers("$.emptyArray").isNotEmpty().match(request); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyMap() throws Exception { + new JsonPathRequestMatchers("$.emptyMap").isNotEmpty().match(request); + } + @Test public void isArray() throws Exception { new JsonPathRequestMatchers("$.arr").isArray().match(request); diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java index 26df89d15d..bf0b58850a 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/result/JsonPathResultMatchersTests.java @@ -33,13 +33,14 @@ import org.springframework.test.web.servlet.StubMvcResult; public class JsonPathResultMatchersTests { private static final String RESPONSE_CONTENT = "{" + // - "'str': 'foo', " + // - "'num': 5, " + // - "'bool': true, " + // - "'arr': [42], " + // - "'emptyArray': [], " + // - "'colorMap': {'red': 'rojo'}, " + // - "'emptyMap': {} " + // + "'str': 'foo', " + // + "'num': 5, " + // + "'bool': true, " + // + "'arr': [42], " + // + "'colorMap': {'red': 'rojo'}, " + // + "'emptyString': '', " + // + "'emptyArray': [], " + // + "'emptyMap': {} " + // "}"; private static final StubMvcResult stubMvcResult; @@ -117,6 +118,61 @@ public class JsonPathResultMatchersTests { new JsonPathResultMatchers("$.emptyMap").doesNotExist().match(stubMvcResult); } + @Test + public void isEmptyForAnEmptyString() throws Exception { + new JsonPathResultMatchers("$.emptyString").isEmpty().match(stubMvcResult); + } + + @Test + public void isEmptyForAnEmptyArray() throws Exception { + new JsonPathResultMatchers("$.emptyArray").isEmpty().match(stubMvcResult); + } + + @Test + public void isEmptyForAnEmptyMap() throws Exception { + new JsonPathResultMatchers("$.emptyMap").isEmpty().match(stubMvcResult); + } + + @Test + public void isNotEmptyForString() throws Exception { + new JsonPathResultMatchers("$.str").isNotEmpty().match(stubMvcResult); + } + + @Test + public void isNotEmptyForNumber() throws Exception { + new JsonPathResultMatchers("$.num").isNotEmpty().match(stubMvcResult); + } + + @Test + public void isNotEmptyForBoolean() throws Exception { + new JsonPathResultMatchers("$.bool").isNotEmpty().match(stubMvcResult); + } + + @Test + public void isNotEmptyForArray() throws Exception { + new JsonPathResultMatchers("$.arr").isNotEmpty().match(stubMvcResult); + } + + @Test + public void isNotEmptyForMap() throws Exception { + new JsonPathResultMatchers("$.colorMap").isNotEmpty().match(stubMvcResult); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyString() throws Exception { + new JsonPathResultMatchers("$.emptyString").isNotEmpty().match(stubMvcResult); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyArray() throws Exception { + new JsonPathResultMatchers("$.emptyArray").isNotEmpty().match(stubMvcResult); + } + + @Test(expected = AssertionError.class) + public void isNotEmptyForAnEmptyMap() throws Exception { + new JsonPathResultMatchers("$.emptyMap").isNotEmpty().match(stubMvcResult); + } + @Test public void isArray() throws Exception { new JsonPathResultMatchers("$.arr").isArray().match(stubMvcResult);