KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > io > DTDTest


1 /*
2  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3  *
4  * This software is open source.
5  * See the bottom of this file for the licence.
6  */

7
8 package org.dom4j.io;
9
10 import junit.framework.AssertionFailedError;
11
12 import junit.textui.TestRunner;
13
14 import java.io.FileInputStream JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.io.InputStream JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20
21 import org.dom4j.AbstractTestCase;
22 import org.dom4j.Document;
23 import org.dom4j.DocumentType;
24 import org.dom4j.dtd.AttributeDecl;
25 import org.dom4j.dtd.ElementDecl;
26 import org.dom4j.dtd.ExternalEntityDecl;
27 import org.dom4j.dtd.InternalEntityDecl;
28 import org.dom4j.tree.DefaultDocumentType;
29
30 import org.xml.sax.EntityResolver JavaDoc;
31 import org.xml.sax.InputSource JavaDoc;
32 import org.xml.sax.SAXException JavaDoc;
33
34 /**
35  * Tests the DocType functionality.
36  *
37  * <p>
38  * Incorporated additional test cases for optional processing of the internal
39  * and external DTD subsets. The "external" and "mixed" tests both <strong>fail
40  * </strong> due to a reported bug. See http://tinyurl.com/4dzyq
41  * </p>
42  *
43  * @author <a HREF="mailto:jstrachan@apache.org">James Strachan </a>
44  * @version $Revision: 1.4 $
45  */

46 public class DTDTest extends AbstractTestCase {
47     /**
48      * Input XML file to read <code>xml/dtd/internal.xml</code>- document
49      * using internal DTD subset, but no external DTD subset.
50      */

51     private static final String JavaDoc XML_INTERNAL_FILE = "xml/dtd/internal.xml";
52
53     /**
54      * Input XML file to read <code>xml/dtd/external.xml</code>- document
55      * using external DTD subset, but no internal DTD subset. The external
56      * entity should be locatable by either PUBLIC or SYSTEM identifier. The
57      * testing harness should use an appropriate EntityResolver to locate the
58      * external entity as a local resource (no internet access).
59      */

60     private static final String JavaDoc XML_EXTERNAL_FILE = "xml/dtd/external.xml";
61
62     /**
63      * Input XML file to read <code>xml/dtd/mixed.xml</code>- document using
64      * both an internal and an external DTD subset. The external entity should
65      * be locatable by either PUBLIC or SYSTEM identifier. The testing harness
66      * should use an appropriate EntityResolver to locate the external entity as
67      * a local resource (no internet access).
68      */

69     private static final String JavaDoc XML_MIXED = "xml/dtd/mixed.xml";
70
71     /**
72      * Input XML file to for {@linkEntityResolver}
73      * <code>xml/dtd/sample.dtd</code>- the external entity providing the
74      * external DTD subset for test cases that need one. The SYSTEM identifier
75      * for this external entity is given by {@link#DTD_SYSTEM_ID}.
76      */

77     private static final String JavaDoc DTD_FILE = "xml/dtd/sample.dtd";
78
79     /**
80      * The PUBLIC identifier, which is <code>-//dom4j//DTD sample</code>, for
81      * the external entity providing DTD for tests.
82      */

83     protected static final String JavaDoc DTD_PUBLICID = "-//dom4j//DTD sample";
84
85     /**
86      * The SYSTEM identifier, which is <code>sample.dtd</code>, for the
87      * external entity providing DTD for tests.
88      */

89     protected static final String JavaDoc DTD_SYSTEM_ID = "sample.dtd";
90
91     public static void main(String JavaDoc[] args) {
92         TestRunner.run(DTDTest.class);
93     }
94
95     // Test case(s)
96
// -------------------------------------------------------------------------
97

98     /**
99      * Test verifies correct identification of the internal DTD subset and
100      * correct non-presence of the external DTD subset.
101      *
102      * @throws Exception
103      * DOCUMENT ME!
104      */

105     public void testInternalDTDSubset() throws Exception JavaDoc {
106         /*
107          * Setup the expected DocumentType.
108          *
109          * @todo dom4j should expose a DefaultDocumentType constructor that
110          * accepts only the elementName property. This is used when only an
111          * internal DTD subset is being provided via the <!DOCTYPE foo [...]>
112          * syntax, in which case there is neither a SYSTEM nor PUBLIC
113          * identifier.
114          */

115         DocumentType expected = new DefaultDocumentType();
116
117         expected.setElementName("greeting");
118
119         expected.setInternalDeclarations(getInternalDeclarations());
120
121         /*
122          * Parse the test XML document and compare the expected and actual
123          * DOCTYPEs.
124          */

125         try {
126             assertSameDocumentType(expected, readDocument(
127                     XML_INTERNAL_FILE, true, false).getDocType());
128         } catch (AssertionFailedError ex) {
129             throw ex;
130         } catch (Throwable JavaDoc t) {
131             fail("Not expecting: " + t);
132         }
133     }
134
135     /**
136      * Test verifies correct identification of the external DTD subset and
137      * correct non-presence of the internal DTD subset.
138      */

139     public void testExternalDTDSubset() {
140         /*
141          * Setup the expected DocumentType.
142          */

143         DocumentType expected = new DefaultDocumentType("another-greeting",
144                 null, DTD_SYSTEM_ID);
145
146         expected.setExternalDeclarations(getExternalDeclarations());
147
148         /*
149          * Parse the test XML document and compare the expected and actual
150          * DOCTYPEs.
151          */

152         try {
153             assertSameDocumentType(expected, readDocument(
154                     XML_EXTERNAL_FILE, false, true).getDocType());
155         } catch (AssertionFailedError ex) {
156             throw ex;
157         } catch (Throwable JavaDoc t) {
158             fail("Not expecting: " + t);
159         }
160     }
161
162     /**
163      * Test verifies correct identification of the internal and external DTD
164      * subsets.
165      */

166     public void testMixedDTDSubset() {
167         /*
168          * Setup the expected DocumentType.
169          */

170         DocumentType expected = new DefaultDocumentType("another-greeting",
171                 null, DTD_SYSTEM_ID);
172
173         expected.setInternalDeclarations(getInternalDeclarations());
174
175         expected.setExternalDeclarations(getExternalDeclarations());
176
177         /*
178          * Parse the test XML document and compare the expected and actual
179          * DOCTYPEs.
180          */

181         try {
182             assertSameDocumentType(expected, readDocument(XML_MIXED,
183                     true, true).getDocType());
184         } catch (AssertionFailedError ex) {
185             throw ex;
186         } catch (Throwable JavaDoc t) {
187             fail("Not expecting: " + t);
188         }
189     }
190
191     // Implementation methods
192
// -------------------------------------------------------------------------
193

194     /**
195      * Test helper method returns a {@link List}of DTD declarations that
196      * represents the expected internal DTD subset (for the tests that use an
197      * internal DTD subset).
198      *
199      * <p>
200      * Note: The declarations returned by this method MUST agree those actually
201      * declared in {@link #XML_INTERNAL_FILE}and {@link
202      * #XML_MIXED}.
203      * </p>
204      *
205      * <p>
206      * </p>
207      *
208      * @return DOCUMENT ME!
209      */

210     protected List JavaDoc getInternalDeclarations() {
211         List JavaDoc decls = new ArrayList JavaDoc();
212
213         decls.add(new ElementDecl("greeting", "(#PCDATA)"));
214
215         decls.add(new AttributeDecl("greeting", "foo", "ID", "#IMPLIED", null));
216
217         decls.add(new InternalEntityDecl("%boolean", "( true | false )"));
218
219         return decls;
220     }
221
222     /**
223      * Test helper method returns a {@link List}of DTD declarations that
224      * represents the expected external DTD subset (for the tests that use an
225      * external DTD subset).
226      *
227      * @return DOCUMENT ME!
228      */

229     protected List JavaDoc getExternalDeclarations() {
230         List JavaDoc decls = new ArrayList JavaDoc();
231
232         decls.add(new ElementDecl("another-greeting", "(#PCDATA)"));
233
234         return decls;
235     }
236
237     /**
238      * Test helper method compares the expected and actual {@link DocumentType}
239      * objects, including their internal and external DTD subsets.
240      *
241      * <p>
242      * </p>
243      *
244      * @param expected
245      * DOCUMENT ME!
246      * @param actual
247      * DOCUMENT ME!
248      */

249     protected void assertSameDocumentType(DocumentType expected,
250             DocumentType actual) {
251         /*
252          * Nothing expected?
253          */

254         if (expected == null) {
255             if (actual == null) {
256                 return; // Nothing found.
257
} else {
258                 fail("Not expecting DOCTYPE.");
259             }
260         } else {
261             /*
262              * Something expected.
263              */

264             if (actual == null) {
265                 fail("Expecting DOCTYPE");
266             }
267
268             log("Expected DocumentType:\n" + expected.toString());
269
270             log("Actual DocumentType:\n" + actual.toString());
271
272             // Check the internal DTD subset.
273
assertSameDTDSubset("Internal", expected.getInternalDeclarations(),
274                     actual.getInternalDeclarations());
275
276             // Check the external DTD subset.
277
assertSameDTDSubset("External", expected.getExternalDeclarations(),
278                     actual.getExternalDeclarations());
279         }
280     }
281
282     /**
283      * Test helper method compares an expected set of DTD declarations with an
284      * actual set of DTD declarations. This method should be invoked seperately
285      * for the internal DTD subset and the external DTD subset. The declarations
286      * must occur in their logical ordering. See <a
287      * HREF="http://tinyurl.com/5jhd8">Lexical Handler </a> for conformance
288      * criteria.
289      *
290      * @param txt
291      * DOCUMENT ME!
292      * @param expected
293      * DOCUMENT ME!
294      * @param actual
295      * DOCUMENT ME!
296      *
297      * @throws AssertionError
298      * DOCUMENT ME!
299      */

300     protected void assertSameDTDSubset(String JavaDoc txt, List JavaDoc expected, List JavaDoc actual) {
301         /*
302          * Nothing expected?
303          */

304         if (expected == null) {
305             if (actual == null) {
306                 return; // Nothing found.
307
} else {
308                 fail("Not expecting " + txt + " DTD subset.");
309             }
310         } else {
311             /*
312              * Something expected.
313              */

314             if (actual == null) {
315                 fail("Expecting " + txt + " DTD subset.");
316             }
317
318             /*
319              * Correct #of declarations found?
320              */

321             assertEquals(txt + " DTD subset has correct #of declarations"
322                     + ": expected=[" + expected.toString() + "]" + ", actual=["
323                     + actual.toString() + "]", expected.size(), actual.size());
324
325             /*
326              * Check order, type, and values of each declaration. Serialization
327              * tests are done separately.
328              */

329             Iterator JavaDoc itr1 = expected.iterator();
330
331             Iterator JavaDoc itr2 = actual.iterator();
332
333             while (itr1.hasNext()) {
334                 Object JavaDoc obj1 = itr1.next();
335
336                 Object JavaDoc obj2 = itr2.next();
337
338                 assertEquals(txt + " DTD subset: Same type of declaration",
339                         obj1.getClass().getName(), obj2.getClass().getName());
340
341                 if (obj1 instanceof AttributeDecl) {
342                     assertSameDecl((AttributeDecl) obj1, (AttributeDecl) obj2);
343                 } else if (obj1 instanceof ElementDecl) {
344                     assertSameDecl((ElementDecl) obj1, (ElementDecl) obj2);
345                 } else if (obj1 instanceof InternalEntityDecl) {
346                     assertSameDecl((InternalEntityDecl) obj1,
347                             (InternalEntityDecl) obj2);
348                 } else if (obj1 instanceof ExternalEntityDecl) {
349                     assertSameDecl((ExternalEntityDecl) obj1,
350                             (ExternalEntityDecl) obj2);
351                 } else {
352                     throw new AssertionError JavaDoc("Unexpected declaration type: "
353                             + obj1.getClass());
354                 }
355             }
356         }
357     }
358
359     /**
360      * Test helper method compares an expected and an actual {@link
361      * AttributeDecl}.
362      *
363      * @param expected
364      * DOCUMENT ME!
365      * @param actual
366      * DOCUMENT ME!
367      */

368     public void assertSameDecl(AttributeDecl expected, AttributeDecl actual) {
369         assertEquals("attributeName is correct", expected.getAttributeName(),
370                 actual.getAttributeName());
371
372         assertEquals("elementName is correct", expected.getElementName(),
373                 actual.getElementName());
374
375         assertEquals("type is correct", expected.getType(), actual.getType());
376
377         assertEquals("value is not correct", expected.getValue(), actual
378                 .getValue());
379
380         assertEquals("valueDefault is correct", expected.getValueDefault(),
381                 actual.getValueDefault());
382
383         assertEquals("toString() is correct", expected.toString(), actual
384                 .toString());
385     }
386
387     /**
388      * Test helper method compares an expected and an actual {@link
389      * ElementDecl}.
390      *
391      * @param expected
392      * DOCUMENT ME!
393      * @param actual
394      * DOCUMENT ME!
395      */

396     protected void assertSameDecl(ElementDecl expected, ElementDecl actual) {
397         assertEquals("name is correct", expected.getName(), actual.getName());
398
399         assertEquals("model is not correct", expected.getModel(), actual
400                 .getModel());
401
402         assertEquals("toString() is correct", expected.toString(), actual
403                 .toString());
404     }
405
406     /**
407      * Test helper method compares an expected and an actual {@link
408      * InternalEntityDecl}.
409      *
410      * @param expected
411      * DOCUMENT ME!
412      * @param actual
413      * DOCUMENT ME!
414      */

415     protected void assertSameDecl(InternalEntityDecl expected,
416             InternalEntityDecl actual) {
417         assertEquals("name is correct", expected.getName(), actual.getName());
418
419         assertEquals("value is not correct", expected.getValue(), actual
420                 .getValue());
421
422         assertEquals("toString() is correct", expected.toString(), actual
423                 .toString());
424     }
425
426     /**
427      * Test helper method compares an expected and an actual {@link
428      * ExternalEntityDecl}.
429      *
430      * @param expected
431      * DOCUMENT ME!
432      * @param actual
433      * DOCUMENT ME!
434      */

435     protected void assertSameDecl(ExternalEntityDecl expected,
436             ExternalEntityDecl actual) {
437         assertEquals("name is correct", expected.getName(), actual.getName());
438
439         assertEquals("publicID is correct", expected.getPublicID(), actual
440                 .getPublicID());
441
442         assertEquals("systemID is correct", expected.getSystemID(), actual
443                 .getSystemID());
444
445         assertEquals("toString() is correct", expected.toString(), actual
446                 .toString());
447     }
448
449     /**
450      * Helper method reads a local resource and parses it as an XML document.
451      * The internal and external DTD subsets are optionally retained by the
452      * parser and exposed via the {@link DocumentType}object on the returned
453      * {@link Document}. The parser is configured with an {@link
454      * EntityResolver}that knows how to find the local resource identified by
455      * {@link #DTD_FILE}whose SYSTEM identifier is given by {@link
456      * #DTD_SYSTEM_ID}.
457      *
458      * @param resourceName
459      * DOCUMENT ME!
460      * @param includeInternal
461      * DOCUMENT ME!
462      * @param includeExternal
463      * DOCUMENT ME!
464      *
465      * @return DOCUMENT ME!
466      *
467      * @throws Exception
468      * DOCUMENT ME!
469      */

470     protected Document readDocument(String JavaDoc resourceName,
471             boolean includeInternal, boolean includeExternal) throws Exception JavaDoc {
472         SAXReader reader = new SAXReader();
473
474         reader.setIncludeInternalDTDDeclarations(includeInternal);
475
476         reader.setIncludeExternalDTDDeclarations(includeExternal);
477
478         reader.setEntityResolver(new MyEntityResolver(DTD_FILE,
479                 DTD_PUBLICID, DTD_SYSTEM_ID));
480
481         return getDocument(resourceName, reader);
482     }
483
484     /**
485      * Provides a resolver for the local test DTD resource.
486      */

487     protected static class MyEntityResolver implements EntityResolver JavaDoc {
488         private String JavaDoc resourceName;
489
490         private String JavaDoc pubId;
491
492         private String JavaDoc sysId;
493
494         public MyEntityResolver(String JavaDoc localResourceName, String JavaDoc publicId,
495                 String JavaDoc systemId) {
496             resourceName = localResourceName;
497
498             sysId = systemId;
499         }
500
501         public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
502                 throws SAXException JavaDoc, IOException JavaDoc {
503             if (pubId != null) {
504                 if (pubId.equals(publicId)) {
505                     return new InputSource JavaDoc(getInputStream(resourceName));
506                 }
507             }
508
509             if (sysId.equals(systemId)) {
510                 return new InputSource JavaDoc(getInputStream(resourceName));
511             } else {
512                 return null;
513             }
514         }
515
516         /**
517          * Returns an {@link InputStream}that will read from the indicated
518          * local resource.
519          *
520          * @param localResourceName
521          * DOCUMENT ME!
522          *
523          * @return DOCUMENT ME!
524          *
525          * @throws IOException
526          * DOCUMENT ME!
527          */

528         protected InputStream JavaDoc getInputStream(String JavaDoc localResourceName)
529                 throws IOException JavaDoc {
530             InputStream JavaDoc is = new FileInputStream JavaDoc(localResourceName);
531
532             return is;
533         }
534     }
535 }
536
537 /*
538  * Redistribution and use of this software and associated documentation
539  * ("Software"), with or without modification, are permitted provided that the
540  * following conditions are met:
541  *
542  * 1. Redistributions of source code must retain copyright statements and
543  * notices. Redistributions must also contain a copy of this document.
544  *
545  * 2. Redistributions in binary form must reproduce the above copyright notice,
546  * this list of conditions and the following disclaimer in the documentation
547  * and/or other materials provided with the distribution.
548  *
549  * 3. The name "DOM4J" must not be used to endorse or promote products derived
550  * from this Software without prior written permission of MetaStuff, Ltd. For
551  * written permission, please contact dom4j-info@metastuff.com.
552  *
553  * 4. Products derived from this Software may not be called "DOM4J" nor may
554  * "DOM4J" appear in their names without prior written permission of MetaStuff,
555  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
556  *
557  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
558  *
559  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
560  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
561  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
562  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
563  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
564  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
565  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
566  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
567  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
568  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
569  * POSSIBILITY OF SUCH DAMAGE.
570  *
571  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
572  */

573
Popular Tags