PullParserTest.java revision 9349ec01a1bebc3b704b400fb00ccfb42e047a02
1/*
2 * Copyright (C) 2010 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 libcore.xml;
18
19import java.io.ByteArrayInputStream;
20import java.io.StringReader;
21import junit.framework.TestCase;
22import org.xmlpull.v1.XmlPullParser;
23import org.xmlpull.v1.XmlPullParserException;
24
25public abstract class PullParserTest extends TestCase {
26
27    public void testAttributeNoValueWithRelaxed() throws Exception {
28        XmlPullParser parser = newPullParser();
29        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
30        parser.setInput(new StringReader("<input checked></input>"));
31        assertEquals(XmlPullParser.START_TAG, parser.next());
32        assertEquals("input", parser.getName());
33        assertEquals("checked", parser.getAttributeName(0));
34        assertEquals("checked", parser.getAttributeValue(0));
35    }
36
37    public void testAttributeUnquotedValueWithRelaxed() throws Exception {
38        XmlPullParser parser = newPullParser();
39        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
40        parser.setInput(new StringReader("<input checked=true></input>"));
41        assertEquals(XmlPullParser.START_TAG, parser.next());
42        assertEquals("input", parser.getName());
43        assertEquals("checked", parser.getAttributeName(0));
44        assertEquals("true", parser.getAttributeValue(0));
45    }
46
47    public void testUnterminatedEntityWithRelaxed() throws Exception {
48        XmlPullParser parser = newPullParser();
49        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
50        parser.setInput(new StringReader("<foo bar='A&W'>mac&cheese</foo>"));
51        assertEquals(XmlPullParser.START_TAG, parser.next());
52        assertEquals("foo", parser.getName());
53        assertEquals("bar", parser.getAttributeName(0));
54        assertEquals("A&W", parser.getAttributeValue(0));
55        assertEquals(XmlPullParser.TEXT, parser.next());
56        assertEquals("mac&cheese", parser.getText());
57    }
58
59    public void testEntitiesAndNamespaces() throws Exception {
60        XmlPullParser parser = newPullParser();
61        parser.setFeature("http://xmlpull.org/v1/doc/features.html#process-namespaces", true);
62        parser.setInput(new StringReader(
63                "<foo:a xmlns:foo='http://foo' xmlns:bar='http://bar'><bar:b/></foo:a>"));
64        testNamespace(parser);
65    }
66
67    public void testEntitiesAndNamespacesWithRelaxed() throws Exception {
68        XmlPullParser parser = newPullParser();
69        parser.setFeature("http://xmlpull.org/v1/doc/features.html#process-namespaces", true);
70        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
71        parser.setInput(new StringReader(
72                "<foo:a xmlns:foo='http://foo' xmlns:bar='http://bar'><bar:b/></foo:a>"));
73        testNamespace(parser);
74    }
75
76    private void testNamespace(XmlPullParser parser) throws Exception {
77        assertEquals(XmlPullParser.START_TAG, parser.next());
78        assertEquals("http://foo", parser.getNamespace());
79        assertEquals("a", parser.getName());
80        assertEquals(XmlPullParser.START_TAG, parser.next());
81        assertEquals("http://bar", parser.getNamespace());
82        assertEquals("b", parser.getName());
83        assertEquals(XmlPullParser.END_TAG, parser.next());
84        assertEquals("http://bar", parser.getNamespace());
85        assertEquals("b", parser.getName());
86        assertEquals(XmlPullParser.END_TAG, parser.next());
87        assertEquals("http://foo", parser.getNamespace());
88        assertEquals("a", parser.getName());
89    }
90
91    public void testRegularNumericEntities() throws Exception {
92        XmlPullParser parser = newPullParser();
93        parser.setInput(new StringReader("<foo>&#65;</foo>"));
94        assertEquals(XmlPullParser.START_TAG, parser.next());
95        assertEquals(XmlPullParser.ENTITY_REF, parser.nextToken());
96        assertEquals("#65", parser.getName());
97        assertEquals("A", parser.getText());
98    }
99
100    public void testNumericEntitiesLargerThanChar() throws Exception {
101        assertParseFailure("<foo>&#2147483647; &#-2147483648;</foo>");
102    }
103
104    public void testNumericEntitiesLargerThanInt() throws Exception {
105        assertParseFailure("<foo>&#2147483648;</foo>");
106    }
107
108    public void testCharacterReferenceOfHexUtf16Surrogates() throws Exception {
109        testCharacterReferenceOfUtf16Surrogates("<foo>&#x10000; &#x10381; &#x10FFF0;</foo>");
110    }
111
112    public void testCharacterReferenceOfDecimalUtf16Surrogates() throws Exception {
113        testCharacterReferenceOfUtf16Surrogates("<foo>&#65536; &#66433; &#1114096;</foo>");
114    }
115
116    private void testCharacterReferenceOfUtf16Surrogates(String xml) throws Exception {
117        XmlPullParser parser = newPullParser();
118        parser.setInput(new StringReader(xml));
119        assertEquals(XmlPullParser.START_TAG, parser.next());
120        assertEquals(XmlPullParser.TEXT, parser.next());
121        assertEquals(new String(new int[]{65536, ' ', 66433, ' ', 1114096}, 0, 5),
122                parser.getText());
123        assertEquals(XmlPullParser.END_TAG, parser.next());
124    }
125
126    public void testCharacterReferenceOfLastUtf16Surrogate() throws Exception {
127        XmlPullParser parser = newPullParser();
128        parser.setInput(new StringReader("<foo>&#x10FFFF;</foo>"));
129        assertEquals(XmlPullParser.START_TAG, parser.next());
130        assertEquals(XmlPullParser.TEXT, parser.next());
131        assertEquals(new String(new int[]{0x10FFFF}, 0, 1), parser.getText());
132        assertEquals(XmlPullParser.END_TAG, parser.next());
133    }
134
135    public void testOmittedNumericEntities() throws Exception {
136        assertParseFailure("<foo>&#;</foo>");
137    }
138
139    /**
140     * Carriage returns followed by line feeds are silently discarded.
141     */
142    public void testCarriageReturnLineFeed() throws Exception {
143        testLineEndings("\r\n<foo\r\na='b\r\nc'\r\n>d\r\ne</foo\r\n>\r\n");
144    }
145
146    /**
147     * Lone carriage returns are treated like newlines.
148     */
149    public void testLoneCarriageReturn() throws Exception {
150        testLineEndings("\r<foo\ra='b\rc'\r>d\re</foo\r>\r");
151    }
152
153    public void testLoneNewLine() throws Exception {
154        testLineEndings("\n<foo\na='b\nc'\n>d\ne</foo\n>\n");
155    }
156
157    private void testLineEndings(String xml) throws Exception {
158        XmlPullParser parser = newPullParser();
159        parser.setInput(new StringReader(xml));
160        assertEquals(XmlPullParser.START_TAG, parser.next());
161        assertEquals("foo", parser.getName());
162        assertEquals("b c", parser.getAttributeValue(0));
163        assertEquals(XmlPullParser.TEXT, parser.next());
164        assertEquals("d\ne", parser.getText());
165        assertEquals(XmlPullParser.END_TAG, parser.next());
166        assertEquals("foo", parser.getName());
167        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
168    }
169
170    public void testXmlDeclaration() throws Exception {
171        XmlPullParser parser = newPullParser();
172        parser.setInput(new StringReader(
173                "<?xml version='1.0' encoding='UTF-8' standalone='no'?><foo/>"));
174        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
175        assertEquals("1.0", parser.getProperty(
176                "http://xmlpull.org/v1/doc/properties.html#xmldecl-version"));
177        assertEquals(Boolean.FALSE, parser.getProperty(
178                "http://xmlpull.org/v1/doc/properties.html#xmldecl-standalone"));
179        assertEquals("UTF-8", parser.getInputEncoding());
180    }
181
182    public void testXmlDeclarationExtraAttributes() throws Exception {
183        assertParseFailure("<?xml version='1.0' encoding='UTF-8' standalone='no' a='b'?><foo/>");
184    }
185
186    public void testCustomEntitiesUsingNext() throws Exception {
187        XmlPullParser parser = newPullParser();
188        parser.setInput(new StringReader(
189                "<foo a='cd&aaaaaaaaaa;ef'>wx&aaaaaaaaaa;yz</foo>"));
190        parser.defineEntityReplacementText("aaaaaaaaaa", "b");
191        assertEquals(XmlPullParser.START_TAG, parser.next());
192        assertEquals("cdbef", parser.getAttributeValue(0));
193        assertEquals(XmlPullParser.TEXT, parser.next());
194        assertEquals("wxbyz", parser.getText());
195    }
196
197    public void testCustomEntitiesUsingNextToken() throws Exception {
198        XmlPullParser parser = newPullParser();
199        parser.setInput(new StringReader(
200                "<foo a='cd&aaaaaaaaaa;ef'>wx&aaaaaaaaaa;yz</foo>"));
201        parser.defineEntityReplacementText("aaaaaaaaaa", "b");
202        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
203        assertEquals("cdbef", parser.getAttributeValue(0));
204        assertEquals(XmlPullParser.TEXT, parser.nextToken());
205        assertEquals("wx", parser.getText());
206        assertEquals(XmlPullParser.ENTITY_REF, parser.nextToken());
207        assertEquals("aaaaaaaaaa", parser.getName());
208        assertEquals("b", parser.getText());
209        assertEquals(XmlPullParser.TEXT, parser.nextToken());
210        assertEquals("yz", parser.getText());
211    }
212
213    public void testCustomEntitiesAreNotEvaluated() throws Exception {
214        XmlPullParser parser = newPullParser();
215        parser.setInput(new StringReader(
216                "<foo a='&a;'>&a;</foo>"));
217        parser.defineEntityReplacementText("a", "&amp; &a;");
218        assertEquals(XmlPullParser.START_TAG, parser.next());
219        assertEquals("&amp; &a;", parser.getAttributeValue(0));
220        assertEquals(XmlPullParser.TEXT, parser.next());
221        assertEquals("&amp; &a;", parser.getText());
222    }
223
224    public void testMissingEntities() throws Exception {
225        assertParseFailure("<foo>&aaa;</foo>");
226    }
227
228    public void testMissingEntitiesWithRelaxed() throws Exception {
229        XmlPullParser parser = newPullParser();
230        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
231        parser.setInput(new StringReader("<foo>&aaa;</foo>"));
232        assertEquals(XmlPullParser.START_TAG, parser.next());
233        assertEquals(XmlPullParser.TEXT, parser.next());
234        assertEquals(null, parser.getName());
235        assertEquals("Expected unresolved entities to be left in-place. The old parser "
236                + "would resolve these to the empty string.", "&aaa;", parser.getText());
237        assertEquals(XmlPullParser.END_TAG, parser.next());
238    }
239
240    public void testMissingEntitiesUsingNextToken() throws Exception {
241        XmlPullParser parser = newPullParser();
242        testMissingEntitiesUsingNextToken(parser);
243    }
244
245    public void testMissingEntitiesUsingNextTokenWithRelaxed() throws Exception {
246        XmlPullParser parser = newPullParser();
247        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
248        testMissingEntitiesUsingNextToken(parser);
249    }
250
251    private void testMissingEntitiesUsingNextToken(XmlPullParser parser) throws Exception {
252        parser.setInput(new StringReader("<foo>&aaa;</foo>"));
253        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
254        assertEquals(XmlPullParser.ENTITY_REF, parser.nextToken());
255        assertEquals("aaa", parser.getName());
256        assertEquals(null, parser.getText());
257        assertEquals(XmlPullParser.END_TAG, parser.next());
258    }
259
260    public void testEntityInAttributeUsingNextToken() throws Exception {
261        XmlPullParser parser = newPullParser();
262        parser.setInput(new StringReader("<foo bar=\"&amp;\"></foo>"));
263        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
264        assertEquals("foo", parser.getName());
265        assertEquals("&", parser.getAttributeValue(null, "bar"));
266    }
267
268    public void testMissingEntitiesInAttributesUsingNext() throws Exception {
269        assertParseFailure("<foo b='&aaa;'></foo>");
270    }
271
272    public void testMissingEntitiesInAttributesUsingNextWithRelaxed() throws Exception {
273        XmlPullParser parser = newPullParser();
274        parser.setInput(new StringReader("<foo b='&aaa;'></foo>"));
275        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
276        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
277        assertEquals(1, parser.getAttributeCount());
278        assertEquals("b", parser.getAttributeName(0));
279        assertEquals("Expected unresolved entities to be left in-place. The old parser "
280                + "would resolve these to the empty string.", "&aaa;", parser.getAttributeValue(0));
281    }
282
283    public void testMissingEntitiesInAttributesUsingNextToken() throws Exception {
284        XmlPullParser parser = newPullParser();
285        parser.setInput(new StringReader("<foo b='&aaa;'></foo>"));
286        testMissingEntitiesInAttributesUsingNextToken(parser);
287    }
288
289    public void testMissingEntitiesInAttributesUsingNextTokenWithRelaxed() throws Exception {
290        XmlPullParser parser = newPullParser();
291        parser.setInput(new StringReader("<foo b='&aaa;'></foo>"));
292        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
293        testMissingEntitiesInAttributesUsingNextToken(parser);
294    }
295
296    private void testMissingEntitiesInAttributesUsingNextToken(XmlPullParser parser)
297            throws Exception {
298        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
299        assertEquals(1, parser.getAttributeCount());
300        assertEquals("b", parser.getAttributeName(0));
301        assertEquals("Expected unresolved entities to be left in-place. The old parser "
302                + "would resolve these to the empty string.", "&aaa;", parser.getAttributeValue(0));
303    }
304
305    public void testGreaterThanInText() throws Exception {
306        XmlPullParser parser = newPullParser();
307        parser.setInput(new StringReader("<foo>></foo>"));
308        assertEquals(XmlPullParser.START_TAG, parser.next());
309        assertEquals(XmlPullParser.TEXT, parser.next());
310        assertEquals(">", parser.getText());
311    }
312
313    public void testGreaterThanInAttribute() throws Exception{
314        XmlPullParser parser = newPullParser();
315        parser.setInput(new StringReader("<foo a='>'></foo>"));
316        assertEquals(XmlPullParser.START_TAG, parser.next());
317        assertEquals(">", parser.getAttributeValue(0));
318    }
319
320    public void testLessThanInText() throws Exception{
321        assertParseFailure("<foo><</foo>");
322    }
323
324    public void testLessThanInAttribute() throws Exception{
325        assertParseFailure("<foo a='<'></foo>");
326    }
327
328    public void testQuotesInAttribute() throws Exception{
329        XmlPullParser parser = newPullParser();
330        parser.setInput(new StringReader("<foo a='\"' b=\"'\"></foo>"));
331        assertEquals(XmlPullParser.START_TAG, parser.next());
332        assertEquals("\"", parser.getAttributeValue(0));
333        assertEquals("'", parser.getAttributeValue(1));
334    }
335
336    public void testQuotesInText() throws Exception{
337        XmlPullParser parser = newPullParser();
338        parser.setInput(new StringReader("<foo>\" '</foo>"));
339        assertEquals(XmlPullParser.START_TAG, parser.next());
340        assertEquals(XmlPullParser.TEXT, parser.next());
341        assertEquals("\" '", parser.getText());
342    }
343
344    public void testCdataDelimiterInAttribute() throws Exception{
345        XmlPullParser parser = newPullParser();
346        parser.setInput(new StringReader("<foo a=']]>'></foo>"));
347        assertEquals(XmlPullParser.START_TAG, parser.next());
348        assertEquals("]]>", parser.getAttributeValue(0));
349    }
350
351    public void testCdataDelimiterInText() throws Exception{
352        assertParseFailure("<foo>]]></foo>");
353    }
354
355    public void testUnexpectedEof() throws Exception {
356        assertParseFailure("<foo><![C");
357    }
358
359    public void testUnexpectedSequence() throws Exception {
360        assertParseFailure("<foo><![Cdata[bar]]></foo>");
361    }
362
363    public void testThreeDashCommentDelimiter() throws Exception {
364        assertParseFailure("<foo><!--a---></foo>");
365    }
366
367    public void testTwoDashesInComment() throws Exception {
368        assertParseFailure("<foo><!-- -- --></foo>");
369    }
370
371    public void testEmptyComment() throws Exception {
372        XmlPullParser parser = newPullParser();
373        parser.setInput(new StringReader("<foo><!----></foo>"));
374        assertEquals(XmlPullParser.START_TAG, parser.next());
375        assertEquals(XmlPullParser.COMMENT, parser.nextToken());
376        assertEquals("", parser.getText());
377    }
378
379    /**
380     * Close braces require lookaheads because we need to defend against "]]>".
381     */
382    public void testManyCloseBraces() throws Exception{
383        XmlPullParser parser = newPullParser();
384        parser.setInput(new StringReader("<foo>]]]]]]]]]]]]]]]]]]]]]]]</foo>"));
385        assertEquals(XmlPullParser.START_TAG, parser.next());
386        assertEquals(XmlPullParser.TEXT, parser.next());
387        assertEquals("]]]]]]]]]]]]]]]]]]]]]]]", parser.getText());
388    }
389
390    public void testCommentUsingNext() throws Exception {
391        XmlPullParser parser = newPullParser();
392        parser.setInput(new StringReader("<foo>ab<!-- comment! -->cd</foo>"));
393        assertEquals(XmlPullParser.START_TAG, parser.next());
394        assertEquals(XmlPullParser.TEXT, parser.next());
395        assertEquals("abcd", parser.getText());
396    }
397
398    public void testCommentUsingNextToken() throws Exception {
399        XmlPullParser parser = newPullParser();
400        parser.setInput(new StringReader("<foo>ab<!-- comment! -->cd</foo>"));
401        assertEquals(XmlPullParser.START_TAG, parser.next());
402        assertEquals(XmlPullParser.TEXT, parser.nextToken());
403        assertEquals("ab", parser.getText());
404        assertEquals(XmlPullParser.COMMENT, parser.nextToken());
405        assertEquals(" comment! ", parser.getText());
406        assertEquals(XmlPullParser.TEXT, parser.nextToken());
407        assertEquals("cd", parser.getText());
408    }
409
410    public void testCdataUsingNext() throws Exception {
411        XmlPullParser parser = newPullParser();
412        parser.setInput(new StringReader("<foo>ab<![CDATA[cdef]]gh&amp;i]]>jk</foo>"));
413        assertEquals(XmlPullParser.START_TAG, parser.next());
414        assertEquals(XmlPullParser.TEXT, parser.next());
415        assertEquals("abcdef]]gh&amp;ijk", parser.getText());
416        assertEquals(XmlPullParser.END_TAG, parser.next());
417    }
418
419    public void testCdataUsingNextToken() throws Exception {
420        XmlPullParser parser = newPullParser();
421        parser.setInput(new StringReader("<foo>ab<![CDATA[cdef]]gh&amp;i]]>jk</foo>"));
422        assertEquals(XmlPullParser.START_TAG, parser.next());
423        assertEquals(XmlPullParser.TEXT, parser.nextToken());
424        assertEquals("ab", parser.getText());
425        assertEquals(XmlPullParser.CDSECT, parser.nextToken());
426        assertEquals("cdef]]gh&amp;i", parser.getText());
427        assertEquals(XmlPullParser.TEXT, parser.nextToken());
428        assertEquals("jk", parser.getText());
429        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
430    }
431
432    public void testEntityLooksLikeCdataClose() throws Exception {
433        XmlPullParser parser = newPullParser();
434        parser.setInput(new StringReader("<foo>&#93;&#93;></foo>"));
435        assertEquals(XmlPullParser.START_TAG, parser.next());
436        assertEquals(XmlPullParser.TEXT, parser.next());
437        assertEquals("]]>", parser.getText());
438    }
439
440    public void testProcessingInstructionUsingNext() throws Exception {
441        XmlPullParser parser = newPullParser();
442        parser.setInput(new StringReader("<foo>ab<?cd efg hij?>kl</foo>"));
443        assertEquals(XmlPullParser.START_TAG, parser.next());
444        assertEquals(XmlPullParser.TEXT, parser.next());
445        assertEquals("abkl", parser.getText());
446        assertEquals(XmlPullParser.END_TAG, parser.next());
447    }
448
449    public void testProcessingInstructionUsingNextToken() throws Exception {
450        XmlPullParser parser = newPullParser();
451        parser.setInput(new StringReader("<foo>ab<?cd efg hij?>kl</foo>"));
452        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
453        assertEquals(XmlPullParser.TEXT, parser.nextToken());
454        assertEquals("ab", parser.getText());
455        assertEquals(XmlPullParser.PROCESSING_INSTRUCTION, parser.nextToken());
456        assertEquals("cd efg hij", parser.getText());
457        assertEquals(XmlPullParser.TEXT, parser.nextToken());
458        assertEquals("kl", parser.getText());
459        assertEquals(XmlPullParser.END_TAG, parser.next());
460    }
461
462    public void testWhitespaceUsingNextToken() throws Exception {
463        XmlPullParser parser = newPullParser();
464        parser.setInput(new StringReader("  \n  <foo> \n </foo>   \n   "));
465        assertEquals(XmlPullParser.IGNORABLE_WHITESPACE, parser.nextToken());
466        assertEquals(true, parser.isWhitespace());
467        assertEquals("  \n  ", parser.getText());
468        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
469        assertEquals(XmlPullParser.TEXT, parser.nextToken());
470        assertEquals(true, parser.isWhitespace());
471        assertEquals(" \n ", parser.getText());
472        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
473        assertEquals(XmlPullParser.IGNORABLE_WHITESPACE, parser.nextToken());
474        assertEquals(true, parser.isWhitespace());
475        assertEquals("   \n   ", parser.getText());
476        assertEquals(XmlPullParser.END_DOCUMENT, parser.nextToken());
477    }
478
479    public void testLinesAndColumns() throws Exception {
480        XmlPullParser parser = newPullParser();
481        parser.setInput(new StringReader("\n"
482                + "  <foo><bar a='\n"
483                + "' b='cde'></bar\n"
484                + "><!--\n"
485                + "\n"
486                + "--><baz/>fg\n"
487                + "</foo>"));
488        assertEquals("1,1", parser.getLineNumber() + "," + parser.getColumnNumber());
489        assertEquals(XmlPullParser.IGNORABLE_WHITESPACE, parser.nextToken());
490        assertEquals("2,3", parser.getLineNumber() + "," + parser.getColumnNumber());
491        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
492        assertEquals("2,8", parser.getLineNumber() + "," + parser.getColumnNumber());
493        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
494        assertEquals("3,11", parser.getLineNumber() + "," + parser.getColumnNumber());
495        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
496        assertEquals("4,2", parser.getLineNumber() + "," + parser.getColumnNumber());
497        assertEquals(XmlPullParser.COMMENT, parser.nextToken());
498        assertEquals("6,4", parser.getLineNumber() + "," + parser.getColumnNumber());
499        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
500        assertEquals("6,10", parser.getLineNumber() + "," + parser.getColumnNumber());
501        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
502        assertEquals("6,10", parser.getLineNumber() + "," + parser.getColumnNumber());
503        assertEquals(XmlPullParser.TEXT, parser.nextToken());
504        assertEquals("7,1", parser.getLineNumber() + "," + parser.getColumnNumber());
505        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
506        assertEquals("7,7", parser.getLineNumber() + "," + parser.getColumnNumber());
507        assertEquals(XmlPullParser.END_DOCUMENT, parser.nextToken());
508        assertEquals("7,7", parser.getLineNumber() + "," + parser.getColumnNumber());
509    }
510
511    public void testEmptyEntityReferenceUsingNext() throws Exception {
512        XmlPullParser parser = newPullParser();
513        parser.setInput(new StringReader("<foo>&empty;</foo>"));
514        parser.defineEntityReplacementText("empty", "");
515        assertEquals(XmlPullParser.START_TAG, parser.next());
516        assertEquals(XmlPullParser.END_TAG, parser.next());
517    }
518
519    public void testEmptyEntityReferenceUsingNextToken() throws Exception {
520        XmlPullParser parser = newPullParser();
521        parser.setInput(new StringReader("<foo>&empty;</foo>"));
522        parser.defineEntityReplacementText("empty", "");
523        assertEquals(XmlPullParser.START_TAG, parser.nextToken());
524        assertEquals(XmlPullParser.ENTITY_REF, parser.nextToken());
525        assertEquals("empty", parser.getName());
526        assertEquals("", parser.getText());
527        assertEquals(XmlPullParser.END_TAG, parser.nextToken());
528    }
529
530    public void testEmptyCdataUsingNext() throws Exception {
531        XmlPullParser parser = newPullParser();
532        parser.setInput(new StringReader("<foo><![CDATA[]]></foo>"));
533        assertEquals(XmlPullParser.START_TAG, parser.next());
534        assertEquals(XmlPullParser.END_TAG, parser.next());
535    }
536
537    public void testEmptyCdataUsingNextToken() throws Exception {
538        XmlPullParser parser = newPullParser();
539        parser.setInput(new StringReader("<foo><![CDATA[]]></foo>"));
540        assertEquals(XmlPullParser.START_TAG, parser.next());
541        assertEquals(XmlPullParser.CDSECT, parser.nextToken());
542        assertEquals("", parser.getText());
543        assertEquals(XmlPullParser.END_TAG, parser.next());
544    }
545
546    public void testParseReader() throws Exception {
547        String snippet = "<dagny dad=\"bob\">hello</dagny>";
548        XmlPullParser parser = newPullParser();
549        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
550        parser.setInput(new StringReader(snippet));
551        validate(parser);
552    }
553
554    public void testParseInputStream() throws Exception {
555        String snippet = "<dagny dad=\"bob\">hello</dagny>";
556        XmlPullParser parser = newPullParser();
557        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
558        parser.setInput(new ByteArrayInputStream(snippet.getBytes()), "UTF-8");
559        validate(parser);
560    }
561
562    static void validate(XmlPullParser parser) throws Exception {
563        assertEquals(XmlPullParser.START_DOCUMENT, parser.getEventType());
564        assertEquals(0, parser.getDepth());
565        assertEquals(XmlPullParser.START_TAG, parser.next());
566        assertEquals(1, parser.getDepth());
567        assertEquals("dagny", parser.getName());
568        assertEquals(1, parser.getAttributeCount());
569        assertEquals("dad", parser.getAttributeName(0));
570        assertEquals("bob", parser.getAttributeValue(0));
571        assertEquals("bob", parser.getAttributeValue(null, "dad"));
572        assertEquals(XmlPullParser.TEXT, parser.next());
573        assertEquals(1, parser.getDepth());
574        assertEquals("hello", parser.getText());
575        assertEquals(XmlPullParser.END_TAG, parser.next());
576        assertEquals(1, parser.getDepth());
577        assertEquals("dagny", parser.getName());
578        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
579        assertEquals(0, parser.getDepth());
580    }
581
582    public void testNextAfterEndDocument() throws Exception {
583        XmlPullParser parser = newPullParser();
584        parser.setInput(new StringReader("<foo></foo>"));
585        assertEquals(XmlPullParser.START_TAG, parser.next());
586        assertEquals(XmlPullParser.END_TAG, parser.next());
587        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
588        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
589    }
590
591    public void testNamespaces() throws Exception {
592        String xml = "<one xmlns='ns:default' xmlns:n1='ns:1' a='b'>\n"
593                + "  <n1:two c='d' n1:e='f' xmlns:n2='ns:2'>text</n1:two>\n"
594                + "</one>";
595
596        XmlPullParser parser = newPullParser();
597        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
598        parser.setInput(new StringReader(xml));
599
600        assertEquals(0, parser.getDepth());
601        assertEquals(0, parser.getNamespaceCount(0));
602
603        try {
604            parser.getNamespaceCount(1);
605            fail();
606        } catch (IndexOutOfBoundsException e) { /* expected */ }
607
608        // one
609        assertEquals(XmlPullParser.START_TAG, parser.next());
610        assertEquals(1, parser.getDepth());
611
612        checkNamespacesInOne(parser);
613
614        // n1:two
615        assertEquals(XmlPullParser.START_TAG, parser.nextTag());
616
617        assertEquals(2, parser.getDepth());
618        checkNamespacesInTwo(parser);
619
620        // Body of two.
621        assertEquals(XmlPullParser.TEXT, parser.next());
622
623        // End of two.
624        assertEquals(XmlPullParser.END_TAG, parser.nextTag());
625
626        // Depth should still be 2.
627        assertEquals(2, parser.getDepth());
628
629        // We should still be able to see the namespaces from two.
630        checkNamespacesInTwo(parser);
631
632        // End of one.
633        assertEquals(XmlPullParser.END_TAG, parser.nextTag());
634
635        // Depth should be back to 1.
636        assertEquals(1, parser.getDepth());
637
638        // We can still see the namespaces in one.
639        checkNamespacesInOne(parser);
640
641        // We shouldn't be able to see the namespaces in two anymore.
642        try {
643            parser.getNamespaceCount(2);
644            fail();
645        } catch (IndexOutOfBoundsException e) { /* expected */ }
646
647        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
648
649        // We shouldn't be able to see the namespaces in one anymore.
650        try {
651            parser.getNamespaceCount(1);
652            fail();
653        } catch (IndexOutOfBoundsException e) { /* expected */ }
654
655        assertEquals(0, parser.getNamespaceCount(0));
656    }
657
658    private void checkNamespacesInOne(XmlPullParser parser) throws XmlPullParserException {
659        assertEquals(2, parser.getNamespaceCount(1));
660
661        // Prefix for default namespace is null.
662        assertNull(parser.getNamespacePrefix(0));
663        assertEquals("ns:default", parser.getNamespaceUri(0));
664
665        assertEquals("n1", parser.getNamespacePrefix(1));
666        assertEquals("ns:1", parser.getNamespaceUri(1));
667
668        assertEquals("ns:default", parser.getNamespace(null));
669
670        // KXML returns null.
671        // assertEquals("ns:default", parser.getNamespace(""));
672    }
673
674    private void checkNamespacesInTwo(XmlPullParser parser) throws XmlPullParserException {
675        // These should still be valid.
676        checkNamespacesInOne(parser);
677
678        assertEquals(3, parser.getNamespaceCount(2));
679
680        // Default ns should still be in the stack
681        assertNull(parser.getNamespacePrefix(0));
682        assertEquals("ns:default", parser.getNamespaceUri(0));
683    }
684
685    public void testTextBeforeDocumentElement() throws Exception {
686        assertParseFailure("not xml<foo/>");
687    }
688
689    public void testTextAfterDocumentElement() throws Exception {
690        assertParseFailure("<foo/>not xml");
691    }
692
693    public void testTextNoDocumentElement() throws Exception {
694        assertParseFailure("not xml");
695    }
696
697    public void testBomAndByteInput() throws Exception {
698        byte[] xml = "\ufeff<?xml version='1.0'?><input/>".getBytes("UTF-8");
699        XmlPullParser parser = newPullParser();
700        parser.setInput(new ByteArrayInputStream(xml), null);
701        assertEquals(XmlPullParser.START_TAG, parser.next());
702        assertEquals("input", parser.getName());
703        assertEquals(XmlPullParser.END_TAG, parser.next());
704        assertEquals("input", parser.getName());
705        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
706    }
707
708    public void testBomAndByteInputWithExplicitCharset() throws Exception {
709        byte[] xml = "\ufeff<?xml version='1.0'?><input/>".getBytes("UTF-8");
710        XmlPullParser parser = newPullParser();
711        parser.setInput(new ByteArrayInputStream(xml), "UTF-8");
712        assertEquals(XmlPullParser.START_TAG, parser.next());
713        assertEquals("input", parser.getName());
714        assertEquals(XmlPullParser.END_TAG, parser.next());
715        assertEquals("input", parser.getName());
716        assertEquals(XmlPullParser.END_DOCUMENT, parser.next());
717    }
718
719    public void testBomAndCharacterInput() throws Exception {
720        assertParseFailure("\ufeff<?xml version='1.0'?><input/>");
721    }
722
723    // http://code.google.com/p/android/issues/detail?id=21425
724    public void testNextTextAdvancesToEndTag() throws Exception {
725        XmlPullParser parser = newPullParser();
726        parser.setInput(new StringReader("<foo>bar</foo>"));
727        assertEquals(XmlPullParser.START_TAG, parser.next());
728        assertEquals("bar", parser.nextText());
729        assertEquals(XmlPullParser.END_TAG, parser.getEventType());
730    }
731
732    public void testNextTag() throws Exception {
733        XmlPullParser parser = newPullParser();
734        parser.setInput(new StringReader("<foo> <bar></bar> </foo>"));
735        assertEquals(XmlPullParser.START_TAG, parser.nextTag());
736        assertEquals("foo", parser.getName());
737        assertEquals(XmlPullParser.START_TAG, parser.nextTag());
738        assertEquals("bar", parser.getName());
739        assertEquals(XmlPullParser.END_TAG, parser.nextTag());
740        assertEquals("bar", parser.getName());
741        assertEquals(XmlPullParser.END_TAG, parser.nextTag());
742        assertEquals("foo", parser.getName());
743    }
744
745    public void testEofInElementSpecRelaxed() throws Exception {
746        assertRelaxedParseFailure("<!DOCTYPE foo [<!ELEMENT foo (unterminated");
747    }
748
749    public void testEofInAttributeValue() throws Exception {
750        assertParseFailure("<!DOCTYPE foo [<!ATTLIST foo x y \"unterminated");
751    }
752
753    public void testEofInEntityValue() throws Exception {
754        assertParseFailure("<!DOCTYPE foo [<!ENTITY aaa \"unterminated");
755    }
756
757    public void testEofInStartTagAttributeValue() throws Exception {
758        assertParseFailure("<long foo=\"unterminated");
759    }
760
761    public void testEofInReadCharRelaxed() throws Exception {
762        assertRelaxedParseFailure("<!DOCTYPE foo [<!ELEMENT foo ()"); // EOF in read('>')
763    }
764
765    public void testEofAfterReadCharArrayRelaxed() throws Exception {
766        assertRelaxedParseFailure("<!DOCTYPE foo [<!ELEMENT foo EMPTY"); // EOF in read('>')
767    }
768
769    private void assertParseFailure(String xml) throws Exception {
770        XmlPullParser parser = newPullParser();
771        assertParseFailure(xml, parser);
772    }
773
774    private void assertRelaxedParseFailure(String xml) throws Exception {
775        XmlPullParser parser = newPullParser();
776        parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true);
777        assertParseFailure(xml, parser);
778    }
779
780    private void assertParseFailure(String xml, XmlPullParser parser) throws Exception {
781        parser.setInput(new StringReader(xml));
782        try {
783            while (parser.next() != XmlPullParser.END_DOCUMENT) {
784            }
785            fail();
786        } catch (XmlPullParserException expected) {
787        }
788    }
789
790    /**
791     * Creates a new pull parser.
792     */
793    abstract XmlPullParser newPullParser();
794}
795