diff --git a/test/src/main/java/org/springframework/ws/mock/client/DefaultXPathExpectations.java b/test/src/main/java/org/springframework/ws/mock/client/DefaultXPathExpectations.java new file mode 100644 index 00000000..2950a785 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/DefaultXPathExpectations.java @@ -0,0 +1,132 @@ +/* + * Copyright 2005-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.mock.client; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; + +import org.springframework.util.Assert; +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.TransformerObjectSupport; +import org.springframework.xml.xpath.XPathExpression; +import org.springframework.xml.xpath.XPathExpressionFactory; + +import org.w3c.dom.Node; + +import static org.springframework.ws.mock.client.Assert.assertEquals; +import static org.springframework.ws.mock.client.Assert.fail; + +/** + * Default implementation of {@link XPathExpectations}. + * + * @author Lukas Krecan + * @author Arjen Poutsma + * @since 2.0 + */ +class DefaultXPathExpectations extends TransformerObjectSupport implements XPathExpectations { + + private final XPathExpression expression; + + private final String expressionString; + + DefaultXPathExpectations(String expression, Map namespaces) { + Assert.hasLength(expression, "'expression' must not be empty"); + this.expression = XPathExpressionFactory.createXPathExpression(expression, namespaces); + this.expressionString = expression; + } + + public RequestMatcher exists() { + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + Node payload = transformToNode(request); + Node result = expression.evaluateAsNode(payload); + if (result == null) { + fail("No match for \"" + expressionString + "\" found"); + } + } + }; + } + + public RequestMatcher doesNotExist() { + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + Node payload = transformToNode(request); + Node result = expression.evaluateAsNode(payload); + if (result != null) { + fail("Match for \"" + expressionString + "\" found"); + } + } + }; + } + + public RequestMatcher evaluatesTo(final boolean expectedValue) { + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + Node payload = transformToNode(request); + boolean result = expression.evaluateAsBoolean(payload); + assertEquals("Evaluation of XPath expression \"" + expressionString + "\" failed.", expectedValue, + result); + + } + }; + } + + public RequestMatcher evaluatesTo(int expectedValue) { + return evaluatesTo((double) expectedValue); + } + + public RequestMatcher evaluatesTo(final double expectedValue) { + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + Node payload = transformToNode(request); + double result = expression.evaluateAsNumber(payload); + assertEquals("Evaluation of XPath expression \"" + expressionString + "\" failed.", expectedValue, + result); + + } + }; + } + + public RequestMatcher evaluatesTo(final String expectedValue) { + Assert.notNull(expectedValue, "'expectedValue' must not be null"); + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + Node payload = transformToNode(request); + String result = expression.evaluateAsString(payload); + assertEquals("Evaluation of XPath expression \"" + expressionString + "\" failed.", expectedValue, + result); + } + }; + } + + private Node transformToNode(WebServiceMessage request) { + DOMResult domResult = new DOMResult(); + try { + transform(request.getPayloadSource(), domResult); + return domResult.getNode(); + } + catch (TransformerException ex) { + fail("Could not transform request payload: " + ex.getMessage()); + return null; + } + } + + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/WebServiceMock.java b/test/src/main/java/org/springframework/ws/mock/client/WebServiceMock.java index 1cd95fb4..ae2b0bb2 100644 --- a/test/src/main/java/org/springframework/ws/mock/client/WebServiceMock.java +++ b/test/src/main/java/org/springframework/ws/mock/client/WebServiceMock.java @@ -19,6 +19,7 @@ package org.springframework.ws.mock.client; import java.io.IOException; import java.net.URI; import java.util.Locale; +import java.util.Map; import javax.xml.namespace.QName; import javax.xml.transform.Source; @@ -89,7 +90,7 @@ public abstract class WebServiceMock { /** * Expects the payload to validate against the given XSD schema(s). * - * @param schema the schema + * @param schema the schema * @param furtherSchemas further schemas, if necessary * @return the request matcher */ @@ -107,6 +108,27 @@ public abstract class WebServiceMock { } } + /** + * Expects the given XPath expression to (not) exist or be evaluated to a value. + * + * @param xpathExpression the XPath expression + * @return the XPath expectations, to be further configured + */ + public static XPathExpectations xpath(String xpathExpression) { + return new DefaultXPathExpectations(xpathExpression, null); + } + + /** + * Expects the given XPath expression to (not) exist or be evaluated to a value. + * + * @param xpathExpression the XPath expression + * @param namespaceMapping the namespaces + * @return the XPath expectations, to be further configured + */ + public static XPathExpectations xpath(String xpathExpression, Map namespaceMapping) { + return new DefaultXPathExpectations(xpathExpression, namespaceMapping); + } + /** * Expects the given SOAP header in the outgoing message. * @@ -210,6 +232,7 @@ public abstract class WebServiceMock { Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); return SoapFaultResponseCallback.createMustUnderstandFault(faultStringOrReason, locale); } + /** * Respond with a {@code Client} (SOAP 1.1) or {@code Sender} (SOAP 1.2) fault. * @@ -246,7 +269,6 @@ public abstract class WebServiceMock { return SoapFaultResponseCallback.createVersionMismatchFault(faultStringOrReason, locale); } - private static ResourceSource createResourceSource(Resource resource) { try { return new ResourceSource(resource); @@ -256,5 +278,4 @@ public abstract class WebServiceMock { } } - } diff --git a/test/src/main/java/org/springframework/ws/mock/client/XPathExpectations.java b/test/src/main/java/org/springframework/ws/mock/client/XPathExpectations.java new file mode 100644 index 00000000..784d8a0b --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/XPathExpectations.java @@ -0,0 +1,75 @@ +/* + * Copyright 2005-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.mock.client; + +/** + * Allows for setting up expectations on XPath expressions. Implementations of this interface are returned by {@link + * WebServiceMock}. + * + * @author Lukas Krecan + * @author Arjen Poutsma + * @since 2.0 + */ +public interface XPathExpectations { + + /** + * Expects the XPath expression to exist. + * + * @return the request matcher + */ + RequestMatcher exists(); + + /** + * Expects the XPath expression to not exist. + * + * @return the request matcher + */ + RequestMatcher doesNotExist(); + + /** + * Expects the XPath expression to evaluate to the given boolean. + * + * @param expectedValue the expected value + * @return the request matcher + */ + RequestMatcher evaluatesTo(final boolean expectedValue); + + /** + * Expects the XPath expression to evaluate to the given integer. + * + * @param expectedValue the expected value + * @return the request matcher + */ + RequestMatcher evaluatesTo(int expectedValue); + + /** + * Expects the XPath expression to evaluate to the given double. + * + * @param expectedValue the expected value + * @return the request matcher + */ + RequestMatcher evaluatesTo(double expectedValue); + + /** + * Expects the XPath expression to evaluate to the given string. + * + * @param expectedValue the expected value + * @return the request matcher + */ + RequestMatcher evaluatesTo(String expectedValue); + +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/DefaultXPathExpectationsTest.java b/test/src/test/java/org/springframework/ws/mock/client/DefaultXPathExpectationsTest.java new file mode 100644 index 00000000..bdbeaeb1 --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/DefaultXPathExpectationsTest.java @@ -0,0 +1,205 @@ +/* + * Copyright 2005-2010 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.mock.client; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.StringSource; + +import org.junit.Test; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.assertNotNull; + +public class DefaultXPathExpectationsTest { + + @Test + public void existsMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b").exists(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void existsNonMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//c").exists(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + } + + @Test + public void notExistsMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//c").doesNotExist(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void notExistsNonMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//a").doesNotExist(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + } + + @Test + public void evaluatesToTrueMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b=1").evaluatesTo(true); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void evaluatesToTrueNonMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b=2").evaluatesTo(true); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + } + + @Test + public void evaluatesToFalseMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b!=1").evaluatesTo(false); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void evaluatesToFalseNonMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b!=2").evaluatesTo(false); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + } + + @Test + public void existsWithNamespacesMatch() throws IOException, AssertionError { + Map ns = Collections.singletonMap("x", "http://example.org"); + RequestMatcher requestMatcher = WebServiceMock.xpath("//x:b", ns).exists(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()) + .andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void existsWithNamespacesNonMatch() throws IOException, AssertionError { + Map ns = Collections.singletonMap("x", "http://example.org"); + RequestMatcher requestMatcher = WebServiceMock.xpath("//b", ns).exists(); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()) + .andReturn(new StringSource("")); + + replay(message); + + requestMatcher.match(null, message); + } + + @Test + public void evaluatesToIntegerMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b").evaluatesTo(1); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void evaluatesToIntegerNonMatch() throws IOException, AssertionError { + RequestMatcher requestMatcher = WebServiceMock.xpath("//b").evaluatesTo(2); + assertNotNull(requestMatcher); + + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource("1")); + + replay(message); + + requestMatcher.match(null, message); + } + +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/WebServiceMockTest.java b/test/src/test/java/org/springframework/ws/mock/client/WebServiceMockTest.java index 33544d9d..21575fe5 100644 --- a/test/src/test/java/org/springframework/ws/mock/client/WebServiceMockTest.java +++ b/test/src/test/java/org/springframework/ws/mock/client/WebServiceMockTest.java @@ -18,6 +18,8 @@ package org.springframework.ws.mock.client; import java.io.IOException; import java.net.URI; +import java.util.Collections; +import java.util.Map; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; @@ -192,4 +194,25 @@ public class WebServiceMockTest { template.sendSourceAndReceiveToResult(new StringSource(actual), result); } + @Test + public void xpathExistsMatch() throws Exception { + final Map ns = Collections.singletonMap("ns", "http://example.com"); + + expect(xpath("/ns:request", ns).exists()); + + template.sendSourceAndReceiveToResult(new StringSource(""), + new StringResult()); + } + + @Test(expected = AssertionError.class) + public void xpathExistsNonMatch() throws Exception { + final Map ns = Collections.singletonMap("ns", "http://example.com"); + + expect(xpath("/ns:foo", ns).exists()); + + template.sendSourceAndReceiveToResult(new StringSource(""), + new StringResult()); + } + + }