Skip to content

Commit b89cb20

Browse files
committed
Lenient date parsing in HeadersResultMatchers
Rather than formatting the expected value, and be susceptible to minor formatting differences (e.g. 01 vs 1 for day of month), parse the actual header value leniently with HttpHeaders and compare time values. Issue: SPR-17330
1 parent 52ed422 commit b89cb20

File tree

3 files changed

+72
-13
lines changed

3 files changed

+72
-13
lines changed

spring-test/src/main/java/org/springframework/test/web/servlet/result/HeaderResultMatchers.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,19 @@
1616

1717
package org.springframework.test.web.servlet.result;
1818

19-
import java.text.SimpleDateFormat;
2019
import java.util.Arrays;
21-
import java.util.Date;
2220
import java.util.List;
23-
import java.util.Locale;
24-
import java.util.TimeZone;
2521

2622
import org.hamcrest.Matcher;
2723

24+
import org.springframework.http.HttpHeaders;
2825
import org.springframework.mock.web.MockHttpServletResponse;
2926
import org.springframework.test.web.servlet.ResultMatcher;
3027

31-
import static org.hamcrest.MatcherAssert.*;
32-
import static org.springframework.test.util.AssertionErrors.*;
28+
import static org.hamcrest.MatcherAssert.assertThat;
29+
import static org.junit.Assert.assertNotNull;
30+
import static org.springframework.test.util.AssertionErrors.assertEquals;
31+
import static org.springframework.test.util.AssertionErrors.assertTrue;
3332

3433
/**
3534
* Factory for response header assertions.
@@ -126,7 +125,7 @@ public ResultMatcher longValue(final String name, final long value) {
126125
}
127126

128127
/**
129-
* Assert the primary value of the named response header as a date String,
128+
* Assert the primary value of the named response header parsed into a date
130129
* using the preferred date format described in RFC 7231.
131130
* <p>The {@link ResultMatcher} returned by this method throws an
132131
* {@link AssertionError} if the response does not contain the specified
@@ -136,12 +135,17 @@ public ResultMatcher longValue(final String name, final long value) {
136135
*/
137136
public ResultMatcher dateValue(final String name, final long value) {
138137
return result -> {
139-
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
140-
format.setTimeZone(TimeZone.getTimeZone("GMT"));
141-
String formatted = format.format(new Date(value));
142138
MockHttpServletResponse response = result.getResponse();
143-
assertTrue("Response does not contain header '" + name + "'", response.containsHeader(name));
144-
assertEquals("Response header '" + name + "'", formatted, response.getHeader(name));
139+
String headerValue = response.getHeader(name);
140+
assertNotNull("Response does not contain header '" + name + "'", headerValue);
141+
142+
HttpHeaders headers = new HttpHeaders();
143+
headers.setDate("expected", value);
144+
headers.set("actual", headerValue);
145+
146+
assertEquals("Response header '" + name + "'='" + headerValue + "' " +
147+
"does not match expected value '" + headers.getFirst("expected") + "'",
148+
headers.getFirstDate("expected"), headers.getFirstDate("actual"));
145149
};
146150
}
147151

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.test.web.servlet.result;
17+
18+
import java.time.ZoneId;
19+
import java.time.ZonedDateTime;
20+
21+
import org.junit.Test;
22+
23+
import org.springframework.http.HttpHeaders;
24+
import org.springframework.mock.web.MockHttpServletRequest;
25+
import org.springframework.mock.web.MockHttpServletResponse;
26+
import org.springframework.test.web.servlet.MvcResult;
27+
import org.springframework.test.web.servlet.StubMvcResult;
28+
29+
/**
30+
* Unit tests for {@link HeaderResultMatchers}.
31+
* @author Rossen Stoyanchev
32+
*/
33+
public class HeaderResultMatchersTests {
34+
35+
private final HeaderResultMatchers matchers = new HeaderResultMatchers();
36+
37+
private final MockHttpServletResponse response = new MockHttpServletResponse();
38+
39+
private final MvcResult mvcResult =
40+
new StubMvcResult(new MockHttpServletRequest(), null, null, null, null, null, this.response);
41+
42+
43+
@Test // SPR-17330
44+
public void matchDateFormattedWithHttpHeaders() throws Exception {
45+
46+
long epochMilli = ZonedDateTime.of(2018, 10, 5, 0, 0, 0, 0, ZoneId.of("GMT")).toInstant().toEpochMilli();
47+
HttpHeaders headers = new HttpHeaders();
48+
headers.setDate("myDate", epochMilli);
49+
this.response.setHeader("d", headers.getFirst("myDate"));
50+
51+
this.matchers.dateValue("d", epochMilli).match(this.mvcResult);
52+
}
53+
54+
}

spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/resultmatchers/HeaderAssertionTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ private void assertIncorrectResponseHeader(ResultMatcher matcher, String unexpec
208208

209209
private void assertMessageContains(AssertionError error, String expected) {
210210
String message = error.getMessage();
211-
assertTrue("Failure message should contain: " + expected, message.contains(expected));
211+
assertTrue("Failure message should contain [" + expected + "], actual is [" + message + "]",
212+
message.contains(expected));
212213
}
213214

214215

0 commit comments

Comments
 (0)