1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.betwixt.xmlunit;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.StringReader;
22 import java.io.StringWriter;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import javax.xml.parsers.DocumentBuilder;
30 import javax.xml.parsers.DocumentBuilderFactory;
31 import javax.xml.parsers.ParserConfigurationException;
32
33 import junit.framework.AssertionFailedError;
34 import junit.framework.TestCase;
35
36 import org.w3c.dom.Attr;
37 import org.w3c.dom.DOMException;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.NamedNodeMap;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44
45 /***
46 * Provides xml test utilities.
47 * Hopefully, these might be moved into [xmlunit] sometime.
48 *
49 * @author Robert Burrell Donkin
50 */
51 public class XmlTestCase extends TestCase {
52
53 protected static boolean debug = false;
54
55 DocumentBuilderFactory domFactory;
56
57
58 public XmlTestCase(String testName) {
59 super(testName);
60 }
61
62
63 public void xmlAssertIsomorphicContent(
64 org.w3c.dom.Document documentOne,
65 org.w3c.dom.Document documentTwo)
66 throws
67 AssertionFailedError {
68 log("Testing documents:" + documentOne.getDocumentElement().getNodeName()
69 + " and " + documentTwo.getDocumentElement().getNodeName());
70 xmlAssertIsomorphicContent(documentOne, documentTwo, false);
71 }
72
73 public void xmlAssertIsomorphicContent(
74 org.w3c.dom.Document documentOne,
75 org.w3c.dom.Document documentTwo,
76 boolean orderIndependent)
77 throws
78 AssertionFailedError {
79 xmlAssertIsomorphicContent(null, documentOne, documentTwo, orderIndependent);
80 }
81
82 public void xmlAssertIsomorphicContent(
83 String message,
84 org.w3c.dom.Document documentOne,
85 org.w3c.dom.Document documentTwo)
86 throws
87 AssertionFailedError {
88
89 xmlAssertIsomorphicContent(message, documentOne, documentTwo, false);
90 }
91
92 public void xmlAssertIsomorphicContent(
93 String message,
94 org.w3c.dom.Document documentOne,
95 org.w3c.dom.Document documentTwo,
96 boolean orderIndependent)
97 throws
98 AssertionFailedError
99 {
100
101
102 xmlAssertIsomorphic(
103 message,
104 documentOne.getDocumentElement(),
105 documentTwo.getDocumentElement(),
106 orderIndependent);
107 }
108
109
110 public void xmlAssertIsomorphic(
111 org.w3c.dom.Node rootOne,
112 org.w3c.dom.Node rootTwo)
113 throws
114 AssertionFailedError {
115 xmlAssertIsomorphic(rootOne, rootTwo, false);
116 }
117
118 public void xmlAssertIsomorphic(
119 org.w3c.dom.Node rootOne,
120 org.w3c.dom.Node rootTwo,
121 boolean orderIndependent)
122 throws
123 AssertionFailedError
124 {
125 xmlAssertIsomorphic(null, rootOne, rootTwo, orderIndependent);
126 }
127
128 public void xmlAssertIsomorphic(
129 String message,
130 org.w3c.dom.Node rootOne,
131 org.w3c.dom.Node rootTwo) {
132
133 xmlAssertIsomorphic(message, rootOne, rootTwo, false);
134
135 }
136
137 public void xmlAssertIsomorphic(
138 String message,
139 org.w3c.dom.Node rootOne,
140 org.w3c.dom.Node rootTwo,
141 boolean orderIndependent)
142 throws
143 AssertionFailedError
144 {
145
146 rootOne.normalize();
147 rootTwo.normalize();
148
149 testIsomorphic(message, rootOne, rootTwo, orderIndependent);
150 }
151
152
153 private void testIsomorphic(
154 String message,
155 org.w3c.dom.Node nodeOne,
156 org.w3c.dom.Node nodeTwo)
157 throws
158 AssertionFailedError {
159
160 testIsomorphic(message, nodeOne, nodeTwo, false);
161 }
162
163
164 private void testIsomorphic(
165 String message,
166 org.w3c.dom.Node nodeOne,
167 org.w3c.dom.Node nodeTwo,
168 boolean orderIndependent)
169 throws
170 AssertionFailedError
171 {
172 try {
173 if (debug) {
174 log(
175 "node 1 name=" + nodeOne.getNodeName()
176 + " qname=" + nodeOne.getLocalName());
177 log(
178 "node 2 name=" + nodeTwo.getNodeName()
179 + " qname=" + nodeTwo.getLocalName());
180 }
181
182
183 log("Comparing node properties");
184 assertEquals(
185 (null == message ? "(Unequal node types)" : message + "(Unequal node types)"),
186 nodeOne.getNodeType(),
187 nodeTwo.getNodeType());
188 assertEquals(
189 (null == message ? "(Unequal node names)" : message + "(Unequal node names)"),
190 nodeOne.getNodeName(),
191 nodeTwo.getNodeName());
192 assertEquals(
193 (null == message ? "(Unequal node values)" : message + "(Unequal node values)"),
194 trim(nodeOne.getNodeValue()),
195 trim(nodeTwo.getNodeValue()));
196 assertEquals(
197 (null == message ? "(Unequal local names)" : message + "(Unequal local names)"),
198 nodeOne.getLocalName(),
199 nodeTwo.getLocalName());
200 assertEquals(
201 (null == message ? "(Unequal namespace)" : message + "(Unequal namespace)"),
202 nodeOne.getNamespaceURI(),
203 nodeTwo.getNamespaceURI());
204
205
206
207 log("Comparing attributes");
208
209 assertEquals(
210 (null == message ? "(Unequal attributes)" : message + "(Unequal attributes)"),
211 nodeOne.hasAttributes(),
212 nodeTwo.hasAttributes());
213 if (nodeOne.hasAttributes()) {
214
215
216
217
218
219 NamedNodeMap attributesOne = nodeOne.getAttributes();
220 NamedNodeMap attributesTwo = nodeTwo.getAttributes();
221
222 assertEquals(
223 (null == message ? "(Unequal attributes)" : message + "(Unequal attributes)"),
224 attributesOne.getLength(),
225 attributesTwo.getLength());
226
227 for (int i=0, size=attributesOne.getLength(); i<size; i++) {
228 Attr attributeOne = (Attr) attributesOne.item(i);
229 Attr attributeTwo = (Attr) attributesTwo.getNamedItemNS(
230 attributeOne.getNamespaceURI(),
231 attributeOne.getLocalName());
232 if (attributeTwo == null) {
233 attributeTwo = (Attr) attributesTwo.getNamedItem(attributeOne.getName());
234 }
235
236
237 if (attributeTwo == null) {
238 String diagnosis = "[Missing attribute (" + attributeOne.getName() + ")]";
239 fail((null == message ? diagnosis : message + diagnosis));
240 }
241
242
243 assertEquals(
244 (null == message ? "(Unequal attribute values)" : message + "(Unequal attribute values)"),
245 attributeOne.getValue(),
246 attributeTwo.getValue());
247 }
248 }
249
250
251
252 log("Comparing children");
253
254
255 List listOne = sanitize(nodeOne.getChildNodes());
256 List listTwo = sanitize(nodeTwo.getChildNodes());
257
258 if (orderIndependent) {
259 log("[Order Independent]");
260 Comparator nodeByName = new NodeByNameComparator();
261 Collections.sort(listOne, nodeByName);
262 Collections.sort(listTwo, nodeByName);
263 }
264
265 Iterator it = listOne.iterator();
266 Iterator iter2 = listTwo.iterator();
267 while (it.hasNext() & iter2.hasNext()) {
268 Node nextOne = ((Node)it.next());
269 Node nextTwo = ((Node)iter2.next());
270 log(nextOne.getNodeName() + ":" + nextOne.getNodeValue());
271 log(nextTwo.getNodeName() + ":" + nextTwo.getNodeValue());
272 }
273
274 assertEquals(
275 (null == message ? "(Unequal child nodes@" + nodeOne.getNodeName() +")":
276 message + "(Unequal child nodes @" + nodeOne.getNodeName() +")"),
277 listOne.size(),
278 listTwo.size());
279
280 it = listOne.iterator();
281 iter2 = listTwo.iterator();
282 while (it.hasNext() & iter2.hasNext()) {
283 Node nextOne = ((Node)it.next());
284 Node nextTwo = ((Node)iter2.next());
285 log(nextOne.getNodeName() + " vs " + nextTwo.getNodeName());
286 testIsomorphic(message, nextOne, nextTwo, orderIndependent);
287
288 }
289
290 } catch (DOMException ex) {
291 fail((null == message ? "" : message + " ") + "DOM exception" + ex.toString());
292 }
293 }
294
295
296 protected DocumentBuilder createDocumentBuilder() {
297 try {
298
299 return getDomFactory().newDocumentBuilder();
300
301 } catch (ParserConfigurationException e) {
302 fail("Cannot create DOM builder: " + e.toString());
303
304 }
305
306 return null;
307 }
308
309 protected DocumentBuilderFactory getDomFactory() {
310
311 if (domFactory == null) {
312 domFactory = DocumentBuilderFactory.newInstance();
313 }
314
315 return domFactory;
316 }
317
318 protected Document parseString(StringWriter writer) {
319 try {
320
321 return createDocumentBuilder().parse(new InputSource(new StringReader(writer.getBuffer().toString())));
322
323 } catch (SAXException e) {
324 fail("Cannot create parse string: " + e.toString());
325
326 } catch (IOException e) {
327 fail("Cannot create parse string: " + e.toString());
328
329 }
330
331 return null;
332 }
333
334 protected Document parseString(String string) {
335 try {
336
337 return createDocumentBuilder().parse(new InputSource(new StringReader(string)));
338
339 } catch (SAXException e) {
340 fail("Cannot create parse string: " + e.toString());
341
342 } catch (IOException e) {
343 fail("Cannot create parse string: " + e.toString());
344
345 }
346
347 return null;
348 }
349
350
351 protected Document parseFile(String path) {
352 try {
353
354 return createDocumentBuilder().parse(new File(path));
355
356 } catch (SAXException e) {
357 fail("Cannot create parse file: " + e.toString());
358
359 } catch (IOException e) {
360 fail("Cannot create parse file: " + e.toString());
361
362 }
363
364 return null;
365 }
366
367 private void log(String message)
368 {
369 if (debug) {
370 System.out.println("[XmlTestCase]" + message);
371 }
372 }
373
374 private String trim(String trimThis)
375 {
376 if (trimThis == null) {
377 return trimThis;
378 }
379
380 return trimThis.trim();
381 }
382
383 private List sanitize(NodeList nodes) {
384 ArrayList list = new ArrayList();
385
386 for (int i=0, size=nodes.getLength(); i<size; i++) {
387 if ( nodes.item(i).getNodeType() == Node.TEXT_NODE ) {
388 if ( !( nodes.item(i).getNodeValue() == null ||
389 nodes.item(i).getNodeValue().trim().length() == 0 )) {
390 list.add(nodes.item(i));
391 } else {
392 log("Ignoring text node:" + nodes.item(i).getNodeValue());
393 }
394 } else {
395 list.add(nodes.item(i));
396 }
397 }
398 return list;
399 }
400
401 private class NodeByNameComparator implements Comparator {
402 public int compare(Object objOne, Object objTwo) {
403 String nameOne = ((Node) objOne).getNodeName();
404 String nameTwo = ((Node) objTwo).getNodeName();
405
406 if (nameOne == null) {
407 if (nameTwo == null) {
408 return 0;
409 }
410 return -1;
411 }
412
413 if (nameTwo == null) {
414 return 1;
415 }
416
417 return nameOne.compareTo(nameTwo);
418 }
419 }
420 }
421