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.HashMap;
28  import java.util.Iterator;
29  import java.util.Map;
30  
31  import junit.framework.Test;
32  import junit.framework.TestSuite;
33  
34  import org.apache.velocity.Template;
35  import org.apache.velocity.VelocityContext;
36  import org.apache.velocity.app.VelocityEngine;
37  import org.apache.velocity.app.event.implement.EscapeHtmlReference;
38  import org.apache.velocity.context.Context;
39  import org.apache.velocity.exception.ParseErrorException;
40  import org.apache.velocity.runtime.RuntimeConstants;
41  
42  /**
43   * Test #evaluate directive.
44   * 
45   * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a>
46   * @version $Id: EvaluateTestCase.java 685287 2008-08-12 20:06:31Z nbubna $
47   */
48  public class EvaluateTestCase extends BaseTestCase
49  {
50      
51      /**
52      * VTL file extension.
53      */
54     private static final String TMPL_FILE_EXT = "vm";
55  
56     /**
57      * Comparison file extension.
58      */
59     private static final String CMP_FILE_EXT = "cmp";
60  
61     /**
62      * Comparison file extension.
63      */
64     private static final String RESULT_FILE_EXT = "res";
65  
66     /**
67      * Path for templates. This property will override the
68      * value in the default velocity properties file.
69      */
70     private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/evaluate";
71  
72     /**
73      * Results relative to the build directory.
74      */
75     private static final String RESULTS_DIR = TEST_RESULT_DIR + "/evaluate";
76  
77     /**
78      * Results relative to the build directory.
79      */
80     private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/evaluate/compare";
81  
82      /**
83       * Default constructor.
84       * @param name
85       */
86      public EvaluateTestCase(String name)
87      {
88          super(name);
89      }
90  
91      public void setUp()
92      {
93          assureResultsDirectoryExists(RESULTS_DIR);
94      }
95  
96      public static Test suite()
97      {
98         return new TestSuite(EvaluateTestCase.class);
99      }
100 
101     /**
102      * Test basic functionality.
103      * @throws Exception
104      */
105     public void testEvaluate()
106     throws Exception
107     {
108         testFile("eval1", new HashMap());
109     }
110 
111     /**
112      * Test evaluate directive preserves macros (VELOCITY-591)
113      * @throws Exception
114      */
115     public void testEvaluateMacroPreserve()
116     throws Exception
117     {
118         Map properties = new HashMap();
119         properties.clear();
120         properties.put(RuntimeConstants.VM_CONTEXT_LOCALSCOPE,"false");
121         testFile("eval2", properties);
122 
123         properties.clear();
124         properties.put(RuntimeConstants.VM_CONTEXT_LOCALSCOPE,"true");
125         testFile("eval2", properties);
126 
127         properties.clear();
128         properties.put(RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL,"false");
129         testFile("eval2", properties);
130 
131 
132     }
133 
134     /**
135      * Test in a macro context.
136      * @throws Exception
137      */
138     public void testEvaluateVMContext()
139     throws Exception
140     {
141         testFile("evalvmcontext", new HashMap());
142     }
143 
144     /**
145      * Test #stop (since it is attached to context).
146      * @throws Exception
147      */
148     public void testStop()
149     throws Exception
150     {
151         VelocityEngine ve = new VelocityEngine();
152         ve.init();
153         
154         Context context = new VelocityContext();        
155         StringWriter writer = new StringWriter();
156         ve.evaluate(context, writer, "test","test #stop test2 #evaluate('test3')");
157         assertEquals("test ", writer.toString());
158         
159         context = new VelocityContext();        
160         writer = new StringWriter();
161         ve.evaluate(context, writer, "test","test test2 #evaluate('test3 #stop test4') test5");
162         assertEquals("test test2 test3  test5", writer.toString());
163         
164     }
165 
166     /**
167      * Test that the event handlers work in #evaluate (since they are
168      * attached to the context).  Only need to check one - they all 
169      * work the same.
170      * @throws Exception
171      */
172     public void testEventHandler()
173     throws Exception
174     {
175         VelocityEngine ve = new VelocityEngine();
176         ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, EscapeHtmlReference.class.getName());
177         ve.init();
178         
179         Context context = new VelocityContext();
180         context.put("lt","<");
181         context.put("gt",">");
182         StringWriter writer = new StringWriter();
183         ve.evaluate(context, writer, "test","${lt}test${gt} #evaluate('${lt}test2${gt}')");
184         assertEquals("&lt;test&gt; &lt;test2&gt;", writer.toString());
185         
186     }
187     
188     
189     /**
190      * Test errors are thrown
191      * @throws Exception
192      */
193     public void testErrors()
194     throws Exception
195     {
196         VelocityEngine ve = new VelocityEngine();
197         ve.init();
198         
199         Context context = new VelocityContext();
200         
201         // no arguments
202         StringWriter writer = new StringWriter();
203         try 
204         {
205             ve.evaluate(context, writer, "test",
206                               "#evaluate()");
207             fail("Expected exception");
208         }
209         catch (ParseErrorException e)
210         {
211             assertEquals("test",e.getTemplateName());
212             assertEquals(1,e.getLineNumber());
213             assertEquals(1,e.getColumnNumber());
214         }
215         
216         // too many arguments
217         writer = new StringWriter();
218         try 
219         {
220             ve.evaluate(context, writer, "test",
221                               "#evaluate('aaa' 'bbb')");
222             fail("Expected exception");
223         }
224         catch (ParseErrorException e)
225         {
226             assertEquals("test",e.getTemplateName());
227             assertEquals(1,e.getLineNumber());
228             assertEquals(17,e.getColumnNumber());
229         }
230         
231         // argument not a string or reference
232         writer = new StringWriter();
233         try 
234         {
235             ve.evaluate(context, writer, "test",
236                               "#evaluate(10)");
237             fail("Expected exception");
238         }
239         catch (ParseErrorException e)
240         {
241             assertEquals("test",e.getTemplateName());
242             assertEquals(1,e.getLineNumber());
243             assertEquals(11,e.getColumnNumber());
244         }
245         
246         // checking line/col for parse error
247         writer = new StringWriter();
248         try 
249         {
250             String eval = "this is a multiline\n\n\n\n\n test #foreach() with an error";
251             context.put("eval",eval);
252             ve.evaluate(context, writer, "test",
253                               "first line\n second line: #evaluate($eval)");
254             fail("Expected exception");
255         }
256         catch (ParseErrorException e)
257         {
258             // should be start of #evaluate
259             assertEquals("test",e.getTemplateName());
260             assertEquals(2,e.getLineNumber());
261             assertEquals(15,e.getColumnNumber());
262         }        
263     }
264     
265     /**
266      * Test a file parses with no errors and compare to existing file.
267      * @param basefilename
268      * @throws Exception
269      */
270     private void testFile(String basefilename, Map properties)
271     throws Exception
272     {
273         VelocityEngine ve = new VelocityEngine();
274         ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
275      
276         for (Iterator i = properties.keySet().iterator(); i.hasNext();)
277         {
278             String key = (String) i.next();
279             String value = (String) properties.get(key);
280             ve.addProperty(key, value);
281         }
282         
283         ve.init();
284         
285         Template template;
286         FileOutputStream fos;
287         Writer fwriter;
288         Context context;
289         
290         template = ve.getTemplate( getFileName(null, basefilename, TMPL_FILE_EXT) );
291         
292         fos = new FileOutputStream (
293                 getFileName(RESULTS_DIR, basefilename, RESULT_FILE_EXT));
294         
295         fwriter = new BufferedWriter( new OutputStreamWriter(fos) );
296         
297         context = new VelocityContext();
298         setupContext(context);
299         template.merge(context, fwriter);
300         fwriter.flush();
301         fwriter.close();
302         
303         if (!isMatch(RESULTS_DIR, COMPARE_DIR, basefilename, RESULT_FILE_EXT, CMP_FILE_EXT))
304         {
305             String result = getFileContents(RESULTS_DIR, basefilename, RESULT_FILE_EXT);
306             String compare = getFileContents(COMPARE_DIR, basefilename, CMP_FILE_EXT);
307 
308             String msg = "Output was incorrect\n"+
309                 "-----Result-----\n"+ result +
310                 "----Expected----\n"+ compare +
311                 "----------------";
312             
313             fail(msg);
314         }
315     }
316         
317     public void setupContext(Context context)
318     {
319     } 
320     
321     
322 }