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 package org.apache.qetest.dtm;
22
23 import java.io.File;
24 import java.io.FileOutputStream;
25 import java.io.StringReader;
26 import java.util.Properties;
27
28 import javax.xml.transform.Source;
29 import javax.xml.transform.stream.StreamSource;
30
31 import org.apache.qetest.FileBasedTest;
32 import org.apache.qetest.LinebyLineCheckService;
33 import org.apache.qetest.OutputNameManager;
34 import org.apache.qetest.xsl.XSLTestfileInfo;
35 import org.apache.xml.dtm.DTM;
36 import org.apache.xml.dtm.DTMManager;
37 import org.apache.xml.dtm.ref.DTMManagerDefault;
38 import org.apache.xpath.objects.XMLStringFactoryImpl;
39
40 /**
41 * Unit test for DTMManager/DTM
42 *
43 * Loads an XML document from a file (or, if no filename is supplied,
44 * an internal string), then dumps its contents. Replaces the old
45 * version, which was specific to the ultra-compressed implementation.
46 * (Which, by the way, we probably ought to revisit as part of our ongoing
47 * speed/size performance evaluation.)
48 *
49 * %REVIEW% Extend to test DOM2DTM, incremental, DOM view of the DTM,
50 * whitespace-filtered, indexed/nonindexed, ...
51 * */
52 public class TestDTM extends FileBasedTest
53 {
54 /**
55 * This test creates a DTM and tests basic functionality of the DTM API
56 * - execute 'build package.trax', 'traxapitest TestDTMIter.java'
57 * - a bunch of convenience variables/initializers are included,
58 * use or delete as is useful
59 * @author Paul Dick
60 * @version $Id$
61 *
62 * Provides nextName(), currentName() functionality for tests
63 * that may produce any number of output files.
64 */
65 protected OutputNameManager outNames;
66
67 /**
68 * Information about an xsl/xml file pair for transforming.
69 * Public members include inputName (for xsl); xmlName; goldName; etc.
70 * If you don't use an .xml file on disk, you don't actually need this.
71 */
72 protected XSLTestfileInfo testFileInfo = new XSLTestfileInfo();
73
74 /** Subdirectory under test\tests\api for our xsl/xml files. */
75 public static final String DTM_SUBDIR = "dtm";
76 public static final String DTM_Prefix = "DTM_";
77
78 String defaultSource=
79 "<?xml version=\"1.0\"?>\n"+
80 " <bdd:dummyDocument xmlns:bdd=\"www.bdd.org\" version=\"99\">\n"+
81 " <!-- Default test document -->	&"+
82 " <?api attrib1=\"yes\" attrib2=\"no\"?>"+
83 " <A>\n"+
84 " <B hat=\"new\" car=\"Honda\" dog=\"Boxer\">Life is good</B>\n"+
85 " </A>\n"+
86 " <C>My Anaconda<xyz:D xmlns:xyz=\"www.xyz.org\"/>Words</C>\n"+
87 " Want a more interesting docuent, provide the URI on the command line!\n"+
88 " <Sub-Doc xmlns:d=\"www.d.com\" a1=\"hello\" a2=\"goodbye\">"+
89 " <!-- Default test Subdocument -->"+
90 " <?api a1=\"yes\" a2=\"no\"?>"+
91 " <A><!-- A Subtree --><B><C><D><E><f:F xmlns:f=\"www.f.com\" a1=\"down\" a2=\"up\"/></E></D></C></B></A>"+
92 " <Aa/><Ab/><Ac><Ac1/></Ac>"+
93 " <Ad:Ad xmlns:Ad=\"www.Ad.com\" xmlns:y=\"www.y.com\" xmlns:z=\"www.z.com\">"+
94 " <Ad1/></Ad:Ad>"+
95 " </Sub-Doc>"+
96 " </bdd:dummyDocument>\n";
97
98 static final String[] TYPENAME=
99 { "NULL",
100 "ELEMENT",
101 "ATTRIBUTE",
102 "TEXT",
103 "CDATA_SECTION",
104 "ENTITY_REFERENCE",
105 "ENTITY",
106 "PROCESSING_INSTRUCTION",
107 "COMMENT",
108 "DOCUMENT",
109 "DOCUMENT_TYPE",
110 "DOCUMENT_FRAGMENT",
111 "NOTATION",
112 "NAMESPACE"
113 };
114
115 /** Just initialize test name, comment, numTestCases. */
TestDTM()116 public TestDTM()
117 {
118 numTestCases = 1;
119 testName = "TestDTM";
120 testComment = "Function test of DTM";
121 }
122
123 /**
124 * Initialize this test - Set names of xml/xsl test files,
125 * REPLACE_other_test_file_init.
126 *
127 * @param p Properties to initialize from (if needed)
128 * @return false if we should abort the test; true otherwise
129 */
doTestFileInit(Properties p)130 public boolean doTestFileInit(Properties p)
131 {
132 // Used for all tests; just dump files in dtm subdir
133 File outSubDir = new File(outputDir + File.separator + DTM_SUBDIR);
134 if (!outSubDir.mkdirs())
135 reporter.logWarningMsg("Could not create output dir: " + outSubDir);
136
137 // Initialize an output name manager to that dir with .out extension
138 outNames = new OutputNameManager(outputDir + File.separator + DTM_SUBDIR
139 + File.separator + testName, ".out");
140
141 String testBasePath = inputDir
142 + File.separator
143 + DTM_SUBDIR
144 + File.separator;
145 String goldBasePath = goldDir
146 + File.separator
147 + DTM_SUBDIR
148 + File.separator
149 + DTM_Prefix;
150
151 //testFileInfo.inputName = testBasePath + "REPLACE_xslxml_filename.xsl";
152 //testFileInfo.xmlName = testBasePath + "REPLACE_xslxml_filename.xml";
153 testFileInfo.goldName = goldBasePath;
154
155 return true;
156 }
157
158 /**
159 * Cleanup this test - REPLACE_other_test_file_cleanup.
160 *
161 * @param p Properties to initialize from (if needed)
162 * @return false if we should abort the test; true otherwise
163 */
doTestFileClose(Properties p)164 public boolean doTestFileClose(Properties p)
165 {
166 // Often will be a no-op
167 return true;
168 }
169
170 /**
171 * Create AxisIterator and walk CHILD axis.
172 * @return false if we should abort the test; true otherwise
173 */
testCase1()174 public boolean testCase1()
175 {
176 reporter.testCaseInit("Basic Functionality of DTM");
177 StringBuffer buf = new StringBuffer();
178 FileOutputStream fos = openFileStream(outNames.nextName());
179 String gold = testFileInfo.goldName + "testcase1.out";
180
181 // Create dtm and generate initial context
182 DTM dtm = generateDTM();
183
184 // DTM -- which will always be true for a node obtained this way, but
185 // won't be true for "shared" DTMs used to hold XSLT variables
186 int rootNode=dtm.getDocument();
187 buf.append(" *** DOCUMENT PROPERTIES: *** "+
188 "\nDocURI=\""+dtm.getDocumentBaseURI()+"\" "+
189 "SystemID=\""+dtm.getDocumentSystemIdentifier(rootNode)+"\"\n"+
190 // removed from test until implemented bugzilla 14753
191 // "DocEncoding=\""+dtm.getDocumentEncoding(rootNode)+"\" "+
192 "StandAlone=\""+dtm.getDocumentStandalone(rootNode)+"\" "+
193 "DocVersion=\""+dtm.getDocumentVersion(rootNode)+"\""+
194 "\n\n");
195
196 // Simple test: Recursively dump the DTM's content.
197 // We'll want to replace this with more serious examples
198 buf.append(" *** DOCUMENT DATA: *** ");
199 recursiveDumpNode(dtm, rootNode, buf);
200
201 // Write results and close output file.
202 writeClose(fos, buf);
203
204 // Verify results
205 LinebyLineCheckService myfilechecker = new LinebyLineCheckService();
206 myfilechecker.check(reporter, new File(outNames.currentName()),
207 new File(gold),
208 "Testcase1");
209 reporter.testCaseClose();
210 return true;
211
212 }
213
recursiveDumpNode(DTM dtm, int nodeHandle, StringBuffer buf)214 void recursiveDumpNode(DTM dtm, int nodeHandle, StringBuffer buf)
215 {
216 // ITERATE over siblings
217 for( ; nodeHandle!=DTM.NULL; nodeHandle=dtm.getNextSibling(nodeHandle) )
218 {
219 buf.append(getNodeInfo(dtm,nodeHandle,""));
220
221 // List the namespaces, if any.
222 // Include only node's local namespaces, not inherited
223 // %ISSUE% Consider inherited?
224 int kid=dtm.getFirstNamespaceNode(nodeHandle,false);
225 if(kid!=DTM.NULL)
226 {
227 buf.append("\n\tNAMESPACES:");
228 for( ; kid!=DTM.NULL; kid=dtm.getNextNamespaceNode(nodeHandle,kid,false))
229 {
230 buf.append(getNodeInfo(dtm,kid,"\t"));
231 }
232 }
233
234 // List the attributes, if any
235 kid=dtm.getFirstAttribute(nodeHandle);
236 if(kid!=DTM.NULL)
237 {
238 buf.append("\n\tATTRIBUTES:");
239 for( ; kid!=DTM.NULL; kid=dtm.getNextSibling(kid))
240 {
241 buf.append(getNodeInfo(dtm,kid,"\t"));
242 }
243 }
244
245 // Recurse into the children, if any
246 recursiveDumpNode(dtm, dtm.getFirstChild(nodeHandle), buf);
247 }
248 }
249
getNodeInfo(DTM dtm, int nodeHandle, String indent)250 String getNodeInfo(DTM dtm, int nodeHandle, String indent)
251 {
252
253 // Formatting hack -- suppress quotes when value is null, to distinguish
254 // it from "null".
255 String buf = new String("null");
256 String value=dtm.getNodeValue(nodeHandle);
257 String vq=(value==null) ? "" : "\"";
258
259 // Skip outputing of text nodes. In most cases they clutter the output,
260 // besides I'm only interested in the elemental structure of the dtm.
261 {
262 buf = new String("\n" + indent+
263 nodeHandle+": "+
264 TYPENAME[dtm.getNodeType(nodeHandle)]+" "+
265 dtm.getNodeNameX(nodeHandle)+ " : " +
266 dtm.getNodeName(nodeHandle)+
267 "\" E-Type="+dtm.getExpandedTypeID(nodeHandle)+
268 " Level=" + dtm.getLevel(nodeHandle)+
269 " Value=" + vq + value + vq + "\n"+
270 indent+
271 "\tPrefix= "+"\""+dtm.getPrefix(nodeHandle)+"\""+
272 " Name= "+"\""+dtm.getLocalName(nodeHandle)+"\""+
273 " URI= "+"\""+dtm.getNamespaceURI(nodeHandle)+"\" "+
274 "Parent=" + dtm.getParent(nodeHandle) +
275 " 1stChild=" + dtm.getFirstChild(nodeHandle) +
276 " NextSib=" + dtm.getNextSibling(nodeHandle)
277 );
278
279 }
280 return buf;
281 }
282
usage()283 public String usage()
284 {
285 return ("Common [optional] options supported by TestDTM:\n"
286 + "(Note: assumes inputDir=.\\tests\\api)\n");
287 }
288
openFileStream(String name)289 FileOutputStream openFileStream(String name)
290 {
291 FileOutputStream fos = null;
292
293 try
294 { fos = new FileOutputStream(name); }
295
296 catch (Exception e)
297 { reporter.checkFail("Failure opening output file."); }
298
299 return fos;
300 }
301
302 // This routine generates a new DTM for each testcase
generateDTM()303 DTM generateDTM()
304 {
305 dtmWSStripper stripper = new dtmWSStripper();
306
307 // Create DTM and generate initial context
308 Source source = new StreamSource(new StringReader(defaultSource));
309 DTMManager manager= new DTMManagerDefault().newInstance(new XMLStringFactoryImpl());
310 DTM dtm=manager.getDTM(source, true, stripper, false, true);
311
312 return dtm;
313 }
314
writeClose(FileOutputStream fos, StringBuffer buf)315 void writeClose(FileOutputStream fos, StringBuffer buf)
316 {
317 // Write results and close output file.
318 try
319 {
320 fos.write(buf.toString().getBytes("UTF-8"));
321 fos.close();
322 }
323
324 catch (Exception e)
325 { reporter.checkFail("Failure writing output."); }
326 }
327
328 /**
329 * Main method to run test from the command line - can be left alone.
330 * @param args command line argument array
331 */
main(String[] args)332 public static void main(String[] args)
333 {
334 TestDTM app = new TestDTM();
335 app.doMain(args);
336 }
337
338
339 }
340