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