KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tapestry > junit > parse > TestTemplateParser


1 // Copyright 2004, 2005 The Apache Software Foundation
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15 package org.apache.tapestry.junit.parse;
16
17 import java.io.IOException JavaDoc;
18 import java.io.InputStream JavaDoc;
19 import java.io.InputStreamReader JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Map JavaDoc;
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 /**
40  * Tests for the Tapestry HTML template parser.
41  *
42  * @author Howard Lewis Ship
43  */

44
45 public class TestTemplateParser extends TestCase
46 {
47     private static class ParserDelegate implements ITemplateParserDelegate
48     {
49         private final String JavaDoc _componentAttributeName;
50
51         public ParserDelegate()
52         {
53             this("jwcid");
54         }
55
56         public ParserDelegate(String JavaDoc componentAttributeName)
57         {
58             _componentAttributeName = componentAttributeName;
59         }
60
61         public boolean getKnownComponent(String JavaDoc componentId)
62         {
63             return true;
64         }
65
66         public boolean getAllowBody(String JavaDoc componentId, Location location)
67         {
68             return true;
69         }
70
71         public boolean getAllowBody(String JavaDoc libraryId, String JavaDoc type, Location location)
72         {
73             return true;
74         }
75
76         public String JavaDoc 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 JavaDoc stream, ITemplateParserDelegate delegate,
93             Resource location) throws TemplateParseException
94     {
95         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
96         char[] block = new char[1000];
97         InputStreamReader JavaDoc reader = new InputStreamReader JavaDoc(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 JavaDoc 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 JavaDoc file) throws TemplateParseException
122     {
123         return run(file, new ParserDelegate());
124     }
125
126     protected TemplateToken[] run(String JavaDoc file, ITemplateParserDelegate delegate)
127             throws TemplateParseException
128     {
129         String JavaDoc thisClassName = getClass().getName();
130         String JavaDoc thisPath = "/" + thisClassName.replace('.', '/') + "/" + file;
131
132         Resource location = new ClasspathResource(new DefaultClassResolver(), thisPath);
133
134         InputStream JavaDoc 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 JavaDoc buildMap(String JavaDoc[] input)
143     {
144         Map JavaDoc result = new HashMap JavaDoc();
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     // Note: the API of TextToken changed ... from startIndex/endIndex to offset/length.
153
// Rather than change *all* the tests, we'll just adjust here.
154

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     /** @since 3.0 * */
167
168     protected void checkLine(TemplateToken token, int line)
169     {
170         assertEquals("Token line", line, token.getLocation().getLineNumber());
171     }
172
173     /** @since 2.0.4 * */
174
175     protected void assertLocalizationToken(TemplateToken token, String JavaDoc key, Map JavaDoc 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 JavaDoc id, String JavaDoc tag, int line)
188     {
189         assertOpenToken(token, id, null, tag, line);
190     }
191
192     protected void assertOpenToken(TemplateToken token, String JavaDoc id, String JavaDoc componentType,
193             String JavaDoc 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 JavaDoc 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 JavaDoc file, String JavaDoc message)
226     {
227         runFailure(file, new ParserDelegate(), message);
228     }
229
230     private void runFailure(String JavaDoc file, ITemplateParserDelegate delegate, String JavaDoc 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         // Just pick a few highlights out of it.
301

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 JavaDoc componentId)
357             {
358                 return !componentId.equals("row");
359             }
360
361             public boolean getAllowBody(String JavaDoc componentId, Location location)
362             {
363                 return true;
364             }
365
366             public boolean getAllowBody(String JavaDoc libraryId, String JavaDoc type, Location location)
367             {
368                 return true;
369             }
370
371             public String JavaDoc 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 JavaDoc id)
405             {
406                 return true;
407             }
408
409             public boolean getAllowBody(String JavaDoc id, Location location)
410             {
411                 return id.equals("form");
412             }
413
414             public boolean getAllowBody(String JavaDoc libraryId, String JavaDoc type, Location location)
415             {
416                 return true;
417             }
418
419             public String JavaDoc 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 JavaDoc[]
475         { "class", "zip", "align", "right", "color", "#ff00ff" }));
476
477     }
478
479     /**
480      * @since 2.0.4
481      */

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     /**
494      * Test that the parser fails if a localization block contains a component.
495      *
496      * @since 2.0.4
497      */

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     /**
507      * Test that the parser fails if an invisible localization is nested within another invisible
508      * localization.
509      *
510      * @since 2.0.4
511      */

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     /**
521      * Test that the abbreviated form (a tag with no body) works.
522      *
523      * @since 2.0.4
524      */

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     /**
537      * Test attributes in the span. Also, checks that the parser caselessly identifies the "key"
538      * attribute and the tag name ("span").
539      *
540      * @since 2.0.4
541      */

542
543     public void testLocalizationAttributes() throws TemplateParseException
544     {
545         TemplateToken[] tokens = run("LocalizationAttributes.html");
546
547         Map JavaDoc attributes = buildMap(new String JavaDoc[]
548         { "alpha", "beta", "Fred", "Wilma" });
549
550         assertLocalizationToken(tokens[1], "localization.with.attributes", attributes, 3);
551     }
552
553     /**
554      * Tests for implicit components (both named and anonymous).
555      *
556      * @since 3.0
557      */

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 JavaDoc[]
569         { "element", "tr", "source", "ognl:items" }));
570
571         assertOpenToken(tokens[5], "$Insert", "Insert", "span", 10);
572
573         assertTemplateAttributes(tokens[5], buildMap(new String JavaDoc[]
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 JavaDoc[]
579         { "value", "ognl:components.loop.value.price" }));
580
581         assertOpenToken(tokens[13], "$InspectorButton", "contrib:InspectorButton", "span", 15);
582     }
583
584     /**
585      * Test for encoded characters in an expression.
586      *
587      * @since 3.0
588      */

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 JavaDoc expression = "ognl: { \"<&>\", \"Fun!\" }";
599
600         assertTemplateAttributes(tokens[0], buildMap(new String JavaDoc[]
601         { "value", expression }));
602
603     }
604
605     /**
606      * Test ability to read string attributes.
607      */

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 JavaDoc[]
618         { "image", "ognl:assets.logo", "alt", "message:logo-title" }));
619
620     }
621
622     /**
623      * Test ability to use a different attribute name than the default ("jwcid").
624      *
625      * @since 4.0
626      */

627
628     public void testOverrideDefaultAttributeName() throws Exception JavaDoc
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     /**
640      * Like {@link #testOverrideDefaultAttributeName()}, but uses a more complicated attribute name
641      * (with a XML-style namespace prefix).
642      */

643
644     public void testNamespaceAttributeName() throws Exception JavaDoc
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