1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.test.web.servlet.samples.standalone.resultmatchers;
18
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import javax.xml.bind.annotation.XmlAccessType;
24 import javax.xml.bind.annotation.XmlAccessorType;
25 import javax.xml.bind.annotation.XmlElement;
26 import javax.xml.bind.annotation.XmlElementWrapper;
27 import javax.xml.bind.annotation.XmlRootElement;
28
29 import org.junit.Before;
30 import org.junit.Test;
31
32 import org.springframework.http.MediaType;
33 import org.springframework.stereotype.Controller;
34 import org.springframework.test.web.Person;
35 import org.springframework.test.web.servlet.MockMvc;
36 import org.springframework.web.bind.annotation.RequestMapping;
37 import org.springframework.web.bind.annotation.ResponseBody;
38
39 import static org.hamcrest.Matchers.*;
40 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
41 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
42 import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
43 import static org.springframework.web.bind.annotation.RequestMethod.*;
44
45
46
47
48
49
50
51
52
53 public class XpathAssertionTests {
54
55 private static final Map<String, String> musicNamespace =
56 Collections.singletonMap("ns", "http://example.org/music/people");
57
58 private MockMvc mockMvc;
59
60 @Before
61 public void setup() throws Exception {
62 this.mockMvc = standaloneSetup(new MusicController())
63 .defaultRequest(get("/").accept(MediaType.APPLICATION_XML, MediaType.parseMediaType("application/xml;charset=UTF-8")))
64 .alwaysExpect(status().isOk())
65 .alwaysExpect(content().contentType(MediaType.parseMediaType("application/xml;charset=UTF-8")))
66 .build();
67 }
68
69 @Test
70 public void testExists() throws Exception {
71
72 String composer = "/ns:people/composers/composer[%s]";
73 String performer = "/ns:people/performers/performer[%s]";
74
75 this.mockMvc.perform(get("/music/people"))
76 .andExpect(xpath(composer, musicNamespace, 1).exists())
77 .andExpect(xpath(composer, musicNamespace, 2).exists())
78 .andExpect(xpath(composer, musicNamespace, 3).exists())
79 .andExpect(xpath(composer, musicNamespace, 4).exists())
80 .andExpect(xpath(performer, musicNamespace, 1).exists())
81 .andExpect(xpath(performer, musicNamespace, 2).exists())
82 .andExpect(xpath(composer, musicNamespace, 1).node(notNullValue()));
83 }
84
85 @Test
86 public void testDoesNotExist() throws Exception {
87
88 String composer = "/ns:people/composers/composer[%s]";
89 String performer = "/ns:people/performers/performer[%s]";
90
91 this.mockMvc.perform(get("/music/people"))
92 .andExpect(xpath(composer, musicNamespace, 0).doesNotExist())
93 .andExpect(xpath(composer, musicNamespace, 5).doesNotExist())
94 .andExpect(xpath(performer, musicNamespace, 0).doesNotExist())
95 .andExpect(xpath(performer, musicNamespace, 3).doesNotExist())
96 .andExpect(xpath(composer, musicNamespace, 0).node(nullValue()));
97 }
98
99 @Test
100 public void testString() throws Exception {
101
102 String composerName = "/ns:people/composers/composer[%s]/name";
103 String performerName = "/ns:people/performers/performer[%s]/name";
104
105 this.mockMvc.perform(get("/music/people"))
106 .andExpect(xpath(composerName, musicNamespace, 1).string("Johann Sebastian Bach"))
107 .andExpect(xpath(composerName, musicNamespace, 2).string("Johannes Brahms"))
108 .andExpect(xpath(composerName, musicNamespace, 3).string("Edvard Grieg"))
109 .andExpect(xpath(composerName, musicNamespace, 4).string("Robert Schumann"))
110 .andExpect(xpath(performerName, musicNamespace, 1).string("Vladimir Ashkenazy"))
111 .andExpect(xpath(performerName, musicNamespace, 2).string("Yehudi Menuhin"))
112 .andExpect(xpath(composerName, musicNamespace, 1).string(equalTo("Johann Sebastian Bach")))
113 .andExpect(xpath(composerName, musicNamespace, 1).string(startsWith("Johann")))
114 .andExpect(xpath(composerName, musicNamespace, 1).string(notNullValue()));
115 }
116
117 @Test
118 public void testNumber() throws Exception {
119
120 String composerDouble = "/ns:people/composers/composer[%s]/someDouble";
121
122 this.mockMvc.perform(get("/music/people"))
123 .andExpect(xpath(composerDouble, musicNamespace, 1).number(21d))
124 .andExpect(xpath(composerDouble, musicNamespace, 2).number(.0025))
125 .andExpect(xpath(composerDouble, musicNamespace, 3).number(1.6035))
126 .andExpect(xpath(composerDouble, musicNamespace, 4).number(Double.NaN))
127 .andExpect(xpath(composerDouble, musicNamespace, 1).number(equalTo(21d)))
128 .andExpect(xpath(composerDouble, musicNamespace, 3).number(closeTo(1.6, .01)));
129 }
130
131 @Test
132 public void testBoolean() throws Exception {
133
134 String performerBooleanValue = "/ns:people/performers/performer[%s]/someBoolean";
135
136 this.mockMvc.perform(get("/music/people"))
137 .andExpect(xpath(performerBooleanValue, musicNamespace, 1).booleanValue(false))
138 .andExpect(xpath(performerBooleanValue, musicNamespace, 2).booleanValue(true));
139 }
140
141 @Test
142 public void testNodeCount() throws Exception {
143
144 this.mockMvc.perform(get("/music/people"))
145 .andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(4))
146 .andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(2))
147 .andExpect(xpath("/ns:people/composers/composer", musicNamespace).nodeCount(equalTo(4)))
148 .andExpect(xpath("/ns:people/performers/performer", musicNamespace).nodeCount(equalTo(2)));
149 }
150
151
152
153 @Test
154 public void testFeedWithLinefeedChars() throws Exception {
155
156
157
158 standaloneSetup(new BlogFeedController()).build()
159 .perform(get("/blog.atom").accept(MediaType.APPLICATION_ATOM_XML))
160 .andExpect(status().isOk())
161 .andExpect(content().contentType(MediaType.APPLICATION_ATOM_XML))
162 .andExpect(xpath("//feed/title").string("Test Feed"))
163 .andExpect(xpath("//feed/icon").string("http://www.example.com/favicon.ico"));
164 }
165
166
167 @Controller
168 private static class MusicController {
169
170 @RequestMapping(value="/music/people")
171 public @ResponseBody PeopleWrapper getPeople() {
172
173 List<Person> composers = Arrays.asList(
174 new Person("Johann Sebastian Bach").setSomeDouble(21),
175 new Person("Johannes Brahms").setSomeDouble(.0025),
176 new Person("Edvard Grieg").setSomeDouble(1.6035),
177 new Person("Robert Schumann").setSomeDouble(Double.NaN));
178
179 List<Person> performers = Arrays.asList(
180 new Person("Vladimir Ashkenazy").setSomeBoolean(false),
181 new Person("Yehudi Menuhin").setSomeBoolean(true));
182
183 return new PeopleWrapper(composers, performers);
184 }
185 }
186
187 @SuppressWarnings("unused")
188 @XmlRootElement(name="people", namespace="http://example.org/music/people")
189 @XmlAccessorType(XmlAccessType.FIELD)
190 private static class PeopleWrapper {
191
192 @XmlElementWrapper(name="composers")
193 @XmlElement(name="composer")
194 private List<Person> composers;
195
196 @XmlElementWrapper(name="performers")
197 @XmlElement(name="performer")
198 private List<Person> performers;
199
200 public PeopleWrapper() {
201 }
202
203 public PeopleWrapper(List<Person> composers, List<Person> performers) {
204 this.composers = composers;
205 this.performers = performers;
206 }
207
208 public List<Person> getComposers() {
209 return this.composers;
210 }
211
212 public List<Person> getPerformers() {
213 return this.performers;
214 }
215 }
216
217
218 @Controller
219 public class BlogFeedController {
220
221 @RequestMapping(value="/blog.atom", method = { GET, HEAD })
222 @ResponseBody
223 public String listPublishedPosts() {
224 return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
225 + "<feed xmlns=\"http://www.w3.org/2005/Atom\">\r\n"
226 + " <title>Test Feed</title>\r\n"
227 + " <icon>http://www.example.com/favicon.ico</icon>\r\n"
228 + "</feed>\r\n\r\n";
229 }
230 }
231
232 }