Fix issue with xpath assertions in Spring Test MVC
Issue: SPR-10704
This commit is contained in:
parent
82ec06ad34
commit
7bab879623
|
|
@ -16,9 +16,6 @@
|
|||
|
||||
package org.springframework.test.util;
|
||||
|
||||
import static org.springframework.test.util.AssertionErrors.*;
|
||||
import static org.springframework.test.util.MatcherAssertionErrors.*;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
|
@ -33,12 +30,16 @@ import javax.xml.xpath.XPathExpressionException;
|
|||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.xml.SimpleNamespaceContext;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import static org.springframework.test.util.AssertionErrors.*;
|
||||
import static org.springframework.test.util.MatcherAssertionErrors.*;
|
||||
|
||||
/**
|
||||
* A helper class for applying assertions via XPath expressions.
|
||||
*
|
||||
|
|
@ -51,6 +52,8 @@ public class XpathExpectationsHelper {
|
|||
|
||||
private final XPathExpression xpathExpression;
|
||||
|
||||
private final boolean hasNamespaces;
|
||||
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
|
|
@ -66,6 +69,7 @@ public class XpathExpectationsHelper {
|
|||
|
||||
this.expression = String.format(expression, args);
|
||||
this.xpathExpression = compileXpathExpression(this.expression, namespaces);
|
||||
this.hasNamespaces = !CollectionUtils.isEmpty(namespaces);
|
||||
}
|
||||
|
||||
private XPathExpression compileXpathExpression(String expression, Map<String, String> namespaces)
|
||||
|
|
@ -104,7 +108,7 @@ public class XpathExpectationsHelper {
|
|||
*/
|
||||
protected Document parseXmlString(String xml) throws Exception {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setNamespaceAware(this.hasNamespaces);
|
||||
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
|
||||
InputSource inputSource = new InputSource(new StringReader(xml));
|
||||
Document document = documentBuilder.parse(inputSource);
|
||||
|
|
|
|||
|
|
@ -16,17 +16,6 @@
|
|||
|
||||
package org.springframework.test.web.servlet.samples.standalone.resultmatchers;
|
||||
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -47,6 +36,12 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.*;
|
||||
|
||||
/**
|
||||
* Examples of expectations on XML response content with XPath expressions.
|
||||
*
|
||||
|
|
@ -57,7 +52,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
*/
|
||||
public class XpathAssertionTests {
|
||||
|
||||
private static final Map<String, String> NS =
|
||||
private static final Map<String, String> musicNamespace =
|
||||
Collections.singletonMap("ns", "http://example.org/music/people");
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
|
@ -78,13 +73,13 @@ public class XpathAssertionTests {
|
|||
String performer = "/ns:people/performers/performer[%s]";
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath(composer, NS, 1).exists())
|
||||
.andExpect(xpath(composer, NS, 2).exists())
|
||||
.andExpect(xpath(composer, NS, 3).exists())
|
||||
.andExpect(xpath(composer, NS, 4).exists())
|
||||
.andExpect(xpath(performer, NS, 1).exists())
|
||||
.andExpect(xpath(performer, NS, 2).exists())
|
||||
.andExpect(xpath(composer, NS, 1).node(notNullValue()));
|
||||
.andExpect(xpath(composer, musicNamespace, 1).exists())
|
||||
.andExpect(xpath(composer, musicNamespace, 2).exists())
|
||||
.andExpect(xpath(composer, musicNamespace, 3).exists())
|
||||
.andExpect(xpath(composer, musicNamespace, 4).exists())
|
||||
.andExpect(xpath(performer, musicNamespace, 1).exists())
|
||||
.andExpect(xpath(performer, musicNamespace, 2).exists())
|
||||
.andExpect(xpath(composer, musicNamespace, 1).node(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -94,11 +89,11 @@ public class XpathAssertionTests {
|
|||
String performer = "/ns:people/performers/performer[%s]";
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath(composer, NS, 0).doesNotExist())
|
||||
.andExpect(xpath(composer, NS, 5).doesNotExist())
|
||||
.andExpect(xpath(performer, NS, 0).doesNotExist())
|
||||
.andExpect(xpath(performer, NS, 3).doesNotExist())
|
||||
.andExpect(xpath(composer, NS, 0).node(nullValue()));
|
||||
.andExpect(xpath(composer, musicNamespace, 0).doesNotExist())
|
||||
.andExpect(xpath(composer, musicNamespace, 5).doesNotExist())
|
||||
.andExpect(xpath(performer, musicNamespace, 0).doesNotExist())
|
||||
.andExpect(xpath(performer, musicNamespace, 3).doesNotExist())
|
||||
.andExpect(xpath(composer, musicNamespace, 0).node(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -108,15 +103,15 @@ public class XpathAssertionTests {
|
|||
String performerName = "/ns:people/performers/performer[%s]/name";
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath(composerName, NS, 1).string("Johann Sebastian Bach"))
|
||||
.andExpect(xpath(composerName, NS, 2).string("Johannes Brahms"))
|
||||
.andExpect(xpath(composerName, NS, 3).string("Edvard Grieg"))
|
||||
.andExpect(xpath(composerName, NS, 4).string("Robert Schumann"))
|
||||
.andExpect(xpath(performerName, NS, 1).string("Vladimir Ashkenazy"))
|
||||
.andExpect(xpath(performerName, NS, 2).string("Yehudi Menuhin"))
|
||||
.andExpect(xpath(composerName, NS, 1).string(equalTo("Johann Sebastian Bach"))) // Hamcrest..
|
||||
.andExpect(xpath(composerName, NS, 1).string(startsWith("Johann")))
|
||||
.andExpect(xpath(composerName, NS, 1).string(notNullValue()));
|
||||
.andExpect(xpath(composerName, musicNamespace, 1).string("Johann Sebastian Bach"))
|
||||
.andExpect(xpath(composerName, musicNamespace, 2).string("Johannes Brahms"))
|
||||
.andExpect(xpath(composerName, musicNamespace, 3).string("Edvard Grieg"))
|
||||
.andExpect(xpath(composerName, musicNamespace, 4).string("Robert Schumann"))
|
||||
.andExpect(xpath(performerName, musicNamespace, 1).string("Vladimir Ashkenazy"))
|
||||
.andExpect(xpath(performerName, musicNamespace, 2).string("Yehudi Menuhin"))
|
||||
.andExpect(xpath(composerName, musicNamespace, 1).string(equalTo("Johann Sebastian Bach"))) // Hamcrest..
|
||||
.andExpect(xpath(composerName, musicNamespace, 1).string(startsWith("Johann")))
|
||||
.andExpect(xpath(composerName, musicNamespace, 1).string(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -125,12 +120,12 @@ public class XpathAssertionTests {
|
|||
String composerDouble = "/ns:people/composers/composer[%s]/someDouble";
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath(composerDouble, NS, 1).number(21d))
|
||||
.andExpect(xpath(composerDouble, NS, 2).number(.0025))
|
||||
.andExpect(xpath(composerDouble, NS, 3).number(1.6035))
|
||||
.andExpect(xpath(composerDouble, NS, 4).number(Double.NaN))
|
||||
.andExpect(xpath(composerDouble, NS, 1).number(equalTo(21d))) // Hamcrest..
|
||||
.andExpect(xpath(composerDouble, NS, 3).number(closeTo(1.6, .01)));
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 1).number(21d))
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 2).number(.0025))
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 3).number(1.6035))
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 4).number(Double.NaN))
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 1).number(equalTo(21d))) // Hamcrest..
|
||||
.andExpect(xpath(composerDouble, musicNamespace, 3).number(closeTo(1.6, .01)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -139,20 +134,36 @@ public class XpathAssertionTests {
|
|||
String performerBooleanValue = "/ns:people/performers/performer[%s]/someBoolean";
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath(performerBooleanValue, NS, 1).booleanValue(false))
|
||||
.andExpect(xpath(performerBooleanValue, NS, 2).booleanValue(true));
|
||||
.andExpect(xpath(performerBooleanValue, musicNamespace, 1).booleanValue(false))
|
||||
.andExpect(xpath(performerBooleanValue, musicNamespace, 2).booleanValue(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeCount() throws Exception {
|
||||
|
||||
this.mockMvc.perform(get("/music/people"))
|
||||
.andExpect(xpath("/ns:people/composers/composer", NS).nodeCount(4))
|
||||
.andExpect(xpath("/ns:people/performers/performer", NS).nodeCount(2))
|
||||
.andExpect(xpath("/ns:people/composers/composer", NS).nodeCount(equalTo(4))) // Hamcrest..
|
||||
.andExpect(xpath("/ns:people/performers/performer", NS).nodeCount(equalTo(2)));
|
||||
.andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(4))
|
||||
.andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(2))
|
||||
.andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(equalTo(4))) // Hamcrest..
|
||||
.andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(equalTo(2)));
|
||||
}
|
||||
|
||||
// SPR-10704
|
||||
|
||||
@Test
|
||||
public void testFeedWithLinefeedChars() throws Exception {
|
||||
|
||||
// Map<String, String> namespace = Collections.singletonMap("ns", "");
|
||||
|
||||
standaloneSetup(new BlogFeedController()).build()
|
||||
.perform(get("/blog.atom").accept(MediaType.APPLICATION_ATOM_XML))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaType.APPLICATION_ATOM_XML))
|
||||
.andExpect(xpath("//feed/title").string("Test Feed"))
|
||||
.andExpect(xpath("//feed/icon").string("http://www.example.com/favicon.ico"));
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class MusicController {
|
||||
|
||||
|
|
@ -203,4 +214,19 @@ public class XpathAssertionTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
public class BlogFeedController {
|
||||
|
||||
@RequestMapping(value="/blog.atom", method = { GET, HEAD })
|
||||
@ResponseBody
|
||||
public String listPublishedPosts() {
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
|
||||
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">\r\n"
|
||||
+ " <title>Test Feed</title>\r\n"
|
||||
+ " <icon>http://www.example.com/favicon.ico</icon>\r\n"
|
||||
+ "</feed>\r\n\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue