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>A</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>� &#-2147483648;</foo>"); 102 } 103 104 public void testNumericEntitiesLargerThanInt() throws Exception { 105 assertParseFailure("<foo>�</foo>"); 106 } 107 108 public void testCharacterReferenceOfHexUtf16Surrogates() throws Exception { 109 testCharacterReferenceOfUtf16Surrogates("<foo>𐀀 𐎁 􏿰</foo>"); 110 } 111 112 public void testCharacterReferenceOfDecimalUtf16Surrogates() throws Exception { 113 testCharacterReferenceOfUtf16Surrogates("<foo>𐀀 𐎁 􏿰</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></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", "& &a;"); 218 assertEquals(XmlPullParser.START_TAG, parser.next()); 219 assertEquals("& &a;", parser.getAttributeValue(0)); 220 assertEquals(XmlPullParser.TEXT, parser.next()); 221 assertEquals("& &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=\"&\"></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&i]]>jk</foo>")); 413 assertEquals(XmlPullParser.START_TAG, parser.next()); 414 assertEquals(XmlPullParser.TEXT, parser.next()); 415 assertEquals("abcdef]]gh&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&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&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>]]></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>∅</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>∅</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 public void testWhitespacesAfterDOCTYPE() throws Exception { 770 XmlPullParser parser = newPullParser(); 771 String test = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 772 "<!DOCTYPE root [\n" + 773 "<!ENTITY dummy \"dummy\">\n" + 774 "]> \n" + 775 "<root></root>"; 776 assertParseSuccess(test, parser); 777 } 778 779 // Regression test for https://code.google.com/p/android/issues/detail?id=182605 780 public void testSetInputParserReuse() throws Exception { 781 XmlPullParser parser = newPullParser(); 782 String test = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 783 "<!DOCTYPE root [\n" + 784 "<!ENTITY dummy \"dummy\">\n" + 785 "]> \n" + 786 "<root></root>"; 787 assertParseSuccess(test, parser); 788 789 // A second call to parser.setInput() on a parser should result in a fully-reset parser. 790 assertParseSuccess(test, parser); 791 } 792 793 private void assertParseFailure(String xml) throws Exception { 794 XmlPullParser parser = newPullParser(); 795 assertParseFailure(xml, parser); 796 } 797 798 private void assertRelaxedParseFailure(String xml) throws Exception { 799 XmlPullParser parser = newPullParser(); 800 parser.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed", true); 801 assertParseFailure(xml, parser); 802 } 803 804 private void assertParseFailure(String xml, XmlPullParser parser) throws Exception { 805 parser.setInput(new StringReader(xml)); 806 try { 807 while (parser.next() != XmlPullParser.END_DOCUMENT) { 808 } 809 fail(); 810 } catch (XmlPullParserException expected) { 811 } 812 } 813 814 private void assertParseSuccess(String xml, XmlPullParser parser) throws Exception { 815 parser.setInput(new StringReader(xml)); 816 while (parser.next() != XmlPullParser.END_DOCUMENT) { 817 } 818 } 819 820 /** 821 * Creates a new pull parser. 822 */ 823 abstract XmlPullParser newPullParser(); 824} 825