1   package org.apache.velocity.test;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.BufferedWriter;
23  import java.io.FileOutputStream;
24  import java.io.OutputStreamWriter;
25  import java.io.StringWriter;
26  import java.io.Writer;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import junit.framework.Test;
31  import junit.framework.TestSuite;
32  
33  import org.apache.velocity.Template;
34  import org.apache.velocity.VelocityContext;
35  import org.apache.velocity.app.VelocityEngine;
36  import org.apache.velocity.app.event.EventCartridge;
37  import org.apache.velocity.app.event.implement.EscapeHtmlReference;
38  import org.apache.velocity.app.event.implement.EscapeJavaScriptReference;
39  import org.apache.velocity.app.event.implement.EscapeReference;
40  import org.apache.velocity.app.event.implement.EscapeSqlReference;
41  import org.apache.velocity.app.event.implement.EscapeXmlReference;
42  import org.apache.velocity.app.event.implement.InvalidReferenceInfo;
43  import org.apache.velocity.app.event.implement.ReportInvalidReferences;
44  import org.apache.velocity.context.Context;
45  import org.apache.velocity.runtime.RuntimeConstants;
46  
47  /**
48   * Tests the operation of the built in event handlers.
49   *
50   * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
51   * @version $Id: BuiltInEventHandlerTestCase.java 704299 2008-10-14 03:13:16Z nbubna $
52   */
53  public class BuiltInEventHandlerTestCase extends BaseTestCase {
54  
55      protected boolean DEBUG = false;
56  
57      /**
58      * VTL file extension.
59      */
60     private static final String TMPL_FILE_EXT = "vm";
61  
62     /**
63      * Comparison file extension.
64      */
65     private static final String CMP_FILE_EXT = "cmp";
66  
67     /**
68      * Comparison file extension.
69      */
70     private static final String RESULT_FILE_EXT = "res";
71  
72     /**
73      * Path for templates. This property will override the
74      * value in the default velocity properties file.
75      */
76     private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/includeevent";
77  
78     /**
79      * Results relative to the build directory.
80      */
81     private static final String RESULTS_DIR = TEST_RESULT_DIR + "/includeevent";
82  
83     /**
84      * Results relative to the build directory.
85      */
86     private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/includeevent/compare";
87  
88      /**
89       * Default constructor.
90       */
91      public BuiltInEventHandlerTestCase(String name)
92      {
93          super(name);
94      }
95  
96      public void setUp()
97      {
98          assureResultsDirectoryExists(RESULTS_DIR);
99      }
100 
101     public static Test suite()
102     {
103        return new TestSuite(BuiltInEventHandlerTestCase.class);
104     }
105 
106     protected void log(String out)
107     {
108         if (DEBUG)
109         {
110             System.out.println (out);
111         }
112     }
113 
114     /**
115      * Test reporting of invalid syntax
116      * @throws Exception
117      */
118     public void testReportInvalidReferences1() throws Exception
119     {
120         VelocityEngine ve = new VelocityEngine();
121         ReportInvalidReferences reporter = new ReportInvalidReferences();
122         ve.init();
123 
124         VelocityContext context = new VelocityContext();
125         EventCartridge ec = new EventCartridge();
126         ec.addEventHandler(reporter);
127         ec.attachToContext(context);
128 
129         context.put("a1","test");
130         context.put("b1","test");
131         Writer writer = new StringWriter();
132 
133         ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()");
134 
135         List errors = reporter.getInvalidReferences();
136         assertEquals(2,errors.size());
137         assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference());
138         assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference());
139 
140         log("Caught invalid references (local configuration).");
141     }
142 
143     public void testReportInvalidReferences2() throws Exception
144     {
145         VelocityEngine ve = new VelocityEngine();
146         ve.setProperty("eventhandler.invalidreference.exception","true");
147         ReportInvalidReferences reporter = new ReportInvalidReferences();
148         ve.init();
149 
150         VelocityContext context = new VelocityContext();
151         EventCartridge ec = new EventCartridge();
152         ec.addEventHandler(reporter);
153         ec.attachToContext(context);
154 
155         context.put("a1","test");
156         context.put("b1","test");
157         Writer writer = new StringWriter();
158 
159         ve.evaluate(context,writer,"test","$a1 no problem");
160 
161         try {
162             ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()");
163             fail ("Expected exception.");
164         } catch (RuntimeException E) {}
165 
166 
167         log("Caught invalid references (global configuration).");
168 
169     }
170 
171     /**
172      * Test escaping
173      * @throws Exception
174      */
175     public void testEscapeHtml() throws Exception
176     {
177         EscapeReference esc = new EscapeHtmlReference();
178         assertEquals("test string&amp;another&lt;b&gt;bold&lt;/b&gt;test",esc.referenceInsert("","test string&another<b>bold</b>test"));
179         assertEquals("&lt;&quot;&gt;",esc.referenceInsert("","<\">"));
180         assertEquals("test string",esc.referenceInsert("","test string"));
181 
182         log("Correctly escaped HTML");
183 
184     }
185 
186     /**
187      * Test escaping
188      * @throws Exception
189      */
190     public void testEscapeXml() throws Exception
191     {
192         EscapeReference esc = new EscapeXmlReference();
193         assertEquals("test string&amp;another&lt;b&gt;bold&lt;/b&gt;test",esc.referenceInsert("","test string&another<b>bold</b>test"));
194         assertEquals("&lt;&quot;&gt;",esc.referenceInsert("","<\">"));
195         assertEquals("&apos;",esc.referenceInsert("","'"));
196         assertEquals("test string",esc.referenceInsert("","test string"));
197 
198         log("Correctly escaped XML");
199 
200     }
201 
202     /**
203      * Test escaping
204      * @throws Exception
205      */
206     public void testEscapeSql() throws Exception
207     {
208         EscapeReference esc = new EscapeSqlReference();
209         assertEquals("Jimmy''s Pizza",esc.referenceInsert("","Jimmy's Pizza"));
210         assertEquals("test string",esc.referenceInsert("","test string"));
211 
212         log("Correctly escaped SQL");
213 
214     }
215 
216     /**
217      * Test escaping
218      * @throws Exception
219      */
220     public void testEscapeJavaScript() throws Exception
221     {
222         EscapeReference esc = new EscapeJavaScriptReference();
223         assertEquals("Jimmy\\'s Pizza",esc.referenceInsert("","Jimmy's Pizza"));
224         assertEquals("test string",esc.referenceInsert("","test string"));
225 
226 
227         log("Correctly escaped Javascript");
228     }
229 
230     /**
231      * test that escape reference handler works with no match restrictions
232      * @throws Exception
233      */
234     public void testEscapeReferenceMatchAll() throws Exception
235     {
236         VelocityEngine ve = new VelocityEngine();
237         ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference");
238         ve.init();
239 
240         Context context;
241         Writer writer;
242 
243         // test normal reference
244         context = new VelocityContext();
245         writer = new StringWriter();
246         context.put("bold","<b>");
247         ve.evaluate(context,writer,"test","$bold test & test");
248         assertEquals("&lt;b&gt; test & test",writer.toString());
249 
250         // test method reference
251         context = new VelocityContext();
252         writer = new StringWriter();
253         context.put("bold","<b>");
254         ve.evaluate(context,writer,"test","$bold.substring(0,1)");
255         assertEquals("&lt;",writer.toString());
256 
257         log("Escape matched all references (global configuration)");
258 
259     }
260 
261     /**
262      * test that escape reference handler works with match restrictions
263      * @throws Exception
264      */
265     public void testEscapeReferenceMatch() throws Exception
266     {
267         // set up HTML match on everything, JavaScript match on _js*
268         VelocityEngine ve = new VelocityEngine();
269         ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference,org.apache.velocity.app.event.implement.EscapeJavaScriptReference");
270         ve.setProperty("eventhandler.escape.javascript.match", "/.*_js.*/");
271         ve.init();
272 
273         Writer writer;
274 
275         // Html no JavaScript
276         writer = new StringWriter();
277         ve.evaluate(newEscapeContext(),writer,"test","$test1");
278         assertEquals("Jimmy's &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
279 
280         // comment out bad test -- requires latest commons-lang
281         /**
282 
283         // JavaScript and HTML
284         writer = new StringWriter();
285         ve.evaluate(newEscapeContext(),writer,"test","$test1_js");
286         assertEquals("Jimmy\\'s &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
287 
288         // JavaScript and HTML
289         writer = new StringWriter();
290         ve.evaluate(newEscapeContext(),writer,"test","$test1_js_test");
291         assertEquals("Jimmy\\'s &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
292 
293         // JavaScript and HTML (method call)
294         writer = new StringWriter();
295         ve.evaluate(newEscapeContext(),writer,"test","$test1_js.substring(0,7)");
296         assertEquals("Jimmy\\'s",writer.toString());
297 
298         **/
299         
300         log("Escape selected references (global configuration)");
301 
302         
303 
304     }
305 
306     private Context newEscapeContext()
307     {
308         Context context = new VelocityContext();
309         context.put("test1","Jimmy's <b>pizza</b>");
310         context.put("test1_js","Jimmy's <b>pizza</b>");
311         context.put("test1_js_test","Jimmy's <b>pizza</b>");
312         return context;
313     }
314 
315     public void testPrintExceptionHandler() throws Exception
316     {
317         VelocityEngine ve1 = new VelocityEngine();
318         ve1.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
319         ve1.init();
320 
321         VelocityEngine ve2 = new VelocityEngine();
322         ve2.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
323         ve2.setProperty("eventhandler.methodexception.message","true");
324         ve2.init();
325 
326         VelocityEngine ve3 = new VelocityEngine();
327         ve3.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
328         ve3.setProperty("eventhandler.methodexception.stacktrace","true");
329         ve3.init();
330 
331         Context context;
332         StringWriter writer;
333 
334         context = new VelocityContext();
335         context.put("list",new ArrayList());
336 
337         // exception only
338         writer = new StringWriter();
339         ve1.evaluate(context,writer,"test","$list.get(0)");
340         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
341         assertTrue(writer.toString().indexOf("Index: 0, Size: 0") == -1);
342         assertTrue(writer.toString().indexOf("ArrayList") == -1);
343 
344         // message
345         writer = new StringWriter();
346         ve2.evaluate(context,writer,"test","$list.get(0)");
347         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
348         assertTrue(writer.toString().indexOf("Index: 0, Size: 0") != -1);
349         assertTrue(writer.toString().indexOf("ArrayList") == -1);
350 
351         // stack trace
352         writer = new StringWriter();
353         ve3.evaluate(context,writer,"test","$list.get(0)");
354         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
355         assertTrue(writer.toString().indexOf("ArrayList") != -1);
356 
357         log("PrintException handler successful.");
358 
359     }
360 
361     public void testIncludeNotFound() throws Exception
362     {
363         VelocityEngine ve = new VelocityEngine();
364         ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeNotFound");
365         ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
366         ve.init();
367 
368         Template template;
369         FileOutputStream fos;
370         Writer fwriter;
371         Context context;
372 
373         template = ve.getTemplate( getFileName(null, "test6", TMPL_FILE_EXT) );
374 
375         fos = new FileOutputStream (
376                 getFileName(RESULTS_DIR, "test6", RESULT_FILE_EXT));
377 
378         fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
379 
380         context = new VelocityContext();
381         template.merge(context, fwriter);
382         fwriter.flush();
383         fwriter.close();
384 
385         if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test6", RESULT_FILE_EXT, CMP_FILE_EXT))
386         {
387             fail("Output incorrect.");
388         }
389 
390         log("IncludeNotFound handler successful.");
391 
392     }
393 
394     public void testIncludeRelativePath() throws Exception
395     {
396         VelocityEngine ve = new VelocityEngine();
397         ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeRelativePath");
398         ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
399         ve.init();
400 
401         Template template;
402         FileOutputStream fos;
403         Writer fwriter;
404         Context context;
405 
406         template = ve.getTemplate( getFileName(null, "subdir/test2", TMPL_FILE_EXT) );
407 
408         fos = new FileOutputStream (
409                 getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT));
410 
411         fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
412 
413         context = new VelocityContext();
414         template.merge(context, fwriter);
415         fwriter.flush();
416         fwriter.close();
417 
418         if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test2", RESULT_FILE_EXT, CMP_FILE_EXT))
419         {
420             fail("Output incorrect.");
421         }
422 
423         log("IncludeRelativePath handler successful.");
424 
425     }
426 }