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