1838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson/*
2838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
3838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson *
4838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * you may not use this file except in compliance with the License.
6838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * You may obtain a copy of the License at
7838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson *
8838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson *
10838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * See the License for the specific language governing permissions and
14838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * limitations under the License.
15838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson */
16838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
17838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonpackage libcore.xml;
18838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
19838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonimport java.io.StringReader;
2076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilsonimport java.util.Arrays;
21838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonimport junit.framework.TestCase;
22838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonimport org.xmlpull.v1.XmlPullParser;
23838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonimport org.xmlpull.v1.XmlPullParserException;
24838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
25838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson/**
26838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson * Test doctype handling in pull parsers.
27838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson */
28838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilsonpublic abstract class PullParserDtdTest extends TestCase {
29838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
3076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    private static final int READ_BUFFER_SIZE = 8192;
3176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
32838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    /**
33838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Android's Expat pull parser permits parameter entities to be declared,
34838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * but it doesn't permit such entities to be used.
35838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     */
36838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testDeclaringParameterEntities() throws Exception {
37838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
38838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            + "  <!ENTITY % a \"android\">"
39838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            + "]><foo></foo>";
40838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
41838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        while (parser.next() != XmlPullParser.END_DOCUMENT) {
42838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        }
43838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
44838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
45838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testUsingParameterEntitiesInDtds() throws Exception {
46995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<!DOCTYPE foo ["
47838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            + "  <!ENTITY % a \"android\">"
48838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            + "  <!ENTITY b \"%a;\">"
49995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson            + "]><foo></foo>");
50838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
51838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
52838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testUsingParameterInDocuments() throws Exception {
53995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<!DOCTYPE foo ["
54838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            + "  <!ENTITY % a \"android\">"
55995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson            + "]><foo>&a;</foo>");
56838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
57838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
5876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testGeneralAndParameterEntityWithTheSameName() throws Exception {
5976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String xml = "<!DOCTYPE foo ["
6076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY a \"aaa\">"
6176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY % a \"bbb\">"
6276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "]><foo>&a;</foo>";
6376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        XmlPullParser parser = newPullParser(xml);
6476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
6576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
6676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("aaa", parser.getText());
6776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
6876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
6976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
7076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
71838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testInternalEntities() throws Exception {
72838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
73838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a \"android\">"
74838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>&a;</foo>";
75838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
76838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
77838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
78838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("android", parser.getText());
79838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
80838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
81838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
82838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
83838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testExternalDtdIsSilentlyIgnored() throws Exception {
84838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo SYSTEM \"http://127.0.0.1:1/no-such-file.dtd\"><foo></foo>";
85838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
86838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
87838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
88838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
89838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
90838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
91838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
92838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
93838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testExternalAndInternalDtd() throws Exception {
94838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo SYSTEM \"http://127.0.0.1:1/no-such-file.dtd\" ["
95838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a \"android\">"
96838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>&a;</foo>";
97838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
98838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
99838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
100838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("android", parser.getText());
101838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
102838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
103838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
104838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
105838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testInternalEntitiesAreParsed() throws Exception {
106838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
107838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a \"&#38;#65;\">" // &#38; expands to '&', &#65; expands to 'A'
108838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>&a;</foo>";
109838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
110838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
111838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
112838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("A", parser.getText());
113838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
114838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
115838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
116838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
117838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testFoolishlyRecursiveInternalEntities() throws Exception {
118838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
119838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a \"&#38;#38;#38;#38;\">" // expand &#38; to '&' only twice
120838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>&a;</foo>";
121838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
122838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
123838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
124838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("&#38;#38;", parser.getText());
125838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
126838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
127838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
128838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
129838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    /**
1307fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson     * Test that the output of {@code &#38;} is parsed, but {@code &amp;} isn't.
1317fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson     * http://www.w3.org/TR/2008/REC-xml-20081126/#sec-entexpand
1327fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson     */
1337fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson    public void testExpansionOfEntityAndCharacterReferences() throws Exception {
1347fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        String xml = "<!DOCTYPE foo ["
1357fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "<!ENTITY example \"<p>An ampersand (&#38;#38;) may be escaped\n"
1367fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "numerically (&#38;#38;#38;) or with a general entity\n"
1377fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "(&amp;amp;).</p>\" >"
1387fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "]><foo>&example;</foo>";
1397fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        XmlPullParser parser = newPullParser(xml);
1407fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
1417fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
1427fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals("p", parser.getName());
1437fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
1447fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals("An ampersand (&) may be escaped\n"
1457fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "numerically (&#38;) or with a general entity\n"
1467fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "(&amp;).", parser.getText());
1477fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
1487fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals("p", parser.getName());
1497fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
1507fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
1517fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson    }
1527fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson
1537fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson    public void testGeneralEntitiesAreStoredUnresolved() throws Exception {
1547fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        String xml = "<!DOCTYPE foo ["
1557fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "<!ENTITY b \"&a;\" >"
1567fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "<!ENTITY a \"android\" >"
1577fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson                + "]><foo>&a;</foo>";
1587fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        XmlPullParser parser = newPullParser(xml);
1597fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
1607fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
1617fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals("android", parser.getText());
1627fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
1637fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
1647fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson    }
1657fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson
16638e84b835c2101206d846f7ab6fc444914661753Jesse Wilson    public void testStructuredEntityAndNextToken() throws Exception {
16738e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        String xml = "<!DOCTYPE foo [<!ENTITY bb \"<bar>baz<!--quux--></bar>\">]><foo>a&bb;c</foo>";
16838e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        XmlPullParser parser = newPullParser(xml);
16938e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.DOCDECL, parser.nextToken());
17038e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
17138e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("foo", parser.getName());
17238e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.nextToken());
17338e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("a", parser.getText());
17438e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.ENTITY_REF, parser.nextToken());
17538e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("bb", parser.getName());
17638e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("", parser.getText());
17738e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
17838e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("bar", parser.getName());
17938e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.nextToken());
18038e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("baz", parser.getText());
18138e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.COMMENT, parser.nextToken());
18238e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("quux", parser.getText());
18338e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
18438e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("bar", parser.getName());
18538e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.nextToken());
18638e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("c", parser.getText());
18738e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
18838e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
18938e84b835c2101206d846f7ab6fc444914661753Jesse Wilson    }
19038e84b835c2101206d846f7ab6fc444914661753Jesse Wilson
1917fac047a67ee9a0295e4dc798c7c6880ccd83513Jesse Wilson    /**
192838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Android's Expat replaces external entities with the empty string.
193838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     */
194838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testUsingExternalEntities() throws Exception {
195838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
196838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a SYSTEM \"http://localhost:1/no-such-file.xml\">"
197838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>&a;</foo>";
198838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
199838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
200838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        // &a; is dropped!
201838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
202838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
203838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
204838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
205773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson    /**
206773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson     * Android's ExpatPullParser replaces missing entities with the empty string
207773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson     * when an external DTD is declared.
208773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson     */
209773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson    public void testExternalDtdAndMissingEntity() throws Exception {
210773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson        String xml = "<!DOCTYPE foo SYSTEM \"http://127.0.0.1:1/no-such-file.dtd\">"
211773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson                + "<foo>&a;</foo>";
212773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson        XmlPullParser parser = newPullParser(xml);
213773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
214773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
215773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
216773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson    }
217773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson
218773533775fab54079cebc329d54f6286f5ac16f2Jesse Wilson
219838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testExternalIdIsCaseSensitive() throws Exception {
220838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        // The spec requires 'SYSTEM' in upper case
221995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<!DOCTYPE foo ["
222838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a system \"http://localhost:1/no-such-file.xml\">"
223995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson                + "]><foo/>");
224838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
225838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
226838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    /**
227838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Use a DTD to specify that {@code <foo>} only contains {@code <bar>} tags.
228838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Validating parsers react to this by dropping whitespace between the two
229838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * tags.
230838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     */
231838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testDtdDoesNotInformIgnorableWhitespace() throws Exception {
232838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
233838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo (bar)*>\n"
234838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT bar ANY>\n"
235838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
236838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo>  \n  <bar></bar>  \t  </foo>";
237838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
238838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
239838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
240838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
241838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("  \n  ", parser.getText());
242838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
243838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("bar", parser.getName());
244838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
245838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("bar", parser.getName());
246838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
247838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("  \t  ", parser.getText());
248838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
249838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
250838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
251838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
252838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testEmptyDoesNotInformIgnorableWhitespace() throws Exception {
253838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
254838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo EMPTY>\n"
255838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
256838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo>  \n  </foo>";
257838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
258838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
259838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
260838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
261838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("  \n  ", parser.getText());
262838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
263838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
264838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
265838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
266838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    /**
267838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Test that the parser doesn't expand the entity attributes.
268838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     */
269838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testAttributeOfTypeEntity() throws Exception {
270838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
271838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY a \"android\">"
272838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo ANY>\n"
273838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ATTLIST foo\n"
274838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "    bar ENTITY #IMPLIED>"
275838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
276838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo bar=\"a\"></foo>";
277838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
278838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
279838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
280838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("a", parser.getAttributeValue(null, "bar"));
281838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
282838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
283838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
284838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
285838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testTagStructureNotValidated() throws Exception {
286838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
287838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo (bar)*>\n"
288838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT bar ANY>\n"
289838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT baz ANY>\n"
290838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
291838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo><bar/><bar/><baz/></foo>";
292838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
293838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
294838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
295838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
296838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("bar", parser.getName());
297838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
298838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
299838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("bar", parser.getName());
300838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
301838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
302838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("baz", parser.getName());
303838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
304838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
305838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
306838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
307838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
308838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testAttributeDefaultValues() throws Exception {
309838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
31076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ATTLIST bar\n"
31176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "    baz (a|b|c)  \"c\">"
31276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "]>"
31376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "<foo>"
31476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "<bar/>"
31576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "<bar baz=\"a\"/>"
31676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "</foo>";
31776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        XmlPullParser parser = newPullParser(xml);
31876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
31976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
32076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("bar", parser.getName());
32176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("c", parser.getAttributeValue(null, "baz"));
32276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
32376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
32476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("bar", parser.getName());
32576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("a", parser.getAttributeValue(null, "baz"));
32676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
32776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
32876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
32976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
33076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
33176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testAttributeDefaultValueEntitiesExpanded() throws Exception {
33276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
33376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY g \"ghi\">"
334838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo ANY>\n"
335838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ATTLIST foo\n"
33676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "    bar CDATA \"abc &amp; def &g; jk\">"
337838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
338838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo></foo>";
339838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
340838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
341838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
34276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("abc & def ghi jk", parser.getAttributeValue(null, "bar"));
34376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
34476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
34576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
34676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
34776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testAttributeDefaultValuesAndNamespaces() throws Exception {
34876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
34976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ATTLIST foo\n"
35076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "    bar:a CDATA \"android\">"
35176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "]>"
35276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "<foo xmlns:bar='http://bar'></foo>";
35376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        XmlPullParser parser = newPullParser(xml);
35476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
35576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
35676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("foo", parser.getName());
35776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        // In Expat, namespaces don't apply to default attributes
35876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        int index = indexOfAttributeWithName(parser, "bar:a");
35976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("", parser.getAttributeNamespace(index));
36076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("bar:a", parser.getAttributeName(index));
36176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("android", parser.getAttributeValue(index));
36276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("CDATA", parser.getAttributeType(index));
363838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
36476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
36576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
36676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
36776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    private int indexOfAttributeWithName(XmlPullParser parser, String name) {
36876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        for (int i = 0; i < parser.getAttributeCount(); i++) {
36976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson            if (parser.getAttributeName(i).equals(name)) {
37076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                return i;
37176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson            }
37276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        }
37376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        return -1;
37476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
37576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
37676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testAttributeEntitiesExpandedEagerly() throws Exception {
377995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<!DOCTYPE foo [\n"
37876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ELEMENT foo ANY>\n"
37976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ATTLIST foo\n"
38076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "    bar CDATA \"abc &amp; def &g; jk\">"
38176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY g \"ghi\">"
38276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "]>"
383995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson                + "<foo></foo>");
384838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
385838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
386838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testRequiredAttributesOmitted() throws Exception {
387838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
388838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo ANY>\n"
389838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ATTLIST foo\n"
390838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "    bar (a|b|c) #REQUIRED>"
391838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
392838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo></foo>";
393838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
394838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
395838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
396838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(null, parser.getAttributeValue(null, "bar"));
397838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
398838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
399838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
400838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testFixedAttributesWithConflictingValues() throws Exception {
401838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
402838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ELEMENT foo ANY>\n"
403838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ATTLIST foo\n"
404838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "    bar (a|b|c) #FIXED \"c\">"
405838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
406838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo bar=\"a\"></foo>";
407838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
408838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
409838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
410838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("a", parser.getAttributeValue(null, "bar"));
411838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
412838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
413838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
414838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testParsingNotations() throws Exception {
415838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
416838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!NOTATION type-a PUBLIC \"application/a\"> \n"
417838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!NOTATION type-b PUBLIC \"image/b\">\n"
418838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!NOTATION type-c PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n"
419838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "     \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> \n"
420838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY file          SYSTEM \"d.xml\">\n"
421838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!ENTITY fileWithNdata SYSTEM \"e.bin\" NDATA type-b>\n"
422838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]>"
423838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "<foo type=\"type-a\"/>";
424838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
425838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
426838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
427838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
428838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
429838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
430838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testCommentsInDoctype() throws Exception {
431838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo ["
432838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "  <!-- ' -->"
433838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson                + "]><foo>android</foo>";
434838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
435838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
436838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
437838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("android", parser.getText());
438838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
439838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
440838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
441838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
442838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testDoctypeNameOnly() throws Exception {
443838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo><foo></foo>";
444838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
445838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
446838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
447838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
448838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals("foo", parser.getName());
449838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
450838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
451838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
45276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testVeryLongEntities() throws Exception {
45376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String a = repeat('a', READ_BUFFER_SIZE + 1);
45476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String b = repeat('b', READ_BUFFER_SIZE + 1);
45576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String c = repeat('c', READ_BUFFER_SIZE + 1);
45676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
45776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String xml = "<!DOCTYPE foo [\n"
45876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY " + a + "  \"d &" + b + "; e\">"
45976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "  <!ENTITY " + b + "  \"f " + c + " g\">"
46076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "]>"
46176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson                + "<foo>h &" + a + "; i</foo>";
46276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        XmlPullParser parser = newPullParser(xml);
46376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
46476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
46576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals("h d f " + c + " g e i", parser.getText());
46676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
46776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
46876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
46976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
47076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    public void testManuallyRegisteredEntitiesWithDoctypeParsing() throws Exception {
47176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        String xml = "<foo>&a;</foo>";
47276c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        XmlPullParser parser = newPullParser(xml);
47376c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        try {
47476c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson            parser.defineEntityReplacementText("a", "android");
47576c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson            fail();
47676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        } catch (UnsupportedOperationException expected) {
47776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        } catch (IllegalStateException expected) {
47876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        }
47976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
48076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
481838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    public void testDoctypeWithNextToken() throws Exception {
482838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        String xml = "<!DOCTYPE foo [<!ENTITY bb \"bar baz\">]><foo>a&bb;c</foo>";
483838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser parser = newPullParser(xml);
484838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.DOCDECL, parser.nextToken());
485838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(" foo [<!ENTITY bb \"bar baz\">]", parser.getText());
486838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertNull(parser.getName());
487838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
48838e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.TEXT, parser.next());
48938e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals("abar bazc", parser.getText());
49038e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
49138e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
49238e84b835c2101206d846f7ab6fc444914661753Jesse Wilson    }
49338e84b835c2101206d846f7ab6fc444914661753Jesse Wilson
49438e84b835c2101206d846f7ab6fc444914661753Jesse Wilson    public void testDoctypeSpansBuffers() throws Exception {
49538e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        char[] doctypeChars = new char[READ_BUFFER_SIZE + 1];
49638e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        Arrays.fill(doctypeChars, 'x');
49738e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        String doctypeBody = " foo [<!--" + new String(doctypeChars) + "-->]";
49838e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        String xml = "<!DOCTYPE" + doctypeBody + "><foo/>";
49938e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        XmlPullParser parser = newPullParser(xml);
50038e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.DOCDECL, parser.nextToken());
50138e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(doctypeBody, parser.getText());
50238e84b835c2101206d846f7ab6fc444914661753Jesse Wilson        assertEquals(XmlPullParser.START_TAG, parser.next());
503838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_TAG, parser.next());
504838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
505838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
506838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
507995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson    public void testDoctypeInDocumentElement() throws Exception {
508995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<foo><!DOCTYPE foo></foo>");
509995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson    }
510995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson
511995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson    public void testDoctypeAfterDocumentElement() throws Exception {
512995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        assertParseFailure("<foo/><!DOCTYPE foo>");
513995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson    }
514995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson
515995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson    private void assertParseFailure(String xml) throws Exception {
516995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        XmlPullParser parser = newPullParser();
517995a384234fd0ba9233ebcce380628bbe346b911Jesse Wilson        parser.setInput(new StringReader(xml));
518838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        try {
519838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            while (parser.next() != XmlPullParser.END_DOCUMENT) {
520838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            }
521838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson            fail();
522838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        } catch (XmlPullParserException expected) {
523838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        }
524838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
525838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
52676c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    private String repeat(char c, int length) {
52776c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        char[] chars = new char[length];
52876c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        Arrays.fill(chars, c);
52976c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson        return new String(chars);
53076c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    }
53176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson
532838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    private XmlPullParser newPullParser(String xml) throws XmlPullParserException {
533838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        XmlPullParser result = newPullParser();
534838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        result.setInput(new StringReader(xml));
535838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson        return result;
536838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    }
537838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson
538838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson    /**
539838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     * Creates a new pull parser.
540838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson     */
54176c85883787791ba605a51d7bea3cfc27b5c5d95Jesse Wilson    abstract XmlPullParser newPullParser() throws XmlPullParserException;
542838419e39510cb3bf04cf5bfef2929a7cf759e65Jesse Wilson}
543