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 809816 2009-09-01 05:14:27Z 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() throws Exception
97      {
98          assureResultsDirectoryExists(RESULTS_DIR);
99          super.setUp();
100     }
101 
102     public static Test suite()
103     {
104        return new TestSuite(BuiltInEventHandlerTestCase.class);
105     }
106 
107     protected void log(String out)
108     {
109         if (DEBUG)
110         {
111             System.out.println (out);
112         }
113     }
114 
115     /**
116      * Test reporting of invalid syntax
117      * @throws Exception
118      */
119     public void testReportInvalidReferences1() throws Exception
120     {
121         VelocityEngine ve = new VelocityEngine();
122         ReportInvalidReferences reporter = new ReportInvalidReferences();
123         ve.init();
124 
125         VelocityContext context = new VelocityContext();
126         EventCartridge ec = new EventCartridge();
127         ec.addEventHandler(reporter);
128         ec.attachToContext(context);
129 
130         context.put("a1","test");
131         context.put("b1","test");
132         Writer writer = new StringWriter();
133 
134         ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()");
135 
136         List errors = reporter.getInvalidReferences();
137         assertEquals(2,errors.size());
138         assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference());
139         assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference());
140 
141         log("Caught invalid references (local configuration).");
142     }
143 
144     public void testReportInvalidReferences2() throws Exception
145     {
146         VelocityEngine ve = new VelocityEngine();
147         ve.setProperty("eventhandler.invalidreference.exception","true");
148         ReportInvalidReferences reporter = new ReportInvalidReferences();
149         ve.init();
150 
151         VelocityContext context = new VelocityContext();
152         EventCartridge ec = new EventCartridge();
153         ec.addEventHandler(reporter);
154         ec.attachToContext(context);
155 
156         context.put("a1","test");
157         context.put("b1","test");
158         Writer writer = new StringWriter();
159 
160         ve.evaluate(context,writer,"test","$a1 no problem");
161 
162         try {
163             ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()");
164             fail ("Expected exception.");
165         } catch (RuntimeException E) {}
166 
167 
168         log("Caught invalid references (global configuration).");
169 
170     }
171 
172     /**
173      * Test escaping
174      * @throws Exception
175      */
176     public void testEscapeHtml() throws Exception
177     {
178         EscapeReference esc = new EscapeHtmlReference();
179         assertEquals("test string&amp;another&lt;b&gt;bold&lt;/b&gt;test",esc.referenceInsert("","test string&another<b>bold</b>test"));
180         assertEquals("&lt;&quot;&gt;",esc.referenceInsert("","<\">"));
181         assertEquals("test string",esc.referenceInsert("","test string"));
182 
183         log("Correctly escaped HTML");
184 
185     }
186 
187     /**
188      * Test escaping
189      * @throws Exception
190      */
191     public void testEscapeXml() throws Exception
192     {
193         EscapeReference esc = new EscapeXmlReference();
194         assertEquals("test string&amp;another&lt;b&gt;bold&lt;/b&gt;test",esc.referenceInsert("","test string&another<b>bold</b>test"));
195         assertEquals("&lt;&quot;&gt;",esc.referenceInsert("","<\">"));
196         assertEquals("&apos;",esc.referenceInsert("","'"));
197         assertEquals("test string",esc.referenceInsert("","test string"));
198 
199         log("Correctly escaped XML");
200 
201     }
202 
203     /**
204      * Test escaping
205      * @throws Exception
206      */
207     public void testEscapeSql() throws Exception
208     {
209         EscapeReference esc = new EscapeSqlReference();
210         assertEquals("Jimmy''s Pizza",esc.referenceInsert("","Jimmy's Pizza"));
211         assertEquals("test string",esc.referenceInsert("","test string"));
212 
213         log("Correctly escaped SQL");
214 
215     }
216 
217     /**
218      * Test escaping
219      * @throws Exception
220      */
221     public void testEscapeJavaScript() throws Exception
222     {
223         EscapeReference esc = new EscapeJavaScriptReference();
224         assertEquals("Jimmy\\'s Pizza",esc.referenceInsert("","Jimmy's Pizza"));
225         assertEquals("test string",esc.referenceInsert("","test string"));
226 
227 
228         log("Correctly escaped Javascript");
229     }
230 
231     /**
232      * test that escape reference handler works with no match restrictions
233      * @throws Exception
234      */
235     public void testEscapeReferenceMatchAll() throws Exception
236     {
237         VelocityEngine ve = new VelocityEngine();
238         ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference");
239         ve.init();
240 
241         Context context;
242         Writer writer;
243 
244         // test normal reference
245         context = new VelocityContext();
246         writer = new StringWriter();
247         context.put("bold","<b>");
248         ve.evaluate(context,writer,"test","$bold test & test");
249         assertEquals("&lt;b&gt; test & test",writer.toString());
250 
251         // test method reference
252         context = new VelocityContext();
253         writer = new StringWriter();
254         context.put("bold","<b>");
255         ve.evaluate(context,writer,"test","$bold.substring(0,1)");
256         assertEquals("&lt;",writer.toString());
257 
258         log("Escape matched all references (global configuration)");
259 
260     }
261 
262     /**
263      * test that escape reference handler works with match restrictions
264      * @throws Exception
265      */
266     public void testEscapeReferenceMatch() throws Exception
267     {
268         // set up HTML match on everything, JavaScript match on _js*
269         VelocityEngine ve = new VelocityEngine();
270         ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference,org.apache.velocity.app.event.implement.EscapeJavaScriptReference");
271         ve.setProperty("eventhandler.escape.javascript.match", "/.*_js.*/");
272         ve.init();
273 
274         Writer writer;
275 
276         // Html no JavaScript
277         writer = new StringWriter();
278         ve.evaluate(newEscapeContext(),writer,"test","$test1");
279         assertEquals("Jimmy's &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
280 
281         // comment out bad test -- requires latest commons-lang
282         /**
283 
284         // JavaScript and HTML
285         writer = new StringWriter();
286         ve.evaluate(newEscapeContext(),writer,"test","$test1_js");
287         assertEquals("Jimmy\\'s &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
288 
289         // JavaScript and HTML
290         writer = new StringWriter();
291         ve.evaluate(newEscapeContext(),writer,"test","$test1_js_test");
292         assertEquals("Jimmy\\'s &lt;b&gt;pizza&lt;/b&gt;",writer.toString());
293 
294         // JavaScript and HTML (method call)
295         writer = new StringWriter();
296         ve.evaluate(newEscapeContext(),writer,"test","$test1_js.substring(0,7)");
297         assertEquals("Jimmy\\'s",writer.toString());
298 
299         **/
300         
301         log("Escape selected references (global configuration)");
302 
303         
304 
305     }
306 
307     private Context newEscapeContext()
308     {
309         Context context = new VelocityContext();
310         context.put("test1","Jimmy's <b>pizza</b>");
311         context.put("test1_js","Jimmy's <b>pizza</b>");
312         context.put("test1_js_test","Jimmy's <b>pizza</b>");
313         return context;
314     }
315 
316     public void testPrintExceptionHandler() throws Exception
317     {
318         VelocityEngine ve1 = new VelocityEngine();
319         ve1.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
320         ve1.init();
321 
322         VelocityEngine ve2 = new VelocityEngine();
323         ve2.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
324         ve2.setProperty("eventhandler.methodexception.message","true");
325         ve2.init();
326 
327         VelocityEngine ve3 = new VelocityEngine();
328         ve3.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions");
329         ve3.setProperty("eventhandler.methodexception.stacktrace","true");
330         ve3.init();
331 
332         Context context;
333         StringWriter writer;
334 
335         context = new VelocityContext();
336         context.put("list",new ArrayList());
337 
338         // exception only
339         writer = new StringWriter();
340         ve1.evaluate(context,writer,"test","$list.get(0)");
341         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
342         assertTrue(writer.toString().indexOf("Index: 0, Size: 0") == -1);
343         assertTrue(writer.toString().indexOf("ArrayList") == -1);
344 
345         // message
346         writer = new StringWriter();
347         ve2.evaluate(context,writer,"test","$list.get(0)");
348         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
349         assertTrue(writer.toString().indexOf("Index: 0, Size: 0") != -1);
350         assertTrue(writer.toString().indexOf("ArrayList") == -1);
351 
352         // stack trace
353         writer = new StringWriter();
354         ve3.evaluate(context,writer,"test","$list.get(0)");
355         assertTrue(writer.toString().indexOf("IndexOutOfBoundsException") != -1);
356         assertTrue(writer.toString().indexOf("ArrayList") != -1);
357 
358         log("PrintException handler successful.");
359 
360     }
361 
362     public void testIncludeNotFound() throws Exception
363     {
364         VelocityEngine ve = new VelocityEngine();
365         ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeNotFound");
366         ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
367         ve.init();
368 
369         Template template;
370         FileOutputStream fos;
371         Writer fwriter;
372         Context context;
373 
374         template = ve.getTemplate( getFileName(null, "test6", TMPL_FILE_EXT) );
375 
376         fos = new FileOutputStream (
377                 getFileName(RESULTS_DIR, "test6", RESULT_FILE_EXT));
378 
379         fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
380 
381         context = new VelocityContext();
382         template.merge(context, fwriter);
383         fwriter.flush();
384         fwriter.close();
385 
386         if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test6", RESULT_FILE_EXT, CMP_FILE_EXT))
387         {
388             fail("Output incorrect.");
389         }
390 
391         log("IncludeNotFound handler successful.");
392 
393     }
394 
395     public void testIncludeNotFoundMissingResourceName() throws Exception
396     {
397         // uses base test support
398         engine.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeNotFound");
399         addTemplate("notfound.vm", "$missingResource");
400         assertEvalEquals("foo", "#parse('foo')");
401     }
402 
403     public void testIncludeRelativePath() throws Exception
404     {
405         VelocityEngine ve = new VelocityEngine();
406         ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeRelativePath");
407         ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
408         ve.init();
409 
410         Template template;
411         FileOutputStream fos;
412         Writer fwriter;
413         Context context;
414 
415         template = ve.getTemplate( getFileName(null, "subdir/test2", TMPL_FILE_EXT) );
416 
417         fos = new FileOutputStream (
418                 getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT));
419 
420         fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
421 
422         context = new VelocityContext();
423         template.merge(context, fwriter);
424         fwriter.flush();
425         fwriter.close();
426 
427         if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test2", RESULT_FILE_EXT, CMP_FILE_EXT))
428         {
429             fail("Output incorrect.");
430         }
431 
432         log("IncludeRelativePath handler successful.");
433 
434     }
435 }