001/* 002 * Copyright 2002-2019 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.web.servlet.result; 018 019import java.util.Map; 020 021import javax.xml.xpath.XPathExpressionException; 022 023import org.hamcrest.Matcher; 024 025import org.springframework.lang.Nullable; 026import org.springframework.test.web.servlet.ResultMatcher; 027import org.springframework.util.AntPathMatcher; 028import org.springframework.web.util.UriComponentsBuilder; 029 030import static org.springframework.test.util.AssertionErrors.assertEquals; 031import static org.springframework.test.util.AssertionErrors.assertTrue; 032 033/** 034 * Static factory methods for {@link ResultMatcher}-based result actions. 035 * 036 * <h3>Eclipse Users</h3> 037 * <p>Consider adding this class as a Java editor favorite. To navigate to 038 * this setting, open the Preferences and type "favorites". 039 * 040 * @author Rossen Stoyanchev 041 * @author Brian Clozel 042 * @author Sam Brannen 043 * @since 3.2 044 */ 045public abstract class MockMvcResultMatchers { 046 047 private static final AntPathMatcher pathMatcher = new AntPathMatcher(); 048 049 050 /** 051 * Access to request-related assertions. 052 */ 053 public static RequestResultMatchers request() { 054 return new RequestResultMatchers(); 055 } 056 057 /** 058 * Access to assertions for the handler that handled the request. 059 */ 060 public static HandlerResultMatchers handler() { 061 return new HandlerResultMatchers(); 062 } 063 064 /** 065 * Access to model-related assertions. 066 */ 067 public static ModelResultMatchers model() { 068 return new ModelResultMatchers(); 069 } 070 071 /** 072 * Access to assertions on the selected view. 073 */ 074 public static ViewResultMatchers view() { 075 return new ViewResultMatchers(); 076 } 077 078 /** 079 * Access to flash attribute assertions. 080 */ 081 public static FlashAttributeResultMatchers flash() { 082 return new FlashAttributeResultMatchers(); 083 } 084 085 /** 086 * Asserts the request was forwarded to the given URL. 087 * <p>This method accepts only exact matches. 088 * @param expectedUrl the exact URL expected 089 */ 090 public static ResultMatcher forwardedUrl(@Nullable String expectedUrl) { 091 return result -> assertEquals("Forwarded URL", expectedUrl, result.getResponse().getForwardedUrl()); 092 } 093 094 /** 095 * Asserts the request was forwarded to the given URL template. 096 * <p>This method accepts exact matches against the expanded and encoded URL template. 097 * @param urlTemplate a URL template; the expanded URL will be encoded 098 * @param uriVars zero or more URI variables to populate the template 099 * @see UriComponentsBuilder#fromUriString(String) 100 */ 101 public static ResultMatcher forwardedUrlTemplate(String urlTemplate, Object... uriVars) { 102 String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString(); 103 return forwardedUrl(uri); 104 } 105 106 /** 107 * Asserts the request was forwarded to the given URL. 108 * <p>This method accepts {@link org.springframework.util.AntPathMatcher} 109 * patterns. 110 * @param urlPattern an Ant-style path pattern to match against 111 * @since 4.0 112 * @see org.springframework.util.AntPathMatcher 113 */ 114 public static ResultMatcher forwardedUrlPattern(String urlPattern) { 115 return result -> { 116 assertTrue("'" + urlPattern + "' is not an Ant-style path pattern", 117 pathMatcher.isPattern(urlPattern)); 118 String url = result.getResponse().getForwardedUrl(); 119 assertTrue("Forwarded URL '" + url + "' does not match the expected URL pattern '" + urlPattern + "'", 120 (url != null && pathMatcher.match(urlPattern, url))); 121 }; 122 } 123 124 /** 125 * Asserts the request was redirected to the given URL. 126 * <p>This method accepts only exact matches. 127 * @param expectedUrl the exact URL expected 128 */ 129 public static ResultMatcher redirectedUrl(String expectedUrl) { 130 return result -> assertEquals("Redirected URL", expectedUrl, result.getResponse().getRedirectedUrl()); 131 } 132 133 /** 134 * Asserts the request was redirected to the given URL template. 135 * <p>This method accepts exact matches against the expanded and encoded URL template. 136 * @param urlTemplate a URL template; the expanded URL will be encoded 137 * @param uriVars zero or more URI variables to populate the template 138 * @see UriComponentsBuilder#fromUriString(String) 139 */ 140 public static ResultMatcher redirectedUrlTemplate(String urlTemplate, Object... uriVars) { 141 String uri = UriComponentsBuilder.fromUriString(urlTemplate).buildAndExpand(uriVars).encode().toUriString(); 142 return redirectedUrl(uri); 143 } 144 145 /** 146 * Asserts the request was redirected to the given URL. 147 * <p>This method accepts {@link org.springframework.util.AntPathMatcher} 148 * patterns. 149 * @param urlPattern an Ant-style path pattern to match against 150 * @since 4.0 151 * @see org.springframework.util.AntPathMatcher 152 */ 153 public static ResultMatcher redirectedUrlPattern(String urlPattern) { 154 return result -> { 155 assertTrue("'" + urlPattern + "' is not an Ant-style path pattern", 156 pathMatcher.isPattern(urlPattern)); 157 String url = result.getResponse().getRedirectedUrl(); 158 assertTrue("Redirected URL '" + url + "' does not match the expected URL pattern '" + urlPattern + "'", 159 (url != null && pathMatcher.match(urlPattern, url))); 160 }; 161 } 162 163 /** 164 * Access to response status assertions. 165 */ 166 public static StatusResultMatchers status() { 167 return new StatusResultMatchers(); 168 } 169 170 /** 171 * Access to response header assertions. 172 */ 173 public static HeaderResultMatchers header() { 174 return new HeaderResultMatchers(); 175 } 176 177 /** 178 * Access to response body assertions. 179 */ 180 public static ContentResultMatchers content() { 181 return new ContentResultMatchers(); 182 } 183 184 /** 185 * Access to response body assertions using a 186 * <a href="https://github.com/jayway/JsonPath">JsonPath</a> expression 187 * to inspect a specific subset of the body. 188 * <p>The JSON path expression can be a parameterized string using 189 * formatting specifiers as defined in 190 * {@link String#format(String, Object...)}. 191 * @param expression the JSON path expression, optionally parameterized with arguments 192 * @param args arguments to parameterize the JSON path expression with 193 * @see #jsonPath(String, Matcher) 194 * @see #jsonPath(String, Matcher, Class) 195 */ 196 public static JsonPathResultMatchers jsonPath(String expression, Object... args) { 197 return new JsonPathResultMatchers(expression, args); 198 } 199 200 /** 201 * Evaluate the given <a href="https://github.com/jayway/JsonPath">JsonPath</a> 202 * expression against the response body and assert the resulting value with 203 * the given Hamcrest {@link Matcher}. 204 * @param expression the JSON path expression 205 * @param matcher a matcher for the value expected at the JSON path 206 * @see #jsonPath(String, Object...) 207 * @see #jsonPath(String, Matcher, Class) 208 */ 209 public static <T> ResultMatcher jsonPath(String expression, Matcher<T> matcher) { 210 return new JsonPathResultMatchers(expression).value(matcher); 211 } 212 213 /** 214 * Evaluate the given <a href="https://github.com/jayway/JsonPath">JsonPath</a> 215 * expression against the response body and assert the resulting value with 216 * the given Hamcrest {@link Matcher}, coercing the resulting value into the 217 * given target type before applying the matcher. 218 * <p>This can be useful for matching numbers reliably — for example, 219 * to coerce an integer into a double. 220 * @param expression the JSON path expression 221 * @param matcher a matcher for the value expected at the JSON path 222 * @param targetType the target type to coerce the matching value into 223 * @since 5.2 224 * @see #jsonPath(String, Object...) 225 * @see #jsonPath(String, Matcher) 226 */ 227 public static <T> ResultMatcher jsonPath(String expression, Matcher<T> matcher, Class<T> targetType) { 228 return new JsonPathResultMatchers(expression).value(matcher, targetType); 229 } 230 231 /** 232 * Access to response body assertions using an XPath expression to 233 * inspect a specific subset of the body. 234 * <p>The XPath expression can be a parameterized string using formatting 235 * specifiers as defined in {@link String#format(String, Object...)}. 236 * @param expression the XPath expression, optionally parameterized with arguments 237 * @param args arguments to parameterize the XPath expression with 238 */ 239 public static XpathResultMatchers xpath(String expression, Object... args) throws XPathExpressionException { 240 return new XpathResultMatchers(expression, null, args); 241 } 242 243 /** 244 * Access to response body assertions using an XPath expression to 245 * inspect a specific subset of the body. 246 * <p>The XPath expression can be a parameterized string using formatting 247 * specifiers as defined in {@link String#format(String, Object...)}. 248 * @param expression the XPath expression, optionally parameterized with arguments 249 * @param namespaces the namespaces referenced in the XPath expression 250 * @param args arguments to parameterize the XPath expression with 251 */ 252 public static XpathResultMatchers xpath(String expression, Map<String, String> namespaces, Object... args) 253 throws XPathExpressionException { 254 255 return new XpathResultMatchers(expression, namespaces, args); 256 } 257 258 /** 259 * Access to response cookie assertions. 260 */ 261 public static CookieResultMatchers cookie() { 262 return new CookieResultMatchers(); 263 } 264 265}