diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java index e3328c8f5c2..a3a49b3988c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/CookieAssertions.java @@ -16,10 +16,14 @@ package org.springframework.test.web.reactive.server; +import org.hamcrest.Matcher; + import org.springframework.http.ResponseCookie; import org.springframework.test.web.support.AbstractCookieAssertions; import org.springframework.util.MultiValueMap; +import static org.hamcrest.MatcherAssert.assertThat; + /** * Assertions on cookies of the response. * @@ -45,4 +49,56 @@ public class CookieAssertions extends AbstractCookieAssertions matcher) { + String value = getCookie(name).getValue(); + assertWithDiagnostics(() -> { + String message = getMessage(name); + assertThat(message, value, matcher); + }); + return getResponseSpec(); + } + + + /** + * Assert a cookie's "Max-Age" attribute with a Hamcrest {@link Matcher}. + */ + public WebTestClient.ResponseSpec maxAge(String name, Matcher matcher) { + long maxAge = getCookie(name).getMaxAge().getSeconds(); + assertWithDiagnostics(() -> { + String message = getMessage(name) + " maxAge"; + assertThat(message, maxAge, matcher); + }); + return getResponseSpec(); + } + + /** + * Assert a cookie's "Path" attribute with a Hamcrest {@link Matcher}. + */ + public WebTestClient.ResponseSpec path(String name, Matcher matcher) { + String path = getCookie(name).getPath(); + assertWithDiagnostics(() -> { + String message = getMessage(name) + " path"; + assertThat(message, path, matcher); + }); + return getResponseSpec(); + } + + /** + * Assert a cookie's "Domain" attribute with a Hamcrest {@link Matcher}. + */ + public WebTestClient.ResponseSpec domain(String name, Matcher matcher) { + String domain = getCookie(name).getDomain(); + assertWithDiagnostics(() -> { + String message = getMessage(name) + " domain"; + assertThat(message, domain, matcher); + }); + return getResponseSpec(); + } + + } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java index c2c3a3a7fbb..df1c2b3fae6 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java @@ -16,9 +16,15 @@ package org.springframework.test.web.reactive.server; +import java.util.List; + +import org.hamcrest.Matcher; + import org.springframework.http.HttpHeaders; import org.springframework.test.web.support.AbstractHeaderAssertions; +import static org.hamcrest.MatcherAssert.assertThat; + /** * Assertions on headers of the response. * @@ -47,4 +53,35 @@ public class HeaderAssertions extends AbstractHeaderAssertions matcher) { + String value = getResponseHeaders().getFirst(name); + assertWithDiagnostics(() -> { + String message = getMessage(name); + assertThat(message, value, matcher); + }); + return getResponseSpec(); + } + + /** + * Assert all values of the response header with a Hamcrest {@link Matcher}. + * @param name the header name + * @param matcher the matcher to use + */ + public WebTestClient.ResponseSpec values(String name, Matcher> matcher) { + List values = getResponseHeaders().get(name); + assertWithDiagnostics(() -> { + String message = getMessage(name); + assertThat(message, values, matcher); + }); + return getResponseSpec(); + } + + } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java index 44602c185a9..51421b59d7b 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java @@ -17,8 +17,10 @@ package org.springframework.test.web.reactive.server; import com.jayway.jsonpath.Configuration; +import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.test.util.JsonPathExpectationsHelper; import org.springframework.test.web.support.AbstractJsonPathAssertions; @@ -41,4 +43,31 @@ public class JsonPathAssertions extends AbstractJsonPathAssertions WebTestClient.BodyContentSpec value(Matcher matcher) { + getPathHelper().assertValue(getContent(), matcher); + return getBodySpec(); + } + + /** + * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, Class)}. + */ + public WebTestClient.BodyContentSpec value(Class targetType, Matcher matcher) { + getPathHelper().assertValue(getContent(), matcher, targetType); + return getBodySpec(); + } + + /** + * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, ParameterizedTypeReference)}. + */ + public WebTestClient.BodyContentSpec value(ParameterizedTypeReference targetType, Matcher matcher) { + getPathHelper().assertValue(getContent(), matcher, targetType); + return getBodySpec(); + } + } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java index 8e3fcacad71..c4b1fb2c16a 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java @@ -16,6 +16,9 @@ package org.springframework.test.web.reactive.server; +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; + import org.springframework.http.HttpStatusCode; import org.springframework.test.web.support.AbstractStatusAssertions; @@ -45,4 +48,14 @@ public class StatusAssertions extends AbstractStatusAssertions matcher) { + int actual = getStatus().value(); + assertWithDiagnostics(() -> MatcherAssert.assertThat("Response status", actual, matcher)); + return getResponseSpec(); + } + } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java index 53dd56bd254..9463d4257a1 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java @@ -19,9 +19,11 @@ package org.springframework.test.web.reactive.server; import java.util.Map; import java.util.Optional; +import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; import org.springframework.http.HttpHeaders; +import org.springframework.test.util.XpathExpectationsHelper; import org.springframework.test.web.support.AbstractXpathAssertions; import org.springframework.util.Assert; @@ -55,4 +57,26 @@ public class XpathAssertions extends AbstractXpathAssertions matcher){ + return assertWith(() -> getXpathHelper().assertString(getContent(), getCharset(), matcher)); + } + + /** + * Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Matcher)}. + */ + public WebTestClient.BodyContentSpec number(Matcher matcher){ + return assertWith(() -> getXpathHelper().assertNumber(getContent(), getCharset(), matcher)); + } + + /** + * Delegates to {@link XpathExpectationsHelper#assertNodeCount(byte[], String, Matcher)}. + */ + public WebTestClient.BodyContentSpec nodeCount(Matcher matcher){ + return assertWith(() -> getXpathHelper().assertNodeCount(getContent(), getCharset(), matcher)); + } + } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java index ece99b233c5..327ad3de13e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java @@ -28,8 +28,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; import org.jspecify.annotations.Nullable; import org.springframework.core.ParameterizedTypeReference; @@ -380,26 +378,20 @@ class DefaultRestTestClient implements RestTestClient { } @Override - public T value(Matcher matcher) { - this.result.assertWithDiagnostics(() -> MatcherAssert.assertThat(this.result.getResponseBody(), matcher)); + public T value(Consumer<@Nullable B> consumer) { + this.result.assertWithDiagnostics(() -> consumer.accept(this.result.getResponseBody())); return self(); } @Override - public T value(Function<@Nullable B, @Nullable R> bodyMapper, Matcher matcher) { + public T value(Function<@Nullable B, @Nullable R> bodyMapper, Consumer consumer) { this.result.assertWithDiagnostics(() -> { B body = this.result.getResponseBody(); - MatcherAssert.assertThat(bodyMapper.apply(body), matcher); + consumer.accept(bodyMapper.apply(body)); }); return self(); } - @Override - public T value(Consumer<@Nullable B> consumer) { - this.result.assertWithDiagnostics(() -> consumer.accept(this.result.getResponseBody())); - return self(); - } - @Override public T consumeWith(Consumer> consumer) { this.result.assertWithDiagnostics(() -> consumer.accept(this.result)); diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java index f1de99fd43e..9a9af7b797c 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java @@ -24,7 +24,6 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; -import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; import org.springframework.core.ParameterizedTypeReference; @@ -682,20 +681,15 @@ public interface RestTestClient { T isEqualTo(@Nullable B expected); /** - * Assert the extracted body with a {@link Matcher}. + * Assert the extracted body with a {@link Consumer}. */ - T value(Matcher matcher); + T value(Consumer<@Nullable B> consumer); /** * Transform the extracted the body with a function, for example, extracting a - * property, and assert the mapped value with a {@link Matcher}. + * property, and assert the mapped value with a {@link Consumer}. */ - T value(Function<@Nullable B, @Nullable R> bodyMapper, Matcher matcher); - - /** - * Assert the extracted body with a {@link Consumer}. - */ - T value(Consumer<@Nullable B> consumer); + T value(Function<@Nullable B, @Nullable R> bodyMapper, Consumer consumer); /** * Assert the exchange result with the given {@link Consumer}. diff --git a/spring-test/src/main/java/org/springframework/test/web/support/AbstractCookieAssertions.java b/spring-test/src/main/java/org/springframework/test/web/support/AbstractCookieAssertions.java index e564b8b9117..81985ae40a7 100644 --- a/spring-test/src/main/java/org/springframework/test/web/support/AbstractCookieAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/support/AbstractCookieAssertions.java @@ -19,14 +19,10 @@ package org.springframework.test.web.support; import java.time.Duration; import java.util.function.Consumer; -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; - import org.springframework.http.ResponseCookie; import org.springframework.test.util.AssertionErrors; import org.springframework.util.MultiValueMap; -import static org.hamcrest.MatcherAssert.assertThat; import static org.springframework.test.util.AssertionErrors.assertEquals; import static org.springframework.test.util.AssertionErrors.fail; @@ -59,6 +55,13 @@ public abstract class AbstractCookieAssertions { return this.exchangeResult; } + /** + * Return the response spec. + */ + protected R getResponseSpec() { + return this.responseSpec; + } + /** * Subclasses must implement this to provide access to response cookies. */ @@ -83,19 +86,6 @@ public abstract class AbstractCookieAssertions { return this.responseSpec; } - /** - * Assert the value of the response cookie with the given name with a Hamcrest - * {@link Matcher}. - */ - public R value(String name, Matcher matcher) { - String value = getCookie(name).getValue(); - assertWithDiagnostics(() -> { - String message = getMessage(name); - MatcherAssert.assertThat(message, value, matcher); - }); - return this.responseSpec; - } - /** * Consume the value of the response cookie with the given name. */ @@ -138,14 +128,11 @@ public abstract class AbstractCookieAssertions { } /** - * Assert a cookie's "Max-Age" attribute with a Hamcrest {@link Matcher}. + * Assert a cookie's "Max-Age" attribute with a {@link Consumer}. */ - public R maxAge(String name, Matcher matcher) { + public R maxAge(String name, Consumer consumer) { long maxAge = getCookie(name).getMaxAge().getSeconds(); - assertWithDiagnostics(() -> { - String message = getMessage(name) + " maxAge"; - assertThat(message, maxAge, matcher); - }); + assertWithDiagnostics(() -> consumer.accept(maxAge)); return this.responseSpec; } @@ -161,17 +148,12 @@ public abstract class AbstractCookieAssertions { return this.responseSpec; } - - /** - * Assert a cookie's "Path" attribute with a Hamcrest {@link Matcher}. + * Assert a cookie's "Path" attribute with a {@link Consumer}. */ - public R path(String name, Matcher matcher) { + public R path(String name, Consumer consumer) { String path = getCookie(name).getPath(); - assertWithDiagnostics(() -> { - String message = getMessage(name) + " path"; - assertThat(message, path, matcher); - }); + assertWithDiagnostics(() -> consumer.accept(path)); return this.responseSpec; } @@ -188,14 +170,11 @@ public abstract class AbstractCookieAssertions { } /** - * Assert a cookie's "Domain" attribute with a Hamcrest {@link Matcher}. + * Assert a cookie's "Domain" attribute with a {@link Consumer}. */ - public R domain(String name, Matcher matcher) { + public R domain(String name, Consumer consumer) { String domain = getCookie(name).getDomain(); - assertWithDiagnostics(() -> { - String message = getMessage(name) + " domain"; - assertThat(message, domain, matcher); - }); + assertWithDiagnostics(() -> consumer.accept(domain)); return this.responseSpec; } @@ -247,7 +226,7 @@ public abstract class AbstractCookieAssertions { return this.responseSpec; } - private ResponseCookie getCookie(String name) { + protected ResponseCookie getCookie(String name) { ResponseCookie cookie = getResponseCookies().getFirst(name); if (cookie != null) { return cookie; @@ -258,7 +237,7 @@ public abstract class AbstractCookieAssertions { throw new IllegalStateException("This code path should not be reachable"); } - private static String getMessage(String cookie) { + protected String getMessage(String cookie) { return "Response cookie '" + cookie + "'"; } } diff --git a/spring-test/src/main/java/org/springframework/test/web/support/AbstractHeaderAssertions.java b/spring-test/src/main/java/org/springframework/test/web/support/AbstractHeaderAssertions.java index 166de6e3860..53018cca374 100644 --- a/spring-test/src/main/java/org/springframework/test/web/support/AbstractHeaderAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/support/AbstractHeaderAssertions.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; import org.springframework.http.CacheControl; @@ -30,7 +29,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils; -import static org.hamcrest.MatcherAssert.assertThat; import static org.springframework.test.util.AssertionErrors.assertEquals; import static org.springframework.test.util.AssertionErrors.assertNotNull; import static org.springframework.test.util.AssertionErrors.assertTrue; @@ -65,6 +63,10 @@ public abstract class AbstractHeaderAssertions { return this.exchangeResult; } + protected R getResponseSpec() { + return this.responseSpec; + } + /** * Subclasses must implement this to provide access to response headers. */ @@ -154,41 +156,13 @@ public abstract class AbstractHeaderAssertions { return this.responseSpec; } - /** - * Assert the first value of the response header with a Hamcrest {@link Matcher}. - * @param name the header name - * @param matcher the matcher to use - */ - public R value(String name, Matcher matcher) { - String value = getResponseHeaders().getFirst(name); - assertWithDiagnostics(() -> { - String message = getMessage(name); - assertThat(message, value, matcher); - }); - return this.responseSpec; - } - - /** - * Assert all values of the response header with a Hamcrest {@link Matcher}. - * @param name the header name - * @param matcher the matcher to use - */ - public R values(String name, Matcher> matcher) { - List values = getResponseHeaders().get(name); - assertWithDiagnostics(() -> { - String message = getMessage(name); - assertThat(message, values, matcher); - }); - return this.responseSpec; - } - /** * Consume the first value of the named response header. * @param name the header name * @param consumer the consumer to use */ public R value(String name, Consumer consumer) { - String value = getRequiredValue(name); + String value = getResponseHeaders().getFirst(name); assertWithDiagnostics(() -> consumer.accept(value)); return this.responseSpec; } @@ -199,7 +173,7 @@ public abstract class AbstractHeaderAssertions { * @param consumer the consumer to use */ public R values(String name, Consumer> consumer) { - List values = getRequiredValues(name); + List values = getResponseHeaders().get(name); assertWithDiagnostics(() -> consumer.accept(values)); return this.responseSpec; } @@ -323,7 +297,7 @@ public abstract class AbstractHeaderAssertions { throw new IllegalStateException("This code path should not be reachable"); } - private static String getMessage(String headerName) { + protected String getMessage(String headerName) { return "Response header '" + headerName + "'"; } } diff --git a/spring-test/src/main/java/org/springframework/test/web/support/AbstractJsonPathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/support/AbstractJsonPathAssertions.java index b2e842aec09..13ba41536f8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/support/AbstractJsonPathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/support/AbstractJsonPathAssertions.java @@ -19,7 +19,6 @@ package org.springframework.test.web.support; import java.util.function.Consumer; import com.jayway.jsonpath.Configuration; -import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; import org.springframework.core.ParameterizedTypeReference; @@ -55,6 +54,19 @@ public abstract class AbstractJsonPathAssertions { } + protected B getBodySpec() { + return this.bodySpec; + } + + protected String getContent() { + return this.content; + } + + protected JsonPathExpectationsHelper getPathHelper() { + return this.pathHelper; + } + + /** * Applies {@link JsonPathExpectationsHelper#assertValue(String, Object)}. */ @@ -143,30 +155,6 @@ public abstract class AbstractJsonPathAssertions { return this.bodySpec; } - /** - * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher)}. - */ - public B value(Matcher matcher) { - this.pathHelper.assertValue(this.content, matcher); - return this.bodySpec; - } - - /** - * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, Class)}. - */ - public B value(Class targetType, Matcher matcher) { - this.pathHelper.assertValue(this.content, matcher, targetType); - return this.bodySpec; - } - - /** - * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, ParameterizedTypeReference)}. - */ - public B value(ParameterizedTypeReference targetType, Matcher matcher) { - this.pathHelper.assertValue(this.content, matcher, targetType); - return this.bodySpec; - } - /** * Consume the result of the JSONPath evaluation. */ diff --git a/spring-test/src/main/java/org/springframework/test/web/support/AbstractStatusAssertions.java b/spring-test/src/main/java/org/springframework/test/web/support/AbstractStatusAssertions.java index 9573e11920f..7384903542f 100644 --- a/spring-test/src/main/java/org/springframework/test/web/support/AbstractStatusAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/support/AbstractStatusAssertions.java @@ -18,9 +18,6 @@ package org.springframework.test.web.support; import java.util.function.Consumer; -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; - import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.test.util.AssertionErrors; @@ -56,6 +53,10 @@ public abstract class AbstractStatusAssertions { return this.exchangeResult; } + protected R getResponseSpec() { + return this.responseSpec; + } + /** * Subclasses must implement this to provide access to the response status. */ @@ -229,16 +230,6 @@ public abstract class AbstractStatusAssertions { return assertSeriesAndReturn(HttpStatus.Series.SERVER_ERROR); } - /** - * Match the response status value with a Hamcrest matcher. - * @param matcher the matcher to use - */ - public R value(Matcher matcher) { - int actual = getStatus().value(); - assertWithDiagnostics(() -> MatcherAssert.assertThat("Response status", actual, matcher)); - return this.responseSpec; - } - /** * Consume the response status value as an integer. * @param consumer the consumer to use diff --git a/spring-test/src/main/java/org/springframework/test/web/support/AbstractXpathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/support/AbstractXpathAssertions.java index 4614d7dec3f..4b351566ec6 100644 --- a/spring-test/src/main/java/org/springframework/test/web/support/AbstractXpathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/support/AbstractXpathAssertions.java @@ -23,8 +23,8 @@ import java.util.function.Consumer; import javax.xml.xpath.XPathExpressionException; -import org.hamcrest.Matcher; import org.jspecify.annotations.Nullable; +import org.w3c.dom.NodeList; import org.springframework.http.HttpHeaders; import org.springframework.test.util.XpathExpectationsHelper; @@ -71,6 +71,13 @@ public abstract class AbstractXpathAssertions { return this.bodySpec; } + /** + * Return the XpathExpectationsHelper. + */ + protected XpathExpectationsHelper getXpathHelper() { + return this.xpathHelper; + } + /** * Subclasses must implement this to provide access to response headers. */ @@ -124,27 +131,6 @@ public abstract class AbstractXpathAssertions { return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), expectedCount)); } - /** - * Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, Matcher)}. - */ - public B string(Matcher matcher){ - return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), matcher)); - } - - /** - * Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Matcher)}. - */ - public B number(Matcher matcher){ - return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), matcher)); - } - - /** - * Delegates to {@link XpathExpectationsHelper#assertNodeCount(byte[], String, Matcher)}. - */ - public B nodeCount(Matcher matcher){ - return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), matcher)); - } - /** * Consume the result of the XPath evaluation as a String. */ @@ -170,12 +156,13 @@ public abstract class AbstractXpathAssertions { */ public B nodeCount(Consumer consumer){ return assertWith(() -> { - Integer value = this.xpathHelper.evaluateXpath(getContent(), getCharset(), Integer.class); + NodeList nodeList = this.xpathHelper.evaluateXpath(getContent(), getCharset(), NodeList.class); + Integer value = (nodeList != null ? nodeList.getLength() : null); consumer.accept(value); }); } - private B assertWith(CheckedExceptionTask task) { + protected B assertWith(CheckedExceptionTask task) { try { task.run(); } @@ -185,7 +172,7 @@ public abstract class AbstractXpathAssertions { return this.bodySpec; } - private String getCharset() { + protected String getCharset() { return getResponseHeaders() .map(HttpHeaders::getContentType) .map(MimeType::getCharset) @@ -210,7 +197,7 @@ public abstract class AbstractXpathAssertions { * Lets us be able to use lambda expressions that could throw checked exceptions, since * {@link XpathExpectationsHelper} throws {@link Exception} on its methods. */ - private interface CheckedExceptionTask { + protected interface CheckedExceptionTask { void run() throws Exception; diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java index a63e649418d..02af4e88e08 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; @@ -101,8 +102,8 @@ class JsonPathAssertionTests { .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON) .expectBody() - .jsonPath("$.composers[0].name").value(equalTo("Johann Sebastian Bach")) - .jsonPath("$.performers[1].name").value(equalTo("Yehudi Menuhin")); + .jsonPath("$.composers[0].name").value(v -> MatcherAssert.assertThat(v, equalTo("Johann Sebastian Bach"))) + .jsonPath("$.performers[1].name").value(v -> MatcherAssert.assertThat(v, equalTo("Yehudi Menuhin"))); } @Test @@ -110,10 +111,10 @@ class JsonPathAssertionTests { client.get().uri("/music/people") .exchange() .expectBody() - .jsonPath("$.composers[0].name").value(startsWith("Johann")) - .jsonPath("$.performers[0].name").value(endsWith("Ashkenazy")) - .jsonPath("$.performers[1].name").value(containsString("di Me")) - .jsonPath("$.composers[1].name").value(is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms")))); + .jsonPath("$.composers[0].name").value(String.class, v -> MatcherAssert.assertThat(v, startsWith("Johann"))) + .jsonPath("$.performers[0].name").value(String.class, v -> MatcherAssert.assertThat(v, endsWith("Ashkenazy"))) + .jsonPath("$.performers[1].name").value(String.class, v -> MatcherAssert.assertThat(v, containsString("di Me"))) + .jsonPath("$.composers[1].name").value(v -> MatcherAssert.assertThat(v, is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms"))))); } @Test @@ -121,11 +122,11 @@ class JsonPathAssertionTests { client.get().uri("/music/people") .exchange() .expectBody() - .jsonPath("$.composers[0].name").value(String.class, startsWith("Johann")) + .jsonPath("$.composers[0].name").value(String.class, v -> MatcherAssert.assertThat(v, startsWith("Johann"))) .jsonPath("$.composers[0].name").value(String.class, s -> assertThat(s).startsWith("Johann")) .jsonPath("$.composers[0].name").value(o -> assertThat((String) o).startsWith("Johann")) - .jsonPath("$.performers[1].name").value(containsString("di Me")) - .jsonPath("$.composers[1].name").value(is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms")))); + .jsonPath("$.performers[1].name").value(String.class, v -> MatcherAssert.assertThat(v, containsString("di Me"))) + .jsonPath("$.composers[1].name").value(v -> MatcherAssert.assertThat(v, is(in(Arrays.asList("Johann Sebastian Bach", "Johannes Brahms"))))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/RestTestClientTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/RestTestClientTests.java index ee1393c16b1..08f9a23289d 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/RestTestClientTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/RestTestClientTests.java @@ -25,7 +25,7 @@ import java.util.Map; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.hamcrest.Matchers; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -44,6 +44,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.util.DefaultUriBuilderFactory; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.equalTo; /** * Tests using the {@link RestTestClient} API. @@ -285,7 +286,7 @@ class RestTestClientTests { void testExpectCookie() { RestTestClientTests.this.client.get().uri("/test") .exchange() - .expectCookie().value("session", Matchers.equalTo("abc")); + .expectCookie().value("session", v -> MatcherAssert.assertThat(v, equalTo("abc"))); } } diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java index 978b7a708bd..efcf21d3163 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java @@ -19,6 +19,7 @@ package org.springframework.test.web.servlet.client.samples; import java.net.URI; import java.util.List; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; @@ -111,7 +112,7 @@ class JsonContentTests { .exchange() .expectStatus().isOk() .expectBody() - .jsonPath("$.firstName").value(containsString("oh")); + .jsonPath("$.firstName").value(String.class, v -> MatcherAssert.assertThat(v, containsString("oh"))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java index 40dfb6d49f0..c66e2169311 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java @@ -21,6 +21,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.core.ParameterizedTypeReference; @@ -64,7 +65,7 @@ class ResponseEntityTests { .exchange() .expectStatus().isOk() .expectHeader().contentType(MediaType.APPLICATION_JSON) - .expectBody(Person.class).value(Person::getName, startsWith("Joh")); + .expectBody(Person.class).value(Person::getName, name -> MatcherAssert.assertThat(name, startsWith("Joh"))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java index d960406c732..ee12416dc71 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java @@ -25,6 +25,7 @@ import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; @@ -104,7 +105,7 @@ class XmlContentTests { .expectStatus().isOk() .expectBody() .xpath("/persons/person").nodeCount(3) - .xpath("/persons/person").nodeCount(equalTo(3)); + .xpath("/persons/person").nodeCount(count -> MatcherAssert.assertThat(count, equalTo(3))); } @Test @@ -114,10 +115,10 @@ class XmlContentTests { .exchange() .expectStatus().isOk() .expectBody() - .xpath("//person/name").string(startsWith("J")) - .xpath("//person/name").string(s -> { - if (!s.startsWith("J")) { - throw new AssertionError("Name does not start with J: " + s); + .xpath("//person/name").string(name -> MatcherAssert.assertThat(name, startsWith("J"))) + .xpath("//person/name").string(name -> { + if (!name.startsWith("J")) { + throw new AssertionError("Name does not start with J: " + name); } }); } diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/ResponseBodyTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/ResponseBodyTests.java index 53451c62652..565b0ccb2b5 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/ResponseBodyTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/ResponseBodyTests.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.function.Consumer; import jakarta.validation.constraints.NotNull; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.core.ParameterizedTypeReference; @@ -46,8 +47,8 @@ class ResponseBodyTests { void json() { execute("/persons/Lee", body -> body.jsonPath("$.name").isEqualTo("Lee") .jsonPath("$.age").isEqualTo(42) - .jsonPath("$.age").value(equalTo(42)) - .jsonPath("$.age").value(Float.class, equalTo(42.0f))); + .jsonPath("$.age").value(v -> MatcherAssert.assertThat(v, equalTo(42))) + .jsonPath("$.age").value(Float.class, v -> MatcherAssert.assertThat(v, equalTo(42.0f)))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/CookieAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/CookieAssertionTests.java index 8a88f246043..15ecd6d3a04 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/CookieAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/CookieAssertionTests.java @@ -18,6 +18,7 @@ package org.springframework.test.web.servlet.samples.client.standalone.resultmat import java.time.Duration; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -75,12 +76,14 @@ public class CookieAssertionTests { @Test public void testEqualTo() { client.get().uri("/").exchange().expectCookie().valueEquals(COOKIE_NAME, "en-US"); - client.get().uri("/").exchange().expectCookie().value(COOKIE_NAME, equalTo("en-US")); + client.get().uri("/").exchange().expectCookie() + .value(COOKIE_NAME, v -> MatcherAssert.assertThat(v, equalTo("en-US"))); } @Test public void testMatcher() { - client.get().uri("/").exchange().expectCookie().value(COOKIE_NAME, startsWith("en-US")); + client.get().uri("/").exchange().expectCookie() + .value(COOKIE_NAME, v -> MatcherAssert.assertThat(v, startsWith("en-US"))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java index ecadf8cf5b2..2b81ebb2e08 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/HeaderAssertionTests.java @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.TimeZone; import java.util.function.Consumer; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -90,7 +91,7 @@ class HeaderAssertionTests { testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo) .exchange() .expectStatus().isOk() - .expectHeader().value(LAST_MODIFIED, equalTo(now)); + .expectHeader().value(LAST_MODIFIED, v -> MatcherAssert.assertThat(v, equalTo(now))); } @Test @@ -106,7 +107,8 @@ class HeaderAssertionTests { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() - .expectHeader().values(VARY, hasItems(containsString("foo"), startsWith("bar"))); + .expectHeader().values(VARY, v -> + MatcherAssert.assertThat(v, hasItems(containsString("foo"), startsWith("bar")))); } @Test @@ -140,7 +142,7 @@ class HeaderAssertionTests { testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) .exchange() .expectStatus().isNotModified() - .expectHeader().value("X-Custom-Header", nullValue()); + .expectHeader().value("X-Custom-Header", v -> MatcherAssert.assertThat(v, nullValue())); } @Test @@ -202,8 +204,11 @@ class HeaderAssertionTests { long secondLater = this.currentTime + 1000; String expected = this.dateFormat.format(new Date(secondLater)); assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEquals(LAST_MODIFIED, expected), expected); - assertIncorrectResponseHeader(spec -> spec.expectHeader().value(LAST_MODIFIED, equalTo(expected)), expected); - // Comparison by date uses HttpHeaders to format the date in the error message. + assertIncorrectResponseHeader(spec -> spec.expectHeader().value(LAST_MODIFIED, value -> { + // Comparison by date uses HttpHeaders to format the date in the error message. + String reason = "Response header '" + LAST_MODIFIED + "'"; + MatcherAssert.assertThat(reason, value, equalTo(expected)); + }), expected); HttpHeaders headers = new HttpHeaders(); headers.setDate("expected", secondLater); assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEqualsDate(LAST_MODIFIED, secondLater), expected); diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/StatusAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/StatusAssertionTests.java index 70432654359..40bf5829916 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/StatusAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/resultmatches/StatusAssertionTests.java @@ -19,6 +19,7 @@ package org.springframework.test.web.servlet.samples.client.standalone.resultmat import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -71,7 +72,8 @@ class StatusAssertionTests { @Test void matcher() { - testClient.get().uri("/badRequest").exchange().expectStatus().value(equalTo(BAD_REQUEST.value())); + testClient.get().uri("/badRequest").exchange().expectStatus() + .value(status -> MatcherAssert.assertThat(status, equalTo(BAD_REQUEST.value()))); } diff --git a/spring-test/src/test/java/org/springframework/test/web/support/CookieAssertionsTests.java b/spring-test/src/test/java/org/springframework/test/web/support/CookieAssertionsTests.java index 6762e1cb8a1..0f75ce95e1c 100644 --- a/spring-test/src/test/java/org/springframework/test/web/support/CookieAssertionsTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/support/CookieAssertionsTests.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.time.Duration; import java.util.Map; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -67,8 +68,9 @@ public class CookieAssertionsTests { @Test void value() { - assertions.value("foo", equalTo("bar")); - assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value("foo", equalTo("what?!"))); + assertions.value("foo", v -> MatcherAssert.assertThat(v, equalTo("bar"))); + assertThatExceptionOfType(AssertionError.class) + .isThrownBy(() -> assertions.value("foo", v -> MatcherAssert.assertThat(v, equalTo("what?!")))); } @Test @@ -96,9 +98,9 @@ public class CookieAssertionsTests { assertThatExceptionOfType(AssertionError.class) .isThrownBy(() -> assertions.maxAge("foo", Duration.ofMinutes(29))); - assertions.maxAge("foo", equalTo(Duration.ofMinutes(30).getSeconds())); - assertThatExceptionOfType(AssertionError.class) - .isThrownBy(() -> assertions.maxAge("foo", equalTo(Duration.ofMinutes(29).getSeconds()))); + assertions.maxAge("foo", v -> MatcherAssert.assertThat(v, equalTo(Duration.ofMinutes(30).getSeconds()))); + assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> + assertions.maxAge("foo", v -> MatcherAssert.assertThat(v, equalTo(Duration.ofMinutes(29).getSeconds())))); } @Test @@ -106,8 +108,9 @@ public class CookieAssertionsTests { assertions.domain("foo", "foo.com"); assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", "what.com")); - assertions.domain("foo", equalTo("foo.com")); - assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.domain("foo", equalTo("what.com"))); + assertions.domain("foo", v -> MatcherAssert.assertThat(v, equalTo("foo.com"))); + assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> + assertions.domain("foo", v -> MatcherAssert.assertThat(v, equalTo("what.com")))); } @Test @@ -115,8 +118,9 @@ public class CookieAssertionsTests { assertions.path("foo", "/foo"); assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", "/what")); - assertions.path("foo", equalTo("/foo")); - assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.path("foo", equalTo("/what"))); + assertions.path("foo", v -> MatcherAssert.assertThat(v, equalTo("/foo"))); + assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> + assertions.path("foo", v -> MatcherAssert.assertThat(v, equalTo("/what")))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/support/HeaderAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/support/HeaderAssertionTests.java index 01e6138adea..903b3fbf9ef 100644 --- a/spring-test/src/test/java/org/springframework/test/web/support/HeaderAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/support/HeaderAssertionTests.java @@ -21,6 +21,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.concurrent.TimeUnit; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.http.CacheControl; @@ -142,7 +143,7 @@ class HeaderAssertionTests { headers.add("foo", "bar"); TestHeaderAssertions assertions = new TestHeaderAssertions(headers); - assertions.value("foo", containsString("a")); + assertions.value("foo", v -> MatcherAssert.assertThat(v, containsString("a"))); } @Test @@ -152,7 +153,7 @@ class HeaderAssertionTests { headers.add("foo", "baz"); TestHeaderAssertions assertions = new TestHeaderAssertions(headers); - assertions.values("foo", hasItems("bar", "baz")); + assertions.values("foo", v -> MatcherAssert.assertThat(v, hasItems("bar", "baz"))); } @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/support/StatusAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/support/StatusAssertionTests.java index 72b3904ca0f..eb67e5d3320 100644 --- a/spring-test/src/test/java/org/springframework/test/web/support/StatusAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/support/StatusAssertionTests.java @@ -16,6 +16,7 @@ package org.springframework.test.web.support; +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; @@ -141,16 +142,17 @@ class StatusAssertionTests { TestStatusAssertions assertions = new TestStatusAssertions(HttpStatus.CONFLICT); // Success - assertions.value(equalTo(409)); - assertions.value(greaterThan(400)); + assertions.value(v -> MatcherAssert.assertThat(v, equalTo(409))); + assertions.value(v -> MatcherAssert.assertThat(v, greaterThan(400))); // Wrong status - assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertions.value(equalTo(200))); + assertThatExceptionOfType(AssertionError.class) + .isThrownBy(() -> assertions.value(v -> MatcherAssert.assertThat(v, equalTo(200)))); } @Test void matchesCustomStatusValue() { - new TestStatusAssertions(600).value(equalTo(600)); + new TestStatusAssertions(600).value(v -> MatcherAssert.assertThat(v, equalTo(600))); } @Test