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; 024import org.w3c.dom.Node; 025import org.w3c.dom.NodeList; 026 027import org.springframework.lang.Nullable; 028import org.springframework.mock.web.MockHttpServletResponse; 029import org.springframework.test.util.XpathExpectationsHelper; 030import org.springframework.test.web.servlet.ResultMatcher; 031 032/** 033 * Factory for assertions on the response content using XPath expressions. 034 * 035 * <p>An instance of this class is typically accessed via 036 * {@link MockMvcResultMatchers#xpath}. 037 * 038 * @author Rossen Stoyanchev 039 * @since 3.2 040 */ 041public class XpathResultMatchers { 042 043 private final XpathExpectationsHelper xpathHelper; 044 045 046 /** 047 * Protected constructor, not for direct instantiation. Use 048 * {@link MockMvcResultMatchers#xpath(String, Object...)} or 049 * {@link MockMvcResultMatchers#xpath(String, Map, Object...)}. 050 * @param expression the XPath expression 051 * @param namespaces the XML namespaces referenced in the XPath expression, or {@code null} 052 * @param args arguments to parameterize the XPath expression with using the 053 * formatting specifiers defined in {@link String#format(String, Object...)} 054 */ 055 protected XpathResultMatchers(String expression, @Nullable Map<String, String> namespaces, Object ... args) 056 throws XPathExpressionException { 057 058 this.xpathHelper = new XpathExpectationsHelper(expression, namespaces, args); 059 } 060 061 062 /** 063 * Evaluate the XPath and assert the {@link Node} content found with the 064 * given Hamcrest {@link Matcher}. 065 */ 066 public ResultMatcher node(Matcher<? super Node> matcher) { 067 return result -> { 068 MockHttpServletResponse response = result.getResponse(); 069 this.xpathHelper.assertNode(response.getContentAsByteArray(), getDefinedEncoding(response), matcher); 070 }; 071 } 072 073 /** 074 * Evaluate the XPath and assert the {@link NodeList} content found with the 075 * given Hamcrest {@link Matcher}. 076 * @since 5.2.2 077 */ 078 public ResultMatcher nodeList(Matcher<? super NodeList> matcher) { 079 return result -> { 080 MockHttpServletResponse response = result.getResponse(); 081 this.xpathHelper.assertNodeList(response.getContentAsByteArray(), getDefinedEncoding(response), matcher); 082 }; 083 } 084 085 /** 086 * Get the response encoding if explicitly defined in the response, {code null} otherwise. 087 */ 088 @Nullable 089 private String getDefinedEncoding(MockHttpServletResponse response) { 090 return (response.isCharset() ? response.getCharacterEncoding() : null); 091 } 092 093 /** 094 * Evaluate the XPath and assert that content exists. 095 */ 096 public ResultMatcher exists() { 097 return result -> { 098 MockHttpServletResponse response = result.getResponse(); 099 this.xpathHelper.exists(response.getContentAsByteArray(), getDefinedEncoding(response)); 100 }; 101 } 102 103 /** 104 * Evaluate the XPath and assert that content doesn't exist. 105 */ 106 public ResultMatcher doesNotExist() { 107 return result -> { 108 MockHttpServletResponse response = result.getResponse(); 109 this.xpathHelper.doesNotExist(response.getContentAsByteArray(), getDefinedEncoding(response)); 110 }; 111 } 112 113 /** 114 * Evaluate the XPath and assert the number of nodes found with the given 115 * Hamcrest {@link Matcher}. 116 */ 117 public ResultMatcher nodeCount(Matcher<Integer> matcher) { 118 return result -> { 119 MockHttpServletResponse response = result.getResponse(); 120 this.xpathHelper.assertNodeCount(response.getContentAsByteArray(), getDefinedEncoding(response), matcher); 121 }; 122 } 123 124 /** 125 * Evaluate the XPath and assert the number of nodes found. 126 */ 127 public ResultMatcher nodeCount(int expectedCount) { 128 return result -> { 129 MockHttpServletResponse response = result.getResponse(); 130 this.xpathHelper.assertNodeCount(response.getContentAsByteArray(), getDefinedEncoding(response), expectedCount); 131 }; 132 } 133 134 /** 135 * Apply the XPath and assert the {@link String} value found with the given 136 * Hamcrest {@link Matcher}. 137 */ 138 public ResultMatcher string(Matcher<? super String> matcher) { 139 return result -> { 140 MockHttpServletResponse response = result.getResponse(); 141 this.xpathHelper.assertString(response.getContentAsByteArray(), getDefinedEncoding(response), matcher); 142 }; 143 } 144 145 /** 146 * Apply the XPath and assert the {@link String} value found. 147 */ 148 public ResultMatcher string(String expectedValue) { 149 return result -> { 150 MockHttpServletResponse response = result.getResponse(); 151 this.xpathHelper.assertString(response.getContentAsByteArray(), getDefinedEncoding(response), expectedValue); 152 }; 153 } 154 155 /** 156 * Evaluate the XPath and assert the {@link Double} value found with the 157 * given Hamcrest {@link Matcher}. 158 */ 159 public ResultMatcher number(Matcher<? super Double> matcher) { 160 return result -> { 161 MockHttpServletResponse response = result.getResponse(); 162 this.xpathHelper.assertNumber(response.getContentAsByteArray(), getDefinedEncoding(response), matcher); 163 }; 164 } 165 166 /** 167 * Evaluate the XPath and assert the {@link Double} value found. 168 */ 169 public ResultMatcher number(Double expectedValue) { 170 return result -> { 171 MockHttpServletResponse response = result.getResponse(); 172 this.xpathHelper.assertNumber(response.getContentAsByteArray(), getDefinedEncoding(response), expectedValue); 173 }; 174 } 175 176 /** 177 * Evaluate the XPath and assert the {@link Boolean} value found. 178 */ 179 public ResultMatcher booleanValue(Boolean value) { 180 return result -> { 181 MockHttpServletResponse response = result.getResponse(); 182 this.xpathHelper.assertBoolean(response.getContentAsByteArray(), getDefinedEncoding(response), value); 183 }; 184 } 185 186}