From 7211db9262bb7e0362873571ea1b72a0d9dbaac2 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:34:02 +0100 Subject: [PATCH] Polishing --- .../simp/stomp/SplittingStompEncoder.java | 13 ++- .../messaging/simp/stomp/StompDecoder.java | 18 ++-- .../convention/TestBeanOverrideProcessor.java | 23 ++--- .../web/reactive/server/CookieAssertions.java | 52 ++++++----- .../web/reactive/server/HeaderAssertions.java | 43 +++++---- .../bean/override/OverrideMetadataTests.java | 43 +++++---- .../TestBeanOverrideProcessorTests.java | 66 +++++++------ .../resultmatches/HeaderAssertionTests.java | 93 +++++++------------ 8 files changed, 173 insertions(+), 178 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java index a72b7ff0f19..02b3f86422c 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/SplittingStompEncoder.java @@ -24,9 +24,9 @@ import java.util.Map; import org.springframework.util.Assert; /** - * Uses {@link org.springframework.messaging.simp.stomp.StompEncoder} to encode - * a message and splits it into parts no larger than the configured - * {@link SplittingStompEncoder#bufferSizeLimit}. + * Uses a {@link StompEncoder} to encode a message and splits it into parts no + * larger than the configured + * {@linkplain #SplittingStompEncoder(StompEncoder, int) buffer size limit}. * * @author Injae Kim * @author Rossen Stoyanchev @@ -40,6 +40,11 @@ public class SplittingStompEncoder { private final int bufferSizeLimit; + /** + * Create a new {@code SplittingStompEncoder}. + * @param encoder the {@link StompEncoder} to use + * @param bufferSizeLimit the buffer size limit + */ public SplittingStompEncoder(StompEncoder encoder, int bufferSizeLimit) { Assert.notNull(encoder, "StompEncoder is required"); Assert.isTrue(bufferSizeLimit > 0, "Buffer size limit must be greater than 0"); @@ -49,7 +54,7 @@ public class SplittingStompEncoder { /** - * Encode the given payload and headers to a STOMP frame, and split into a + * Encode the given payload and headers to a STOMP frame, and split it into a * list of parts based on the configured buffer size limit. * @param headers the STOMP message headers * @param payload the STOMP message payload diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java index 18f917ca32d..16fbe5dd8f6 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,10 +78,10 @@ public class StompDecoder { * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a * list of {@link Message Messages}. If the input buffer contains partial STOMP frame * content, or additional content with a partial STOMP frame, the buffer is - * reset and an empty list is returned. + * reset, and an empty list is returned. * @param byteBuffer the buffer to decode the STOMP frame from * @return the decoded messages, or an empty list if none - * @throws StompConversionException raised in case of decoding issues + * @throws StompConversionException in case of decoding issues */ public List> decode(ByteBuffer byteBuffer) { return decode(byteBuffer, null); @@ -93,18 +93,18 @@ public class StompDecoder { *

If the given ByteBuffer contains only partial STOMP frame content and no * complete STOMP frames, an empty list is returned, and the buffer is reset * to where it was. - *

If the buffer contains one or more STOMP frames, those are returned and - * the buffer reset to point to the beginning of the unused partial content. - *

The output partialMessageHeaders map is used to store successfully parsed + *

If the buffer contains one or more STOMP frames, those are returned, and + * the buffer is reset to point to the beginning of the unused partial content. + *

The {@code partialMessageHeaders} map is used to store successfully parsed * headers in case of partial content. The caller can then check if a * "content-length" header was read, which helps to determine how much more * content is needed before the next attempt to decode. * @param byteBuffer the buffer to decode the STOMP frame from * @param partialMessageHeaders an empty output map that will store the last - * successfully parsed partialMessageHeaders in case of partial message content + * successfully parsed partial message headers in case of partial message content * in cases where the partial buffer ended with a partial STOMP frame * @return the decoded messages, or an empty list if none - * @throws StompConversionException raised in case of decoding issues + * @throws StompConversionException in case of decoding issues */ public List> decode(ByteBuffer byteBuffer, @Nullable MultiValueMap partialMessageHeaders) { @@ -127,7 +127,7 @@ public class StompDecoder { } /** - * Decode a single STOMP frame from the given {@code buffer} into a {@link Message}. + * Decode a single STOMP frame from the given {@code byteBuffer} into a {@link Message}. */ @Nullable private Message decodeMessage(ByteBuffer byteBuffer, @Nullable MultiValueMap headers) { diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java index f62b70d215c..4e5bb1d7745 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessor.java @@ -56,10 +56,10 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { Assert.isTrue(expectedMethodNames.length > 0, "At least one expectedMethodName is required"); Set expectedNames = new LinkedHashSet<>(Arrays.asList(expectedMethodNames)); - final List found = Arrays.stream(enclosingClass.getDeclaredMethods()) - .filter(method -> Modifier.isStatic(method.getModifiers())) - .filter(method -> expectedNames.contains(method.getName()) - && expectedMethodReturnType.isAssignableFrom(method.getReturnType())) + List found = Arrays.stream(enclosingClass.getDeclaredMethods()) + .filter(method -> Modifier.isStatic(method.getModifiers()) && + expectedNames.contains(method.getName()) && + expectedMethodReturnType.isAssignableFrom(method.getReturnType())) .toList(); Assert.state(found.size() == 1, () -> "Found " + found.size() + " static methods " + @@ -71,13 +71,13 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { @Override public OverrideMetadata createMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride) { - final Class enclosingClass = field.getDeclaringClass(); - // if we can get an explicit method name right away, fail fast if it doesn't match + Class declaringClass = field.getDeclaringClass(); + // If we can, get an explicit method name right away; fail fast if it doesn't match. if (overrideAnnotation instanceof TestBean testBeanAnnotation) { Method overrideMethod = null; String beanName = null; if (!testBeanAnnotation.methodName().isBlank()) { - overrideMethod = ensureMethod(enclosingClass, field.getType(), testBeanAnnotation.methodName()); + overrideMethod = ensureMethod(declaringClass, field.getType(), testBeanAnnotation.methodName()); } if (!testBeanAnnotation.name().isBlank()) { beanName = testBeanAnnotation.name(); @@ -85,9 +85,8 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { return new MethodConventionOverrideMetadata(field, overrideMethod, beanName, overrideAnnotation, typeToOverride); } - // otherwise defer the resolution of the static method until OverrideMetadata#createOverride - return new MethodConventionOverrideMetadata(field, null, null, overrideAnnotation, - typeToOverride); + // Otherwise defer the resolution of the static method until OverrideMetadata#createOverride. + return new MethodConventionOverrideMetadata(field, null, null, overrideAnnotation, typeToOverride); } static final class MethodConventionOverrideMetadata extends OverrideMetadata { @@ -100,6 +99,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { public MethodConventionOverrideMetadata(Field field, @Nullable Method overrideMethod, @Nullable String beanName, Annotation overrideAnnotation, ResolvableType typeToOverride) { + super(field, overrideAnnotation, typeToOverride, BeanOverrideStrategy.REPLACE_DEFINITION); this.overrideMethod = overrideMethod; this.beanName = beanName; @@ -121,6 +121,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { @Override protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, @Nullable Object existingBeanInstance) { + Method methodToInvoke = this.overrideMethod; if (methodToInvoke == null) { methodToInvoke = ensureMethod(field().getDeclaringClass(), field().getType(), @@ -135,7 +136,7 @@ public class TestBeanOverrideProcessor implements BeanOverrideProcessor { } catch (IllegalAccessException | InvocationTargetException ex) { throw new IllegalArgumentException("Could not invoke bean overriding method " + methodToInvoke.getName() + - ", a static method with no input parameters is expected", ex); + "; a static method with no formal parameters is expected", ex); } return override; 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 f9804915f72..d87162e1f61 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,10 @@ import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; import org.springframework.http.ResponseCookie; -import org.springframework.test.util.AssertionErrors; import static org.hamcrest.MatcherAssert.assertThat; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.fail; /** * Assertions on cookies of the response. @@ -48,18 +49,20 @@ public class CookieAssertions { /** - * Expect a header with the given name to match the specified values. + * Expect a response cookie with the given name to match the specified value. */ public WebTestClient.ResponseSpec valueEquals(String name, String value) { + String cookieValue = getCookie(name).getValue(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name); - AssertionErrors.assertEquals(message, value, getCookie(name).getValue()); + assertEquals(message, value, cookieValue); }); return this.responseSpec; } /** - * Assert the first value of the response cookie with a Hamcrest {@link Matcher}. + * Assert the value of the response cookie with the given name with a Hamcrest + * {@link Matcher}. */ public WebTestClient.ResponseSpec value(String name, Matcher matcher) { String value = getCookie(name).getValue(); @@ -71,7 +74,7 @@ public class CookieAssertions { } /** - * Consume the value of the response cookie. + * Consume the value of the response cookie with the given name. */ public WebTestClient.ResponseSpec value(String name, Consumer consumer) { String value = getCookie(name).getValue(); @@ -94,25 +97,25 @@ public class CookieAssertions { ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name); if (cookie != null) { String message = getMessage(name) + " exists with value=[" + cookie.getValue() + "]"; - this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); + this.exchangeResult.assertWithDiagnostics(() -> fail(message)); } return this.responseSpec; } /** - * Assert a cookie's maxAge attribute. + * Assert a cookie's "Max-Age" attribute. */ public WebTestClient.ResponseSpec maxAge(String name, Duration expected) { Duration maxAge = getCookie(name).getMaxAge(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " maxAge"; - AssertionErrors.assertEquals(message, expected, maxAge); + assertEquals(message, expected, maxAge); }); return this.responseSpec; } /** - * Assert a cookie's maxAge attribute with a Hamcrest {@link Matcher}. + * 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(); @@ -124,19 +127,19 @@ public class CookieAssertions { } /** - * Assert a cookie's path attribute. + * Assert a cookie's "Path" attribute. */ public WebTestClient.ResponseSpec path(String name, String expected) { String path = getCookie(name).getPath(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " path"; - AssertionErrors.assertEquals(message, expected, path); + assertEquals(message, expected, path); }); return this.responseSpec; } /** - * Assert a cookie's path attribute with a Hamcrest {@link Matcher}. + * Assert a cookie's "Path" attribute with a Hamcrest {@link Matcher}. */ public WebTestClient.ResponseSpec path(String name, Matcher matcher) { String path = getCookie(name).getPath(); @@ -148,19 +151,19 @@ public class CookieAssertions { } /** - * Assert a cookie's domain attribute. + * Assert a cookie's "Domain" attribute. */ public WebTestClient.ResponseSpec domain(String name, String expected) { String path = getCookie(name).getDomain(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " domain"; - AssertionErrors.assertEquals(message, expected, path); + assertEquals(message, expected, path); }); return this.responseSpec; } /** - * Assert a cookie's domain attribute with a Hamcrest {@link Matcher}. + * Assert a cookie's "Domain" attribute with a Hamcrest {@link Matcher}. */ public WebTestClient.ResponseSpec domain(String name, Matcher matcher) { String domain = getCookie(name).getDomain(); @@ -172,37 +175,37 @@ public class CookieAssertions { } /** - * Assert a cookie's secure attribute. + * Assert a cookie's "Secure" attribute. */ public WebTestClient.ResponseSpec secure(String name, boolean expected) { boolean isSecure = getCookie(name).isSecure(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " secure"; - AssertionErrors.assertEquals(message, expected, isSecure); + assertEquals(message, expected, isSecure); }); return this.responseSpec; } /** - * Assert a cookie's httpOnly attribute. + * Assert a cookie's "HttpOnly" attribute. */ public WebTestClient.ResponseSpec httpOnly(String name, boolean expected) { boolean isHttpOnly = getCookie(name).isHttpOnly(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " httpOnly"; - AssertionErrors.assertEquals(message, expected, isHttpOnly); + assertEquals(message, expected, isHttpOnly); }); return this.responseSpec; } /** - * Assert a cookie's sameSite attribute. + * Assert a cookie's "SameSite" attribute. */ public WebTestClient.ResponseSpec sameSite(String name, String expected) { String sameSite = getCookie(name).getSameSite(); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name) + " sameSite"; - AssertionErrors.assertEquals(message, expected, sameSite); + assertEquals(message, expected, sameSite); }); return this.responseSpec; } @@ -211,13 +214,12 @@ public class CookieAssertions { private ResponseCookie getCookie(String name) { ResponseCookie cookie = this.exchangeResult.getResponseCookies().getFirst(name); if (cookie == null) { - this.exchangeResult.assertWithDiagnostics(() -> - AssertionErrors.fail("No cookie with name '" + name + "'")); + this.exchangeResult.assertWithDiagnostics(() -> fail("No cookie with name '" + name + "'")); } return Objects.requireNonNull(cookie); } - private String getMessage(String cookie) { + private static String getMessage(String cookie) { return "Response cookie '" + cookie + "'"; } 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 c3750d27c3c..66ac0730a25 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,19 +23,19 @@ import java.util.Objects; import java.util.function.Consumer; import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; import org.springframework.http.CacheControl; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; -import org.springframework.test.util.AssertionErrors; 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; +import static org.springframework.test.util.AssertionErrors.fail; /** * Assertions on headers of the response. @@ -73,8 +73,8 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec valueEquals(String headerName, long value) { String actual = getHeaders().getFirst(headerName); this.exchangeResult.assertWithDiagnostics(() -> - assertTrue("Response does not contain header '" + headerName + "'", actual != null)); - return assertHeader(headerName, value, Long.parseLong(Objects.requireNonNull(actual))); + assertNotNull("Response does not contain header '" + headerName + "'", actual)); + return assertHeader(headerName, value, Long.parseLong(actual)); } /** @@ -94,7 +94,7 @@ public class HeaderAssertions { headers.setDate("expected", value); headers.set("actual", headerValue); - assertEquals("Response header '" + headerName + "'='" + headerValue + "' " + + assertEquals(getMessage(headerName) + "='" + headerValue + "' " + "does not match expected value '" + headers.getFirst("expected") + "'", headers.getFirstDate("expected"), headers.getFirstDate("actual")); }); @@ -109,7 +109,7 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec valueMatches(String name, String pattern) { String value = getRequiredValue(name); String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]"; - this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, value.matches(pattern))); + this.exchangeResult.assertWithDiagnostics(() -> assertTrue(message, value.matches(pattern))); return this.responseSpec; } @@ -123,16 +123,16 @@ public class HeaderAssertions { * @since 5.3 */ public WebTestClient.ResponseSpec valuesMatch(String name, String... patterns) { + List values = getRequiredValues(name); this.exchangeResult.assertWithDiagnostics(() -> { - List values = getRequiredValues(name); - AssertionErrors.assertTrue( + assertTrue( getMessage(name) + " has fewer or more values " + values + " than number of patterns to match with " + Arrays.toString(patterns), values.size() == patterns.length); for (int i = 0; i < values.size(); i++) { String value = values.get(i); String pattern = patterns[i]; - AssertionErrors.assertTrue( + assertTrue( getMessage(name) + "[" + i + "]='" + value + "' does not match '" + pattern + "'", value.matches(pattern)); } @@ -150,7 +150,7 @@ public class HeaderAssertions { String value = getHeaders().getFirst(name); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name); - MatcherAssert.assertThat(message, value, matcher); + assertThat(message, value, matcher); }); return this.responseSpec; } @@ -165,7 +165,7 @@ public class HeaderAssertions { List values = getHeaders().get(name); this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name); - MatcherAssert.assertThat(message, values, matcher); + assertThat(message, values, matcher); }); return this.responseSpec; } @@ -201,8 +201,7 @@ public class HeaderAssertions { private List getRequiredValues(String name) { List values = getHeaders().get(name); if (CollectionUtils.isEmpty(values)) { - this.exchangeResult.assertWithDiagnostics(() -> - AssertionErrors.fail(getMessage(name) + " not found")); + this.exchangeResult.assertWithDiagnostics(() -> fail(getMessage(name) + " not found")); } return Objects.requireNonNull(values); } @@ -214,7 +213,7 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec exists(String name) { if (!getHeaders().containsKey(name)) { String message = getMessage(name) + " does not exist"; - this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); + this.exchangeResult.assertWithDiagnostics(() -> fail(message)); } return this.responseSpec; } @@ -225,7 +224,7 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec doesNotExist(String name) { if (getHeaders().containsKey(name)) { String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(name) + "]"; - this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); + this.exchangeResult.assertWithDiagnostics(() -> fail(message)); } return this.responseSpec; } @@ -272,7 +271,7 @@ public class HeaderAssertions { MediaType actual = getHeaders().getContentType(); String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; this.exchangeResult.assertWithDiagnostics(() -> - AssertionErrors.assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); + assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); return this.responseSpec; } @@ -310,16 +309,16 @@ public class HeaderAssertions { return this.exchangeResult.getResponseHeaders(); } - private String getMessage(String headerName) { - return "Response header '" + headerName + "'"; - } - private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { this.exchangeResult.assertWithDiagnostics(() -> { String message = getMessage(name); - AssertionErrors.assertEquals(message, expected, actual); + assertEquals(message, expected, actual); }); return this.responseSpec; } + private static String getMessage(String headerName) { + return "Response header '" + headerName + "'"; + } + } diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java index feb9cf9a4b6..731250bcb4f 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/OverrideMetadataTests.java @@ -29,12 +29,35 @@ import org.springframework.lang.Nullable; import static org.assertj.core.api.Assertions.assertThat; +/** + * Tests for {@link OverrideMetadata}. + * + * @author Simon Baslé + * @since 6.2 + */ class OverrideMetadataTests { + @Test + void implicitConfigurations() throws Exception { + OverrideMetadata metadata = exampleOverride(); + assertThat(metadata.getExpectedBeanName()).as("expectedBeanName").isEqualTo(metadata.field().getName()); + } + + + @NonNull + String annotated = "exampleField"; + + private static OverrideMetadata exampleOverride() throws Exception { + Field field = OverrideMetadataTests.class.getDeclaredField("annotated"); + return new ConcreteOverrideMetadata(Objects.requireNonNull(field), field.getAnnotation(NonNull.class), + ResolvableType.forClass(String.class), BeanOverrideStrategy.REPLACE_DEFINITION); + } + static class ConcreteOverrideMetadata extends OverrideMetadata { ConcreteOverrideMetadata(Field field, Annotation overrideAnnotation, ResolvableType typeToOverride, BeanOverrideStrategy strategy) { + super(field, overrideAnnotation, typeToOverride, strategy); } @@ -44,25 +67,11 @@ class OverrideMetadataTests { } @Override - protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, @Nullable Object existingBeanInstance) { + protected Object createOverride(String beanName, @Nullable BeanDefinition existingBeanDefinition, + @Nullable Object existingBeanInstance) { + return BeanOverrideStrategy.REPLACE_DEFINITION; } } - @NonNull - public String annotated = "exampleField"; - - static OverrideMetadata exampleOverride() throws NoSuchFieldException { - final Field annotated = OverrideMetadataTests.class.getField("annotated"); - return new ConcreteOverrideMetadata(Objects.requireNonNull(annotated), annotated.getAnnotation(NonNull.class), - ResolvableType.forClass(String.class), BeanOverrideStrategy.REPLACE_DEFINITION); - } - - @Test - void implicitConfigurations() throws NoSuchFieldException { - final OverrideMetadata metadata = exampleOverride(); - assertThat(metadata.getExpectedBeanName()).as("expectedBeanName") - .isEqualTo(metadata.field().getName()); - } - } diff --git a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java index 8b3bce0e3e6..ab4c912e617 100644 --- a/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/bean/override/convention/TestBeanOverrideProcessorTests.java @@ -24,78 +24,85 @@ import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; import org.springframework.core.ResolvableType; -import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.test.context.bean.override.convention.TestBeanOverrideProcessor.MethodConventionOverrideMetadata; import org.springframework.test.context.bean.override.example.ExampleService; import org.springframework.test.context.bean.override.example.FailingExampleService; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatException; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +/** + * Tests for {@link TestBeanOverrideProcessor}. + * + * @author Simon Baslé + * @since 6.2 + */ class TestBeanOverrideProcessorTests { @Test void ensureMethodFindsFromList() { - Method m = TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class, + Method method = TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class, "example1", "example2", "example3"); - assertThat(m.getName()).isEqualTo("example2"); + assertThat(method.getName()).isEqualTo("example2"); } @Test void ensureMethodNotFound() { - assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( - MethodConventionConf.class, ExampleService.class, "example1", "example3")) + assertThatIllegalStateException() + .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class, + "example1", "example3")) .withMessage("Found 0 static methods instead of exactly one, matching a name in [example1, example3] with return type " + - ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()) - .isInstanceOf(IllegalStateException.class); + ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()); } @Test void ensureMethodTwoFound() { - assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( - MethodConventionConf.class, ExampleService.class, "example2", "example4")) + assertThatIllegalStateException() + .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class, + "example2", "example4")) .withMessage("Found 2 static methods instead of exactly one, matching a name in [example2, example4] with return type " + - ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()) - .isInstanceOf(IllegalStateException.class); + ExampleService.class.getName() + " on class " + MethodConventionConf.class.getName()); } @Test void ensureMethodNoNameProvided() { - assertThatException().isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod( - MethodConventionConf.class, ExampleService.class)) - .withMessage("At least one expectedMethodName is required") - .isInstanceOf(IllegalArgumentException.class); + assertThatIllegalArgumentException() + .isThrownBy(() -> TestBeanOverrideProcessor.ensureMethod(MethodConventionConf.class, ExampleService.class)) + .withMessage("At least one expectedMethodName is required"); } @Test void createMetaDataForUnknownExplicitMethod() throws NoSuchFieldException { - Field f = ExplicitMethodNameConf.class.getField("a"); - final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); + Field field = ExplicitMethodNameConf.class.getField("a"); + TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class)); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); - assertThatException().isThrownBy(() -> processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) + assertThatIllegalStateException() + .isThrownBy(() -> processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) .withMessage("Found 0 static methods instead of exactly one, matching a name in [explicit1] with return type " + - ExampleService.class.getName() + " on class " + ExplicitMethodNameConf.class.getName()) - .isInstanceOf(IllegalStateException.class); + ExampleService.class.getName() + " on class " + ExplicitMethodNameConf.class.getName()); } @Test void createMetaDataForKnownExplicitMethod() throws NoSuchFieldException { - Field f = ExplicitMethodNameConf.class.getField("b"); - final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); + Field field = ExplicitMethodNameConf.class.getField("b"); + TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class)); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); - assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) - .isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class); + assertThat(processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) + .isInstanceOf(MethodConventionOverrideMetadata.class); } @Test void createMetaDataWithDeferredEnsureMethodCheck() throws NoSuchFieldException { - Field f = MethodConventionConf.class.getField("field"); - final TestBean overrideAnnotation = Objects.requireNonNull(AnnotationUtils.getAnnotation(f, TestBean.class)); + Field field = MethodConventionConf.class.getField("field"); + TestBean overrideAnnotation = Objects.requireNonNull(field.getAnnotation(TestBean.class)); TestBeanOverrideProcessor processor = new TestBeanOverrideProcessor(); - assertThat(processor.createMetadata(f, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) - .isInstanceOf(TestBeanOverrideProcessor.MethodConventionOverrideMetadata.class); + assertThat(processor.createMetadata(field, overrideAnnotation, ResolvableType.forClass(ExampleService.class))) + .isInstanceOf(MethodConventionOverrideMetadata.class); } + static class MethodConventionConf { @TestBean @@ -127,4 +134,5 @@ class TestBeanOverrideProcessorTests { return new FailingExampleService(); } } + } 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 b623995b043..9c1cbccfcb0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,9 +35,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.request.WebRequest; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.fail; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItems; @@ -53,10 +51,7 @@ import static org.springframework.http.HttpHeaders.VARY; * * @author Rossen Stoyanchev */ -public class HeaderAssertionTests { - - private static final String ERROR_MESSAGE = "Should have thrown an AssertionError"; - +class HeaderAssertionTests { private String now; @@ -70,7 +65,7 @@ public class HeaderAssertionTests { @BeforeEach - public void setup() { + void setup() { this.dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); this.dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); this.now = dateFormat.format(new Date(this.currentTime)); @@ -83,7 +78,7 @@ public class HeaderAssertionTests { @Test - public void stringWithCorrectResponseHeaderValue() { + void stringWithCorrectResponseHeaderValue() { testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo) .exchange() .expectStatus().isOk() @@ -91,7 +86,7 @@ public class HeaderAssertionTests { } @Test - public void stringWithMatcherAndCorrectResponseHeaderValue() { + void stringWithMatcherAndCorrectResponseHeaderValue() { testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, minuteAgo) .exchange() .expectStatus().isOk() @@ -99,7 +94,7 @@ public class HeaderAssertionTests { } @Test - public void multiStringHeaderValue() { + void multiStringHeaderValue() { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() @@ -107,7 +102,7 @@ public class HeaderAssertionTests { } @Test - public void multiStringHeaderValueWithMatchers() { + void multiStringHeaderValueWithMatchers() { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() @@ -115,7 +110,7 @@ public class HeaderAssertionTests { } @Test - public void dateValueWithCorrectResponseHeaderValue() { + void dateValueWithCorrectResponseHeaderValue() { testClient.get().uri("/persons/1") .header(IF_MODIFIED_SINCE, minuteAgo) .exchange() @@ -124,7 +119,7 @@ public class HeaderAssertionTests { } @Test - public void longValueWithCorrectResponseHeaderValue() { + void longValueWithCorrectResponseHeaderValue() { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() @@ -132,7 +127,7 @@ public class HeaderAssertionTests { } @Test - public void stringWithMissingResponseHeader() { + void stringWithMissingResponseHeader() { testClient.get().uri("/persons/1") .header(IF_MODIFIED_SINCE, now) .exchange() @@ -141,7 +136,7 @@ public class HeaderAssertionTests { } @Test - public void stringWithMatcherAndMissingResponseHeader() { + void stringWithMatcherAndMissingResponseHeader() { testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) .exchange() .expectStatus().isNotModified() @@ -149,25 +144,18 @@ public class HeaderAssertionTests { } @Test - public void longValueWithMissingResponseHeader() { - try { - testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) - .exchange() - .expectStatus().isNotModified() - .expectHeader().valueEquals("X-Custom-Header", 99L); - - fail(ERROR_MESSAGE); - } - catch (AssertionError err) { - if (ERROR_MESSAGE.equals(err.getMessage())) { - throw err; - } - assertThat(err.getMessage()).startsWith("Response does not contain header 'X-Custom-Header'"); - } + void longValueWithMissingResponseHeader() { + String headerName = "X-Custom-Header"; + assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> + testClient.get().uri("/persons/1").header(IF_MODIFIED_SINCE, now) + .exchange() + .expectStatus().isNotModified() + .expectHeader().valueEquals(headerName, 99L)) + .withMessage("Response does not contain header '%s'", headerName); } @Test - public void exists() { + void exists() { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() @@ -175,7 +163,7 @@ public class HeaderAssertionTests { } @Test - public void existsFail() { + void existsFail() { assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> testClient.get().uri("/persons/1") .exchange() @@ -184,7 +172,7 @@ public class HeaderAssertionTests { } @Test - public void doesNotExist() { + void doesNotExist() { testClient.get().uri("/persons/1") .exchange() .expectStatus().isOk() @@ -192,7 +180,7 @@ public class HeaderAssertionTests { } @Test - public void doesNotExistFail() { + void doesNotExistFail() { assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> testClient.get().uri("/persons/1") .exchange() @@ -201,7 +189,7 @@ public class HeaderAssertionTests { } @Test - public void longValueWithIncorrectResponseHeaderValue() { + void longValueWithIncorrectResponseHeaderValue() { assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> testClient.get().uri("/persons/1") .exchange() @@ -210,7 +198,7 @@ public class HeaderAssertionTests { } @Test - public void stringWithMatcherAndIncorrectResponseHeaderValue() { + void stringWithMatcherAndIncorrectResponseHeaderValue() { long secondLater = this.currentTime + 1000; String expected = this.dateFormat.format(new Date(secondLater)); assertIncorrectResponseHeader(spec -> spec.expectHeader().valueEquals(LAST_MODIFIED, expected), expected); @@ -222,30 +210,13 @@ public class HeaderAssertionTests { } private void assertIncorrectResponseHeader(Consumer assertions, String expected) { - try { - WebTestClient.ResponseSpec spec = testClient.get().uri("/persons/1") - .header(IF_MODIFIED_SINCE, minuteAgo) - .exchange() - .expectStatus().isOk(); - - assertions.accept(spec); - - fail(ERROR_MESSAGE); - } - catch (AssertionError err) { - if (ERROR_MESSAGE.equals(err.getMessage())) { - throw err; - } - assertMessageContains(err, "Response header '" + LAST_MODIFIED + "'"); - assertMessageContains(err, expected); - assertMessageContains(err, this.now); - } - } - - private void assertMessageContains(AssertionError error, String expected) { - assertThat(error.getMessage()) - .as("Failure message should contain [" + expected + "], actual is [" + error.getMessage() + "]") - .contains(expected); + WebTestClient.ResponseSpec spec = testClient.get().uri("/persons/1") + .header(IF_MODIFIED_SINCE, minuteAgo) + .exchange() + .expectStatus().isOk(); + assertThatExceptionOfType(AssertionError.class) + .isThrownBy(() -> assertions.accept(spec)) + .withMessageContainingAll("Response header '" + LAST_MODIFIED + "'", expected, this.now); }