1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.tests.javax.xml.parsers;
18
19import junit.framework.TestCase;
20
21import org.apache.harmony.tests.org.xml.sax.support.MethodLogger;
22import org.apache.harmony.tests.org.xml.sax.support.MockHandler;
23import org.apache.harmony.tests.org.xml.sax.support.MockResolver;
24import org.w3c.dom.DOMImplementation;
25import org.w3c.dom.Document;
26import org.w3c.dom.Element;
27import org.w3c.dom.EntityReference;
28import org.w3c.dom.Text;
29import org.xml.sax.EntityResolver;
30import org.xml.sax.ErrorHandler;
31import org.xml.sax.InputSource;
32import org.xml.sax.SAXException;
33import org.xml.sax.SAXParseException;
34
35import tests.support.resource.Support_Resources;
36
37import javax.xml.parsers.DocumentBuilder;
38import javax.xml.parsers.DocumentBuilderFactory;
39
40import java.io.ByteArrayInputStream;
41import java.io.File;
42import java.io.FileInputStream;
43import java.io.IOException;
44import java.io.InputStream;
45import java.net.URL;
46
47public class DocumentBuilderTest extends TestCase {
48
49    private class MockDocumentBuilder extends DocumentBuilder {
50
51        public MockDocumentBuilder() {
52            super();
53        }
54
55        /*
56         * @see javax.xml.parsers.DocumentBuilder#getDOMImplementation()
57         */
58        @Override
59        public DOMImplementation getDOMImplementation() {
60            // it is a fake
61            return null;
62        }
63
64        /*
65         * @see javax.xml.parsers.DocumentBuilder#isNamespaceAware()
66         */
67        @Override
68        public boolean isNamespaceAware() {
69            // it is a fake
70            return false;
71        }
72
73        /*
74         * @see javax.xml.parsers.DocumentBuilder#isValidating()
75         */
76        @Override
77        public boolean isValidating() {
78            // it is a fake
79            return false;
80        }
81
82        /*
83         * @see javax.xml.parsers.DocumentBuilder#newDocument()
84         */
85        @Override
86        public Document newDocument() {
87            // it is a fake
88            return null;
89        }
90
91        /*
92         * @see javax.xml.parsers.DocumentBuilder#parse(org.xml.sax.InputSource)
93         */
94        @Override
95        public Document parse(InputSource is) throws SAXException, IOException {
96            // it is a fake
97            return null;
98        }
99
100        /*
101         * @see javax.xml.parsers.DocumentBuilder#setEntityResolver(
102         *  org.xml.sax.EntityResolver)
103         */
104        @Override
105        public void setEntityResolver(EntityResolver er) {
106            // it is a fake
107        }
108
109        /*
110         * @see javax.xml.parsers.DocumentBuilder#setErrorHandler(
111         *  org.xml.sax.ErrorHandler)
112         */
113        @Override
114        public void setErrorHandler(ErrorHandler eh) {
115            // it is a fake
116        }
117
118        public Object clone() throws CloneNotSupportedException {
119            return super.clone();
120        }
121    }
122
123    DocumentBuilderFactory dbf;
124
125    DocumentBuilder db;
126
127    protected void setUp() throws Exception {
128
129        dbf = DocumentBuilderFactory.newInstance();
130
131        dbf.setIgnoringElementContentWhitespace(true);
132
133        db = dbf.newDocumentBuilder();
134        super.setUp();
135    }
136
137    protected void tearDown() throws Exception {
138        super.tearDown();
139    }
140
141    public void testDocumentBuilder() {
142        try {
143            new MockDocumentBuilder();
144        } catch (Exception e) {
145            fail("unexpected exception " + e.toString());
146        }
147    }
148
149    /**
150     *  javax.xml.parsers.DocumentBuilder#getSchema()
151     *  TBD getSchema() is not supported
152     */
153 /*   public void test_getSchema() {
154        assertNull(db.getSchema());
155        SchemaFactory sf =
156            SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
157        try {
158            Schema schema = sf.newSchema();
159            dbf.setSchema(schema);
160            assertNotNull(dbf.newDocumentBuilder().getSchema());
161        } catch (ParserConfigurationException pce) {
162            fail("Unexpected ParserConfigurationException " + pce.toString());
163        } catch (SAXException sax) {
164            fail("Unexpected SAXException " + sax.toString());
165        }
166    }
167*/
168    public void testNewDocument() {
169        Document d;
170
171        try {
172            d = dbf.newDocumentBuilder().newDocument();
173        } catch (Exception e) {
174            throw new RuntimeException("Unexpected exception", e);
175        }
176
177        assertNotNull(d);
178        assertNull(d.getDoctype());
179        assertNull(d.getDocumentElement());
180        assertNull(d.getNamespaceURI());
181    }
182
183    public void testGetImplementation() {
184        DOMImplementation d;
185
186        try {
187            d = dbf.newDocumentBuilder().getDOMImplementation();
188        } catch (Exception e) {
189            throw new RuntimeException("Unexpected exception", e);
190        }
191
192        assertNotNull(d);
193    }
194
195    public void testIsNamespaceAware() {
196        try {
197            dbf.setNamespaceAware(true);
198            assertTrue(dbf.newDocumentBuilder().isNamespaceAware());
199            dbf.setNamespaceAware(false);
200            assertFalse(dbf.newDocumentBuilder().isNamespaceAware());
201        } catch (Exception e) {
202            throw new RuntimeException("Unexpected exception", e);
203        }
204    }
205
206    public void testIsValidating() {
207        try {
208            dbf.setValidating(false);
209            assertFalse(dbf.newDocumentBuilder().isValidating());
210        } catch (Exception e) {
211            throw new RuntimeException("Unexpected exception", e);
212        }
213    }
214
215    public void testIsXIncludeAware() {
216        try {
217            dbf.setXIncludeAware(false);
218            assertFalse(dbf.newDocumentBuilder().isXIncludeAware());
219        } catch (Exception e) {
220            throw new RuntimeException("Unexpected exception", e);
221        }
222    }
223
224    /**
225     * Tests that the Base URI for the document is populated with the file URI.
226     */
227    public void testGetBaseURI() throws IOException, SAXException {
228        File f = Support_Resources.resourceToTempFile("/simple.xml");
229        Document d = db.parse(f);
230        assertTrue(d.getDocumentElement().getBaseURI().startsWith("file://"));
231    }
232
233    /**
234     * javax.xml.parsers.DocumentBuilder#parse(java.io.File)
235     * Case 1: Try to parse correct xml document.
236     * Case 2: Try to call parse() with null argument.
237     * Case 3: Try to parse a non-existent file.
238     * Case 4: Try to parse incorrect xml file.
239     */
240    public void test_parseLjava_io_File() throws IOException {
241        File f = Support_Resources.resourceToTempFile("/simple.xml");
242
243        // case 1: Trivial use.
244        try {
245            Document d = db.parse(f);
246            assertNotNull(d);
247       //      TBD getXmlEncoding() IS NOT SUPPORTED
248       //     assertEquals("ISO-8859-1", d.getXmlEncoding());
249            assertEquals(2, d.getChildNodes().getLength());
250            assertEquals("#comment",
251                    d.getChildNodes().item(0).getNodeName());
252            assertEquals("breakfast_menu",
253                    d.getChildNodes().item(1).getNodeName());
254        } catch (IOException ioe) {
255            fail("Unexpected IOException " + ioe.toString());
256        } catch (SAXException sax) {
257            fail("Unexpected SAXException " + sax.toString());
258        }
259
260        // case 2: Try to call parse with null argument
261        try {
262            db.parse((File)null);
263            fail("Expected IllegalArgumentException was not thrown");
264        } catch (IllegalArgumentException iae) {
265            // expected
266        } catch (IOException ioe) {
267            fail("Unexpected IOException " + ioe.toString());
268        } catch (SAXException sax) {
269            fail("Unexpected SAXException " + sax.toString());
270        }
271
272        // case 3: Try to parse a non-existent file
273        try {
274            db.parse(new File("_"));
275            fail("Expected IOException was not thrown");
276        } catch (IOException ioe) {
277            // expected
278        } catch (SAXException sax) {
279            fail("Unexpected SAXException " + sax.toString());
280        }
281
282        // case 4: Try to parse incorrect xml file
283        f = Support_Resources.resourceToTempFile("/wrong.xml");
284        try {
285            db.parse(f);
286            fail("Expected SAXException was not thrown");
287        } catch (IOException ioe) {
288            fail("Unexpected IOException " + ioe.toString());
289        } catch (SAXException sax) {
290            // expected
291        }
292    }
293
294    /**
295     * javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream)
296     * Case 1: Try to parse correct xml document.
297     * Case 2: Try to call parse() with null argument.
298     * Case 3: Try to parse a non-existent file.
299     * Case 4: Try to parse incorrect xml file.
300     */
301    public void test_parseLjava_io_InputStream() {
302        InputStream is = getClass().getResourceAsStream("/simple.xml");
303        // case 1: Trivial use.
304        try {
305            Document d = db.parse(is);
306            assertNotNull(d);
307            // TBD getXmlEncoding() IS NOT SUPPORTED
308            // assertEquals("ISO-8859-1", d.getXmlEncoding());
309            assertEquals(2, d.getChildNodes().getLength());
310            assertEquals("#comment",
311                    d.getChildNodes().item(0).getNodeName());
312            assertEquals("breakfast_menu",
313                    d.getChildNodes().item(1).getNodeName());
314        } catch (IOException ioe) {
315            fail("Unexpected IOException " + ioe.toString());
316        } catch (SAXException sax) {
317            fail("Unexpected SAXException " + sax.toString());
318        }
319
320        // case 2: Try to call parse with null argument
321        try {
322            db.parse((InputStream)null);
323            fail("Expected IllegalArgumentException was not thrown");
324        } catch (IllegalArgumentException iae) {
325            // expected
326        } catch (IOException ioe) {
327            fail("Unexpected IOException " + ioe.toString());
328        } catch (SAXException sax) {
329            fail("Unexpected SAXException " + sax.toString());
330        }
331
332        // case 3: Try to parse a non-existent file
333        try {
334            db.parse(new FileInputStream("_"));
335            fail("Expected IOException was not thrown");
336        } catch (IOException ioe) {
337            // expected
338        } catch (SAXException sax) {
339            fail("Unexpected SAXException " + sax.toString());
340        }
341
342        // case 4: Try to parse incorrect xml file
343        try {
344            is = getClass().getResourceAsStream("/wrong.xml");
345            db.parse(is);
346            fail("Expected SAXException was not thrown");
347        } catch (IOException ioe) {
348            fail("Unexpected IOException " + ioe.toString());
349        } catch (SAXException sax) {
350            // expected
351        }
352    }
353
354    /**
355     * javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream)
356     * Case 1: Try to parse correct xml document.
357     * Case 2: Try to call parse() with null argument.
358     * Case 3: Try to parse a non-existent file.
359     * Case 4: Try to parse incorrect xml file.
360     */
361    public void testParseInputSource() {
362        InputStream stream = getClass().getResourceAsStream("/simple.xml");
363        InputSource is = new InputSource(stream);
364
365        // case 1: Trivial use.
366        try {
367            Document d = db.parse(is);
368            assertNotNull(d);
369            // TBD getXmlEncoding() IS NOT SUPPORTED
370            // assertEquals("ISO-8859-1", d.getXmlEncoding());
371            assertEquals(2, d.getChildNodes().getLength());
372            assertEquals("#comment",
373                    d.getChildNodes().item(0).getNodeName());
374            assertEquals("breakfast_menu",
375                    d.getChildNodes().item(1).getNodeName());
376        } catch (IOException ioe) {
377            fail("Unexpected IOException " + ioe.toString());
378        } catch (SAXException sax) {
379            fail("Unexpected SAXException " + sax.toString());
380        }
381
382        // case 2: Try to call parse with null argument
383        try {
384            db.parse((InputSource)null);
385            fail("Expected IllegalArgumentException was not thrown");
386        } catch (IllegalArgumentException iae) {
387            // expected
388        } catch (IOException ioe) {
389            fail("Unexpected IOException " + ioe.toString());
390        } catch (SAXException sax) {
391            fail("Unexpected SAXException " + sax.toString());
392        }
393
394        // case 3: Try to parse a non-existent file
395        try {
396            db.parse(new InputSource(new FileInputStream("_")));
397            fail("Expected IOException was not thrown");
398        } catch (IOException ioe) {
399            // expected
400        } catch (SAXException sax) {
401            fail("Unexpected SAXException " + sax.toString());
402        }
403
404        // case 4: Try to parse incorrect xml file
405        try {
406            is = new InputSource(getClass().getResourceAsStream("/wrong.xml"));
407            db.parse(is);
408            fail("Expected SAXException was not thrown");
409        } catch (IOException ioe) {
410            fail("Unexpected IOException " + ioe.toString());
411        } catch (SAXException sax) {
412            // expected
413        }
414    }
415
416    /**
417     * javax.xml.parsers.DocumentBuilder#parse(java.io.InputStream,
418     *     java.lang.String)
419     * Case 1: Try to parse correct xml document.
420     * Case 2: Try to call parse() with null argument.
421     * Case 3: Try to parse a non-existent file.
422     * Case 4: Try to parse incorrect xml file.
423     */
424    public void test_parseLjava_io_InputStreamLjava_lang_String() {
425        InputStream is = getClass().getResourceAsStream("/systemid.xml");
426        // case 1: Trivial use.
427        try {
428            Document d = db.parse(is, SAXParserTestSupport.XML_SYSTEM_ID);
429            assertNotNull(d);
430//           TBD getXmlEncoding() is not supported
431//           assertEquals("UTF-8", d.getXmlEncoding());
432            assertEquals(4, d.getChildNodes().getLength());
433            assertEquals("collection",
434                    d.getChildNodes().item(0).getNodeName());
435            assertEquals("#comment",
436                    d.getChildNodes().item(1).getNodeName());
437            assertEquals("collection",
438                    d.getChildNodes().item(2).getNodeName());
439            assertEquals("#comment",
440                    d.getChildNodes().item(3).getNodeName());
441        } catch (IOException ioe) {
442            fail("Unexpected IOException " + ioe.toString());
443        } catch (SAXException sax) {
444            fail("Unexpected SAXException " + sax.toString());
445        }
446
447        // case 2: Try to call parse with null argument
448        try {
449            db.parse((InputStream)null, SAXParserTestSupport.XML_SYSTEM_ID);
450            fail("Expected IllegalArgumentException was not thrown");
451        } catch (IllegalArgumentException iae) {
452            // expected
453        } catch (IOException ioe) {
454            fail("Unexpected IOException " + ioe.toString());
455        } catch (SAXException sax) {
456            fail("Unexpected SAXException " + sax.toString());
457        }
458
459        // case 3: Try to parse a non-existent file
460// Doesn't make sense this way...
461//        try {
462//            db.parse(is, "/");
463//            fail("Expected IOException was not thrown");
464//        } catch (IOException ioe) {
465//            // expected
466//        } catch (SAXException sax) {
467//            fail("Unexpected SAXException " + sax.toString());
468//        }
469
470        // case 4: Try to parse incorrect xml file
471        try {
472            is = getClass().getResourceAsStream("/wrong.xml");
473            db.parse(is, SAXParserTestSupport.XML_SYSTEM_ID);
474            fail("Expected SAXException was not thrown");
475        } catch (IOException ioe) {
476            fail("Unexpected IOException " + ioe.toString());
477        } catch (SAXException sax) {
478            // expected
479        }
480    }
481
482    /**
483     * javax.xml.parsers.DocumentBuilder#parse(java.lang.String)
484     * Case 1: Try to parse correct xml document.
485     * Case 2: Try to call parse() with null argument.
486     * Case 3: Try to parse a non-existent uri.
487     * Case 4: Try to parse incorrect xml file.
488     */
489    public void test_parseLjava_lang_String() throws Exception {
490        // case 1: Trivial use.
491        URL resource = getClass().getResource("/simple.xml");
492        Document d = db.parse(resource.toString());
493        assertNotNull(d);
494//          TBD  getXmlEncoding() is not supported
495//          assertEquals("ISO-8859-1", d.getXmlEncoding());
496        assertEquals(2, d.getChildNodes().getLength());
497        assertEquals("#comment",
498                d.getChildNodes().item(0).getNodeName());
499        assertEquals("breakfast_menu",
500                d.getChildNodes().item(1).getNodeName());
501
502        // case 2: Try to call parse with null argument
503        try {
504            db.parse((String)null);
505            fail("Expected IllegalArgumentException was not thrown");
506        } catch (IllegalArgumentException iae) {
507            // expected
508        }
509
510        // case 3: Try to parse a non-existent uri
511        try {
512            db.parse("_");
513            fail("Expected IOException was not thrown");
514        } catch (IOException ioe) {
515            // expected
516        }
517
518        // case 4: Try to parse incorrect xml file
519        try {
520            resource = getClass().getResource("/wrong.xml");
521            db.parse(resource.toString());
522            fail("Expected SAXException was not thrown");
523        } catch (SAXException sax) {
524            // expected
525        }
526    }
527
528    public void testReset() {
529        // Make sure EntityResolver gets reset
530        InputStream source = new ByteArrayInputStream("<a>&foo;</a>".getBytes());
531        InputStream entity = new ByteArrayInputStream("bar".getBytes());
532
533        MockResolver resolver = new MockResolver();
534        resolver.addEntity("foo", "foo", new InputSource(entity));
535
536        Document d;
537
538        try {
539            db = dbf.newDocumentBuilder();
540            db.setEntityResolver(resolver);
541            db.reset();
542            d = db.parse(source);
543        } catch (Exception e) {
544            throw new RuntimeException("Unexpected exception", e);
545        }
546
547        Element root = (Element)d.getElementsByTagName("a").item(0);
548        assertEquals("foo", ((EntityReference)root.getFirstChild()).getNodeName());
549
550        // Make sure ErrorHandler gets reset
551        source = new ByteArrayInputStream("</a>".getBytes());
552
553        MethodLogger logger = new MethodLogger();
554        ErrorHandler handler = new MockHandler(logger);
555
556        try {
557            db = dbf.newDocumentBuilder();
558            db.setErrorHandler(handler);
559            db.reset();
560            d = db.parse(source);
561        } catch (SAXParseException e) {
562            // Expected
563        } catch (Exception e) {
564            throw new RuntimeException("Unexpected exception", e);
565        }
566
567        assertEquals(0, logger.size());
568    }
569
570    public void testSetErrorHandler() {
571        // Ordinary case
572        InputStream source = new ByteArrayInputStream("</a>".getBytes());
573
574        MethodLogger logger = new MethodLogger();
575        ErrorHandler handler = new MockHandler(logger);
576
577        try {
578            db = dbf.newDocumentBuilder();
579            db.setErrorHandler(handler);
580            db.parse(source);
581        } catch (SAXParseException e) {
582            // Expected, ErrorHandler does not mask exception
583        } catch (Exception e) {
584            throw new RuntimeException("Unexpected exception", e);
585        }
586
587        assertEquals("error", logger.getMethod());
588        assertTrue(logger.getArgs()[0] instanceof SAXParseException);
589
590        // null case
591        source = new ByteArrayInputStream("</a>".getBytes());
592
593        try {
594            db = dbf.newDocumentBuilder();
595            db.setErrorHandler(null);
596            db.parse(source);
597        } catch (SAXParseException e) {
598            // Expected
599        } catch (Exception e) {
600            throw new RuntimeException("Unexpected exception", e);
601        }
602    }
603
604    public void testSetEntityResolver() {
605        // Ordinary case
606        InputStream source = new ByteArrayInputStream("<a>&foo;</a>".getBytes());
607        InputStream entity = new ByteArrayInputStream("bar".getBytes());
608
609        MockResolver resolver = new MockResolver();
610        resolver.addEntity("foo", "foo", new InputSource(entity));
611
612        Document d;
613
614        try {
615            db = dbf.newDocumentBuilder();
616            db.setEntityResolver(resolver);
617            d = db.parse(source);
618        } catch (Exception e) {
619            throw new RuntimeException("Unexpected exception", e);
620        }
621
622        Element root = (Element)d.getElementsByTagName("a").item(0);
623        assertEquals("bar", ((Text)root.getFirstChild()).getData());
624
625        // null case
626        source = new ByteArrayInputStream("<a>&foo;</a>".getBytes());
627
628        try {
629            db = dbf.newDocumentBuilder();
630            db.setEntityResolver(null);
631            d = db.parse(source);
632        } catch (Exception e) {
633            throw new RuntimeException("Unexpected exception", e);
634        }
635
636        root = (Element)d.getElementsByTagName("a").item(0);
637        assertEquals("foo", ((EntityReference)root.getFirstChild()).getNodeName());
638    }
639
640}
641