~ubuntu-branches/ubuntu/precise/xom/precise

« back to all changes in this revision

Viewing changes to src/nu/xom/tests/BuilderTest.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2007-11-25 15:50:40 UTC
  • Revision ID: james.westby@ubuntu.com-20071125155040-r75ikcqf1vu0cei7
Tags: upstream-1.1
ImportĀ upstreamĀ versionĀ 1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2002-2005 Elliotte Rusty Harold
 
2
   
 
3
   This library is free software; you can redistribute it and/or modify
 
4
   it under the terms of version 2.1 of the GNU Lesser General Public 
 
5
   License as published by the Free Software Foundation.
 
6
   
 
7
   This library is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
10
   GNU Lesser General Public License for more details.
 
11
   
 
12
   You should have received a copy of the GNU Lesser General Public
 
13
   License along with this library; if not, write to the 
 
14
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 
15
   Boston, MA 02111-1307  USA
 
16
   
 
17
   You can contact Elliotte Rusty Harold by sending e-mail to
 
18
   elharo@metalab.unc.edu. Please include the word "XOM" in the
 
19
   subject line. The XOM home page is located at http://www.xom.nu/
 
20
*/
 
21
 
 
22
package nu.xom.tests;
 
23
 
 
24
import java.io.ByteArrayOutputStream;
 
25
import java.io.CharConversionException;
 
26
import java.io.File;
 
27
import java.io.FileNotFoundException;
 
28
import java.io.FileOutputStream;
 
29
import java.io.IOException;
 
30
import java.io.OutputStreamWriter;
 
31
import java.io.PrintStream;
 
32
import java.io.Reader;
 
33
import java.io.StringReader;
 
34
import java.io.ByteArrayInputStream;
 
35
import java.io.InputStream;
 
36
import java.io.UTFDataFormatException;
 
37
import java.io.Writer;
 
38
import java.lang.ref.WeakReference;
 
39
import java.lang.reflect.Constructor;
 
40
import java.lang.reflect.InvocationTargetException;
 
41
 
 
42
import org.xml.sax.Attributes;
 
43
import org.xml.sax.InputSource;
 
44
import org.xml.sax.Locator;
 
45
import org.xml.sax.SAXException;
 
46
import org.xml.sax.SAXNotRecognizedException;
 
47
import org.xml.sax.SAXNotSupportedException;
 
48
import org.xml.sax.SAXParseException;
 
49
import org.xml.sax.XMLFilter;
 
50
import org.xml.sax.XMLReader;
 
51
import org.xml.sax.helpers.AttributesImpl;
 
52
import org.xml.sax.helpers.LocatorImpl;
 
53
import org.xml.sax.helpers.XMLFilterImpl;
 
54
import org.xml.sax.helpers.XMLReaderFactory;
 
55
 
 
56
import nu.xom.Attribute;
 
57
import nu.xom.Builder;
 
58
import nu.xom.Comment;
 
59
import nu.xom.DocType;
 
60
import nu.xom.Document;
 
61
import nu.xom.Element;
 
62
import nu.xom.Elements;
 
63
import nu.xom.NodeFactory;
 
64
import nu.xom.ParsingException;
 
65
import nu.xom.ProcessingInstruction;
 
66
import nu.xom.Serializer;
 
67
import nu.xom.ValidityException;
 
68
import nu.xom.WellformednessException;
 
69
import nu.xom.XMLException;
 
70
 
 
71
 
 
72
/**
 
73
 * <p>
 
74
 *  Tests building documents from streams, strings, files,
 
75
 *  and other input sources.
 
76
 * </p>
 
77
 * 
 
78
 * @author Elliotte Rusty Harold
 
79
 * @version 1.1b7
 
80
 *
 
81
 */
 
82
public class BuilderTest extends XOMTestCase {
 
83
 
 
84
    
 
85
    private File inputDir = new File("data");
 
86
 
 
87
    // This class tests error conditions, which Xerces
 
88
    // annoyingly logs to System.err. So we hide System.err 
 
89
    // before each test and restore it after each test.
 
90
    private PrintStream systemErr = System.err;
 
91
    
 
92
    protected void setUp() {
 
93
        System.setErr(new PrintStream(new ByteArrayOutputStream()));
 
94
    }
 
95
    
 
96
    
 
97
    protected void tearDown() {
 
98
        System.setErr(systemErr);
 
99
    }
 
100
    
 
101
       
 
102
    // Custom parser to test what happens when parser supplies 
 
103
    // malformed data
 
104
    private static class CustomReader extends XMLFilterImpl {
 
105
        
 
106
        public void setFeature(String name, boolean value) {};
 
107
 
 
108
        public void parse(InputSource in) throws SAXException  {
 
109
            this.getContentHandler().startDocument();
 
110
            this.getContentHandler().startElement("87", "87", "87", new AttributesImpl());
 
111
            this.getContentHandler().endElement("87", "87", "87");
 
112
            this.getContentHandler().endDocument();  
 
113
        }
 
114
        
 
115
    }
 
116
    
 
117
    
 
118
    private static class DoNothingReader extends CustomReader {
 
119
        
 
120
        public void parse(InputSource in) throws SAXException  {}
 
121
        
 
122
    }
 
123
    
 
124
 
 
125
    private static class StartAndEndReader extends CustomReader {
 
126
        
 
127
        public void parse(InputSource in) throws SAXException  {
 
128
            this.getContentHandler().startDocument();
 
129
            this.getContentHandler().endDocument();  
 
130
        }
 
131
        
 
132
    }
 
133
    
 
134
 
 
135
    private static class StartOnlyReader extends CustomReader {
 
136
        
 
137
        public void parse(InputSource in) throws SAXException  {
 
138
            this.getContentHandler().startDocument();
 
139
        }
 
140
        
 
141
    }
 
142
    
 
143
 
 
144
    private static class EndOnlyReader extends CustomReader {
 
145
        
 
146
        public void parse(InputSource in) throws SAXException  {
 
147
            this.getContentHandler().endDocument();  
 
148
        }
 
149
        
 
150
    }
 
151
    
 
152
 
 
153
    public BuilderTest(String name) {
 
154
        super(name);   
 
155
    }
 
156
    
 
157
    
 
158
    // flag to turn on and off tests based on 
 
159
    // http://nagoya.apache.org/bugzilla/show_bug.cgi?id=24124
 
160
    private boolean xercesBroken = false;
 
161
    
 
162
    private String elementDeclaration = "<!ELEMENT root (#PCDATA)>";
 
163
    private String defaultAttributeDeclaration 
 
164
      = "<!ATTLIST test name CDATA \"value\">";
 
165
    private String attributeDeclaration 
 
166
      = "<!ATTLIST root anattribute CDATA #REQUIRED>";
 
167
    private String attributeDeclaration2 
 
168
      = "<!ATTLIST root anotherattribute CDATA \"value\">";
 
169
    private String unparsedEntityDeclaration 
 
170
      = "<!ENTITY hatch-pic SYSTEM " +
 
171
        "\"http://www.example.com/images/cup.gif\" NDATA gif>";
 
172
    private String unparsedEntityDeclarationPublic
 
173
      = "<!ENTITY public-pic PUBLIC \"public ID\" " +
 
174
        "\"http://www.example.com/images/cup.gif\" NDATA gif>";
 
175
    private String internalEntityDeclaration 
 
176
      = "<!ENTITY Pub-Status \"" +
 
177
        "This is a pre-release of the specification.\">";
 
178
    private String externalEntityDeclarationPublic = 
 
179
      "<!ENTITY open-hatch " 
 
180
      + "PUBLIC \"-//Textuality//TEXT Standard " +
 
181
        "open-hatch boilerplate//EN\" "
 
182
      + "\"http://www.textuality.com/boilerplate/OpenHatch.xml\">";
 
183
    private String externalEntityDeclarationSystem = 
 
184
      "<!ENTITY test SYSTEM " +
 
185
      "\"http://www.textuality.com/boilerplate/OpenHatch.xml\">";
 
186
    private String notationDeclarationSystem 
 
187
     = "<!NOTATION ISODATE SYSTEM "
 
188
     + "\"http://www.iso.ch/cate/d15903.html\">";
 
189
    private String notationDeclarationPublicAndSystem 
 
190
     = "<!NOTATION DATE PUBLIC \"DATE PUBLIC ID\" "
 
191
     + "\"http://www.iso.ch/cate/d15903.html\">";
 
192
    private String notationDeclarationPublic = "<!NOTATION gif PUBLIC "
 
193
    + "\"-//Textuality//TEXT Standard open-hatch boilerplate//EN\">";
 
194
 
 
195
    private String source = "<!DOCTYPE test [\r\n"
 
196
     + elementDeclaration + "\n" 
 
197
     + attributeDeclaration + "\n"
 
198
     + defaultAttributeDeclaration + "\n"
 
199
     + attributeDeclaration2 + "\n"
 
200
     + internalEntityDeclaration + "\n"
 
201
     + externalEntityDeclarationPublic + "\n"
 
202
     + externalEntityDeclarationSystem + "\n"
 
203
     + unparsedEntityDeclaration + "\n"
 
204
     + unparsedEntityDeclarationPublic + "\n"
 
205
     + notationDeclarationPublic + "\n"
 
206
     + notationDeclarationSystem + "\n"
 
207
     + notationDeclarationPublicAndSystem + "\n"
 
208
     + "]>\r\n"
 
209
     + "<?xml-stylesheet href=\"file.css\" type=\"text/css\"?>" 
 
210
     + "<!-- test -->"
 
211
     + "<test xmlns:xlink='http://www.w3.org/TR/1999/xlink'>Hello dear"
 
212
     + "\r\n<em id=\"p1\" xmlns:none=\"http://www.example.com\">"
 
213
     + "very important</em>"
 
214
     + "<span xlink:type='simple'>here&apos;s the link</span>\r\n"
 
215
     + "<svg:svg xmlns:svg='http://www.w3.org/TR/2000/svg'>"
 
216
     + "<svg:text>text in a namespace</svg:text></svg:svg>\r\n"
 
217
     + "<svg xmlns='http://www.w3.org/TR/2000/svg'><text>text in a " 
 
218
     +   "namespace</text></svg></test>\r\n<!--epilog-->";
 
219
     
 
220
    private String validDoc = "<!DOCTYPE test [\r\n"
 
221
     + "<!ELEMENT test (#PCDATA)>\n" 
 
222
     + "]>\r\n"
 
223
     + "<?xml-stylesheet href=\"file.css\" type=\"text/css\"?>" 
 
224
     + "<!-- test -->"
 
225
     + "<test>Hello dear</test>"
 
226
     + "<!--epilog-->";
 
227
     
 
228
    private Builder builder = new Builder();
 
229
    private Builder validator = new Builder(true);
 
230
    private String base = "http://www.example.com/";
 
231
 
 
232
    private String attributeDoc = "<!DOCTYPE test [\n"
 
233
     + "<!ELEMENT test (#PCDATA)>\n" 
 
234
     + "<!NOTATION GIF SYSTEM \"text/gif\">\n"
 
235
     + "<!ENTITY data SYSTEM \"http://www.example.org/cup.gif\">\n"
 
236
     + "<!ATTLIST test notationatt NOTATION (GIF) \"GIF\">\n" 
 
237
     + "<!ATTLIST test cdataatt CDATA \"GIF\">\n" 
 
238
     + "<!ATTLIST test entityatt ENTITY \"data\">\n" 
 
239
     + "<!ATTLIST test entitiesatt ENTITIES \"data\">\n" 
 
240
     + "<!ATTLIST test nmtokenatt NMTOKEN \" 1 \">\n" 
 
241
     + "<!ATTLIST test nmtokensatt NMTOKENS \" 1   2  3 \">\n" 
 
242
     + "<!ATTLIST test idatt ID \" p1 \">\n" 
 
243
     + "<!ATTLIST test idrefatt IDREF \" p1 \">\n" 
 
244
     + "<!ATTLIST test idrefsatt IDREFS \" p1 p2 \">\n" 
 
245
     + "]>\r\n"
 
246
     + "<test>Hello dear</test>";
 
247
    
 
248
    
 
249
    public void testDoNothingParser() 
 
250
      throws ParsingException, IOException {
 
251
        
 
252
        try {
 
253
            XMLReader parser = new DoNothingReader();
 
254
            Builder builder = new Builder(parser);
 
255
            builder.build("http://www.example.org/");
 
256
            fail("built from bad data");
 
257
        }
 
258
        catch (ParsingException success) {
 
259
            assertNotNull(success.getMessage());
 
260
            assertEquals("http://www.example.org/", success.getURI());
 
261
        }      
 
262
        
 
263
    }    
 
264
 
 
265
 
 
266
    public void testStartAndEndParser() 
 
267
      throws ParsingException, IOException {
 
268
        
 
269
        XMLReader parser = new StartAndEndReader();
 
270
        Builder builder = new Builder(parser);
 
271
        Document doc = builder.build("http://www.example.org/");
 
272
        assertNotNull(doc.getRootElement());
 
273
        
 
274
    }    
 
275
 
 
276
 
 
277
    public void testStartOnlyParser() 
 
278
      throws ParsingException, IOException {
 
279
        
 
280
        XMLReader parser = new StartOnlyReader();
 
281
        Builder builder = new Builder(parser);
 
282
        Document doc = builder.build("http://www.example.org/");
 
283
        assertNotNull(doc.getRootElement());
 
284
        
 
285
    }    
 
286
 
 
287
 
 
288
    public void testEndOnlyParser() 
 
289
      throws ParsingException, IOException {
 
290
        
 
291
        try {
 
292
            XMLReader parser = new EndOnlyReader();
 
293
            Builder builder = new Builder(parser);
 
294
            builder.build("http://www.example.org/");
 
295
            fail("built from bad data");
 
296
        }
 
297
        catch (ParsingException success) {
 
298
            assertTrue(success.getCause() instanceof NullPointerException);
 
299
        }      
 
300
        
 
301
    }    
 
302
 
 
303
 
 
304
    public void testBuildInternalDTDSubsetWithFixedDefaultAttributeValue() 
 
305
      throws ParsingException, IOException {
 
306
        
 
307
        String doctype = "<!DOCTYPE xsl:stylesheet [\n"
 
308
            + "<!ATTLIST a b CDATA #FIXED \"c\">]>";
 
309
        String document = doctype + "\n<root/>";
 
310
        Builder builder = new Builder();
 
311
        Document doc = builder.build(document, null);
 
312
        DocType dt = doc.getDocType();
 
313
        String internalDTDSubset = dt.getInternalDTDSubset();
 
314
        assertTrue(internalDTDSubset.indexOf("#FIXED \"c\"") > 0);
 
315
        
 
316
    }
 
317
    
 
318
    
 
319
    public void testNotationAttributeType() 
 
320
      throws IOException, ParsingException {
 
321
        
 
322
        Reader reader = new StringReader(attributeDoc);
 
323
        Document document = builder.build(reader);
 
324
        Element root = document.getRootElement();
 
325
        Attribute att = root.getAttribute("notationatt"); 
 
326
        assertEquals(Attribute.Type.NOTATION, att.getType()); 
 
327
        
 
328
    }
 
329
    
 
330
    
 
331
    public void testCDATAAttributeType() 
 
332
      throws IOException, ParsingException {
 
333
        
 
334
        Reader reader = new StringReader(attributeDoc);
 
335
        Document document = builder.build(reader);
 
336
        Element root = document.getRootElement();
 
337
        Attribute att = root.getAttribute("cdataatt"); 
 
338
        assertEquals(Attribute.Type.CDATA, att.getType());
 
339
        
 
340
    }
 
341
    
 
342
    
 
343
    public void testEntityAttributeType() 
 
344
      throws IOException, ParsingException {
 
345
        
 
346
        Reader reader = new StringReader(attributeDoc);
 
347
        Document document = builder.build(reader);
 
348
        Element root = document.getRootElement();
 
349
        Attribute att = root.getAttribute("entityatt"); 
 
350
        assertEquals(Attribute.Type.ENTITY, att.getType()); 
 
351
        
 
352
    }
 
353
    
 
354
    
 
355
    public void testEntitiesAttributeType() 
 
356
      throws IOException, ParsingException {
 
357
        
 
358
        Reader reader = new StringReader(attributeDoc);
 
359
        Document document = builder.build(reader);
 
360
        Element root = document.getRootElement();
 
361
        Attribute att = root.getAttribute("entitiesatt"); 
 
362
        assertEquals(Attribute.Type.ENTITIES, att.getType());
 
363
 
 
364
    }
 
365
    
 
366
    
 
367
    public void testNameTokenAttributeType() 
 
368
      throws IOException, ParsingException {
 
369
        
 
370
        Reader reader = new StringReader(attributeDoc);
 
371
        Document document = builder.build(reader);
 
372
        Element root = document.getRootElement();
 
373
        Attribute att = root.getAttribute("nmtokenatt"); 
 
374
        assertEquals(Attribute.Type.NMTOKEN, att.getType());      
 
375
        assertEquals("1", att.getValue());
 
376
 
 
377
    }
 
378
    
 
379
    
 
380
    // I'm specifically worried about a Xerces runtime MalformedURIException here
 
381
    public void testIllegalSystemIDThrowsRightException() {
 
382
        
 
383
        String document = "<!DOCTYPE root SYSTEM \"This is not a URI\"><root/>";
 
384
        try{
 
385
            builder.build(document, null);
 
386
        }
 
387
        catch (Exception ex) {
 
388
            assertTrue(ex instanceof ParsingException);
 
389
        }
 
390
            
 
391
    }
 
392
    
 
393
    
 
394
    public void testNameTokensAttributeType() 
 
395
      throws IOException, ParsingException {
 
396
        
 
397
        Reader reader = new StringReader(attributeDoc);
 
398
        Document document = builder.build(reader);
 
399
        Element root = document.getRootElement();
 
400
        Attribute att = root.getAttribute("nmtokensatt"); 
 
401
        assertEquals(Attribute.Type.NMTOKENS, att.getType());      
 
402
        assertEquals("1 2 3", att.getValue()); 
 
403
        
 
404
    }
 
405
    
 
406
    
 
407
    // verify that XML 1.1 is not supported
 
408
    public void testXML11() throws IOException {
 
409
        
 
410
        String data = "<?xml version='1.1'?><root/>";
 
411
        try {
 
412
            builder.build(data, "http://www.example.com");
 
413
            fail("XML 1.1 allowed");
 
414
        }
 
415
        catch (ParsingException ex) {
 
416
            assertNotNull(ex.getMessage());   
 
417
        }
 
418
        
 
419
    }
 
420
    
 
421
    
 
422
    // verify that XML 1.2 is not supported
 
423
    public void testXML12() throws IOException {
 
424
        
 
425
        String data = "<?xml version='1.2'?><root/>";
 
426
        try {
 
427
            builder.build(data, "http://www.example.com");
 
428
            fail("XML 1.2 allowed");
 
429
        }
 
430
        catch (ParsingException ex) {
 
431
            assertNotNull(ex.getMessage());   
 
432
        }
 
433
        
 
434
    }
 
435
    
 
436
    
 
437
    // verify that XML 2.0 is not supported
 
438
    public void testXML20() throws IOException {
 
439
        
 
440
        String data = "<?xml version='2.0'?><root/>";
 
441
        try {
 
442
            builder.build(data, "http://www.example.com");
 
443
            fail("XML 2.0 allowed");
 
444
        }
 
445
        catch (ParsingException ex) {
 
446
            assertNotNull(ex.getMessage());   
 
447
        }
 
448
        
 
449
    }
 
450
    
 
451
    
 
452
    public void testIDAttributeType() 
 
453
      throws IOException, ParsingException {
 
454
        
 
455
        Reader reader = new StringReader(attributeDoc);
 
456
        Document document = builder.build(reader);
 
457
        Element root = document.getRootElement();
 
458
        Attribute att = root.getAttribute("idatt"); 
 
459
        assertEquals(Attribute.Type.ID, att.getType());      
 
460
        assertEquals("p1", att.getValue()); 
 
461
 
 
462
    }
 
463
    
 
464
    
 
465
    public void testIDREFAttributeType() 
 
466
      throws IOException, ParsingException {
 
467
        
 
468
        Reader reader = new StringReader(attributeDoc);
 
469
        Document document = builder.build(reader);
 
470
        Element root = document.getRootElement();
 
471
        Attribute att = root.getAttribute("idrefatt"); 
 
472
        assertEquals(Attribute.Type.IDREF, att.getType());      
 
473
        assertEquals("p1", att.getValue()); 
 
474
 
 
475
    }
 
476
    
 
477
    
 
478
    public void testIDREFSAttributeType() 
 
479
      throws IOException, ParsingException {
 
480
        
 
481
        Reader reader = new StringReader(attributeDoc);
 
482
        Document document = builder.build(reader);
 
483
        Element root = document.getRootElement();
 
484
        Attribute att = root.getAttribute("idrefsatt"); 
 
485
        assertEquals(Attribute.Type.IDREFS, att.getType());      
 
486
        assertEquals("p1 p2", att.getValue()); 
 
487
        
 
488
    }
 
489
 
 
490
    
 
491
    public void testBuildFromReader() 
 
492
      throws IOException, ParsingException {
 
493
        
 
494
        Reader reader = new StringReader(source);
 
495
        Document document = builder.build(reader);
 
496
        verify(document);        
 
497
        assertEquals("", document.getBaseURI());
 
498
        
 
499
    }
 
500
    
 
501
    
 
502
    public void testBuildFromReaderWithBase()
 
503
      throws IOException, ParsingException {
 
504
        
 
505
        Reader reader = new StringReader(source);
 
506
        Document document = builder.build(reader, base);
 
507
        verify(document);        
 
508
        assertEquals(base, document.getBaseURI());
 
509
        
 
510
    }
 
511
 
 
512
 
 
513
    private static class NoLocator extends XMLFilterImpl {
 
514
 
 
515
        public NoLocator(XMLReader reader) {
 
516
            super(reader);
 
517
        }
 
518
        
 
519
        public void setDocumentLocator(Locator locator) {}
 
520
        
 
521
    }    
 
522
    
 
523
    
 
524
    public void testBuildWithoutLocator()
 
525
      throws IOException, ParsingException, SAXException {
 
526
        
 
527
        XMLReader xerces = XMLReaderFactory.createXMLReader(
 
528
          "org.apache.xerces.parsers.SAXParser");
 
529
        XMLReader filter = new NoLocator(xerces);
 
530
        
 
531
        Builder builder = new Builder(filter);
 
532
        Document document = builder.build(source, "http://www.example.org/");
 
533
        verify(document);
 
534
        assertEquals("http://www.example.org/", document.getBaseURI());
 
535
        
 
536
    }
 
537
 
 
538
    
 
539
    private static class WeirdAttributeTypes extends XMLFilterImpl {
 
540
 
 
541
        public WeirdAttributeTypes(XMLReader reader) {
 
542
            super(reader);
 
543
        }
 
544
        
 
545
        public void startElement(String uri, String localName,
 
546
          String qualifiedName, Attributes atts) throws SAXException {
 
547
            
 
548
            AttributesImpl newAtts = new AttributesImpl(atts);
 
549
            for (int i = 0; i < newAtts.getLength(); i++) {
 
550
                newAtts.setType(i, "WEIRD");
 
551
            }
 
552
            
 
553
            super.startElement(uri, localName, qualifiedName, newAtts);
 
554
            
 
555
        }
 
556
        
 
557
    }    
 
558
 
 
559
    
 
560
    public void testWeirdAttributeTypes()
 
561
      throws IOException, ParsingException, SAXException {
 
562
        
 
563
        XMLReader xerces = XMLReaderFactory.createXMLReader(
 
564
          "org.apache.xerces.parsers.SAXParser");
 
565
        XMLReader filter = new WeirdAttributeTypes(xerces);
 
566
        
 
567
        Builder builder = new Builder(filter);
 
568
        Document document = builder.build(attributeDoc, "http://www.example.org/");
 
569
        Element root = document.getRootElement();
 
570
        assertTrue(root.getAttributeCount() > 0);
 
571
        for (int i = 0; i < root.getAttributeCount(); i++) {
 
572
            assertEquals(Attribute.Type.UNDECLARED, root.getAttribute(i).getType());
 
573
        }
 
574
        
 
575
    }
 
576
    
 
577
    
 
578
    // Here we're faking the non-standard behavior of some older parsers
 
579
    private static class ParenthesizedEnumeratedAttributeTypes extends XMLFilterImpl {
 
580
 
 
581
        public ParenthesizedEnumeratedAttributeTypes(XMLReader reader) {
 
582
            super(reader);
 
583
        }
 
584
        
 
585
        public void startElement(String uri, String localName,
 
586
          String qualifiedName, Attributes atts) throws SAXException {
 
587
            
 
588
            AttributesImpl newAtts = new AttributesImpl(atts);
 
589
            for (int i = 0; i < newAtts.getLength(); i++) {
 
590
                newAtts.setType(i, "(test, data, value)");
 
591
            }
 
592
            
 
593
            super.startElement(uri, localName, qualifiedName, newAtts);
 
594
            
 
595
        }
 
596
        
 
597
    }    
 
598
 
 
599
    
 
600
    public void testParenthesizedEnumeratedAttributeTypes()
 
601
      throws IOException, ParsingException, SAXException {
 
602
        
 
603
        XMLReader xerces = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
 
604
        XMLReader filter = new ParenthesizedEnumeratedAttributeTypes(xerces);
 
605
        
 
606
        Builder builder = new Builder(filter);
 
607
        Document document = builder.build(attributeDoc, "http://www.example.org/");
 
608
        Element root = document.getRootElement();
 
609
        assertTrue(root.getAttributeCount() > 0);
 
610
        for (int i = 0; i < root.getAttributeCount(); i++) {
 
611
            assertEquals(Attribute.Type.ENUMERATION, root.getAttribute(i).getType());
 
612
        }
 
613
        
 
614
    }
 
615
    
 
616
    
 
617
    public void testBuildFromInputStreamWithBase()
 
618
      throws IOException, ParsingException {
 
619
        InputStream in = new ByteArrayInputStream(source.getBytes("UTF-8"));
 
620
        Document document = builder.build(in, base);
 
621
        verify(document);        
 
622
        assertEquals(base, document.getBaseURI());    
 
623
    }
 
624
    
 
625
    
 
626
    public void testBuildFromInputStreamWithoutBase()
 
627
      throws IOException, ParsingException {
 
628
        InputStream in = new ByteArrayInputStream(source.getBytes("UTF-8"));
 
629
        Document document = builder.build(in);
 
630
        verify(document);        
 
631
        assertEquals("", document.getBaseURI());
 
632
    }
 
633
 
 
634
    
 
635
    public void testBuildFromStringWithBase()
 
636
      throws IOException, ParsingException {
 
637
        Document document = builder.build(source, base);
 
638
        verify(document);       
 
639
        assertEquals(base, document.getBaseURI());  
 
640
    }
 
641
    
 
642
    
 
643
    public void testBuildDocumentThatUsesDoubleQuoteNumericCharacterReferenceInEntityDeclaration()
 
644
      throws IOException, ParsingException {
 
645
        
 
646
        String data = "<!DOCTYPE doc [\n"
 
647
            + "<!ELEMENT doc (#PCDATA)>"
 
648
            + " <!ENTITY e \"&#34;\">\n"
 
649
            + "]><root />";
 
650
        
 
651
        Document document = builder.build(data, null);
 
652
 
 
653
        Document roundtrip = builder.build(document.toXML(), null);
 
654
        assertEquals(document, roundtrip);
 
655
        
 
656
    }
 
657
    
 
658
    
 
659
    public void testBuildDocumentThatDeclaresStandardEntityReferences()
 
660
      throws IOException, ParsingException {
 
661
        
 
662
        String data = "<!DOCTYPE doc [\n"
 
663
            + "<!ELEMENT doc (#PCDATA)>"
 
664
            + "<!ENTITY lt     \"&#38;#60;\">\n"
 
665
            + "<!ENTITY gt     \"&#62;\">\n"
 
666
            + "<!ENTITY amp    \"&#38;#38;\">\n"
 
667
            + "<!ENTITY apos   \"&#39;\">\n"
 
668
            + "<!ENTITY quot   \"&#34;\">\n"
 
669
            + "]><root />";
 
670
        
 
671
        Document document = builder.build(data, null);
 
672
        Document roundtrip = builder.build(document.toXML(), null);
 
673
        assertEquals(document, roundtrip);
 
674
        
 
675
    }
 
676
    
 
677
    
 
678
    public void testBuildDocumentThatUsesAmpersandNumericCharacterReferenceInEntityDeclaration()
 
679
      throws IOException, ParsingException {
 
680
        
 
681
        String data = "<!DOCTYPE doc [\n"
 
682
            + "<!ELEMENT doc (#PCDATA)>"
 
683
            + " <!ENTITY e \"&#x26;\">\n"
 
684
            + "]><root />";
 
685
        
 
686
        Document document = builder.build(data, null);
 
687
 
 
688
        Document roundtrip = builder.build(document.toXML(), null);
 
689
        assertEquals(document, roundtrip);
 
690
        
 
691
    }
 
692
    
 
693
    
 
694
    public void testBuildDocumentThatUsesDoubleQuoteNumericCharacterReferenceInAttributeDeclaration()
 
695
      throws IOException, ParsingException {
 
696
        
 
697
        String data = "<!DOCTYPE doc [\n"
 
698
            + "<!ATTLIST root test (CDATA) \"&#x34;\">\n"
 
699
            + "]><root />";
 
700
        
 
701
        Document document = builder.build(data, null);
 
702
 
 
703
        Document roundtrip = builder.build(document.toXML(), null);
 
704
        assertEquals(document, roundtrip);
 
705
        
 
706
    }
 
707
    
 
708
    
 
709
    public void testMemoryFreedByBuilder()
 
710
      throws IOException, ParsingException, InterruptedException {
 
711
        
 
712
        String data = "<root />";
 
713
        
 
714
        Document document = builder.build(data, null);
 
715
        WeakReference ref = new WeakReference(document);
 
716
        document = null;
 
717
        System.gc();
 
718
        System.gc();
 
719
        System.gc();
 
720
        Thread.sleep(1000);
 
721
        assertNull(ref.get());
 
722
        
 
723
    }
 
724
    
 
725
    
 
726
    public void testBuildFromInvalidDoc()
 
727
      throws IOException, ParsingException {
 
728
        
 
729
        try {
 
730
            validator.build(source, base);
 
731
            fail("Built invalid doc");
 
732
        }
 
733
        catch (ValidityException ex) {
 
734
            Document document = ex.getDocument();
 
735
            // Can't do a full verify just yet due to bugs in Xerces
 
736
            // verify(ex.getDocument());
 
737
            assertTrue(document.getChild(1) instanceof ProcessingInstruction);
 
738
            assertTrue(document.getChild(2) instanceof Comment);        
 
739
            DocType doctype = document.getDocType();
 
740
            Element root = document.getRootElement();
 
741
    
 
742
            // assertEquals(1, root.getAttributeCount());
 
743
            // assertEquals("value", root.getAttributeValue("name"));
 
744
            assertEquals("test", root.getQualifiedName());
 
745
            assertEquals("test", root.getLocalName());
 
746
            assertEquals("", root.getNamespaceURI());
 
747
            
 
748
            assertTrue(doctype != null);
 
749
            assertTrue(document.getChild(0) instanceof DocType);
 
750
            assertTrue(document.getChild(4) instanceof Comment);
 
751
            assertTrue(document.getChild(2) instanceof Comment);
 
752
            assertEquals(" test ", document.getChild(2).getValue());
 
753
            assertEquals("epilog", document.getChild(4).getValue());
 
754
            assertTrue(document.getChild(1) instanceof ProcessingInstruction);
 
755
            assertEquals("test", doctype.getRootElementName());
 
756
            assertNull(doctype.getPublicID());
 
757
            assertNull(doctype.getSystemID());
 
758
            
 
759
            String internalDTDSubset = doctype.getInternalDTDSubset();
 
760
            assertTrue(
 
761
              internalDTDSubset, 
 
762
              internalDTDSubset.indexOf(elementDeclaration) > 0
 
763
            );
 
764
            assertTrue(
 
765
              internalDTDSubset, 
 
766
              internalDTDSubset.indexOf(attributeDeclaration) > 0
 
767
            );
 
768
            assertTrue(
 
769
              internalDTDSubset, 
 
770
              internalDTDSubset.indexOf(attributeDeclaration2) > 0
 
771
            );
 
772
            assertTrue(
 
773
              internalDTDSubset, 
 
774
              internalDTDSubset.indexOf(internalEntityDeclaration) > 0
 
775
            );
 
776
            assertTrue(
 
777
              internalDTDSubset, 
 
778
              internalDTDSubset.indexOf(externalEntityDeclarationPublic) > 0
 
779
            );
 
780
            assertTrue(
 
781
              internalDTDSubset, 
 
782
              internalDTDSubset.indexOf(externalEntityDeclarationSystem) > 0
 
783
            );
 
784
            assertTrue(
 
785
              internalDTDSubset,
 
786
              internalDTDSubset.indexOf(unparsedEntityDeclaration) > 0
 
787
            );
 
788
            assertTrue(
 
789
              internalDTDSubset,
 
790
              internalDTDSubset.indexOf(unparsedEntityDeclarationPublic) > 0
 
791
            );
 
792
            assertTrue(
 
793
              internalDTDSubset, 
 
794
              internalDTDSubset.indexOf(notationDeclarationPublic) > 0
 
795
            );
 
796
            assertTrue(
 
797
              internalDTDSubset, 
 
798
              internalDTDSubset.indexOf(notationDeclarationSystem) > 0
 
799
            );
 
800
            assertTrue(
 
801
              internalDTDSubset, 
 
802
              internalDTDSubset.indexOf(notationDeclarationPublicAndSystem) > 0
 
803
            );
 
804
            
 
805
        }  
 
806
        
 
807
    }
 
808
    
 
809
    
 
810
    public void testBuildFromStringWithNullBase()
 
811
      throws IOException, ParsingException {
 
812
        Document document = builder.build(source, null);
 
813
        verify(document);        
 
814
        assertEquals("", document.getBaseURI());    
 
815
    }
 
816
    
 
817
    
 
818
    private void verify(Document document) {
 
819
        
 
820
        assertTrue(document.getChild(1) instanceof ProcessingInstruction);
 
821
        assertTrue(document.getChild(2) instanceof Comment);        
 
822
        DocType doctype = document.getDocType();
 
823
        Element root = document.getRootElement();
 
824
 
 
825
        assertEquals(1, root.getAttributeCount());
 
826
        assertEquals("value", root.getAttributeValue("name"));
 
827
        assertEquals("test", root.getQualifiedName());
 
828
        assertEquals("test", root.getLocalName());
 
829
        assertEquals("", root.getNamespaceURI());
 
830
        
 
831
        assertTrue(doctype != null);
 
832
        assertTrue(document.getChild(0) instanceof DocType);
 
833
        assertTrue(document.getChild(4) instanceof Comment);
 
834
        assertTrue(document.getChild(2) instanceof Comment);
 
835
        assertEquals(" test ", document.getChild(2).getValue());
 
836
        assertEquals("epilog", document.getChild(4).getValue());
 
837
        assertTrue(document.getChild(1) instanceof ProcessingInstruction);
 
838
        assertEquals("test", doctype.getRootElementName());
 
839
        assertNull(doctype.getPublicID());
 
840
        assertNull(doctype.getSystemID());
 
841
        
 
842
        String internalDTDSubset = doctype.getInternalDTDSubset();
 
843
        assertTrue(
 
844
          internalDTDSubset, 
 
845
          internalDTDSubset.indexOf(elementDeclaration) > 0
 
846
        );
 
847
        assertTrue(
 
848
          internalDTDSubset, 
 
849
          internalDTDSubset.indexOf(attributeDeclaration) > 0
 
850
        );
 
851
        assertTrue(
 
852
          internalDTDSubset, 
 
853
          internalDTDSubset.indexOf(attributeDeclaration2) > 0
 
854
        );
 
855
        assertTrue(
 
856
          internalDTDSubset, 
 
857
          internalDTDSubset.indexOf(internalEntityDeclaration) > 0
 
858
        );
 
859
        assertTrue(
 
860
          internalDTDSubset, 
 
861
          internalDTDSubset.indexOf(externalEntityDeclarationPublic) > 0
 
862
        );
 
863
        assertTrue(
 
864
          internalDTDSubset, 
 
865
          internalDTDSubset.indexOf(externalEntityDeclarationSystem) > 0
 
866
        );
 
867
        assertTrue(
 
868
          internalDTDSubset,
 
869
          internalDTDSubset.indexOf(unparsedEntityDeclaration) > 0
 
870
        );
 
871
        assertTrue(
 
872
          internalDTDSubset,
 
873
          internalDTDSubset.indexOf(unparsedEntityDeclarationPublic) > 0
 
874
        );
 
875
        assertTrue(
 
876
          internalDTDSubset, 
 
877
          internalDTDSubset.indexOf(notationDeclarationPublic) > 0
 
878
        );
 
879
        assertTrue(
 
880
          internalDTDSubset, 
 
881
          internalDTDSubset.indexOf(notationDeclarationSystem) > 0
 
882
        );
 
883
        assertTrue(
 
884
          internalDTDSubset, 
 
885
          internalDTDSubset.indexOf(notationDeclarationPublicAndSystem) > 0
 
886
        );
 
887
               
 
888
    }
 
889
 
 
890
    
 
891
    public void testValidateFromReader() 
 
892
      throws IOException, ParsingException {
 
893
        
 
894
        Reader reader1 = new StringReader(validDoc);
 
895
        Document document1 = validator.build(reader1);       
 
896
        assertEquals("", document1.getBaseURI());
 
897
        Reader reader2 = new StringReader(validDoc);
 
898
        Document document2 = builder.build(reader2);  
 
899
        assertEquals(document2, document1); 
 
900
        
 
901
    }
 
902
 
 
903
    
 
904
    public void testDocumentWithDefaultNamespaceOnPrefixedElement()
 
905
      throws IOException, ParsingException {
 
906
        
 
907
        Reader reader = new StringReader("<pre:root " +
 
908
                "xmlns='http://www.example.org/' " +
 
909
                "xmlns:pre='http://www.cafeconleche.org/'/>");
 
910
        Document document = builder.build(reader); 
 
911
        Element root = document.getRootElement();
 
912
        assertEquals("http://www.example.org/", root.getNamespaceURI(""));    
 
913
        assertEquals("http://www.cafeconleche.org/", root.getNamespaceURI("pre"));    
 
914
        assertEquals("http://www.cafeconleche.org/", root.getNamespaceURI());   
 
915
        
 
916
    } 
 
917
    
 
918
    
 
919
    public void testValidateFromReaderWithBase()
 
920
      throws IOException, ParsingException {
 
921
        
 
922
        Reader reader = new StringReader(validDoc);
 
923
        Document document = validator.build(reader, base); 
 
924
        assertEquals(base, document.getBaseURI());
 
925
        Reader reader2 = new StringReader(validDoc);
 
926
        Document document2 = builder.build(reader2);  
 
927
        assertEquals(document2, document);    
 
928
        
 
929
    }
 
930
    
 
931
    
 
932
    public void testValidateFromInputStreamWithBase()
 
933
      throws IOException, ParsingException {
 
934
        
 
935
        InputStream in = new ByteArrayInputStream(validDoc.getBytes("UTF-8"));
 
936
        Document document = validator.build(in, base);  
 
937
        assertEquals(base, document.getBaseURI());  
 
938
        Reader reader2 = new StringReader(validDoc);
 
939
        Document document2 = builder.build(reader2);  
 
940
        assertEquals(document2, document);     
 
941
        
 
942
    }
 
943
    
 
944
    
 
945
    public void testValidateInSeries()
 
946
      throws IOException, ParsingException {
 
947
          
 
948
        try {
 
949
            Reader reader = new StringReader(source);
 
950
            validator.build(reader);   
 
951
            fail("Allowed invalid doc");
 
952
        }
 
953
        catch (ValidityException success) {
 
954
            assertNotNull(success.getMessage());   
 
955
        }  
 
956
        // now make sure validating a valid document doesn't
 
957
        // throw an exception
 
958
        InputStream in = new ByteArrayInputStream(validDoc.getBytes("UTF-8"));
 
959
        validator.build(in, base);   
 
960
        
 
961
    }
 
962
    
 
963
    
 
964
    public void testValidateFromInputStreamWithoutBase()
 
965
      throws IOException, ParsingException {
 
966
        
 
967
        InputStream in = new ByteArrayInputStream(validDoc.getBytes("UTF-8"));
 
968
        Document document = validator.build(in);        
 
969
        assertEquals("", document.getBaseURI());
 
970
        Reader reader2 = new StringReader(validDoc);
 
971
        Document document2 = builder.build(reader2);  
 
972
        assertEquals(document2, document);  
 
973
        
 
974
    }
 
975
 
 
976
    
 
977
    public void testValidateFromStringWithBase()
 
978
      throws IOException, ParsingException {
 
979
        
 
980
        Document document = validator.build(validDoc, base);        
 
981
        assertEquals(base, document.getBaseURI());  
 
982
        Reader reader2 = new StringReader(validDoc);
 
983
        Document document2 = builder.build(reader2);  
 
984
        assertEquals(document2, document);     
 
985
        
 
986
    }
 
987
    
 
988
    
 
989
    public void testValidateWithCrimson()
 
990
      throws IOException, ParsingException {
 
991
        
 
992
        XMLReader crimson;
 
993
        try {
 
994
            crimson = XMLReaderFactory.createXMLReader(
 
995
              "org.apache.crimson.parser.XMLReaderImpl");
 
996
        } 
 
997
        catch (SAXException ex) {
 
998
            // can't test Crimson if you can't load it
 
999
            return;
 
1000
        }
 
1001
        Builder validator = new Builder(crimson, true);
 
1002
        Document document = validator.build(validDoc, base);        
 
1003
        assertEquals(base, document.getBaseURI());  
 
1004
        Reader reader2 = new StringReader(validDoc);
 
1005
        Document document2 = builder.build(reader2);  
 
1006
        assertEquals(document2, document);    
 
1007
        
 
1008
    }
 
1009
 
 
1010
    
 
1011
    public void testNotationAttributeTypeWithCrimson()
 
1012
      throws IOException, ParsingException {
 
1013
        
 
1014
        XMLReader crimson;
 
1015
        try {
 
1016
            crimson = XMLReaderFactory.createXMLReader(
 
1017
              "org.apache.crimson.parser.XMLReaderImpl");
 
1018
        } 
 
1019
        catch (SAXException ex) {
 
1020
            // can't test Crimson if you can't load it
 
1021
            return;
 
1022
        }
 
1023
        
 
1024
        String data = " <!DOCTYPE doc [\n"
 
1025
            + "<!ATTLIST e a NOTATION (n) #IMPLIED>\n"
 
1026
            + "<!ELEMENT document (e)*>\n"
 
1027
            + "<!ELEMENT e (#PCDATA)>\n"
 
1028
            + "<!NOTATION n PUBLIC \"whatever\">"
 
1029
            + "]><document />";
 
1030
        
 
1031
        Builder builder = new Builder(crimson);
 
1032
        Document document = builder.build(data, base); 
 
1033
        
 
1034
        String s = document.toXML();
 
1035
        Document roundTrip = builder.build(s, base);
 
1036
        assertEquals(document, roundTrip);
 
1037
        
 
1038
    }
 
1039
   
 
1040
    
 
1041
    public void testEnumerationAttributeType()
 
1042
      throws IOException, ParsingException {
 
1043
        
 
1044
        XMLReader crimson;
 
1045
        try {
 
1046
            crimson = XMLReaderFactory.createXMLReader(
 
1047
              "org.apache.crimson.parser.XMLReaderImpl");
 
1048
        } 
 
1049
        catch (SAXException ex) {
 
1050
            // can't test Crimson if you can't load it
 
1051
            return;
 
1052
        }
 
1053
        Builder builder = new Builder(crimson, false);
 
1054
        String doc = "<!DOCTYPE root [" +
 
1055
                "<!ATTLIST root att (yes | no) #IMPLIED>" +
 
1056
                "]><root att='yes'/>";
 
1057
        Document document = builder.build(doc, base); 
 
1058
        Element root = document.getRootElement();
 
1059
        Attribute att = root.getAttribute(0);
 
1060
        assertEquals(Attribute.Type.ENUMERATION, att.getType());
 
1061
        
 
1062
    }
 
1063
 
 
1064
    
 
1065
    public void testWarningDoesNotStopBuild()
 
1066
      throws IOException, ParsingException, SAXException {
 
1067
        
 
1068
        XMLReader xerces;
 
1069
        try {
 
1070
            xerces = XMLReaderFactory.createXMLReader(
 
1071
              "org.apache.xerces.parsers.SAXParser");
 
1072
        } 
 
1073
        catch (SAXException ex) {
 
1074
            // can't test Xerces if you can't load it
 
1075
            return;
 
1076
        }
 
1077
        // This document generates a warning due to the duplicate
 
1078
        // attribute declaration
 
1079
        xerces.setFeature(
 
1080
          "http://apache.org/xml/features/validation/warn-on-duplicate-attdef", 
 
1081
          true);
 
1082
        Builder builder = new Builder(xerces, true);
 
1083
        Document document = builder.build("<!DOCTYPE root [" +
 
1084
                "<!ELEMENT root ANY>" +
 
1085
                "<!ATTLIST root b CDATA #IMPLIED>" +
 
1086
                "<!ATTLIST root b NMTOKEN #REQUIRED>" +
 
1087
                "]><root b='test'/>", base); 
 
1088
        // The main test is that the document is built successfully.
 
1089
        assertEquals(2, document.getChildCount());
 
1090
        assertEquals("root", document.getRootElement().getQualifiedName());
 
1091
        
 
1092
    }   
 
1093
    
 
1094
    
 
1095
    private static class EntitySkipper extends XMLFilterImpl {
 
1096
 
 
1097
        public EntitySkipper(XMLReader reader) {
 
1098
            super(reader);
 
1099
        }
 
1100
        
 
1101
        public void characters(char[] data, int start, int length) 
 
1102
          throws SAXException {
 
1103
            super.skippedEntity("name");
 
1104
        }
 
1105
        
 
1106
    }
 
1107
    
 
1108
    
 
1109
    public void testSkippedEntityThrowsParsingException()
 
1110
      throws IOException, ParsingException, SAXException {
 
1111
        
 
1112
        XMLReader xerces = XMLReaderFactory.createXMLReader(
 
1113
          "org.apache.xerces.parsers.SAXParser");
 
1114
        XMLReader filter = new EntitySkipper(xerces);
 
1115
        
 
1116
        Builder builder = new Builder(filter, true);
 
1117
        try {
 
1118
            builder.build("<root>replace</root>", base); 
 
1119
            fail("Allowed skipped entity");
 
1120
        }
 
1121
        catch (ParsingException success) {
 
1122
            assertNotNull(success.getMessage());
 
1123
        }   
 
1124
        
 
1125
    }   
 
1126
    
 
1127
    
 
1128
    public void testValidateFromStringWithNullBase()
 
1129
      throws IOException, ParsingException {
 
1130
        Document document = validator.build(validDoc, null);    
 
1131
        assertEquals("", document.getBaseURI());  
 
1132
        Reader reader2 = new StringReader(validDoc);
 
1133
        Document document2 = builder.build(reader2);  
 
1134
        assertEquals(document2, document);     
 
1135
    }
 
1136
 
 
1137
 
 
1138
    public void testCannotBuildNamespaceMalformedDocument()
 
1139
      throws IOException {
 
1140
        
 
1141
        try {
 
1142
            builder.build("<root:root/>", null);
 
1143
            fail("Builder allowed undeclared prefix");
 
1144
        }
 
1145
        catch (ParsingException success) {
 
1146
            assertNotNull(success.getMessage());   
 
1147
        }   
 
1148
        
 
1149
    }
 
1150
 
 
1151
    
 
1152
    public void testInvalidDocFromReader() 
 
1153
      throws IOException, ParsingException {
 
1154
        
 
1155
        Reader reader = new StringReader(source);
 
1156
        try {
 
1157
            validator.build(reader);   
 
1158
            fail("Allowed invalid doc");
 
1159
        }
 
1160
        catch (ValidityException success) {
 
1161
            assertNotNull(success.getMessage());
 
1162
            assertTrue(success.getErrorCount() > 0);
 
1163
            for (int i = 0; i < success.getErrorCount(); i++) {
 
1164
                assertNotNull(success.getValidityError(i));   
 
1165
                assertTrue(success.getLineNumber(i) >= -1);   
 
1166
                assertTrue(success.getColumnNumber(i) >= -1);   
 
1167
            }   
 
1168
            if (!xercesBroken) {
 
1169
                Document doc = builder.build(new StringReader(source)); 
 
1170
                this.verify(success.getDocument());
 
1171
                assertEquals(doc, success.getDocument());
 
1172
            }
 
1173
        }
 
1174
        
 
1175
    }
 
1176
    
 
1177
    
 
1178
    public void testNamespaceMalformedDocumentWithCrimson() 
 
1179
      throws IOException {
 
1180
        
 
1181
        StringReader reader = new StringReader("<root:root/>");
 
1182
        XMLReader crimson;
 
1183
        try {
 
1184
            crimson = XMLReaderFactory.createXMLReader(
 
1185
              "org.apache.crimson.parser.XMLReaderImpl");
 
1186
        }
 
1187
        catch (SAXException ex) {
 
1188
           // No Crimson in classpath; therefore can't test it
 
1189
           return;
 
1190
        }
 
1191
        Builder builder = new Builder(crimson);
 
1192
        try {
 
1193
            builder.build(reader);   
 
1194
            fail("Crimson allowed namespace malformed doc");
 
1195
        }
 
1196
        catch (ParsingException success) {
 
1197
            assertNotNull(success.getMessage());
 
1198
        }      
 
1199
        
 
1200
    }
 
1201
 
 
1202
    
 
1203
    public void testValidateNamespaceMalformedInvalidDocumentWithCrimson() 
 
1204
      throws IOException {
 
1205
        
 
1206
        StringReader reader = new StringReader("<!DOCTYPE root [" +
 
1207
                "<!ELEMENT root (a)>\n" +
 
1208
                "<!ELEMENT a (#PCDATA)> \n" +
 
1209
                "]>\n" +
 
1210
                "<root><b:b /></root>");
 
1211
        XMLReader crimson;
 
1212
        try {
 
1213
            crimson = XMLReaderFactory.createXMLReader(
 
1214
              "org.apache.crimson.parser.XMLReaderImpl");
 
1215
        }
 
1216
        catch (SAXException ex) {
 
1217
           // No Crimson in classpath; therefore can't test it
 
1218
           return;
 
1219
        }
 
1220
        Builder builder = new Builder(crimson);
 
1221
        try {
 
1222
            builder.build(reader);   
 
1223
            fail("Crimson allowed namespace malformed doc");
 
1224
        }
 
1225
        catch (ValidityException ex) {
 
1226
            fail("Crimson should have thrown ParsingException instead");
 
1227
        }      
 
1228
        catch (ParsingException success) {
 
1229
            assertNotNull(success.getMessage());
 
1230
        }      
 
1231
        
 
1232
    }
 
1233
    
 
1234
    
 
1235
    public void testInvalidDocFromReaderWithBase()
 
1236
      throws IOException, ParsingException {
 
1237
        
 
1238
        Reader reader1 = new StringReader(source);
 
1239
        try {
 
1240
            validator.build(reader1, base); 
 
1241
            fail("Allowed invalid doc");
 
1242
        }
 
1243
        catch (ValidityException ex) {
 
1244
            assertNotNull(ex.getMessage()); 
 
1245
            assertEquals(base, ex.getURI());
 
1246
            assertTrue(ex.getErrorCount() > 0);
 
1247
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1248
                assertNotNull(ex.getValidityError(i));   
 
1249
                assertTrue(ex.getLineNumber(i) >= -1);   
 
1250
                assertTrue(ex.getColumnNumber(i) >= -1);   
 
1251
            }   
 
1252
            if (!xercesBroken) {
 
1253
                Document doc = builder.build(new StringReader(source), base); 
 
1254
                this.verify(ex.getDocument());
 
1255
                assertEquals(doc, ex.getDocument());
 
1256
            }
 
1257
        }
 
1258
        
 
1259
    }
 
1260
 
 
1261
    
 
1262
    public void testInvalidDocFromInputStreamWithBase()
 
1263
      throws IOException, ParsingException {
 
1264
        
 
1265
        InputStream in = new ByteArrayInputStream(source.getBytes("UTF-8"));
 
1266
        try {
 
1267
            validator.build(in, base);  
 
1268
            fail("Allowed invalid doc");
 
1269
        }
 
1270
        catch (ValidityException ex) {
 
1271
            assertNotNull(ex.getMessage());  
 
1272
            assertEquals(base, ex.getURI());
 
1273
            assertTrue(ex.getErrorCount() > 0);
 
1274
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1275
                assertNotNull(ex.getValidityError(i));
 
1276
                assertTrue(ex.getLineNumber(i) >= -1);   
 
1277
                assertTrue(ex.getColumnNumber(i) >= -1);   
 
1278
            }   
 
1279
            if (!xercesBroken) {
 
1280
                Document doc = builder.build(
 
1281
                  new ByteArrayInputStream(source.getBytes("UTF-8")), base
 
1282
                ); 
 
1283
                this.verify(ex.getDocument());
 
1284
                assertEquals(doc, ex.getDocument());
 
1285
            }
 
1286
        }
 
1287
        
 
1288
    }
 
1289
    
 
1290
    
 
1291
    public void testInvalidDocFromInputStreamWithoutBase()
 
1292
      throws IOException, ParsingException {
 
1293
        
 
1294
        InputStream in = new ByteArrayInputStream(source.getBytes("UTF-8"));
 
1295
        try {
 
1296
            validator.build(in);        
 
1297
            fail("Allowed invalid doc");
 
1298
        }
 
1299
        catch (ValidityException ex) {
 
1300
            assertNotNull(ex.getMessage());   
 
1301
            assertTrue(ex.getErrorCount() > 0);
 
1302
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1303
                assertNotNull(ex.getValidityError(i));   
 
1304
                assertTrue(ex.getLineNumber(i) >= -1);   
 
1305
                assertTrue(ex.getColumnNumber(i) >= -1);   
 
1306
            }   
 
1307
            if (!xercesBroken) {
 
1308
                Document doc = builder.build(
 
1309
                  new ByteArrayInputStream(source.getBytes("UTF-8"))
 
1310
                ); 
 
1311
                this.verify(ex.getDocument());
 
1312
                assertEquals(doc, ex.getDocument());
 
1313
            }
 
1314
        }
 
1315
        
 
1316
    }
 
1317
 
 
1318
    
 
1319
    public void testInvalidDocFromStringWithBase()
 
1320
      throws IOException, ParsingException {
 
1321
        
 
1322
        try {
 
1323
            validator.build(source, base);        
 
1324
            fail("Allowed invalid doc");
 
1325
        }
 
1326
        catch (ValidityException ex) {
 
1327
            assertNotNull(ex.getMessage()); 
 
1328
            assertEquals(base, ex.getURI());
 
1329
            assertTrue(ex.getErrorCount() > 0);
 
1330
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1331
                assertNotNull(ex.getValidityError(i));   
 
1332
                assertTrue(ex.getLineNumber(i) >= -1);   
 
1333
                assertTrue(ex.getColumnNumber(i) >= -1);   
 
1334
            }   
 
1335
            if (!xercesBroken) {
 
1336
                Document doc = builder.build(source, base); 
 
1337
                this.verify(ex.getDocument());
 
1338
                assertEquals(doc, ex.getDocument());
 
1339
            }
 
1340
        }
 
1341
        
 
1342
    }
 
1343
    
 
1344
 
 
1345
    public void testInvalidDocWithCrimson()
 
1346
      throws IOException, ParsingException {
 
1347
        
 
1348
        XMLReader crimson;
 
1349
        try {
 
1350
            crimson = XMLReaderFactory.createXMLReader(
 
1351
              "org.apache.crimson.parser.XMLReaderImpl");
 
1352
        } 
 
1353
        catch (SAXException ex) {
 
1354
            // can't test Crimson if you can't load it
 
1355
            return;
 
1356
        }
 
1357
        Builder validator = new Builder(crimson, true);
 
1358
        try {
 
1359
            validator.build(source, null);    
 
1360
            fail("Allowed invalid doc");
 
1361
        }
 
1362
        catch (ValidityException ex) {
 
1363
            assertTrue(ex.getErrorCount() > 0);
 
1364
            assertNull(ex.getURI());
 
1365
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1366
                assertNotNull(ex.getValidityError(i));   
 
1367
            }    
 
1368
        }
 
1369
        
 
1370
    }         
 
1371
 
 
1372
    
 
1373
    public void testInvalidDocFromStringWithNullBase()
 
1374
      throws IOException, ParsingException {
 
1375
        
 
1376
        try {
 
1377
            validator.build(source, null);    
 
1378
            fail("Allowed invalid doc");
 
1379
        }
 
1380
        catch (ValidityException ex) {
 
1381
            assertTrue(ex.getErrorCount() > 0);
 
1382
            assertNull(ex.getURI());
 
1383
            for (int i = 0; i < ex.getErrorCount(); i++) {
 
1384
                assertNotNull(ex.getValidityError(i));   
 
1385
            }   
 
1386
            if (!xercesBroken) {
 
1387
                Document doc = builder.build(source, null); 
 
1388
                this.verify(ex.getDocument());
 
1389
                assertEquals(doc, ex.getDocument());
 
1390
            } 
 
1391
        }
 
1392
        
 
1393
    }
 
1394
    
 
1395
    
 
1396
    public void testJavaEncodings() 
 
1397
      throws IOException, ParsingException {
 
1398
        
 
1399
        String str = "<?xml version='1.0' encoding='ISO8859_1'?>" +
 
1400
            "<root>Ć©</root>"; 
 
1401
        byte[] data = str.getBytes("8859_1"); 
 
1402
        InputStream in = new ByteArrayInputStream(data);
 
1403
        Document doc = builder.build(in);
 
1404
        assertEquals("Ć©", doc.getValue()); 
 
1405
        
 
1406
    }
 
1407
 
 
1408
    
 
1409
    // Crimson improperly converts 0x0D and 0x0A to spaces
 
1410
    // even when the attribute type is not CDATA.
 
1411
    // This bug explains why the canonicalizer tests fail
 
1412
    // with Crimson
 
1413
    public void testCrimsonCharacterReferenceBug()
 
1414
      throws IOException, ParsingException {
 
1415
        
 
1416
        String data = 
 
1417
          "<!DOCTYPE test [<!ATTLIST test name ID #IMPLIED>]>"
 
1418
          + "<test name='&#x0D;'/>";
 
1419
        InputStream in = new ByteArrayInputStream(
 
1420
          data.getBytes("UTF8"));
 
1421
        Document document = builder.build(in, null);      
 
1422
        assertEquals("\r", 
 
1423
          document.getRootElement().getAttributeValue("name"));
 
1424
        
 
1425
    }
 
1426
    
 
1427
    
 
1428
    public void testBaseRelativeResolution()
 
1429
      throws IOException, ParsingException {
 
1430
        builder.build(new File(inputDir, "baserelative/test.xml"));
 
1431
    }
 
1432
    
 
1433
    
 
1434
    // make sure transcoders on input are using normalization
 
1435
    // form C when converting from other encodings
 
1436
    public void testNFC()
 
1437
      throws IOException, ParsingException {
 
1438
        
 
1439
        Document doc = builder.build(new File(inputDir, "nfctest.xml"));
 
1440
        Element root = doc.getRootElement();
 
1441
        String s = root.getValue();
 
1442
        assertEquals(1, s.length());
 
1443
        assertEquals(0xE9, s.charAt(0));
 
1444
        
 
1445
    }
 
1446
    
 
1447
    
 
1448
    // This tests XOM's workaround for a bug in Crimson, Xerces,
 
1449
    // and possibly other parsers
 
1450
    public void testBaseRelativeResolutionRemotely()
 
1451
      throws IOException, ParsingException {
 
1452
        builder.build("http://www.cafeconleche.org");
 
1453
    }
 
1454
    
 
1455
    
 
1456
    public void testExternalEntityResolution()
 
1457
      throws IOException, ParsingException {
 
1458
        
 
1459
        File input = new File(inputDir, "entitytest.xml");
 
1460
        Builder builder = new Builder(false);
 
1461
        Document doc = builder.build(input);
 
1462
        Element root = doc.getRootElement();
 
1463
        Element external = root.getFirstChildElement("external");
 
1464
        assertEquals("Hello from an entity!", external.getValue());
 
1465
        
 
1466
    }
 
1467
     
 
1468
    
 
1469
    // This test exposes a bug in Crimson but not Xerces.
 
1470
    // It's testing whether the external DTD subset is read,
 
1471
    // default attribute values applied, and comments and
 
1472
    // processing instructions in the external DTD subset are not
 
1473
    // reported.
 
1474
    public void testExternalDTDSubset()
 
1475
      throws IOException, ParsingException {
 
1476
        
 
1477
        File input = new File(inputDir, "externalDTDtest.xml");
 
1478
        Builder builder = new Builder(false);
 
1479
        Document doc = builder.build(input);
 
1480
        assertEquals(2, doc.getChildCount());
 
1481
        Element root = doc.getRootElement();
 
1482
        Attribute name = root.getAttribute("name");
 
1483
        assertEquals("value", name.getValue());
 
1484
        DocType doctype = doc.getDocType();
 
1485
        assertEquals("", doctype.getInternalDTDSubset());
 
1486
        
 
1487
    }
 
1488
 
 
1489
    
 
1490
    /* <?xml version="1.0"?>
 
1491
<!DOCTYPE root [
 
1492
  <!ELEMENT root (#PCDATA)>
 
1493
  <!-- comment -->
 
1494
  <?target PI data?>
 
1495
  <!NOTATION JPEG SYSTEM "image/jpeg">
 
1496
  <!ATTLIST  root source ENTITY #REQUIRED>
 
1497
  <!ENTITY picture SYSTEM "picture.jpg" NDATA JPEG>  
 
1498
]>
 
1499
<root source="picture">
 
1500
  This document is intended to test the building of
 
1501
  various constructs in the internal DTD subset.
 
1502
</root>
 
1503
*/
 
1504
    public void testInternalDTDSubset() 
 
1505
      throws ValidityException, ParsingException, IOException {
 
1506
        
 
1507
        File input = new File(inputDir, "internaldtdsubsettest.xml");
 
1508
        Builder builder = new Builder(false);
 
1509
        Document doc = builder.build(input);
 
1510
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1511
        assertTrue(internalSubset.indexOf("<!-- comment -->") > 0);
 
1512
        assertTrue(internalSubset.indexOf("<?target PI data?>") > 0);
 
1513
        assertTrue(internalSubset.indexOf("<!ELEMENT root (#PCDATA)>") > 0);
 
1514
        assertTrue(internalSubset.indexOf("<!ATTLIST root source ENTITY #REQUIRED>") > 0);
 
1515
        // some confusion in the parser resolving these as relative URLs.
 
1516
        // This is in accordance with the SAX spec, see 
 
1517
        // http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html#notationDecl(java.lang.String,%20java.lang.String,%20java.lang.String)
 
1518
        // but how does it know the notation system ID is really a URL?
 
1519
        assertTrue(internalSubset.indexOf("<!ENTITY picture SYSTEM ") > 0);
 
1520
        assertTrue(internalSubset.indexOf("picture.jpg\" NDATA JPEG>") > 0);
 
1521
        assertTrue(internalSubset.indexOf("<!NOTATION JPEG SYSTEM ") > 0);
 
1522
        assertTrue(internalSubset.indexOf("image/jpeg\">") > 0);
 
1523
        
 
1524
    }
 
1525
    
 
1526
 
 
1527
    public void testInternalEntityDeclDollarSign() 
 
1528
      throws ValidityException, ParsingException, IOException {
 
1529
        
 
1530
        String input = "<!DOCTYPE root [<!ENTITY test '$!@#$^'>] ><root />";
 
1531
        Builder builder = new Builder(false);
 
1532
        Document doc = builder.build(input, null);
 
1533
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1534
        assertTrue(internalSubset.indexOf("<!ENTITY test \"$!@#$^\">") > 0);
 
1535
 
 
1536
    }
 
1537
    
 
1538
 
 
1539
    public void testInternalDTDSubset5To9() 
 
1540
      throws ValidityException, ParsingException, IOException {
 
1541
        
 
1542
        String input = "<!DOCTYPE root [<!ATTLIST root source CDATA '56789'>] ><root />";
 
1543
        Builder builder = new Builder(false);
 
1544
        Document doc = builder.build(input, null);
 
1545
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1546
        assertTrue(internalSubset.indexOf("<!ATTLIST root source CDATA \"56789\">") > 0);
 
1547
 
 
1548
    }
 
1549
    
 
1550
 
 
1551
    public void testInternalDTDSubsetPunctuation() 
 
1552
      throws ValidityException, ParsingException, IOException {
 
1553
        
 
1554
        String input = "<!DOCTYPE root [<!ATTLIST root source CDATA '+,()!'>] ><root />";
 
1555
        Builder builder = new Builder(false);
 
1556
        Document doc = builder.build(input, null);
 
1557
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1558
        assertTrue(internalSubset.indexOf("<!ATTLIST root source CDATA \"+,()!\">") > 0);
 
1559
 
 
1560
    }
 
1561
    
 
1562
 
 
1563
/*<!ELEMENT test (#PCDATA)>
 
1564
<!-- comment should not be here -->
 
1565
<?processing instruction should not be here?>
 
1566
<!ATTLIST test name (CDATA) #FIXED "value">
 
1567
<!ATTLIST test name CDATA "value">
 
1568
<!ATTLIST root anattribute CDATA #REQUIRED>
 
1569
<!ATTLIST root anotherattribute CDATA "value">
 
1570
<!ENTITY hatch-pic SYSTEM "http://www.example.com/images/cup.gif" NDATA gif>
 
1571
<!ENTITY public-pic PUBLIC "public ID" "http://www.example.com/images/cup.gif" NDATA gif>
 
1572
<!ENTITY Pub-Status "This is a pre-release of the specification.">
 
1573
<!ENTITY open-hatch PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN" "http://www.textuality.com/boilerplate/OpenHatch.xml">
 
1574
<!ENTITY test SYSTEM "http://www.textuality.com/boilerplate/OpenHatch.xml">
 
1575
<!NOTATION ISODATE SYSTEM "http://www.iso.ch/cate/d15903.html">
 
1576
<!NOTATION DATE PUBLIC "DATE PUBLIC ID" "http://www.iso.ch/cate/d15903.html">
 
1577
<!NOTATION gif PUBLIC "-//Textuality//TEXT Standard open-hatch boilerplate//EN"> */    
 
1578
    public void testInternalAndExternalDTDSubset() 
 
1579
      throws ValidityException, ParsingException, IOException {
 
1580
        
 
1581
        File input = new File(inputDir, "internalandexternaldtdsubsettest.xml");
 
1582
        Builder builder = new Builder(false);
 
1583
        Document doc = builder.build(input);
 
1584
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1585
        assertTrue(internalSubset.indexOf("<!-- comment -->") > 0);
 
1586
        assertTrue(internalSubset.indexOf("<?target PI data?>") > 0);
 
1587
        assertTrue(internalSubset.indexOf("<!ELEMENT root (#PCDATA)>") > 0);
 
1588
        assertTrue(internalSubset.indexOf("<!ATTLIST root source ENTITY #REQUIRED>") > 0);
 
1589
        assertTrue(internalSubset.indexOf("<!ENTITY picture SYSTEM ") > 0);
 
1590
        assertTrue(internalSubset.indexOf("picture.jpg\" NDATA JPEG>") > 0);
 
1591
        assertTrue(internalSubset.indexOf("<!NOTATION JPEG SYSTEM ") > 0);
 
1592
        assertTrue(internalSubset.indexOf("image/jpeg\">") > 0);
 
1593
        
 
1594
        assertEquals(-1, internalSubset.indexOf("comment should not be here"));
 
1595
        assertEquals(-1, internalSubset.indexOf("processing instruction should not be here"));
 
1596
        assertEquals(-1, internalSubset.indexOf("anattribute"));
 
1597
        assertEquals(-1, internalSubset.indexOf("anotherattribute"));
 
1598
        assertEquals(-1, internalSubset.indexOf("hatch-pic"));
 
1599
        assertEquals(-1, internalSubset.indexOf("public-pic"));
 
1600
        assertEquals(-1, internalSubset.indexOf("open-hatch"));
 
1601
        assertEquals(-1, internalSubset.indexOf("Pub-Status-pic"));
 
1602
        assertEquals(-1, internalSubset.indexOf("Textuality"));
 
1603
        assertEquals(-1, internalSubset.indexOf("15903"));
 
1604
        
 
1605
    }
 
1606
    
 
1607
 
 
1608
    public void testInternalAndExternalDTDSubsetWithCrimson() 
 
1609
      throws ValidityException, ParsingException, IOException {
 
1610
        
 
1611
        XMLReader crimson;
 
1612
        try {
 
1613
            crimson = XMLReaderFactory.createXMLReader(
 
1614
              "org.apache.crimson.parser.XMLReaderImpl");
 
1615
        } 
 
1616
        catch (SAXException ex) {
 
1617
            // can't test Crimson if you can't load it
 
1618
            return;
 
1619
        }
 
1620
        
 
1621
        Builder builder = new Builder(crimson);
 
1622
        File input = new File(inputDir, "internalandexternaldtdsubsettest.xml");
 
1623
        Document doc = builder.build(input);
 
1624
        String internalSubset = doc.getDocType().getInternalDTDSubset();
 
1625
        assertTrue(internalSubset.indexOf("<!-- comment -->") > 0);
 
1626
        assertTrue(internalSubset.indexOf("<?target PI data?>") > 0);
 
1627
        assertTrue(internalSubset.indexOf("<!ELEMENT root (#PCDATA)>") > 0);
 
1628
        assertTrue(internalSubset.indexOf("<!ATTLIST root source ENTITY #REQUIRED>") > 0);
 
1629
        assertTrue(internalSubset.indexOf("<!ENTITY picture SYSTEM ") > 0);
 
1630
        assertTrue(internalSubset.indexOf("picture.jpg\" NDATA JPEG>") > 0);
 
1631
        assertTrue(internalSubset.indexOf("<!NOTATION JPEG SYSTEM ") > 0);
 
1632
        assertTrue(internalSubset.indexOf("image/jpeg\">") > 0);
 
1633
        
 
1634
        assertEquals(-1, internalSubset.indexOf("comment should not be here"));
 
1635
        assertEquals(-1, internalSubset.indexOf("processing instruction should not be here"));
 
1636
        assertEquals(-1, internalSubset.indexOf("anattribute"));
 
1637
        assertEquals(-1, internalSubset.indexOf("anotherattribute"));
 
1638
        assertEquals(-1, internalSubset.indexOf("hatch-pic"));
 
1639
        assertEquals(-1, internalSubset.indexOf("public-pic"));
 
1640
        assertEquals(-1, internalSubset.indexOf("open-hatch"));
 
1641
        assertEquals(-1, internalSubset.indexOf("Pub-Status-pic"));
 
1642
        assertEquals(-1, internalSubset.indexOf("Textuality"));
 
1643
        assertEquals(-1, internalSubset.indexOf("15903"));
 
1644
        
 
1645
    }
 
1646
    
 
1647
 
 
1648
    // This test exposes a bug in Crimson, Xerces 2.5 and earlier, 
 
1649
    // and possibly other parsers. I've reported the bug in Xerces,
 
1650
    // and it is fixed in Xerces 2.6.
 
1651
    public void testBaseRelativeResolutionRemotelyWithDirectory()
 
1652
      throws IOException, ParsingException {
 
1653
        builder.build("http://www.ibiblio.org/xml");
 
1654
    } 
 
1655
 
 
1656
    
 
1657
    // This test exposes a bug in Crimson, Xerces 2.5 and earlier, 
 
1658
    // and possibly other parsers. I've reported the bug in Xerces,
 
1659
    // and it should be fixed in Xerces 2.6.
 
1660
    public void testRelativeURIResolutionAgainstARedirectedBase()
 
1661
      throws IOException, ParsingException {
 
1662
        builder.build("http://www.ibiblio.org/xml/redirecttest.xml");
 
1663
    } 
 
1664
 
 
1665
    
 
1666
    public void testDontGetNodeFactory() {
 
1667
        
 
1668
        Builder builder = new Builder();
 
1669
        NodeFactory factory = builder.getNodeFactory();
 
1670
        if (factory != null) {
 
1671
            assertFalse(
 
1672
              factory.getClass().getName().endsWith("NonVerifyingFactory")
 
1673
            );
 
1674
        }
 
1675
        
 
1676
    }
 
1677
    
 
1678
    
 
1679
    public void testGetNodeFactory() {
 
1680
        NodeFactory factory = new NodeFactory();
 
1681
        Builder builder = new Builder(factory);   
 
1682
        assertEquals(factory, builder.getNodeFactory());
 
1683
    }
 
1684
    
 
1685
    
 
1686
    // Make sure additional namespaces aren't added for 
 
1687
    // attributes. This test is flaky because it assumes 
 
1688
    // the parser reports attributes in the correct order,
 
1689
    // which is not guaranteed. I use a custom SAX Filter to 
 
1690
    // make sure the namespace declaration comes before the attribute.
 
1691
    public void testAttributesVsNamespaces() 
 
1692
      throws ParsingException, IOException, SAXException {
 
1693
          
 
1694
       XMLFilter filter = new OrderingFilter();
 
1695
       filter.setParent(
 
1696
         XMLReaderFactory.createXMLReader(
 
1697
           "org.apache.xerces.parsers.SAXParser"
 
1698
         )
 
1699
       );
 
1700
       Builder builder = new Builder(filter);
 
1701
       String data ="<a/>"; 
 
1702
       Document doc = builder.build(data, null);
 
1703
       Element root = doc.getRootElement();
 
1704
       root.removeAttribute(root.getAttribute(0));
 
1705
       assertNull(root.getNamespaceURI("pre"));
 
1706
       
 
1707
    }
 
1708
 
 
1709
    
 
1710
    private static class OrderingFilter extends XMLFilterImpl {
 
1711
        
 
1712
        public void startElement(String namespaceURI, String localName,
 
1713
          String qualifiedName, Attributes atts) throws SAXException {    
 
1714
    
 
1715
            AttributesImpl newAttributes = new AttributesImpl();
 
1716
            newAttributes.addAttribute(
 
1717
              "",
 
1718
              "pre",
 
1719
              "xmlns:pre",
 
1720
              "CDATA",
 
1721
              "http://www.example.com/");
 
1722
            newAttributes.addAttribute(
 
1723
              "http://www.example.com/",
 
1724
              "name",
 
1725
              "pre:name",
 
1726
              "CDATA",
 
1727
              "value");
 
1728
            super.startElement(namespaceURI, localName, qualifiedName, 
 
1729
              newAttributes);
 
1730
        }        
 
1731
 
 
1732
    }
 
1733
 
 
1734
    
 
1735
    public void testValidateMalformedDocument() 
 
1736
      throws IOException {
 
1737
        
 
1738
        Reader reader = new StringReader("<!DOCTYPE root [" +
 
1739
                "<!ELEMENT root (a, b)>" +
 
1740
                "<!ELEMENT a (EMPTY)>" +
 
1741
                "<!ELEMENT b (PCDATA)>" +
 
1742
                "]><root><a/><b></b>");
 
1743
        try {
 
1744
            validator.build(reader);   
 
1745
            fail("Allowed malformed doc");
 
1746
        }
 
1747
        catch (ValidityException ex) {
 
1748
            fail("Threw validity error instead of well-formedness error");
 
1749
        }
 
1750
        catch (ParsingException ex) {
 
1751
            assertNotNull(ex.getMessage());
 
1752
            assertNull(ex.getURI());
 
1753
        }
 
1754
        
 
1755
    }    
 
1756
 
 
1757
    
 
1758
    /* Test for particular bug in Crimson with mixed content declarations */ 
 
1759
    public void testBuildInternalDTDSubsetWithCrimson() 
 
1760
      throws ParsingException, IOException {
 
1761
 
 
1762
        String dtd = "  <!ELEMENT doc (#PCDATA|a)*>\n";
 
1763
        
 
1764
        String document = "<!DOCTYPE a [\n" + dtd + "]>\n<a/>";
 
1765
        XMLReader crimson;
 
1766
        try {
 
1767
            crimson = XMLReaderFactory.createXMLReader(
 
1768
              "org.apache.crimson.parser.XMLReaderImpl");
 
1769
        } 
 
1770
        catch (SAXException ex) {
 
1771
            // can't test Crimson if you can't load it
 
1772
            return;
 
1773
        }
 
1774
        
 
1775
        Builder builder = new Builder(crimson);
 
1776
        Document doc = builder.build(document, null);
 
1777
        
 
1778
        String parsedDTD = doc.getDocType().getInternalDTDSubset();
 
1779
        assertEquals(dtd, parsedDTD);
 
1780
        
 
1781
    }
 
1782
    
 
1783
    
 
1784
    /* Test for particular bug in Crimson with mixed content declarations */ 
 
1785
    public void testBuildXMLNamespaceDeclarationWithCrimson() 
 
1786
      throws ParsingException, IOException {
 
1787
        
 
1788
        String document = "<doc xmlns:xml='http://www.w3.org/XML/1998/namespace' />";
 
1789
        XMLReader crimson;
 
1790
        try {
 
1791
            crimson = XMLReaderFactory.createXMLReader(
 
1792
              "org.apache.crimson.parser.XMLReaderImpl");
 
1793
        } 
 
1794
        catch (SAXException ex) {
 
1795
            // can't test Crimson if you can't load it
 
1796
            return;
 
1797
        }
 
1798
        
 
1799
        Builder builder = new Builder(crimson);
 
1800
        Document doc = builder.build(document, null);
 
1801
        
 
1802
        assertEquals("<doc />", doc.getRootElement().toXML());
 
1803
        
 
1804
    }
 
1805
    
 
1806
    
 
1807
    public void testBuildIllegalXMLNamespaceDeclarationWithCrimson() 
 
1808
      throws ParsingException, IOException {
 
1809
        
 
1810
        String document = "<doc xmlns:xml='http://www.w3.org/XML/2005/namespace' />";
 
1811
        XMLReader crimson;
 
1812
        try {
 
1813
            crimson = XMLReaderFactory.createXMLReader(
 
1814
              "org.apache.crimson.parser.XMLReaderImpl");
 
1815
        } 
 
1816
        catch (SAXException ex) {
 
1817
            // can't test Crimson if you can't load it
 
1818
            return;
 
1819
        }
 
1820
        
 
1821
        Builder builder = new Builder(crimson);
 
1822
        try {
 
1823
            builder.build(document, null);
 
1824
            fail("Allowed wrong namespace URI for xml prefix");
 
1825
        }
 
1826
        catch (ParsingException success) {
 
1827
            assertNotNull(success.getMessage());
 
1828
        }
 
1829
        
 
1830
    }
 
1831
    
 
1832
    
 
1833
    public void testATTLISTDeclaresXMLSpacePreserveOnlyWithCrimson() 
 
1834
      throws ParsingException, IOException {
 
1835
 
 
1836
        String dtd = "<!DOCTYPE a [<!ATTLIST doc xml:space (preserve) 'preserve'>]\n>";
 
1837
        
 
1838
        String data = dtd + "<doc />";
 
1839
        XMLReader crimson;
 
1840
        try {
 
1841
            crimson = XMLReaderFactory.createXMLReader(
 
1842
              "org.apache.crimson.parser.XMLReaderImpl");
 
1843
        } 
 
1844
        catch (SAXException ex) {
 
1845
            // can't test Crimson if you can't load it
 
1846
            return;
 
1847
        }
 
1848
        
 
1849
        Builder builder = new Builder(crimson);
 
1850
        Document doc = builder.build(data, null);
 
1851
        assertEquals(1, doc.getRootElement().getAttributeCount());
 
1852
        
 
1853
    }
 
1854
    
 
1855
    
 
1856
    public void testNoInternalSubsetWithCrimson() 
 
1857
      throws ParsingException, IOException {
 
1858
 
 
1859
        XMLReader crimson;
 
1860
        try {
 
1861
            crimson = XMLReaderFactory.createXMLReader(
 
1862
              "org.apache.crimson.parser.XMLReaderImpl");
 
1863
        } 
 
1864
        catch (SAXException ex) {
 
1865
            // can't test Crimson if you can't load it
 
1866
            return;
 
1867
        }
 
1868
        
 
1869
        File input = new File(inputDir, "externalDTDtest.xml");
 
1870
        Builder builder = new Builder(crimson);
 
1871
        Document doc = builder.build(input);
 
1872
        String subset = doc.getDocType().getInternalDTDSubset();
 
1873
        assertEquals("", subset);
 
1874
        
 
1875
    }
 
1876
    
 
1877
    
 
1878
    public void testValidateMalformedDocumentWithCrimson() 
 
1879
      throws IOException {
 
1880
        
 
1881
        Reader reader = new StringReader("<!DOCTYPE root [" +
 
1882
                "<!ELEMENT root (a, b)>" +
 
1883
                "<!ELEMENT a (EMPTY)>" +
 
1884
                "<!ELEMENT b (PCDATA)>" +
 
1885
                "]><root><a/><b></b>");
 
1886
        XMLReader crimson;
 
1887
        try {
 
1888
            crimson = XMLReaderFactory.createXMLReader(
 
1889
              "org.apache.crimson.parser.XMLReaderImpl");
 
1890
        } 
 
1891
        catch (SAXException ex) {
 
1892
            // can't test Crimson if you can't load it
 
1893
            return;
 
1894
        }
 
1895
        Builder validator = new Builder(crimson, true);
 
1896
        try {
 
1897
            validator.build(reader);   
 
1898
            fail("Allowed malformed doc");
 
1899
        }
 
1900
        catch (ValidityException ex) {
 
1901
            fail("Crimson threw validity error instead of well-formedness error");
 
1902
        }
 
1903
        catch (ParsingException success) {
 
1904
            assertNotNull(success.getMessage());
 
1905
            assertNull(success.getURI());
 
1906
        }
 
1907
        
 
1908
    }        
 
1909
 
 
1910
    
 
1911
    // This is testing a work-around for a Xerces bug
 
1912
    // http://nagoya.apache.org/bugzilla/show_bug.cgi?id=27583
 
1913
    // that reports this as an IOException rather than a SAXException
 
1914
    public void testBuildMalformedDocumentWithUnpairedSurrogate() 
 
1915
      throws IOException {
 
1916
        
 
1917
        String doc = "<doc>A\uD800A</doc>";
 
1918
        try {
 
1919
            builder.build(doc, "http://www.example.com");   
 
1920
            fail("Allowed malformed doc");
 
1921
        }
 
1922
        catch (ParsingException success) {
 
1923
            assertNotNull(success.getMessage());
 
1924
            assertEquals("http://www.example.com/", success.getURI());
 
1925
        }
 
1926
        
 
1927
    }
 
1928
    
 
1929
    
 
1930
    public void testBuildMalformedDocumentWithBadUnicodeData() 
 
1931
      throws IOException {
 
1932
        
 
1933
        File f = new File(inputDir, "xmlconf");
 
1934
        f = new File(f, "xmltest");
 
1935
        f = new File(f, "not-wf");
 
1936
        f = new File(f, "sa");
 
1937
        f = new File(f, "170.xml");
 
1938
        if (f.exists()) {
 
1939
            try {
 
1940
                builder.build(f);   
 
1941
                fail("Allowed malformed doc");
 
1942
            }
 
1943
            catch (ParsingException success) {
 
1944
                assertNotNull(success.getMessage());
 
1945
                assertTrue(success.getURI().endsWith(
 
1946
                  "data/xmlconf/xmltest/not-wf/sa/170.xml"));
 
1947
                assertTrue(success.getURI().startsWith("file:/"));
 
1948
            }
 
1949
        }
 
1950
        
 
1951
    }
 
1952
    
 
1953
    
 
1954
    public void testBuildAnotherMalformedDocumentWithBadUnicodeData() 
 
1955
      throws IOException {
 
1956
        
 
1957
        String filename = "data/oasis/p02fail30.xml";
 
1958
        File f = new File(inputDir, "oasis");
 
1959
        f = new File(f, "p02fail30.xml");
 
1960
        if (f.exists()) {
 
1961
            try {
 
1962
                builder.build(f);   
 
1963
                fail("Allowed malformed doc");
 
1964
            }
 
1965
            catch (ParsingException success) {
 
1966
                assertNotNull(success.getMessage());
 
1967
                assertTrue(success.getURI().endsWith(filename));
 
1968
                assertTrue(success.getURI().startsWith("file:/"));
 
1969
            }
 
1970
        }
 
1971
        
 
1972
    }
 
1973
    
 
1974
    
 
1975
    public void testBuildMalformedDocumentWithBadParser() 
 
1976
      throws ParsingException, IOException {
 
1977
        
 
1978
        try {
 
1979
            XMLReader parser = new CustomReader();
 
1980
            Builder builder = new Builder(parser);
 
1981
            builder.build("http://www.example.org/");
 
1982
            fail("built from bad data");
 
1983
        }
 
1984
        catch (ParsingException success) {
 
1985
            assertNotNull(success.getMessage());
 
1986
            assertTrue(success.getCause() instanceof WellformednessException);
 
1987
        }      
 
1988
        
 
1989
    }
 
1990
 
 
1991
    
 
1992
    public void testBuildMalformedDocumentWithCrimson() 
 
1993
      throws IOException {
 
1994
        
 
1995
        Reader reader = new StringReader("<!DOCTYPE root [" +
 
1996
                "<!ELEMENT root (a, b)>" +
 
1997
                "<!ELEMENT a (EMPTY)>" +
 
1998
                "<!ELEMENT b (PCDATA)>" +
 
1999
                "]><root><a/><b></b>");
 
2000
        XMLReader crimson;
 
2001
        try {
 
2002
            crimson = XMLReaderFactory.createXMLReader(
 
2003
              "org.apache.crimson.parser.XMLReaderImpl");
 
2004
        } 
 
2005
        catch (SAXException ex) {
 
2006
            // can't test Crimson if you can't load it
 
2007
            return;
 
2008
        }
 
2009
        Builder builder = new Builder(crimson);
 
2010
        try {
 
2011
            builder.build(reader);   
 
2012
            fail("Allowed malformed doc");
 
2013
        }
 
2014
        catch (ValidityException ex) {
 
2015
            fail("Crimson threw validity error instead of well-formedness error");
 
2016
        }
 
2017
        catch (ParsingException ex) {
 
2018
            assertNotNull(ex.getMessage());
 
2019
            assertNull(ex.getURI());
 
2020
        }
 
2021
        
 
2022
    }   
 
2023
    
 
2024
    
 
2025
    public void testNestedExceptionWithSAXParseException() 
 
2026
      throws IOException {
 
2027
        
 
2028
        Reader reader = new StringReader("<root ");
 
2029
        Builder builder = new Builder();
 
2030
        try {
 
2031
            builder.build(reader);   
 
2032
            fail("Allowed malformed doc");
 
2033
        }
 
2034
        catch (ValidityException ex) {
 
2035
            fail("Parser threw validity error instead of well-formedness error");
 
2036
        }
 
2037
        catch (ParsingException ex) {
 
2038
            assertNotNull(ex.getCause());
 
2039
        }
 
2040
        
 
2041
    }   
 
2042
    
 
2043
    
 
2044
    public void testBuildFunkyNamespacesWithUntrustedParser() 
 
2045
      throws ParsingException, IOException, SAXException {
 
2046
        
 
2047
        Reader reader = new StringReader(
 
2048
          "<root xmlns='http://example.org/'>" +
 
2049
          "<pre:a xmlns:pre='http://www.root.org/' " +
 
2050
          "xmlns='http://www.red.com'>" +
 
2051
          "<b/>" +
 
2052
          "</pre:a></root>");
 
2053
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2054
          "org.apache.xerces.parsers.SAXParser");
 
2055
        XMLFilter filter = new XMLFilterImpl();
 
2056
        filter.setParent(parser);
 
2057
        Builder builder = new Builder(filter);
 
2058
        Document doc = builder.build(reader);  
 
2059
        Element root = doc.getRootElement();
 
2060
        Element prea = (Element) root.getChild(0);
 
2061
        Element b = (Element) prea.getChild(0);
 
2062
        assertEquals("http://www.red.com", b.getNamespaceURI());
 
2063
        
 
2064
    }   
 
2065
    
 
2066
    
 
2067
    // from XML Conformance Test Suite; James Clark test
 
2068
    // valid 097
 
2069
    public void testLineBreaksInInternalDTDSubset()
 
2070
      throws ParsingException, IOException {
 
2071
        
 
2072
        Document doc = builder.build(new File(inputDir, "097.xml"));
 
2073
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2074
            + "<!DOCTYPE doc [\n"
 
2075
            + "  <!ELEMENT doc (#PCDATA)>\n"
 
2076
            + "  <!ENTITY % e SYSTEM \"097.ent\">\n"
 
2077
            + "  <!ATTLIST doc a1 CDATA \"v1\">\n"
 
2078
            + "  <!ATTLIST doc a2 CDATA #IMPLIED>\n"
 
2079
            + "]>\n"
 
2080
            + "<doc a1=\"v1\" />\n";
 
2081
        String actual = doc.toXML();
 
2082
        assertEquals(expectedResult, actual);
 
2083
        
 
2084
    }
 
2085
    
 
2086
    
 
2087
    public void testBuildDocumentThatUndeclaresDefaultNamespace()
 
2088
      throws ParsingException, IOException {
 
2089
        
 
2090
        Document doc = builder.build(new File(inputDir, "undeclare.xml"));
 
2091
        String expectedResult = "<?xml version=\"1.0\"?>\n" 
 
2092
          + "<root xmlns=\"http://www.example.org\" " 
 
2093
          + "xmlns:pre=\"http://www.red.com/\" test=\"test\" " 
 
2094
          + "pre:red=\"value\">some data<something xmlns=\"\" />" 
 
2095
          + "</root>\n";
 
2096
        String actual = doc.toXML();
 
2097
        assertEquals(expectedResult, actual);
 
2098
        
 
2099
    }
 
2100
    
 
2101
    
 
2102
    public void testBuildFromFileThatContainsNonASCIICharacterInName()
 
2103
      throws ParsingException, IOException {
 
2104
        
 
2105
        File f = new File(inputDir, "resumĆ©.xml");
 
2106
        try {
 
2107
            Writer out = new OutputStreamWriter(
 
2108
              new FileOutputStream(f), "UTF8");
 
2109
            out.write("<resumĆ© />");
 
2110
            out.flush();
 
2111
            out.close();
 
2112
            Document doc = builder.build(f);
 
2113
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2114
                + "<resumĆ© />\n";
 
2115
            String actual = doc.toXML();
 
2116
            assertEquals(expectedResult, actual);
 
2117
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2118
            assertTrue(doc.getBaseURI().endsWith("data/resum%C3%A9.xml"));
 
2119
        }
 
2120
        finally {
 
2121
            if (f.exists()) f.delete();
 
2122
        }
 
2123
        
 
2124
    }
 
2125
    
 
2126
    
 
2127
    // This test fails on Mac OS X. It passes on Linux. 
 
2128
    public void testBuildFromFileThatContainsPlane1CharacterInName()
 
2129
      throws ParsingException, IOException { 
 
2130
        
 
2131
        int gclef = 0x1D120;
 
2132
        char high = (char) ((gclef - 0x10000)/0x400 + 0xD800);
 
2133
        char low = (char) ((gclef - 0x10000) % 0x400 + 0xDC00); 
 
2134
        File f = new File(inputDir, "music" + high + "" + low + ".xml");
 
2135
        try {
 
2136
            Writer out = new OutputStreamWriter(
 
2137
              new FileOutputStream(f), "UTF8");
 
2138
            out.write("<resumĆ© />");
 
2139
            out.flush();
 
2140
            out.close();
 
2141
            Document doc = builder.build(f);
 
2142
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2143
                + "<resumĆ© />\n";
 
2144
            String actual = doc.toXML();
 
2145
            assertEquals(expectedResult, actual);
 
2146
        }
 
2147
        finally {
 
2148
            if (f.exists()) f.delete();
 
2149
        }
 
2150
        
 
2151
    }
 
2152
    
 
2153
    
 
2154
    private File makeFile(String name) throws IOException {
 
2155
        
 
2156
        File f = new File(inputDir, "" + name);
 
2157
        Writer out = new OutputStreamWriter(
 
2158
          new FileOutputStream(f), "UTF8");
 
2159
        out.write("<data/>");
 
2160
        out.flush();
 
2161
        out.close();
 
2162
        return f;
 
2163
        
 
2164
    }
 
2165
 
 
2166
 
 
2167
    public void testBuildFromFileThatContainsAmpersandInName()
 
2168
      throws ParsingException, IOException {
 
2169
        
 
2170
        Document doc = builder.build(new File(inputDir, "&file.xml"));
 
2171
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2172
            + "<data />\n";
 
2173
        String actual = doc.toXML();
 
2174
        assertEquals(expectedResult, actual);
 
2175
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2176
        assertTrue(doc.getBaseURI().endsWith("data/&file.xml"));
 
2177
        
 
2178
    }
 
2179
  
 
2180
    
 
2181
    public void testBuildFromFileThatContainsSpaceInName()
 
2182
      throws ParsingException, IOException {
 
2183
        
 
2184
        File f = makeFile("space file.xml");
 
2185
        Document doc = builder.build(f);
 
2186
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2187
            + "<data />\n";
 
2188
        String actual = doc.toXML();
 
2189
        f.delete();
 
2190
        assertEquals(expectedResult, actual);
 
2191
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2192
        assertTrue(doc.getBaseURI().endsWith("data/space%" 
 
2193
          + Integer.toHexString(' ') + "file.xml"));
 
2194
        
 
2195
    }
 
2196
  
 
2197
    
 
2198
    public void testBuildFromFileThatContainsSharpInName()
 
2199
      throws ParsingException, IOException {
 
2200
        
 
2201
        File f = new File(inputDir, "#file.xml");
 
2202
        try {
 
2203
            Writer out = new OutputStreamWriter(
 
2204
              new FileOutputStream(f), "UTF8");
 
2205
            out.write("<data />");
 
2206
            out.flush();
 
2207
            out.close();
 
2208
            Document doc = builder.build(f);
 
2209
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2210
                + "<data />\n";
 
2211
            String actual = doc.toXML();
 
2212
            assertEquals(expectedResult, actual);
 
2213
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2214
            assertTrue(doc.getBaseURI().endsWith("data/%23file.xml"));
 
2215
        }
 
2216
        finally {
 
2217
            if (f.exists()) f.delete();
 
2218
        }
 
2219
        
 
2220
    }
 
2221
  
 
2222
    
 
2223
    public void testBuildFromFileThatContainsExclamationPointInName()
 
2224
      throws ParsingException, IOException {
 
2225
        
 
2226
        Document doc = builder.build(new File(inputDir, "!file.xml"));
 
2227
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2228
            + "<data />\n";
 
2229
        String actual = doc.toXML();
 
2230
        assertEquals(expectedResult, actual);
 
2231
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2232
        assertTrue(doc.getBaseURI().endsWith("data/!file.xml"));
 
2233
        
 
2234
    }
 
2235
  
 
2236
    
 
2237
    public void testBuildFromFileThatContainsDoubleQuoteInName()
 
2238
      throws ParsingException, IOException {
 
2239
        
 
2240
        File f = makeFile("\"file\".xml");
 
2241
        try {
 
2242
            Document doc = builder.build(f);
 
2243
            f.delete();
 
2244
            String expectedResult = "<?xml version=\"1.0\"?>\n<data />\n";
 
2245
            String actual = doc.toXML();
 
2246
            assertEquals(expectedResult, actual);
 
2247
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2248
            assertTrue(doc.getBaseURI().endsWith("data/%22file%22.xml"));
 
2249
        }
 
2250
        catch (FileNotFoundException ex) {
 
2251
            // This platform doesn't allow double quotes in file names 
 
2252
        }
 
2253
        
 
2254
    }
 
2255
  
 
2256
    
 
2257
    public void testBuildFromFileThatContainsSingleQuoteInName()
 
2258
      throws ParsingException, IOException {
 
2259
        
 
2260
        File f = makeFile("'file'.xml");
 
2261
        Document doc = builder.build(f);
 
2262
        f.delete();
 
2263
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2264
            + "<data />\n";
 
2265
        String actual = doc.toXML();
 
2266
        assertEquals(expectedResult, actual);
 
2267
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2268
        assertTrue(doc.getBaseURI().endsWith("data/'file'.xml"));
 
2269
        
 
2270
    }
 
2271
  
 
2272
    
 
2273
    public void testBuildFromFileThatContainsParenthesesInName()
 
2274
      throws ParsingException, IOException {
 
2275
        
 
2276
        Document doc = builder.build(new File(inputDir, "()file.xml"));
 
2277
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2278
            + "<data />\n";
 
2279
        String actual = doc.toXML();
 
2280
        assertEquals(expectedResult, actual);
 
2281
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2282
        assertTrue(doc.getBaseURI().endsWith("data/()file.xml"));
 
2283
        
 
2284
    }
 
2285
  
 
2286
    
 
2287
    public void testBuildFromFileThatContainsCurlyBracesInName()
 
2288
      throws ParsingException, IOException {
 
2289
        
 
2290
        Document doc = builder.build(new File(inputDir, "{file}.xml"));
 
2291
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2292
            + "<data />\n";
 
2293
        String actual = doc.toXML();
 
2294
        assertEquals(expectedResult, actual);
 
2295
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2296
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2297
          + Integer.toHexString('{').toUpperCase() + "file%"
 
2298
          + Integer.toHexString('}').toUpperCase() + ".xml"));
 
2299
        
 
2300
    }
 
2301
  
 
2302
    
 
2303
    public void testBuildFromFileThatContainsSquareBracketsInName()
 
2304
      throws ParsingException, IOException {
 
2305
        
 
2306
        Document doc = builder.build(new File(inputDir, "[file].xml"));
 
2307
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2308
            + "<data />\n";
 
2309
        String actual = doc.toXML();
 
2310
        assertEquals(expectedResult, actual);
 
2311
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2312
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2313
          + Integer.toHexString('[').toUpperCase() + "file%"
 
2314
          + Integer.toHexString(']').toUpperCase() + ".xml"));
 
2315
        
 
2316
    }
 
2317
  
 
2318
    
 
2319
    public void testBuildFromFileThatContainsVerticalBarInName()
 
2320
      throws ParsingException, IOException {
 
2321
        
 
2322
        File f = makeFile("|file.xml");
 
2323
        try {
 
2324
            Document doc = builder.build(f);
 
2325
            f.delete();
 
2326
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2327
                + "<data />\n";
 
2328
            String actual = doc.toXML();
 
2329
            assertEquals(expectedResult, actual);
 
2330
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2331
            assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2332
              + Integer.toHexString('|').toUpperCase()
 
2333
              + "file.xml"));
 
2334
        }
 
2335
        catch (FileNotFoundException ex) {
 
2336
            // This platform doesn't allow vertical bars in file names 
 
2337
        }
 
2338
        
 
2339
    }
 
2340
 
 
2341
    
 
2342
    public void testBuildFromFileThatContainsColonInName()
 
2343
      throws ParsingException, IOException {
 
2344
        
 
2345
        File f = makeFile(":file.xml");
 
2346
        try {
 
2347
            Document doc = builder.build(f);
 
2348
            f.delete();
 
2349
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2350
                + "<data />\n";
 
2351
            String actual = doc.toXML();
 
2352
            assertEquals(expectedResult, actual);
 
2353
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2354
            assertTrue(doc.getBaseURI().endsWith("data/:file.xml"));
 
2355
        }
 
2356
        catch (FileNotFoundException ex) {
 
2357
            // This platform doesn't allow colons in file names 
 
2358
        }
 
2359
        
 
2360
    }
 
2361
 
 
2362
    
 
2363
    public void testBuildFromFileThatContainsUnderscoreInName()
 
2364
      throws ParsingException, IOException {
 
2365
        
 
2366
        File f = makeFile("_file.xml");
 
2367
        Document doc = builder.build(f);
 
2368
        f.delete();
 
2369
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2370
            + "<data />\n";
 
2371
        String actual = doc.toXML();
 
2372
        assertEquals(expectedResult, actual);
 
2373
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2374
        assertTrue(doc.getBaseURI().endsWith("data/_file.xml"));
 
2375
        
 
2376
    }
 
2377
 
 
2378
    
 
2379
    public void testBuildFromFileThatContainsUppercaseASCIIInName()
 
2380
      throws ParsingException, IOException {
 
2381
        
 
2382
        File f = makeFile("ABCDEFGHIJKLMONPQRSTUVWXYZ.xml");
 
2383
        Document doc = builder.build(f);
 
2384
        f.delete();
 
2385
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2386
            + "<data />\n";
 
2387
        String actual = doc.toXML();
 
2388
        assertEquals(expectedResult, actual);
 
2389
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2390
        assertTrue(doc.getBaseURI().endsWith("data/ABCDEFGHIJKLMONPQRSTUVWXYZ.xml"));
 
2391
        
 
2392
    }
 
2393
 
 
2394
    
 
2395
    public void testBuildFromFileThatContainsAsteriskInName()
 
2396
      throws ParsingException, IOException {
 
2397
        
 
2398
        File f = makeFile("*file.xml");
 
2399
        try {
 
2400
            Document doc = builder.build(f);
 
2401
            f.delete();
 
2402
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2403
                + "<data />\n";
 
2404
            String actual = doc.toXML();
 
2405
            assertEquals(expectedResult, actual);
 
2406
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2407
            assertTrue(doc.getBaseURI().endsWith("data/*file.xml"));
 
2408
        }
 
2409
        catch (FileNotFoundException ex) {
 
2410
            // This platform doesn't allow asterisks in file names 
 
2411
        }
 
2412
        
 
2413
    }
 
2414
  
 
2415
    
 
2416
    public void testBuildFromFileThatContainsSemicolonInName()
 
2417
      throws ParsingException, IOException {
 
2418
        
 
2419
        Document doc = builder.build(new File(inputDir, ";file.xml"));
 
2420
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2421
            + "<data />\n";
 
2422
        String actual = doc.toXML();
 
2423
        assertEquals(expectedResult, actual);
 
2424
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2425
        assertTrue(doc.getBaseURI().endsWith("data/;file.xml"));
 
2426
        
 
2427
    }
 
2428
  
 
2429
    
 
2430
    public void testBuildFromFileThatContainsPlusSignInName()
 
2431
      throws ParsingException, IOException {
 
2432
        
 
2433
        Document doc = builder.build(new File(inputDir, "+file.xml"));
 
2434
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2435
            + "<data />\n";
 
2436
        String actual = doc.toXML();
 
2437
        assertEquals(expectedResult, actual);
 
2438
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2439
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2440
          + Integer.toHexString('+').toUpperCase() + "file.xml"));
 
2441
        
 
2442
    }
 
2443
  
 
2444
    
 
2445
    public void testBuildFromFileThatContainsCommaInName()
 
2446
      throws ParsingException, IOException {
 
2447
        
 
2448
        File f = new File(inputDir, ",file.xml");
 
2449
        try {
 
2450
            Writer out = new OutputStreamWriter(
 
2451
              new FileOutputStream(f), "UTF8");
 
2452
            out.write("<data />");
 
2453
            out.flush();
 
2454
            out.close();
 
2455
            Document doc = builder.build(f);
 
2456
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2457
                + "<data />\n";
 
2458
            String actual = doc.toXML();
 
2459
            assertEquals(expectedResult, actual);
 
2460
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2461
            assertTrue(doc.getBaseURI().endsWith("data/,file.xml"));
 
2462
        }
 
2463
        finally {
 
2464
            if (f.exists()) f.delete();
 
2465
        }
 
2466
        
 
2467
    }
 
2468
  
 
2469
    
 
2470
    public void testBuildFromFileThatContainsBackslashInName()
 
2471
      throws ParsingException, IOException {
 
2472
        
 
2473
        String os = System.getProperty("os.name", "Unix");
 
2474
        if (os.indexOf("Windows") >= 0) return;
 
2475
  
 
2476
        File f = new File(inputDir, "\\file.xml");
 
2477
        try {
 
2478
            Writer out = new OutputStreamWriter(
 
2479
              new FileOutputStream(f), "UTF8");
 
2480
            out.write("<data />");
 
2481
            out.flush();
 
2482
            out.close();
 
2483
            Document doc = builder.build(f);
 
2484
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2485
                + "<data />\n";
 
2486
            String actual = doc.toXML();
 
2487
            assertEquals(expectedResult, actual);
 
2488
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2489
            assertTrue(doc.getBaseURI().endsWith("data/%5Cfile.xml"));
 
2490
        }
 
2491
        finally {
 
2492
            if (f.exists()) f.delete();
 
2493
        }
 
2494
        
 
2495
    }
 
2496
  
 
2497
    
 
2498
    public void testBuildFromFileThatContainsC0ControlCharacterInName()
 
2499
      throws ParsingException, IOException {
 
2500
        
 
2501
        File f = new File(inputDir, "\u0019file.xml");
 
2502
        try {
 
2503
            Writer out = new OutputStreamWriter(
 
2504
              new FileOutputStream(f), "UTF8");
 
2505
            out.write("<data />");
 
2506
            out.flush();
 
2507
            out.close();
 
2508
            Document doc = builder.build(f);
 
2509
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2510
                + "<data />\n";
 
2511
            String actual = doc.toXML();
 
2512
            assertEquals(expectedResult, actual);
 
2513
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2514
            assertTrue(doc.getBaseURI().endsWith("data/%19file.xml"));
 
2515
        }
 
2516
        catch (FileNotFoundException ex) {
 
2517
            // This platform doesn't allow C0 controls in file names 
 
2518
        }
 
2519
        finally {
 
2520
            if (f.exists()) f.delete();
 
2521
        }
 
2522
        
 
2523
    }
 
2524
  
 
2525
    
 
2526
    public void testBuildFromFileThatContainsTabCharacterInName()
 
2527
      throws ParsingException, IOException {
 
2528
        
 
2529
        File f = new File(inputDir, "\tfile.xml");
 
2530
        try {
 
2531
            Writer out = new OutputStreamWriter(
 
2532
              new FileOutputStream(f), "UTF8");
 
2533
            out.write("<data />");
 
2534
            out.flush();
 
2535
            out.close();
 
2536
            Document doc = builder.build(f);
 
2537
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2538
                + "<data />\n";
 
2539
            String actual = doc.toXML();
 
2540
            assertEquals(expectedResult, actual);
 
2541
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2542
            assertTrue(doc.getBaseURI().endsWith("data/%09file.xml"));
 
2543
        }
 
2544
        catch (FileNotFoundException ex) {
 
2545
            // This platform doesn't allow tabs in file names 
 
2546
        }
 
2547
        finally {
 
2548
            if (f.exists()) f.delete();
 
2549
        }
 
2550
        
 
2551
    }
 
2552
  
 
2553
    
 
2554
    public void testBuildFromFileThatContainsTildeInName()
 
2555
      throws ParsingException, IOException {
 
2556
        
 
2557
        File f = new File(inputDir, "~file.xml");
 
2558
        try {
 
2559
            Writer out = new OutputStreamWriter(
 
2560
              new FileOutputStream(f), "UTF8");
 
2561
            out.write("<data />");
 
2562
            out.flush();
 
2563
            out.close();
 
2564
            Document doc = builder.build(f);
 
2565
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2566
                + "<data />\n";
 
2567
            String actual = doc.toXML();
 
2568
            assertEquals(expectedResult, actual);
 
2569
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2570
            assertTrue(doc.getBaseURI().endsWith("data/~file.xml"));
 
2571
        }
 
2572
        finally {
 
2573
            if (f.exists()) f.delete();
 
2574
        }
 
2575
        
 
2576
    }
 
2577
  
 
2578
    
 
2579
    public void testBuildFromFileThatContainsAngleBracketsInName()
 
2580
      throws ParsingException, IOException {
 
2581
        
 
2582
        File f = makeFile("<file>.xml");
 
2583
        try {
 
2584
            Document doc = builder.build(f);
 
2585
            f.delete();
 
2586
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2587
                + "<data />\n";
 
2588
            String actual = doc.toXML();
 
2589
            assertEquals(expectedResult, actual);
 
2590
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2591
            assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2592
              + Integer.toHexString('<').toUpperCase() + "file%"
 
2593
              + Integer.toHexString('>').toUpperCase() + ".xml"));
 
2594
        }
 
2595
        catch (FileNotFoundException ex) {
 
2596
            // This platform doesn't allow < and > in file names 
 
2597
        }
 
2598
        
 
2599
    }
 
2600
  
 
2601
    
 
2602
    public void testBuildFromFileThatContainsDollarSignInName()
 
2603
      throws ParsingException, IOException {
 
2604
        
 
2605
        Document doc = builder.build(new File(inputDir, "$file.xml"));
 
2606
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2607
            + "<data />\n";
 
2608
        String actual = doc.toXML();
 
2609
        assertEquals(expectedResult, actual);
 
2610
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2611
        assertTrue(doc.getBaseURI().endsWith("data/$file.xml"));
 
2612
        
 
2613
    }
 
2614
  
 
2615
    
 
2616
    public void testBuildFromFileThatContainsPercentSignInName()
 
2617
      throws ParsingException, IOException {
 
2618
        
 
2619
        Document doc = builder.build(new File(inputDir, "%file.xml"));
 
2620
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2621
            + "<data />\n";
 
2622
        String actual = doc.toXML();
 
2623
        assertEquals(expectedResult, actual);
 
2624
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2625
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2626
          + Integer.toHexString('%') + "file.xml"));
 
2627
        
 
2628
    }
 
2629
  
 
2630
    
 
2631
    public void testBuildFromFileThatContainsQuestionMarkInName()
 
2632
      throws ParsingException, IOException {
 
2633
        
 
2634
        File f = makeFile("?file.xml");
 
2635
        try {
 
2636
            Document doc = builder.build(f);
 
2637
            f.delete();
 
2638
            String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2639
                + "<data />\n";
 
2640
            String actual = doc.toXML();
 
2641
            assertEquals(expectedResult, actual);
 
2642
            assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2643
            assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2644
              + Integer.toHexString('?').toUpperCase() + "file.xml"));
 
2645
        }
 
2646
        catch (FileNotFoundException ex) {
 
2647
            // This platform doesn't allow question marks in file names 
 
2648
        }
 
2649
        
 
2650
    }
 
2651
  
 
2652
    
 
2653
    public void testBuildFromFileThatContainsAtSignInName()
 
2654
      throws ParsingException, IOException {
 
2655
        
 
2656
        Document doc = builder.build(new File(inputDir, "@file.xml"));
 
2657
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2658
            + "<data />\n";
 
2659
        String actual = doc.toXML();
 
2660
        assertEquals(expectedResult, actual);
 
2661
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2662
        assertTrue(doc.getBaseURI().endsWith("data/%"
 
2663
          + Integer.toHexString('@') + "file.xml"));
 
2664
        
 
2665
    }
 
2666
  
 
2667
    
 
2668
    public void testBuildFromFileThatContainsEqualsSignInName()
 
2669
      throws ParsingException, IOException {
 
2670
        
 
2671
        Document doc = builder.build(new File(inputDir, "=file.xml"));
 
2672
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2673
            + "<data />\n";
 
2674
        String actual = doc.toXML();
 
2675
        assertEquals(expectedResult, actual);
 
2676
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2677
        assertTrue(doc.getBaseURI().endsWith("data/=file.xml"));
 
2678
        
 
2679
    }
 
2680
  
 
2681
    
 
2682
    public void testBuildFromFileThatContainsCaretInName()
 
2683
      throws ParsingException, IOException {
 
2684
        
 
2685
        Document doc = builder.build(new File(inputDir, "^file.xml"));
 
2686
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2687
            + "<data />\n";
 
2688
        String actual = doc.toXML();
 
2689
        assertEquals(expectedResult, actual);
 
2690
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2691
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2692
          + Integer.toHexString('^').toUpperCase() + "file.xml"));
 
2693
        
 
2694
    }
 
2695
  
 
2696
    
 
2697
    public void testBuildFromFileThatContainsBactickInName()
 
2698
      throws ParsingException, IOException {
 
2699
        
 
2700
        Document doc = builder.build(new File(inputDir, "`file.xml"));
 
2701
        String expectedResult = "<?xml version=\"1.0\"?>\n"
 
2702
            + "<data />\n";
 
2703
        String actual = doc.toXML();
 
2704
        assertEquals(expectedResult, actual);
 
2705
        assertTrue(doc.getBaseURI().startsWith("file:/"));
 
2706
        assertTrue(doc.getBaseURI().endsWith("data/%" 
 
2707
          + Integer.toHexString('`') + "file.xml"));
 
2708
        
 
2709
    }
 
2710
    
 
2711
    
 
2712
    private static class NonValidatingFilter extends XMLFilterImpl {
 
2713
        
 
2714
        public void setFeature(String uri, boolean value) 
 
2715
          throws SAXNotRecognizedException, SAXNotSupportedException {
 
2716
           
 
2717
            if ("http://xml.org/sax/features/validation".equals(uri) && value) {
 
2718
                throw new SAXNotSupportedException("");
 
2719
            }
 
2720
            super.setFeature(uri, value);
 
2721
            
 
2722
        }
 
2723
        
 
2724
        public boolean getFeature(String uri) 
 
2725
          throws SAXNotRecognizedException, SAXNotSupportedException {
 
2726
            
 
2727
            if ("http://xml.org/sax/features/validation".equals(uri)) {
 
2728
                return false;
 
2729
            }
 
2730
            return super.getFeature(uri);
 
2731
            
 
2732
        }
 
2733
        
 
2734
        
 
2735
    }
 
2736
    
 
2737
    
 
2738
    public void testNonValidatingParserException() throws SAXException {
 
2739
        
 
2740
        XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
 
2741
        XMLFilter filter = new NonValidatingFilter();
 
2742
        filter.setParent(parser);
 
2743
        
 
2744
        try {
 
2745
            new Builder(filter, true, null);
 
2746
            fail("Validating with a non-validating parser");
 
2747
        }
 
2748
        catch (XMLException success) {
 
2749
            assertNotNull(success.getMessage());
 
2750
        }
 
2751
        
 
2752
    }
 
2753
  
 
2754
    private static class NonEntityResolvingFilter extends XMLFilterImpl {
 
2755
        
 
2756
        public void setFeature(String uri, boolean value) 
 
2757
          throws SAXNotRecognizedException, SAXNotSupportedException {
 
2758
           
 
2759
            if (value && (
 
2760
              "http://xml.org/sax/features/validation".equals(uri) 
 
2761
              || "http://xml.org/sax/features/external-general-entities".equals(uri))
 
2762
              || "http://xml.org/sax/features/external-parameter-entities".equals(uri)) {
 
2763
                throw new SAXNotSupportedException("");
 
2764
            }
 
2765
            super.setFeature(uri, value);
 
2766
            
 
2767
        }
 
2768
        
 
2769
        public boolean getFeature(String uri) 
 
2770
          throws SAXNotRecognizedException, SAXNotSupportedException {
 
2771
            
 
2772
            if ("http://xml.org/sax/features/validation".equals(uri)
 
2773
              || "http://xml.org/sax/features/external-general-entities".equals(uri)
 
2774
              || "http://xml.org/sax/features/external-parameter-entities".equals(uri)) {
 
2775
                return false;
 
2776
            }
 
2777
            return super.getFeature(uri);
 
2778
            
 
2779
        }
 
2780
        
 
2781
        
 
2782
    }
 
2783
    
 
2784
    
 
2785
    public void testNonEntityResolvingParserException() throws SAXException {
 
2786
        
 
2787
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2788
          "org.apache.xerces.parsers.SAXParser");
 
2789
        XMLFilter filter = new NonEntityResolvingFilter();
 
2790
        filter.setParent(parser);
 
2791
        
 
2792
        try {
 
2793
            new Builder(filter, false, null);
 
2794
            fail("Accepted a non-entity resolving parser");
 
2795
        }
 
2796
        catch (XMLException success) {
 
2797
            assertNotNull(success.getMessage());
 
2798
        }
 
2799
        
 
2800
    }
 
2801
  
 
2802
    
 
2803
    // Fake certain errors to test workarounds for bugs in certain
 
2804
    // parsers, especially Piccolo. 
 
2805
    private static class ExceptionTester extends XMLFilterImpl {
 
2806
        
 
2807
        private Exception ex;
 
2808
        
 
2809
        ExceptionTester(Exception ex) {
 
2810
            this.ex = ex;
 
2811
        }
 
2812
        
 
2813
        public void parse(InputSource in) throws IOException, SAXException {
 
2814
            if (ex instanceof IOException) throw (IOException) ex;
 
2815
            else if (ex instanceof SAXException) throw (SAXException) ex;
 
2816
            else throw (RuntimeException) ex;
 
2817
        }
 
2818
        
 
2819
    }
 
2820
    
 
2821
    
 
2822
    public void testParserThrowsNullPointerException() 
 
2823
      throws SAXException, IOException {
 
2824
        
 
2825
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2826
          "org.apache.xerces.parsers.SAXParser");
 
2827
        Exception cause = new NullPointerException();
 
2828
        XMLFilter filter = new ExceptionTester(cause);
 
2829
        filter.setParent(parser);
 
2830
        Builder builder = new Builder(filter);
 
2831
        
 
2832
        try {
 
2833
            builder.build("<data/>");
 
2834
        }
 
2835
        catch (ParsingException success) {
 
2836
            assertEquals(cause, success.getCause());
 
2837
        }
 
2838
        
 
2839
    }
 
2840
    
 
2841
    
 
2842
    public void testParserThrowsNegativeArraySizeException() 
 
2843
      throws SAXException, IOException {
 
2844
        
 
2845
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2846
          "org.apache.xerces.parsers.SAXParser");
 
2847
        Exception cause = new NegativeArraySizeException();
 
2848
        XMLFilter filter = new ExceptionTester(cause);
 
2849
        filter.setParent(parser);
 
2850
        Builder builder = new Builder(filter);
 
2851
        
 
2852
        try {
 
2853
            builder.build("<data/>");
 
2854
        }
 
2855
        catch (ParsingException success) {
 
2856
            assertEquals(cause, success.getCause());
 
2857
        }
 
2858
        
 
2859
    }
 
2860
    
 
2861
    
 
2862
    public void testParserThrowsArrayIndexOutOfBoundsException() 
 
2863
      throws SAXException, IOException {
 
2864
        
 
2865
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2866
          "org.apache.xerces.parsers.SAXParser");
 
2867
        Exception cause = new ArrayIndexOutOfBoundsException();
 
2868
        XMLFilter filter = new ExceptionTester(cause);
 
2869
        filter.setParent(parser);
 
2870
        Builder builder = new Builder(filter);
 
2871
        
 
2872
        try {
 
2873
            builder.build("<data/>");
 
2874
        }
 
2875
        catch (ParsingException success) {
 
2876
            assertEquals(cause, success.getCause());
 
2877
        }
 
2878
        
 
2879
    }
 
2880
    
 
2881
    
 
2882
    public void testParserThrowsUTFDataFormatException() 
 
2883
      throws SAXException, IOException {
 
2884
        
 
2885
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2886
          "org.apache.xerces.parsers.SAXParser");
 
2887
        Exception cause = new UTFDataFormatException();
 
2888
        XMLFilter filter = new ExceptionTester(cause);
 
2889
        filter.setParent(parser);
 
2890
        Builder builder = new Builder(filter);
 
2891
        
 
2892
        try {
 
2893
            builder.build("<data/>");
 
2894
        }
 
2895
        catch (ParsingException success) {
 
2896
            assertEquals(cause, success.getCause());
 
2897
        }
 
2898
        
 
2899
    }
 
2900
    
 
2901
 
 
2902
    public void testParserThrowsCharConversionException() 
 
2903
      throws SAXException, IOException {
 
2904
        
 
2905
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2906
          "org.apache.xerces.parsers.SAXParser");
 
2907
        Exception cause = new CharConversionException();
 
2908
        XMLFilter filter = new ExceptionTester(cause);
 
2909
        filter.setParent(parser);
 
2910
        Builder builder = new Builder(filter);
 
2911
        
 
2912
        try {
 
2913
            builder.build("<data/>");
 
2914
        }
 
2915
        catch (ParsingException success) {
 
2916
            assertEquals(cause, success.getCause());
 
2917
        }
 
2918
        
 
2919
    }
 
2920
    
 
2921
 
 
2922
    public void testParserThrowsPlainSAXException() 
 
2923
      throws SAXException, IOException {
 
2924
        
 
2925
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2926
          "org.apache.xerces.parsers.SAXParser");
 
2927
        Exception cause = new SAXException("What happened to no-args constructor?");
 
2928
        XMLFilter filter = new ExceptionTester(cause);
 
2929
        filter.setParent(parser);
 
2930
        Builder builder = new Builder(filter);
 
2931
        
 
2932
        try {
 
2933
            builder.build("<data/>");
 
2934
        }
 
2935
        catch (ParsingException success) {
 
2936
            assertEquals(cause, success.getCause());
 
2937
        }
 
2938
        
 
2939
    }
 
2940
    
 
2941
 
 
2942
    public void testParserThrowsUnexpectedRuntimeException() 
 
2943
      throws SAXException, IOException {
 
2944
        
 
2945
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2946
          "org.apache.xerces.parsers.SAXParser");
 
2947
        Exception cause = new RuntimeException();
 
2948
        XMLFilter filter = new ExceptionTester(cause);
 
2949
        filter.setParent(parser);
 
2950
        Builder builder = new Builder(filter);
 
2951
        
 
2952
        try {
 
2953
            builder.build("<data/>");
 
2954
        }
 
2955
        catch (ParsingException success) {
 
2956
            assertEquals(cause, success.getCause());
 
2957
        }
 
2958
        
 
2959
    }
 
2960
    
 
2961
 
 
2962
    public void testParserThrowsIOException() 
 
2963
      throws SAXException, ParsingException {
 
2964
        
 
2965
        XMLReader parser = XMLReaderFactory.createXMLReader(
 
2966
          "org.apache.xerces.parsers.SAXParser");
 
2967
        Exception cause = new IOException();
 
2968
        XMLFilter filter = new ExceptionTester(cause);
 
2969
        filter.setParent(parser);
 
2970
        Builder builder = new Builder(filter);
 
2971
        
 
2972
        try {
 
2973
            builder.build("<data/>");
 
2974
        }
 
2975
        catch (IOException success) {
 
2976
            assertEquals(cause, success);
 
2977
        }
 
2978
        
 
2979
    }
 
2980
    
 
2981
    
 
2982
    public void testCrimsonIgnoresWarning() 
 
2983
      throws SAXException, ParsingException, IOException {
 
2984
        
 
2985
        
 
2986
        XMLReader parser;
 
2987
        try {
 
2988
          parser = XMLReaderFactory.createXMLReader(
 
2989
            "org.apache.crimson.parser.XMLReaderImpl"
 
2990
          );
 
2991
        }
 
2992
        catch (SAXException ex) {
 
2993
            // Can't test Crimson if you can't load it
 
2994
            return;
 
2995
        }
 
2996
        XMLFilter filter = new WarningFilter();
 
2997
        filter.setParent(parser);
 
2998
        Builder builder = new Builder(filter);
 
2999
        
 
3000
        Document doc = builder.build("<data/>", null);
 
3001
        assertEquals("<?xml version=\"1.0\"?>\n<data />\n", doc.toXML());
 
3002
        
 
3003
    }
 
3004
    
 
3005
    
 
3006
    private static class WarningFilter extends XMLFilterImpl {
 
3007
        
 
3008
        public void startElement(String namespaceURI, String localName,
 
3009
          String qualifiedName, Attributes atts) throws SAXException {    
 
3010
    
 
3011
            this.getErrorHandler().warning(
 
3012
              new SAXParseException("Warning", new LocatorImpl())
 
3013
            );
 
3014
            super.startElement(namespaceURI, localName, qualifiedName, 
 
3015
              atts);
 
3016
            
 
3017
        }        
 
3018
 
 
3019
    }
 
3020
    
 
3021
 
 
3022
    public void testSaxonsAElfredIsVerified() 
 
3023
      throws SAXException, IOException {
 
3024
        
 
3025
        XMLReader parser;
 
3026
        try {
 
3027
          parser = XMLReaderFactory.createXMLReader(
 
3028
            "com.icl.saxon.aelfred.SAXDriver"
 
3029
          );
 
3030
        }
 
3031
        catch (SAXException ex) {
 
3032
            // Can't test SAXON if you can't load it
 
3033
            return;
 
3034
        }
 
3035
        Builder builder = new Builder(parser);
 
3036
        
 
3037
        try {
 
3038
            // known bug in Saxon; doesn't catch 
 
3039
            // colon in processing instruction targets
 
3040
            builder.build("<?test:data ?><data/>", null);
 
3041
            fail("Didn't verify Saxon's input");
 
3042
        }
 
3043
        catch (ParsingException success) {
 
3044
            assertNotNull(success.getMessage());
 
3045
        }
 
3046
        
 
3047
    }
 
3048
    
 
3049
    
 
3050
    public void testSaxon7sAElfredIsVerified() 
 
3051
      throws SAXException, IOException {
 
3052
        
 
3053
        XMLReader parser;
 
3054
        try {
 
3055
          parser = XMLReaderFactory.createXMLReader(
 
3056
            "net.sf.saxon.aelfred.SAXDriver"
 
3057
          );
 
3058
        }
 
3059
        catch (SAXException ex) {
 
3060
            // Can't test SAXON if you can't load it
 
3061
            return;
 
3062
        }
 
3063
        Builder builder = new Builder(parser);
 
3064
        
 
3065
        try {
 
3066
            // known bug in Saxon: doesn't catch 
 
3067
            // colon in processing instruction targets
 
3068
            builder.build("<?test:data ?><data/>", null);
 
3069
            fail("Didn't verify Saxon's input");
 
3070
        }
 
3071
        catch (ParsingException success) {
 
3072
            assertNotNull(success.getMessage());
 
3073
        }
 
3074
        
 
3075
    }
 
3076
    
 
3077
    
 
3078
   public void testGNUJAXPIsVerified() 
 
3079
      throws SAXException, IOException {
 
3080
        
 
3081
        XMLReader parser;
 
3082
        try {
 
3083
          parser = XMLReaderFactory.createXMLReader(
 
3084
            "gnu.xml.aelfred2.XmlReader"
 
3085
          );
 
3086
        }
 
3087
        catch (SAXException ex) {
 
3088
            // Can't test GNU JAXP if you can't load it
 
3089
            return;
 
3090
        }
 
3091
        Builder builder = new Builder(parser);
 
3092
        
 
3093
        try {
 
3094
            // known bug in GNUJAXP: doesn't catch 
 
3095
            // colon in processing instruction targets
 
3096
            builder.build("<?test:data ?><data/>", null);
 
3097
            fail("Didn't verify GNU JAXP's input");
 
3098
        }
 
3099
        catch (ParsingException success) {
 
3100
            assertNotNull(success.getMessage());
 
3101
        }
 
3102
        
 
3103
    }
 
3104
   
 
3105
   
 
3106
   public void testCatalogOnTopOfTrustedParserIsTrusted() throws  
 
3107
     NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
 
3108
       
 
3109
        try {
 
3110
            XMLReader parser = XMLReaderFactory.createXMLReader(
 
3111
              "org.apache.crimson.parser.XMLReaderImpl"
 
3112
            );
 
3113
        
 
3114
            Class filter = Class.forName("org.apache.xml.resolver.tools.ResolvingXMLFilter");
 
3115
            Class[] types = {XMLReader.class};
 
3116
            Constructor constructor = filter.getConstructor(types);
 
3117
            Object[] args = {parser};
 
3118
            XMLReader reader = (XMLReader) constructor.newInstance(args);
 
3119
            Builder builder = new Builder(reader);
 
3120
            // If the factory is a nonverifying factory, then 
 
3121
            // getNodeFactory() won't return it.
 
3122
            assertNull(builder.getNodeFactory());
 
3123
        }
 
3124
        catch (ClassNotFoundException ex) {
 
3125
            // Can't test if we can't find the class
 
3126
        }
 
3127
        catch (SAXException ex) {
 
3128
            // Need a trusted parser to test this
 
3129
        }
 
3130
 
 
3131
    }
 
3132
   
 
3133
    
 
3134
    // XML conformance test case xmlconf/xmltest/valid/not-sa/014.ent
 
3135
    // shows how this can be necessary. In brief, the internal DTD 
 
3136
    // subset can define or override parameter entities used in the
 
3137
    // external DTD subset, and that the external DTD subset depends
 
3138
    // on for well-formedness
 
3139
    public void testPreserveParameterEntitiesInInternalDTDSubset() 
 
3140
      throws ParsingException, IOException {
 
3141
       
 
3142
        String data = "<!DOCTYPE doc [\n" 
 
3143
          + "<!ENTITY % e 'INCLUDE'>]><doc />";
 
3144
        Document doc = builder.build(data, null);
 
3145
        String subset = doc.getDocType().getInternalDTDSubset();
 
3146
        assertEquals("  <!ENTITY % e \"INCLUDE\">\n", subset);
 
3147
        
 
3148
    }
 
3149
    
 
3150
   
 
3151
    public void testTrickyCaseFromAppendixA2OfXMLSpec() 
 
3152
      throws ParsingException, IOException {
 
3153
        
 
3154
        String data = "<?xml version='1.0'?>\n"
 
3155
          + "<!DOCTYPE test [\n"
 
3156
          + "<!ELEMENT test (#PCDATA) >\n"
 
3157
          + "<!ENTITY % xx '&#37;zz;'>\n"
 
3158
          + "<!ENTITY % zz '&#60;!ENTITY tricky \"error-prone\" >' >\n"
 
3159
          + "%xx;\n"
 
3160
          + "]>\n"
 
3161
          + "<test>This sample shows a &tricky; method.</test>\n";
 
3162
        
 
3163
        Document doc = builder.build(data, null);
 
3164
        String s = doc.toXML();
 
3165
        Document roundTrip = builder.build(s, null);
 
3166
        assertEquals(doc, roundTrip);
 
3167
        
 
3168
    }
 
3169
    
 
3170
    
 
3171
    // This is an example of case where preserving external entity
 
3172
    // declaration in internal DTD subset is necessary to maintain
 
3173
    // well-formedness
 
3174
    public void testPreserveExternalGeneralEntityDeclaration() 
 
3175
      throws ParsingException, IOException {
 
3176
     
 
3177
        Document doc = builder.build(new File(inputDir, "ge.xml"));
 
3178
        DocType doctype = doc.getDocType();
 
3179
        assertEquals("  <!ENTITY ccl SYSTEM \"ge.txt\">\n", doctype.getInternalDTDSubset());  
 
3180
    }
 
3181
    
 
3182
    
 
3183
    // This is an example of case where preserving external entity
 
3184
    // declaration in internal DTD subset is necessary to maintain
 
3185
    // validity
 
3186
    public void testPreserveExternalParameterEntityDeclaration() 
 
3187
      throws ParsingException, IOException {
 
3188
     
 
3189
        Document doc = builder.build(new File(inputDir, "pe.xml"));
 
3190
        DocType doctype = doc.getDocType();
 
3191
        assertEquals("  <!ENTITY % ccl SYSTEM \"pe.txt\">\n", doctype.getInternalDTDSubset());  
 
3192
    }
 
3193
    
 
3194
        
 
3195
    public void testNMTOKENSNormalizationOfCarriageReturnLineFeedEntityReferences() 
 
3196
      throws ParsingException, IOException {
 
3197
        
 
3198
        String data = "<!DOCTYPE attributes  [\n"
 
3199
          + "<!ATTLIST attributes nmtokens NMTOKENS #IMPLIED>]>\n"
 
3200
          + "<attributes nmtokens =  \" this&#x0d;&#x0a; also  gets&#x20; normalized \" />";
 
3201
        
 
3202
        Document doc = builder.build(data, null);
 
3203
        String s = doc.toXML();
 
3204
        Document roundTrip = builder.build(s, null);
 
3205
        assertEquals(doc, roundTrip);
 
3206
        
 
3207
    }
 
3208
    
 
3209
    
 
3210
    public void testXMLConformanceTestSuiteDocuments() 
 
3211
      throws ParsingException, IOException {
 
3212
      
 
3213
        File data = new File("data");
 
3214
        File canonical = new File(data, "canonical");
 
3215
        File masterList = new File(canonical, "xmlconf");
 
3216
        masterList = new File(masterList, "xmlconf.xml");
 
3217
        if (masterList.exists()) {
 
3218
            Document xmlconf = builder.build(masterList);
 
3219
            Elements testcases = xmlconf.getRootElement().getChildElements("TESTCASES");
 
3220
            processTestCases(testcases);
 
3221
        }
 
3222
 
 
3223
    }
 
3224
 
 
3225
    
 
3226
    // xmlconf/xmltest/valid/sa/097.xml appears to be screwed up by a lot
 
3227
    // of parsers 
 
3228
    private void processTestCases(Elements testcases) 
 
3229
      throws ParsingException, IOException {
 
3230
        
 
3231
        for (int i = 0; i < testcases.size(); i++) {
 
3232
              Element testcase = testcases.get(i); 
 
3233
              Elements tests = testcase.getChildElements("TEST");
 
3234
              processTests(tests);
 
3235
              Elements level2 = testcase.getChildElements("TESTCASES");
 
3236
              // need to be recursive to handle recursive IBM test cases
 
3237
              processTestCases(level2);
 
3238
        }
 
3239
        
 
3240
    }
 
3241
 
 
3242
 
 
3243
    private void processTests(Elements tests) 
 
3244
      throws ParsingException, IOException  {
 
3245
        
 
3246
        Element parent = new Element("e");
 
3247
        Element child = new Element("a");
 
3248
        parent.appendChild(child);
 
3249
            
 
3250
        int size = tests.size();
 
3251
        for (int i = 0; i < size; i++) {
 
3252
            Element test = tests.get(i);
 
3253
            String namespace = test.getAttributeValue("NAMESPACE");
 
3254
            if ("no".equals(namespace)) continue;
 
3255
            String type = test.getAttributeValue("TYPE");
 
3256
            if ("not-wf".equals(type)) continue;
 
3257
            String uri = test.getAttributeValue("URI");
 
3258
            String base = test.getBaseURI();
 
3259
            // Hack because URIUtil isn't public; and I don't want to
 
3260
            // depend on 1.4 only java.net.URI
 
3261
            parent.setBaseURI(base);
 
3262
            child.addAttribute(new Attribute("xml:base", 
 
3263
              "http://www.w3.org/XML/1998/namespace", uri));
 
3264
            String resolvedURI = child.getBaseURI();
 
3265
            
 
3266
            Document doc = builder.build(resolvedURI);
 
3267
            ByteArrayOutputStream out = new ByteArrayOutputStream();
 
3268
            try {
 
3269
                Serializer serializer = new Serializer(out);
 
3270
                serializer.write(doc);
 
3271
            }
 
3272
            finally {
 
3273
                out.close();
 
3274
            }           
 
3275
            byte[] actual = out.toByteArray();
 
3276
            
 
3277
            InputStream in = new ByteArrayInputStream(actual);
 
3278
            try {
 
3279
                Document roundTrip = builder.build(in, resolvedURI);
 
3280
                assertEquals("Failed to roundtrip " + uri, doc, roundTrip);
 
3281
            }
 
3282
            catch (ParsingException ex) {
 
3283
                System.out.println(ex.getURI());
 
3284
                System.out.println(doc.toXML());
 
3285
                throw ex;
 
3286
            }
 
3287
            finally {
 
3288
                in.close();
 
3289
            }
 
3290
        }
 
3291
        
 
3292
    }
 
3293
    
 
3294
}