1 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.apache.xerces.parsers.SAXParser; 37 import org.w3c.dom.Attr ; 38 import org.w3c.dom.DOMException ; 39 import org.w3c.dom.Document ; 40 import org.w3c.dom.NamedNodeMap ; 41 import org.w3c.dom.Node ; 42 import org.w3c.dom.NodeList ; 43 import org.xml.sax.InputSource ; 44 import org.xml.sax.SAXException ; 45 import org.xml.sax.SAXParseException ; 46 import org.xml.sax.helpers.DefaultHandler ; 47 48 55 public class XmlTestCase extends TestCase { 56 57 private static final String NAMESPACES_FEATURE_ID 58 = "http://xml.org/sax/features/namespaces"; 59 60 private static final String NAMESPACE_PREFIXES_FEATURE_ID 61 = "http://xml.org/sax/features/namespace-prefixes"; 62 63 private static final String VALIDATION_FEATURE_ID 64 = "http://xml.org/sax/features/validation"; 65 66 private static final String SCHEMA_VALIDATION_FEATURE_ID 67 = "http://apache.org/xml/features/validation/schema"; 68 69 private static final String SCHEMA_FULL_CHECKING_FEATURE_ID 70 = "http://apache.org/xml/features/validation/schema-full-checking"; 71 72 private static final String DYNAMIC_VALIDATION_FEATURE_ID 73 = "http://apache.org/xml/features/validation/dynamic"; 74 75 private static final String NONAMESPACE_SCHEMA_LOCATION_PROPERTY_ID 76 = "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; 77 78 79 protected static boolean debug = false; 80 81 DocumentBuilderFactory domFactory; 82 83 84 public XmlTestCase(String testName) { 85 super(testName); 86 } 87 88 89 public void xmlAssertIsomorphicContent( 90 org.w3c.dom.Document documentOne, 91 org.w3c.dom.Document documentTwo) 92 throws 93 AssertionFailedError { 94 log("Testing documents:" + documentOne.getDocumentElement().getNodeName() 95 + " and " + documentTwo.getDocumentElement().getNodeName()); 96 xmlAssertIsomorphicContent(documentOne, documentTwo, false); 97 } 98 99 public void xmlAssertIsomorphicContent( 100 org.w3c.dom.Document documentOne, 101 org.w3c.dom.Document documentTwo, 102 boolean orderIndependent) 103 throws 104 AssertionFailedError { 105 xmlAssertIsomorphicContent(null, documentOne, documentTwo, orderIndependent); 106 } 107 108 public void xmlAssertIsomorphicContent( 109 String message, 110 org.w3c.dom.Document documentOne, 111 org.w3c.dom.Document documentTwo) 112 throws 113 AssertionFailedError { 114 115 xmlAssertIsomorphicContent(message, documentOne, documentTwo, false); 116 } 117 118 public void xmlAssertIsomorphicContent( 119 String message, 120 org.w3c.dom.Document documentOne, 121 org.w3c.dom.Document documentTwo, 122 boolean orderIndependent) 123 throws 124 AssertionFailedError 125 { 126 xmlAssertIsomorphic( 129 message, 130 documentOne.getDocumentElement(), 131 documentTwo.getDocumentElement(), 132 orderIndependent); 133 } 134 135 136 public void xmlAssertIsomorphic( 137 org.w3c.dom.Node rootOne, 138 org.w3c.dom.Node rootTwo) 139 throws 140 AssertionFailedError { 141 xmlAssertIsomorphic(rootOne, rootTwo, false); 142 } 143 144 public void xmlAssertIsomorphic( 145 org.w3c.dom.Node rootOne, 146 org.w3c.dom.Node rootTwo, 147 boolean orderIndependent) 148 throws 149 AssertionFailedError 150 { 151 xmlAssertIsomorphic(null, rootOne, rootTwo, orderIndependent); 152 } 153 154 public void xmlAssertIsomorphic( 155 String message, 156 org.w3c.dom.Node rootOne, 157 org.w3c.dom.Node rootTwo) { 158 159 xmlAssertIsomorphic(message, rootOne, rootTwo, false); 160 161 } 162 163 public void xmlAssertIsomorphic( 164 String message, 165 org.w3c.dom.Node rootOne, 166 org.w3c.dom.Node rootTwo, 167 boolean orderIndependent) 168 throws 169 AssertionFailedError 170 { 171 rootOne.normalize(); 173 rootTwo.normalize(); 174 testIsomorphic(message, rootOne, rootTwo, orderIndependent); 176 } 177 178 179 private void testIsomorphic( 180 String message, 181 org.w3c.dom.Node nodeOne, 182 org.w3c.dom.Node nodeTwo) 183 throws 184 AssertionFailedError { 185 186 testIsomorphic(message, nodeOne, nodeTwo, false); 187 } 188 189 190 private void testIsomorphic( 191 String message, 192 org.w3c.dom.Node nodeOne, 193 org.w3c.dom.Node nodeTwo, 194 boolean orderIndependent) 195 throws 196 AssertionFailedError 197 { 198 try { 199 if (debug) { 200 log( 201 "node 1 name=" + nodeOne.getNodeName() 202 + " qname=" + nodeOne.getLocalName()); 203 log( 204 "node 2 name=" + nodeTwo.getNodeName() 205 + " qname=" + nodeTwo.getLocalName()); 206 } 207 208 log("Comparing node properties"); 210 assertEquals( 211 (null == message ? "(Unequal node types)" : message + "(Unequal node types)"), 212 nodeOne.getNodeType(), 213 nodeTwo.getNodeType()); 214 assertEquals( 215 (null == message ? "(Unequal node names)" : message + "(Unequal node names)"), 216 nodeOne.getNodeName(), 217 nodeTwo.getNodeName()); 218 assertEquals( 219 (null == message ? "(Unequal node values)" : message + "(Unequal node values)"), 220 trim(nodeOne.getNodeValue()), 221 trim(nodeTwo.getNodeValue())); 222 assertEquals( 223 (null == message ? "(Unequal local names)" : message + "(Unequal local names)"), 224 nodeOne.getLocalName(), 225 nodeTwo.getLocalName()); 226 assertEquals( 227 (null == message ? "(Unequal namespace)" : message + "(Unequal namespace)"), 228 nodeOne.getNamespaceURI(), 229 nodeTwo.getNamespaceURI()); 230 231 232 log("Comparing attributes"); 234 assertEquals( 236 (null == message ? "(Unequal attributes)" : message + "(Unequal attributes)"), 237 nodeOne.hasAttributes(), 238 nodeTwo.hasAttributes()); 239 if (nodeOne.hasAttributes()) { 240 NamedNodeMap attributesOne = nodeOne.getAttributes(); 246 NamedNodeMap attributesTwo = nodeTwo.getAttributes(); 247 248 assertEquals( 249 (null == message ? "(Unequal attributes)" : message + "(Unequal attributes)"), 250 attributesOne.getLength(), 251 attributesTwo.getLength()); 252 253 for (int i=0, size=attributesOne.getLength(); i<size; i++) { 254 Attr attributeOne = (Attr ) attributesOne.item(i); 255 Attr attributeTwo = (Attr ) attributesTwo.getNamedItemNS( 256 attributeOne.getNamespaceURI(), 257 attributeOne.getLocalName()); 258 if (attributeTwo == null) { 259 attributeTwo = (Attr ) attributesTwo.getNamedItem(attributeOne.getName()); 260 } 261 262 if (attributeTwo == null) { 264 String diagnosis = "[Missing attribute (" + attributeOne.getName() + ")]"; 265 fail((null == message ? diagnosis : message + diagnosis)); 266 } 267 268 assertEquals( 270 (null == message ? "(Unequal attribute values)" : message + "(Unequal attribute values)"), 271 attributeOne.getValue(), 272 attributeTwo.getValue()); 273 } 274 } 275 276 277 log("Comparing children"); 279 List listOne = sanitize(nodeOne.getChildNodes()); 282 List listTwo = sanitize(nodeTwo.getChildNodes()); 283 284 if (orderIndependent) { 285 log("[Order Independent]"); 286 Comparator nodeByName = new NodeByNameComparator(); 287 Collections.sort(listOne, nodeByName); 288 Collections.sort(listTwo, nodeByName); 289 } 290 291 Iterator it = listOne.iterator(); 292 Iterator iter2 = listTwo.iterator(); 293 while (it.hasNext() & iter2.hasNext()) { 294 Node nextOne = ((Node )it.next()); 295 Node nextTwo = ((Node )iter2.next()); 296 log(nextOne.getNodeName() + ":" + nextOne.getNodeValue()); 297 log(nextTwo.getNodeName() + ":" + nextTwo.getNodeValue()); 298 } 299 300 assertEquals( 301 (null == message ? "(Unequal child nodes@" + nodeOne.getNodeName() +")": 302 message + "(Unequal child nodes @" + nodeOne.getNodeName() +")"), 303 listOne.size(), 304 listTwo.size()); 305 306 it = listOne.iterator(); 307 iter2 = listTwo.iterator(); 308 while (it.hasNext() & iter2.hasNext()) { 309 Node nextOne = ((Node )it.next()); 310 Node nextTwo = ((Node )iter2.next()); 311 log(nextOne.getNodeName() + " vs " + nextTwo.getNodeName()); 312 testIsomorphic(message, nextOne, nextTwo, orderIndependent); 313 314 } 315 316 } catch (DOMException ex) { 317 fail((null == message ? "" : message + " ") + "DOM exception" + ex.toString()); 318 } 319 } 320 321 322 protected DocumentBuilder createDocumentBuilder() { 323 try { 324 325 return getDomFactory().newDocumentBuilder(); 326 327 } catch (ParserConfigurationException e) { 328 fail("Cannot create DOM builder: " + e.toString()); 329 330 } 331 return null; 333 } 334 335 protected DocumentBuilderFactory getDomFactory() { 336 if (domFactory == null) { 338 domFactory = DocumentBuilderFactory.newInstance(); 339 } 340 341 return domFactory; 342 } 343 344 protected Document parseString(StringWriter writer) { 345 try { 346 347 return createDocumentBuilder().parse(new InputSource (new StringReader (writer.getBuffer().toString()))); 348 349 } catch (SAXException e) { 350 fail("Cannot create parse string: " + e.toString()); 351 352 } catch (IOException e) { 353 fail("Cannot create parse string: " + e.toString()); 354 355 } 356 return null; 358 } 359 360 protected Document parseString(String string) { 361 try { 362 363 return createDocumentBuilder().parse(new InputSource (new StringReader (string))); 364 365 } catch (SAXException e) { 366 fail("Cannot create parse string: " + e.toString()); 367 368 } catch (IOException e) { 369 fail("Cannot create parse string: " + e.toString()); 370 371 } 372 return null; 374 } 375 376 377 protected Document parseFile(String path) { 378 try { 379 380 return createDocumentBuilder().parse(new File (path)); 381 382 } catch (SAXException e) { 383 fail("Cannot create parse file: " + e.toString()); 384 385 } catch (IOException e) { 386 fail("Cannot create parse file: " + e.toString()); 387 388 } 389 return null; 391 } 392 393 private void log(String message) 394 { 395 if (debug) { 396 System.out.println("[XmlTestCase]" + message); 397 } 398 } 399 400 401 private void log(String message, Exception e) 402 { 403 if (debug) { 404 System.out.println("[XmlTestCase]" + message); 405 e.printStackTrace(); 406 } 407 } 408 409 private String trim(String trimThis) 410 { 411 if (trimThis == null) { 412 return trimThis; 413 } 414 415 return trimThis.trim(); 416 } 417 418 private List sanitize(NodeList nodes) { 419 ArrayList list = new ArrayList (); 420 421 for (int i=0, size=nodes.getLength(); i<size; i++) { 422 if ( nodes.item(i).getNodeType() == Node.TEXT_NODE ) { 423 if ( !( nodes.item(i).getNodeValue() == null || 424 nodes.item(i).getNodeValue().trim().length() == 0 )) { 425 list.add(nodes.item(i)); 426 } else { 427 log("Ignoring text node:" + nodes.item(i).getNodeValue()); 428 } 429 } else { 430 list.add(nodes.item(i)); 431 } 432 } 433 return list; 434 } 435 436 private class NodeByNameComparator implements Comparator { 437 public int compare(Object objOne, Object objTwo) { 438 String nameOne = ((Node ) objOne).getNodeName(); 439 String nameTwo = ((Node ) objTwo).getNodeName(); 440 441 if (nameOne == null) { 442 if (nameTwo == null) { 443 return 0; 444 } 445 return -1; 446 } 447 448 if (nameTwo == null) { 449 return 1; 450 } 451 452 return nameOne.compareTo(nameTwo); 453 } 454 } 455 456 457 public void validateWithSchema(InputSource documentSource, final InputSource schemaSource) 458 throws ParserConfigurationException , SAXException , IOException 459 { 460 class XMLUnitHandler extends DefaultHandler { 461 ArrayList errors = new ArrayList (); 462 ArrayList warnings = new ArrayList (); 463 InputSource schemaSource; 464 465 XMLUnitHandler(InputSource schemaSource) { 466 this.schemaSource = schemaSource; 467 schemaSource.setSystemId("schema.xsd"); 468 } 469 470 public InputSource resolveEntity(String publicId, String systemId) { 471 return schemaSource; 472 } 473 474 public void error(SAXParseException ex) { 475 errors.add(ex); 476 } 477 478 public void warning(SAXParseException ex) { 479 warnings.add(ex); 480 } 481 482 void reportErrors() throws SAXException { 483 if (errors.size() > 0) { 484 throw (SAXException ) errors.get(0); 485 } 486 } 487 488 } 489 490 SAXParser parser = new SAXParser(); 496 497 parser.setFeature(NAMESPACES_FEATURE_ID, true); 499 parser.setFeature(NAMESPACE_PREFIXES_FEATURE_ID, false); 500 parser.setFeature(VALIDATION_FEATURE_ID, true); 501 parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, true); 502 parser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, false); 503 parser.setFeature(DYNAMIC_VALIDATION_FEATURE_ID, false); 504 505 parser.setProperty(NONAMESPACE_SCHEMA_LOCATION_PROPERTY_ID, "schema.xsd"); 507 508 XMLUnitHandler handler = new XMLUnitHandler(schemaSource); 509 510 parser.setContentHandler(handler); 512 parser.setErrorHandler(handler); 513 parser.setEntityResolver(handler); 514 515 parser.parse(documentSource); 517 handler.reportErrors(); 518 } 519 520 public boolean isValid(InputSource documentSource, InputSource schemaSource) 521 throws ParserConfigurationException , IOException 522 { 523 boolean result = false; 524 try 525 { 526 validateWithSchema(documentSource, schemaSource); 527 result = true; 528 } 529 catch (SAXException se) 530 { 531 log("Validation failed.", se); 532 } 533 534 return result; 535 } 536 537 public void xmlAssertIsValid(InputSource documentSource, InputSource schemaSource) 538 throws ParserConfigurationException , IOException 539 { 540 try 541 { 542 validateWithSchema(documentSource, schemaSource); 543 } 544 catch (SAXException se) 545 { 546 se.printStackTrace(); 547 fail("Validation failure: " + se.getMessage()); 548 } 549 } 550 } 551 552 | Popular Tags |