1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id$ 20 */ 21 22 /* 23 * 24 * ProgrammaticDOMTest.java 25 * 26 */ 27 package org.apache.qetest.xalanj2; 28 29 import android.platform.test.annotations.FlakyTest; 30 import java.io.File; 31 import java.util.Properties; 32 33 import javax.xml.parsers.DocumentBuilder; 34 import javax.xml.parsers.DocumentBuilderFactory; 35 import javax.xml.transform.Templates; 36 import javax.xml.transform.Transformer; 37 import javax.xml.transform.TransformerFactory; 38 import javax.xml.transform.dom.DOMResult; 39 import javax.xml.transform.dom.DOMSource; 40 import javax.xml.transform.stream.StreamResult; 41 42 import org.apache.qetest.FileBasedTest; 43 import org.apache.qetest.Logger; 44 import org.apache.qetest.OutputNameManager; 45 import org.apache.qetest.QetestUtils; 46 import org.apache.qetest.xsl.XSLTestfileInfo; 47 import org.junit.Test; 48 import org.w3c.dom.Document; 49 import org.w3c.dom.DocumentFragment; 50 import org.w3c.dom.Element; 51 import org.w3c.dom.Node; 52 import org.xml.sax.InputSource; 53 54 //------------------------------------------------------------------------- 55 56 /** 57 * Functionality/system/integration tests for DOMSource. 58 * Various kinds of DOM elements, documents used. 59 * @author shane_curcuru@lotus.com 60 * @version $Id$ 61 */ 62 public class ProgrammaticDOMTest extends FileBasedTest 63 { 64 65 /** Provides nextName(), currentName() functionality. */ 66 protected OutputNameManager outNames; 67 68 /** Simple DOMTest.xml/xsl file pair. */ 69 protected XSLTestfileInfo testFileInfo = new XSLTestfileInfo(); 70 71 /** Subdirectory under test\tests\api for our xsl/xml files. */ 72 public static final String TRAX_SUBDIR = File.separator + "trax" + File.separator; 73 74 private static final String xslNamespace = "http://www.w3.org/1999/XSL/Transform"; 75 private static final String nsNamespace = "http://www.w3.org/XML/1998/namespace"; 76 77 /** Just initialize test name, comment, numTestCases. */ ProgrammaticDOMTest()78 public ProgrammaticDOMTest() 79 { 80 numTestCases = 2; // REPLACE_num 81 testName = "ProgrammaticDOMTest"; 82 testComment = "Functionality/system/integration tests for DOMSource"; 83 } 84 85 86 /** 87 * Initialize this test - Set names of xml/xsl test files. 88 * 89 * @param p Properties to initialize from (if needed) 90 * @return false if we should abort the test; true otherwise 91 */ doTestFileInit(Properties p)92 public boolean doTestFileInit(Properties p) 93 { 94 // Used for all tests; just dump files in trax subdir 95 File outSubDir = new File(outputDir + TRAX_SUBDIR); 96 if (!outSubDir.mkdirs()) 97 reporter.logWarningMsg("Could not create output dir: " + outSubDir); 98 // Initialize an output name manager to that dir with .out extension 99 outNames = new OutputNameManager(outputDir + TRAX_SUBDIR 100 + testName, ".out"); 101 102 testFileInfo.inputName = QetestUtils.filenameToURL(inputDir 103 + TRAX_SUBDIR + "identity.xsl"); 104 testFileInfo.xmlName = QetestUtils.filenameToURL(inputDir 105 + TRAX_SUBDIR + "identity.xml"); 106 testFileInfo.goldName = goldDir + TRAX_SUBDIR + "identity.out"; 107 108 try 109 { 110 TransformerFactory tf = TransformerFactory.newInstance(); 111 if (!(tf.getFeature(DOMSource.FEATURE) 112 && tf.getFeature(DOMResult.FEATURE))) 113 { // The rest of this test relies on DOM 114 reporter.logErrorMsg("DOM*.FEATURE not supported! Some tests may be invalid!"); 115 } 116 } 117 catch (Throwable t) 118 { 119 reporter.checkFail( 120 "Problem creating factory; Some tests may be invalid!"); 121 reporter.logThrowable(reporter.ERRORMSG, t, 122 "Problem creating factory; Some tests may be invalid!"); 123 } 124 125 return true; 126 } 127 128 129 /** 130 * Pass various forms of XML DOM's to a transform. 131 * Reproduce Bugzilla 1361. 132 * http://nagoya.apache.org/bugzilla/show_bug.cgi?id=1361 133 * 134 * @return false if we should abort the test; true otherwise 135 */ testCase1()136 public boolean testCase1() 137 { 138 reporter.testCaseInit("Pass various forms of XML DOM's to a transform"); 139 140 try 141 { 142 // Startup a factory and docbuilder, create some nodes/DOMs 143 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 144 dfactory.setNamespaceAware(true); 145 DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); 146 147 reporter.logTraceMsg("parsing xml, xsl files"); 148 Document xslDoc = docBuilder.parse(new InputSource(testFileInfo.inputName)); 149 Document xmlDoc = docBuilder.parse(new InputSource(testFileInfo.xmlName)); 150 TransformerFactory factory = TransformerFactory.newInstance(); 151 152 // Try a transform with XSL Document and XML Document (common usage) 153 Templates templates = factory.newTemplates(new DOMSource(xslDoc)); 154 Transformer transformer = templates.newTransformer(); 155 reporter.logInfoMsg("About to transform(xmlDoc, StreamResult(" + outNames.nextName() + "))"); 156 transformer.transform(new DOMSource(xmlDoc), new StreamResult(outNames.currentName())); 157 fileChecker.check(reporter, 158 new File(outNames.currentName()), 159 new File(testFileInfo.goldName), 160 "transform(xmlDoc,...) into " + outNames.currentName()); 161 162 // Programmatically build the XML file into a Document and transform 163 Document xmlBuiltDoc = docBuilder.newDocument(); 164 appendIdentityDOMXML(xmlBuiltDoc, xmlBuiltDoc, true); 165 transformer = templates.newTransformer(); 166 reporter.logInfoMsg("About to transform(xmlBuiltDoc, StreamResult(" + outNames.nextName() + "))"); 167 transformer.transform(new DOMSource(xmlBuiltDoc), new StreamResult(outNames.currentName())); 168 fileChecker.check(reporter, 169 new File(outNames.currentName()), 170 new File(testFileInfo.goldName), 171 "transform(xmlBuiltDoc,...) into " + outNames.currentName()); 172 173 // Again, with identity transformer 174 transformer = factory.newTransformer(); 175 reporter.logInfoMsg("About to identityTransform(xmlBuiltDoc, StreamResult(" + outNames.nextName() + "))"); 176 transformer.transform(new DOMSource(xmlBuiltDoc), new StreamResult(outNames.currentName())); 177 fileChecker.check(reporter, 178 new File(outNames.currentName()), 179 new File(testFileInfo.goldName), 180 "identityTransform(xmlBuiltDoc,...) into " + outNames.currentName()); 181 182 183 // Programmatically build the XML file into a DocFrag and transform 184 xmlBuiltDoc = docBuilder.newDocument(); 185 DocumentFragment xmlBuiltDocFrag = xmlBuiltDoc.createDocumentFragment(); 186 appendIdentityDOMXML(xmlBuiltDocFrag, xmlBuiltDoc, true); 187 transformer = templates.newTransformer(); 188 reporter.logInfoMsg("About to transform(xmlBuiltDocFrag, StreamResult(" + outNames.nextName() + "))"); 189 transformer.transform(new DOMSource(xmlBuiltDocFrag), new StreamResult(outNames.currentName())); 190 fileChecker.check(reporter, 191 new File(outNames.currentName()), 192 new File(testFileInfo.goldName), 193 "transform(xmlBuiltDocFrag,...) into " + outNames.currentName()); 194 195 // Again, with identity transformer 196 transformer = factory.newTransformer(); 197 reporter.logInfoMsg("About to identityTransform(xmlBuiltDocFrag, StreamResult(" + outNames.nextName() + "))"); 198 transformer.transform(new DOMSource(xmlBuiltDocFrag), new StreamResult(outNames.currentName())); 199 fileChecker.check(reporter, 200 new File(outNames.currentName()), 201 new File(testFileInfo.goldName), 202 "identityTransform(xmlBuiltDocFrag,...) into " + outNames.currentName()); 203 204 205 // Programmatically build the XML file into an Element and transform 206 xmlBuiltDoc = docBuilder.newDocument(); 207 // Note: Here, we implicitly already have the outer list 208 // element, so ensure the worker method doesn't add again 209 Element xmlBuiltElem = xmlBuiltDoc.createElement("list"); 210 appendIdentityDOMXML(xmlBuiltElem, xmlBuiltDoc, false); 211 transformer = templates.newTransformer(); 212 reporter.logInfoMsg("About to transform(xmlBuiltElem, StreamResult(" + outNames.nextName() + "))"); 213 transformer.transform(new DOMSource(xmlBuiltElem), new StreamResult(outNames.currentName())); 214 fileChecker.check(reporter, 215 new File(outNames.currentName()), 216 new File(testFileInfo.goldName), 217 "transform(xmlBuiltElem,...) into " + outNames.currentName()); 218 219 // Again, with identity transformer 220 transformer = factory.newTransformer(); 221 reporter.logInfoMsg("About to identityTransform(xmlBuiltElem, StreamResult(" + outNames.nextName() + "))"); 222 transformer.transform(new DOMSource(xmlBuiltElem), new StreamResult(outNames.currentName())); 223 fileChecker.check(reporter, 224 new File(outNames.currentName()), 225 new File(testFileInfo.goldName), 226 "identityTransform(xmlBuiltElem,...) into " + outNames.currentName()); 227 } 228 catch (Throwable t) 229 { 230 reporter.checkFail("Problem with various XML elems/documents"); 231 reporter.logThrowable(reporter.ERRORMSG, t, "Problem with various XML elems/documents"); 232 } 233 234 reporter.testCaseClose(); 235 return true; 236 } 237 238 239 /** 240 * Build a stylesheet DOM programmatically and use it. 241 * 242 * @return false if we should abort the test; true otherwise 243 */ testCase2()244 public boolean testCase2() 245 { 246 reporter.testCaseInit("Build a stylesheet DOM programmatically and use it"); 247 248 try 249 { 250 // Startup a factory and docbuilder, create some nodes/DOMs 251 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 252 dfactory.setNamespaceAware(true); 253 DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); 254 255 reporter.logTraceMsg("parsing xml file"); 256 Document xmlDoc = docBuilder.parse(new InputSource(testFileInfo.xmlName)); 257 TransformerFactory factory = TransformerFactory.newInstance(); 258 Transformer transformer = null; 259 260 // Programmatically build the XSL file into a Document and transform 261 Document xslBuiltDoc = docBuilder.newDocument(); 262 appendIdentityDOMXSL(xslBuiltDoc, xslBuiltDoc, true); 263 // For debugging, write the generated stylesheet out 264 // Note this will not textually exactly match the identity.xsl file 265 reporter.logInfoMsg("Writing out xslBuiltDoc to "+ outNames.nextName()); 266 transformer = factory.newTransformer(); 267 transformer.transform(new DOMSource(xslBuiltDoc), new StreamResult(outNames.currentName())); 268 269 reporter.logInfoMsg("About to newTransformer(xslBuiltDoc)"); 270 transformer = factory.newTransformer(new DOMSource(xslBuiltDoc)); 271 reporter.logInfoMsg("About to transform(xmlDoc, StreamResult(" + outNames.nextName() + "))"); 272 transformer.transform(new DOMSource(xmlDoc), new StreamResult(outNames.currentName())); 273 fileChecker.check(reporter, 274 new File(outNames.currentName()), 275 new File(testFileInfo.goldName), 276 "transform(xslBuiltDoc,...) into " + outNames.currentName()); 277 278 279 // Programmatically build the XSL file into a DocFrag and transform 280 xslBuiltDoc = docBuilder.newDocument(); 281 DocumentFragment xslBuiltDocFrag = xslBuiltDoc.createDocumentFragment(); 282 appendIdentityDOMXSL(xslBuiltDocFrag, xslBuiltDoc, true); 283 // For debugging, write the generated stylesheet out 284 reporter.logInfoMsg("Writing out xslBuiltDocFrag to "+ outNames.nextName()); 285 transformer = factory.newTransformer(); 286 transformer.transform(new DOMSource(xslBuiltDocFrag), new StreamResult(outNames.currentName())); 287 288 reporter.logCriticalMsg("//@todo Verify that this is even a valid operation!"); 289 reporter.logCriticalMsg("Bugzilla#5133 NPE below MOVED to SmoketestOuttakes.java 27-Nov-01 -sc"); 290 /* @todo Bugzilla#5133 NPE below MOVED to SmoketestOuttakes.java 27-Nov-01 -sc 291 // Check that the DOM is actually correct, esp namespace nodes on top level 292 // java.lang.NullPointerException 293 // at org.apache.xalan.transformer.TransformerImpl.createResultContentHandler(TransformerImpl.java, Compiled Code) 294 295 296 reporter.logInfoMsg("About to newTransformer(xslBuiltDocFrag)"); 297 transformer = factory.newTransformer(new DOMSource(xslBuiltDocFrag)); 298 reporter.logInfoMsg("About to transform(xmlDoc, StreamResult(" + outNames.nextName() + "))"); 299 transformer.transform(new DOMSource(xmlDoc), new StreamResult(outNames.currentName())); 300 fileChecker.check(reporter, 301 new File(outNames.currentName()), 302 new File(testFileInfo.goldName), 303 "transform(xslBuiltDocFrag,...) into " + outNames.currentName()); 304 ** @todo Bugzilla#5133 NPE above MOVED to SmoketestOuttakes.java 27-Nov-01 -sc */ 305 } 306 catch (Throwable t) 307 { 308 reporter.checkFail("Problem with various XSL1 elems/documents"); 309 reporter.logThrowable(reporter.ERRORMSG, t, "Problem with various XSL1 elems/documents"); 310 } 311 312 /* @todo Bugzilla#5133 DOM003 Namespace error below MOVED to SmoketestOuttakes.java 27-Nov-01 -sc 313 //org.w3c.dom.DOMException: DOM003 Namespace error 314 // at org.apache.xerces.dom.AttrNSImpl.<init>(AttrNSImpl.java:134) 315 // at org.apache.xerces.dom.CoreDocumentImpl.createAttributeNS(CoreDocumentImpl.java:1363) 316 // at org.apache.xerces.dom.ElementImpl.setAttributeNS(ElementImpl.java:596) 317 // at org.apache.qetest.xalanj2.ProgrammaticDOMTest.testCase2(ProgrammaticDOMTest.java:355) 318 319 try 320 { 321 // Startup a factory and docbuilder, create some nodes/DOMs 322 DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); 323 dfactory.setNamespaceAware(true); 324 DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); 325 326 reporter.logTraceMsg("parsing xml file"); 327 Document xmlDoc = docBuilder.parse(new InputSource(testFileInfo.xmlName)); 328 TransformerFactory factory = TransformerFactory.newInstance(); 329 Transformer transformer = null; 330 331 // Programmatically build the XSL file into an Element and transform 332 Document xslBuiltDoc = docBuilder.newDocument(); 333 // Note: Here, we implicitly already have the outer list 334 // element, so ensure the worker method doesn't add again 335 Element xslBuiltElem = xslBuiltDoc.createElementNS(xslNamespace, "xsl:stylesheet"); 336 xslBuiltElem.setAttributeNS(null, "version", "1.0"); 337 xslBuiltElem.setAttributeNS(nsNamespace, "xmlns:xsl", xslNamespace); 338 appendIdentityDOMXSL(xslBuiltElem, xslBuiltDoc, false); 339 // For debugging, write the generated stylesheet out 340 reporter.logInfoMsg("Writing out xslBuiltElem to "+ outNames.nextName()); 341 transformer = factory.newTransformer(); 342 transformer.transform(new DOMSource(xslBuiltElem), new StreamResult(outNames.currentName())); 343 344 reporter.logCriticalMsg("//@todo Verify that this is even a valid operation!"); 345 reporter.logInfoMsg("About to newTransformer(xslBuiltElem)"); 346 transformer = factory.newTransformer(new DOMSource(xslBuiltElem)); 347 reporter.logInfoMsg("About to transform(xmlDoc, StreamResult(" + outNames.nextName() + "))"); 348 transformer.transform(new DOMSource(xmlDoc), new StreamResult(outNames.currentName())); 349 fileChecker.check(reporter, 350 new File(outNames.currentName()), 351 new File(testFileInfo.goldName), 352 "transform(xslBuiltElem,...) into " + outNames.currentName()); 353 } 354 catch (Throwable t) 355 { 356 reporter.checkFail("Problem with various XSL2 elems/documents"); 357 reporter.logThrowable(reporter.ERRORMSG, t, "Problem with various XSL2 elems/documents"); 358 } 359 ** @todo Bugzilla#5133 DOM003 Namespace error above MOVED to SmoketestOuttakes.java 27-Nov-01 -sc */ 360 361 reporter.testCaseClose(); 362 return true; 363 } 364 365 366 /** 367 * Adds identity.xml elems to Node passed in. 368 * Subject to change; hackish for now 369 * @author curcuru 370 * @param n Node to append DOM elems to 371 * @param factory Document providing createElement, etc. services 372 * @param useOuterElem if we should append the top-level <list> elem 373 */ appendIdentityDOMXML(Node n, Document factory, boolean useOuterElem)374 public void appendIdentityDOMXML(Node n, Document factory, boolean useOuterElem) 375 { 376 try 377 { 378 Node container = null; 379 if (useOuterElem) 380 { 381 // If asked to, create and append top-level <list> 382 container = factory.createElement("list"); 383 n.appendChild(container); 384 } 385 else 386 { 387 // Otherwise, just use their Node 388 container = n; 389 } 390 container.appendChild(factory.createTextNode("\n ")); 391 392 Element elemItem = factory.createElement("item"); 393 elemItem.appendChild(factory.createTextNode("Xalan-J 1.x")); 394 container.appendChild(elemItem); 395 container.appendChild(factory.createTextNode("\n ")); 396 397 elemItem = factory.createElement("item"); 398 elemItem.appendChild(factory.createTextNode("Xalan-J 2.x")); 399 container.appendChild(elemItem); 400 container.appendChild(factory.createTextNode("\n ")); 401 402 elemItem = factory.createElement("item"); 403 elemItem.appendChild(factory.createTextNode("Xalan-C 1.x")); 404 container.appendChild(elemItem); 405 container.appendChild(factory.createTextNode("\n ")); 406 407 Element elemInnerList = factory.createElement("list"); 408 container.appendChild(elemInnerList); 409 elemInnerList.appendChild(factory.createTextNode("\n ")); 410 411 elemItem = factory.createElement("item"); 412 elemItem.appendChild(factory.createTextNode("Xalan documentation")); 413 elemInnerList.appendChild(elemItem); 414 elemInnerList.appendChild(factory.createTextNode("\n ")); 415 416 elemItem = factory.createElement("item"); 417 elemItem.appendChild(factory.createTextNode("Xalan tests")); 418 elemInnerList.appendChild(elemItem); 419 elemInnerList.appendChild(factory.createTextNode("\n ")); 420 421 container.appendChild(factory.createTextNode("\n")); 422 } 423 catch (Exception e) 424 { 425 reporter.logErrorMsg("appendDOMTestXML threw: " + e.toString()); 426 reporter.logThrowable(Logger.ERRORMSG, e, "appendDOMTestXML threw"); 427 } 428 } 429 430 431 /** 432 * Adds identity.xsl elems to Node passed in. 433 * Subject to change; hackish for now 434 * @author curcuru 435 * @param n Node to append DOM elems to 436 * @param factory Document providing createElement, etc. services 437 * @param useOuterElem if we should append the top-level <stylesheet> elem 438 */ appendIdentityDOMXSL(Node n, Document factory, boolean useOuterElem)439 public void appendIdentityDOMXSL(Node n, Document factory, boolean useOuterElem) 440 { 441 try 442 { 443 /// <xsl:template match="@*|node()"> 444 Element template = factory.createElementNS(xslNamespace, "xsl:template"); 445 template.setAttributeNS(null, "match", "@*|node()"); 446 447 /// <xsl:copy> 448 Element copyElem = factory.createElementNS(xslNamespace, "xsl:copy"); 449 450 /// <xsl:apply-templates select="@*|node()"/> 451 Element applyTemplatesElem = factory.createElementNS(xslNamespace, "xsl:apply-templates"); 452 applyTemplatesElem.setAttributeNS(null, "select", "@*|node()"); 453 454 // Stick it all together with faked-up newlines for readability 455 copyElem.appendChild(factory.createTextNode("\n ")); 456 copyElem.appendChild(applyTemplatesElem); 457 copyElem.appendChild(factory.createTextNode("\n ")); 458 459 template.appendChild(factory.createTextNode("\n ")); 460 template.appendChild(copyElem); 461 template.appendChild(factory.createTextNode("\n")); 462 463 464 if (useOuterElem) 465 { 466 // If asked to, create and append top-level <stylesheet> elem 467 /// <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 468 Element stylesheetElem = factory.createElementNS(xslNamespace, "xsl:stylesheet"); 469 stylesheetElem.setAttributeNS(null, "version", "1.0"); 470 471 // Following is not officially needed by the DOM, but may help 472 // less-sophisticated DOM readers downstream 473 // Removed due to DOM003 Namespace error 474 // stylesheetElem.setAttributeNS(nsNamespace, "xmlns:xsl", xslNamespace); 475 stylesheetElem.appendChild(template); 476 n.appendChild(stylesheetElem); 477 } 478 else 479 { 480 // Otherwise, just use their Node 481 n.appendChild(template); 482 } 483 484 } 485 catch (Exception e) 486 { 487 reporter.logErrorMsg("appendIdentityDOMXSL threw: " + e.toString()); 488 reporter.logThrowable(Logger.ERRORMSG, e, "appendIdentityDOMXSL threw"); 489 } 490 } 491 492 493 /** 494 * Convenience method to print out usage information - update if needed. 495 * @return String denoting usage of this test class 496 */ usage()497 public String usage() 498 { 499 return ("Common [optional] options supported by ProgrammaticDOMTest:\n" 500 + "(Note: assumes inputDir=.\\tests\\api)\n" 501 + "REPLACE_any_new_test_arguments\n" 502 + super.usage()); // Grab our parent classes usage as well 503 } 504 505 506 /** 507 * Main method to run test from the command line - can be left alone. 508 * @param args command line argument array 509 */ main(String[] args)510 public static void main(String[] args) 511 { 512 ProgrammaticDOMTest app = new ProgrammaticDOMTest(); 513 app.doMain(args); 514 } 515 516 // Android-added: Run main method as a JUnit test case. 517 @FlakyTest(bugId = 292520220) 518 @Test main()519 public void main() { 520 main(new String[0]); 521 } 522 } 523