1 15 package org.apache.tapestry.junit.parse; 16 17 import java.io.IOException ; 18 import java.io.InputStream ; 19 import java.io.InputStreamReader ; 20 import java.util.HashMap ; 21 import java.util.Map ; 22 23 import junit.framework.TestCase; 24 25 import org.apache.hivemind.Location; 26 import org.apache.hivemind.Resource; 27 import org.apache.hivemind.impl.DefaultClassResolver; 28 import org.apache.hivemind.util.ClasspathResource; 29 import org.apache.tapestry.parse.ITemplateParserDelegate; 30 import org.apache.tapestry.parse.LocalizationToken; 31 import org.apache.tapestry.parse.OpenToken; 32 import org.apache.tapestry.parse.TemplateParseException; 33 import org.apache.tapestry.parse.TemplateParser; 34 import org.apache.tapestry.parse.TemplateToken; 35 import org.apache.tapestry.parse.TemplateTokenFactory; 36 import org.apache.tapestry.parse.TextToken; 37 import org.apache.tapestry.parse.TokenType; 38 39 44 45 public class TestTemplateParser extends TestCase 46 { 47 private static class ParserDelegate implements ITemplateParserDelegate 48 { 49 private final String _componentAttributeName; 50 51 public ParserDelegate() 52 { 53 this("jwcid"); 54 } 55 56 public ParserDelegate(String componentAttributeName) 57 { 58 _componentAttributeName = componentAttributeName; 59 } 60 61 public boolean getKnownComponent(String componentId) 62 { 63 return true; 64 } 65 66 public boolean getAllowBody(String componentId, Location location) 67 { 68 return true; 69 } 70 71 public boolean getAllowBody(String libraryId, String type, Location location) 72 { 73 return true; 74 } 75 76 public String getComponentAttributeName() 77 { 78 return _componentAttributeName; 79 } 80 } 81 82 protected TemplateToken[] run(char[] templateData, ITemplateParserDelegate delegate, 83 Resource location) throws TemplateParseException 84 { 85 TemplateParser parser = new TemplateParser(); 86 87 parser.setFactory(new TemplateTokenFactory()); 88 89 return parser.parse(templateData, delegate, location); 90 } 91 92 protected TemplateToken[] run(InputStream stream, ITemplateParserDelegate delegate, 93 Resource location) throws TemplateParseException 94 { 95 StringBuffer buffer = new StringBuffer (); 96 char[] block = new char[1000]; 97 InputStreamReader reader = new InputStreamReader (stream); 98 99 try 100 { 101 while (true) 102 { 103 int count = reader.read(block, 0, block.length); 104 105 if (count < 0) 106 break; 107 108 buffer.append(block, 0, count); 109 } 110 111 reader.close(); 112 } 113 catch (IOException ex) 114 { 115 fail("Unable to read from stream."); 116 } 117 118 return run(buffer.toString().toCharArray(), delegate, location); 119 } 120 121 protected TemplateToken[] run(String file) throws TemplateParseException 122 { 123 return run(file, new ParserDelegate()); 124 } 125 126 protected TemplateToken[] run(String file, ITemplateParserDelegate delegate) 127 throws TemplateParseException 128 { 129 String thisClassName = getClass().getName(); 130 String thisPath = "/" + thisClassName.replace('.', '/') + "/" + file; 131 132 Resource location = new ClasspathResource(new DefaultClassResolver(), thisPath); 133 134 InputStream stream = getClass().getResourceAsStream(file); 135 136 if (stream == null) 137 throw new TemplateParseException("File " + file + " not found."); 138 139 return run(stream, delegate, location); 140 } 141 142 private Map buildMap(String [] input) 143 { 144 Map result = new HashMap (); 145 146 for (int i = 0; i < input.length; i += 2) 147 result.put(input[i], input[i + 1]); 148 149 return result; 150 } 151 152 155 protected void assertTextToken(TemplateToken token, int startIndex, int endIndex) 156 { 157 TextToken t = (TextToken) token; 158 159 int expectedLength = endIndex - startIndex + 1; 160 161 assertEquals("Text token type.", TokenType.TEXT, t.getType()); 162 assertEquals("Text token start index.", startIndex, t.getOffset()); 163 assertEquals("Text token end index.", expectedLength, t.getLength()); 164 } 165 166 167 168 protected void checkLine(TemplateToken token, int line) 169 { 170 assertEquals("Token line", line, token.getLocation().getLineNumber()); 171 } 172 173 174 175 protected void assertLocalizationToken(TemplateToken token, String key, Map attributes, int line) 176 { 177 LocalizationToken t = (LocalizationToken) token; 178 179 assertEquals("Localization token type.", TokenType.LOCALIZATION, t.getType()); 180 assertEquals("Localization key.", key, t.getKey()); 181 182 assertEquals("Localization attributes.", attributes, t.getAttributes()); 183 184 checkLine(token, line); 185 } 186 187 protected void assertOpenToken(TemplateToken token, String id, String tag, int line) 188 { 189 assertOpenToken(token, id, null, tag, line); 190 } 191 192 protected void assertOpenToken(TemplateToken token, String id, String componentType, 193 String tag, int line) 194 { 195 OpenToken t = (OpenToken) token; 196 197 assertEquals("Open token type", TokenType.OPEN, t.getType()); 198 assertEquals("Open token id", id, t.getId()); 199 assertEquals("Open token component type", componentType, t.getComponentType()); 200 assertEquals("Open token tag", tag, t.getTag()); 201 202 checkLine(token, line); 203 } 204 205 protected void assertTemplateAttributes(TemplateToken token, Map expected) 206 { 207 OpenToken t = (OpenToken) token; 208 209 assertEquals("Attributes", expected, t.getAttributesMap()); 210 } 211 212 protected void assertCloseToken(TemplateToken token, int line) 213 { 214 assertEquals("Close token type.", TokenType.CLOSE, token.getType()); 215 216 checkLine(token, line); 217 } 218 219 protected void assertTokenCount(TemplateToken[] tokens, int count) 220 { 221 assertNotNull("Parsed tokens.", tokens); 222 assertEquals("Parsed token count.", count, tokens.length); 223 } 224 225 private void runFailure(String file, String message) 226 { 227 runFailure(file, new ParserDelegate(), message); 228 } 229 230 private void runFailure(String file, ITemplateParserDelegate delegate, String message) 231 { 232 try 233 { 234 run(file, delegate); 235 236 fail("Invalid document " + file + " parsed without exception."); 237 } 238 catch (TemplateParseException ex) 239 { 240 assertEquals(message, ex.getMessage()); 241 assertTrue(ex.getLocation().toString().indexOf(file) > 0); 242 } 243 } 244 245 public void testAllStatic() throws TemplateParseException 246 { 247 TemplateToken[] tokens = run("AllStatic.html"); 248 249 assertTokenCount(tokens, 1); 250 assertTextToken(tokens[0], 0, 172); 251 } 252 253 public void testSingleEmptyTag() throws TemplateParseException 254 { 255 TemplateToken[] tokens = run("SingleEmptyTag.html"); 256 257 assertTokenCount(tokens, 4); 258 259 assertTextToken(tokens[0], 0, 38); 260 assertOpenToken(tokens[1], "emptyTag", "span", 3); 261 assertCloseToken(tokens[2], 3); 262 assertTextToken(tokens[3], 63, 102); 263 } 264 265 public void testSimpleNested() throws TemplateParseException 266 { 267 TemplateToken[] tokens = run("SimpleNested.html"); 268 269 assertTokenCount(tokens, 8); 270 assertOpenToken(tokens[1], "outer", "span", 3); 271 assertOpenToken(tokens[3], "inner", "span", 4); 272 assertCloseToken(tokens[4], 4); 273 assertCloseToken(tokens[6], 5); 274 } 275 276 public void testMixedNesting() throws TemplateParseException 277 { 278 TemplateToken[] tokens = run("MixedNesting.html"); 279 280 assertTokenCount(tokens, 5); 281 assertOpenToken(tokens[1], "row", "span", 4); 282 assertCloseToken(tokens[3], 7); 283 } 284 285 public void testSingleQuotes() throws TemplateParseException 286 { 287 TemplateToken[] tokens = run("SingleQuotes.html"); 288 289 assertTokenCount(tokens, 7); 290 assertOpenToken(tokens[1], "first", "span", 5); 291 assertOpenToken(tokens[4], "second", "span", 7); 292 } 293 294 public void testComplex() throws TemplateParseException 295 { 296 TemplateToken[] tokens = run("Complex.html"); 297 298 assertTokenCount(tokens, 19); 299 300 302 assertOpenToken(tokens[1], "ifData", "span", 3); 303 assertOpenToken(tokens[3], "e", "span", 10); 304 assertOpenToken(tokens[5], "row", "tr", 11); 305 } 306 307 public void testStartWithStaticTag() throws TemplateParseException 308 { 309 TemplateToken[] tokens = run("StartWithStaticTag.html"); 310 311 assertTokenCount(tokens, 4); 312 assertTextToken(tokens[0], 0, 232); 313 assertOpenToken(tokens[1], "justBecause", "span", 9); 314 } 315 316 public void testUnterminatedCommentFailure() 317 { 318 runFailure("UnterminatedComment.html", "Comment on line 3 did not end."); 319 } 320 321 public void testUnclosedOpenTagFailure() 322 { 323 runFailure("UnclosedOpenTag.html", "Tag <body> on line 4 is never closed."); 324 } 325 326 public void testMissingAttributeValueFailure() 327 { 328 runFailure( 329 "MissingAttributeValue.html", 330 "Tag <img> on line 9 is missing a value for attribute src."); 331 } 332 333 public void testIncompleteCloseFailure() 334 { 335 runFailure("IncompleteClose.html", "Incomplete close tag on line 6."); 336 } 337 338 public void testMismatchedCloseTagsFailure() 339 { 340 runFailure( 341 "MismatchedCloseTags.html", 342 "Closing tag </th> on line 9 does not have a matching open tag."); 343 } 344 345 public void testInvalidDynamicNestingFailure() 346 { 347 runFailure( 348 "InvalidDynamicNesting.html", 349 "Closing tag </body> on line 12 is improperly nested with tag <span> on line 8."); 350 } 351 352 public void testUnknownComponentIdFailure() 353 { 354 ITemplateParserDelegate delegate = new ITemplateParserDelegate() 355 { 356 public boolean getKnownComponent(String componentId) 357 { 358 return !componentId.equals("row"); 359 } 360 361 public boolean getAllowBody(String componentId, Location location) 362 { 363 return true; 364 } 365 366 public boolean getAllowBody(String libraryId, String type, Location location) 367 { 368 return true; 369 } 370 371 public String getComponentAttributeName() 372 { 373 return "jwcid"; 374 } 375 }; 376 377 runFailure( 378 "Complex.html", 379 delegate, 380 "Tag <tr> on line 11 references unknown component id 'row'."); 381 } 382 383 public void testBasicRemove() throws TemplateParseException 384 { 385 TemplateToken[] tokens = run("BasicRemove.html"); 386 387 assertTokenCount(tokens, 10); 388 assertTextToken(tokens[0], 0, 119); 389 assertTextToken(tokens[1], 188, 268); 390 assertOpenToken(tokens[2], "e", "span", 23); 391 assertTextToken(tokens[3], 341, 342); 392 assertOpenToken(tokens[4], "row", "tr", 24); 393 assertTextToken(tokens[5], 359, 377); 394 assertCloseToken(tokens[6], 26); 395 assertTextToken(tokens[7], 383, 383); 396 assertCloseToken(tokens[8], 27); 397 assertTextToken(tokens[9], 391, 401); 398 } 399 400 public void testBodyRemove() throws TemplateParseException 401 { 402 ITemplateParserDelegate delegate = new ITemplateParserDelegate() 403 { 404 public boolean getKnownComponent(String id) 405 { 406 return true; 407 } 408 409 public boolean getAllowBody(String id, Location location) 410 { 411 return id.equals("form"); 412 } 413 414 public boolean getAllowBody(String libraryId, String type, Location location) 415 { 416 return true; 417 } 418 419 public String getComponentAttributeName() 420 { 421 return "jwcid"; 422 } 423 }; 424 425 TemplateToken[] tokens = run("BodyRemove.html", delegate); 426 427 assertTokenCount(tokens, 8); 428 assertOpenToken(tokens[1], "form", "form", 9); 429 assertOpenToken(tokens[3], "inputType", "select", 11); 430 assertCloseToken(tokens[4], 15); 431 assertCloseToken(tokens[6], 16); 432 } 433 434 public void testRemovedComponentFailure() 435 { 436 runFailure( 437 "RemovedComponent.html", 438 "Tag <span> on line 5 is a dynamic component, and may not appear inside an ignored block."); 439 } 440 441 public void testNestedRemoveFailure() 442 { 443 runFailure( 444 "NestedRemove.html", 445 "Tag <span> on line 4 should be ignored, but is already inside " 446 + "an ignored block (ignored blocks may not be nested)."); 447 } 448 449 public void testBasicContent() throws TemplateParseException 450 { 451 TemplateToken[] tokens = run("BasicContent.html"); 452 453 assertTokenCount(tokens, 4); 454 assertTextToken(tokens[0], 108, 165); 455 assertOpenToken(tokens[1], "nested", "span", 9); 456 assertCloseToken(tokens[2], 9); 457 assertTextToken(tokens[3], 188, 192); 458 } 459 460 public void testIgnoredContentFailure() 461 { 462 runFailure( 463 "IgnoredContent.html", 464 "Tag <td> on line 7 is the template content, and may not be in an ignored block."); 465 } 466 467 public void testTagAttributes() throws TemplateParseException 468 { 469 TemplateToken[] tokens = run("TagAttributes.html"); 470 471 assertTokenCount(tokens, 5); 472 assertOpenToken(tokens[1], "tag", null, "span", 3); 473 474 assertTemplateAttributes(tokens[1], buildMap(new String [] 475 { "class", "zip", "align", "right", "color", "#ff00ff" })); 476 477 } 478 479 482 483 public void testBasicLocalization() throws TemplateParseException 484 { 485 TemplateToken[] tokens = run("BasicLocalization.html"); 486 487 assertTokenCount(tokens, 3); 488 assertTextToken(tokens[0], 0, 35); 489 assertLocalizationToken(tokens[1], "the.localization.key", null, 3); 490 assertTextToken(tokens[2], 89, 117); 491 } 492 493 498 499 public void testComponentInsideLocalization() 500 { 501 runFailure( 502 "ComponentInsideLocalization.html", 503 "Tag <span> on line 9 is a dynamic component, and may not appear inside an ignored block."); 504 } 505 506 512 513 public void testNestedLocalizations() 514 { 515 runFailure( 516 "NestedLocalizations.html", 517 "Tag <span> on line 4 is a dynamic component, and may not appear inside an ignored block."); 518 } 519 520 525 526 public void testEmptyLocalization() throws TemplateParseException 527 { 528 TemplateToken[] tokens = run("EmptyLocalization.html"); 529 530 assertTokenCount(tokens, 3); 531 assertTextToken(tokens[0], 0, 62); 532 assertLocalizationToken(tokens[1], "empty.localization", null, 3); 533 assertTextToken(tokens[2], 97, 122); 534 } 535 536 542 543 public void testLocalizationAttributes() throws TemplateParseException 544 { 545 TemplateToken[] tokens = run("LocalizationAttributes.html"); 546 547 Map attributes = buildMap(new String [] 548 { "alpha", "beta", "Fred", "Wilma" }); 549 550 assertLocalizationToken(tokens[1], "localization.with.attributes", attributes, 3); 551 } 552 553 558 559 public void testImplicitComponents() throws TemplateParseException 560 { 561 TemplateToken[] tokens = run("ImplicitComponents.html"); 562 563 assertTokenCount(tokens, 18); 564 565 assertOpenToken(tokens[1], "$Body", "Body", "body", 4); 566 assertOpenToken(tokens[3], "loop", "Foreach", "tr", 7); 567 568 assertTemplateAttributes(tokens[3], buildMap(new String [] 569 { "element", "tr", "source", "ognl:items" })); 570 571 assertOpenToken(tokens[5], "$Insert", "Insert", "span", 10); 572 573 assertTemplateAttributes(tokens[5], buildMap(new String [] 574 { "value", "ognl:components.loop.value.name" })); 575 576 assertOpenToken(tokens[8], "$Insert$0", "Insert", "span", 11); 577 578 assertTemplateAttributes(tokens[8], buildMap(new String [] 579 { "value", "ognl:components.loop.value.price" })); 580 581 assertOpenToken(tokens[13], "$InspectorButton", "contrib:InspectorButton", "span", 15); 582 } 583 584 589 590 public void testEncodedExpressionCharacters() throws TemplateParseException 591 { 592 TemplateToken[] tokens = run("EncodedExpressionCharacters.html"); 593 594 assertTokenCount(tokens, 3); 595 596 assertOpenToken(tokens[0], "$Insert", "Insert", "span", 1); 597 598 String expression = "ognl: { \"<&>\", \"Fun!\" }"; 599 600 assertTemplateAttributes(tokens[0], buildMap(new String [] 601 { "value", expression })); 602 603 } 604 605 608 609 public void testStringAttributes() throws TemplateParseException 610 { 611 TemplateToken[] tokens = run("StringAttributes.html"); 612 613 assertTokenCount(tokens, 4); 614 615 assertOpenToken(tokens[1], "$Image", "Image", "img", 2); 616 617 assertTemplateAttributes(tokens[1], buildMap(new String [] 618 { "image", "ognl:assets.logo", "alt", "message:logo-title" })); 619 620 } 621 622 627 628 public void testOverrideDefaultAttributeName() throws Exception 629 { 630 TemplateToken[] tokens = run("OverrideDefaultAttributeName.html", new ParserDelegate("id")); 631 632 assertTokenCount(tokens, 8); 633 assertOpenToken(tokens[1], "outer", "span", 3); 634 assertOpenToken(tokens[3], "inner", "span", 4); 635 assertCloseToken(tokens[4], 4); 636 assertCloseToken(tokens[6], 5); 637 } 638 639 643 644 public void testNamespaceAttributeName() throws Exception 645 { 646 TemplateToken[] tokens = run("NamespaceAttributeName.html", new ParserDelegate("t:id")); 647 648 assertTokenCount(tokens, 8); 649 assertOpenToken(tokens[1], "outer", "span", 3); 650 assertOpenToken(tokens[3], "inner", "span", 4); 651 assertCloseToken(tokens[4], 4); 652 assertCloseToken(tokens[6], 5); 653 } 654 } | Popular Tags |