• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 junit.framework.TestCase;
23 import org.apache.velocity.VelocityContext;
24 import org.apache.velocity.app.Velocity;
25 import org.apache.velocity.app.VelocityEngine;
26 import org.apache.velocity.runtime.RuntimeConstants;
27 import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
28 import org.apache.velocity.runtime.resource.util.StringResourceRepository;
29 import org.apache.velocity.test.misc.TestLogger;
30 
31 import java.io.File;
32 import java.io.IOException;
33 import java.io.StringWriter;
34 import java.nio.charset.StandardCharsets;
35 import java.nio.file.Files;
36 import java.nio.file.Paths;
37 import java.util.Locale;
38 
39 /**
40  * Base test case that provides utility methods for
41  * the rest of the tests.
42  *
43  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
44  * @author Nathan Bubna
45  * @version $Id$
46  */
47 public abstract class BaseTestCase extends TestCase implements TemplateTestBase
48 {
49     protected VelocityEngine engine;
50     protected VelocityContext context;
51     protected boolean DEBUG = Boolean.getBoolean("test.debug");
52     protected TestLogger log;
53     protected String stringRepoName = "string.repo";
54 
BaseTestCase(String name)55     public BaseTestCase(String name)
56     {
57         super(name);
58 
59         // if we're just running one case, then have DEBUG
60         // automatically set to true
61         String test = System.getProperty("test");
62         if (test != null)
63         {
64             DEBUG = test.equals(getClass().getSimpleName());
65         }
66     }
67 
createEngine()68     protected VelocityEngine createEngine()
69     {
70         VelocityEngine ret = new VelocityEngine();
71         ret.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, log);
72 
73         // use string resource loader by default, instead of file
74         ret.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file,string");
75         ret.addProperty("string.resource.loader.class", StringResourceLoader.class.getName());
76         ret.addProperty("string.resource.loader.repository.name", stringRepoName);
77         ret.addProperty("string.resource.loader.repository.static", "false");
78 
79         setUpEngine(ret);
80         return ret;
81     }
82 
83     @Override
setUp()84     protected void setUp() throws Exception
85     {
86         //by default, make the engine's log output go to the test-report
87         log = new TestLogger(false, false);
88         engine = createEngine();
89         context = new VelocityContext();
90         setUpContext(context);
91     }
92 
setUpEngine(VelocityEngine engine)93     protected void setUpEngine(VelocityEngine engine)
94     {
95         // extension hook
96     }
97 
setUpContext(VelocityContext context)98     protected void setUpContext(VelocityContext context)
99     {
100         // extension hook
101     }
102 
getStringRepository()103     protected StringResourceRepository getStringRepository()
104     {
105         StringResourceRepository repo =
106             (StringResourceRepository)engine.getApplicationAttribute(stringRepoName);
107         if (repo == null)
108         {
109             engine.init();
110             repo =
111                 (StringResourceRepository)engine.getApplicationAttribute(stringRepoName);
112         }
113         return repo;
114     }
115 
addTemplate(String name, String template)116     protected void addTemplate(String name, String template)
117     {
118         info("Template '"+name+"':  "+template);
119         getStringRepository().putStringResource(name, template);
120     }
121 
removeTemplate(String name)122     protected void removeTemplate(String name)
123     {
124         info("Removed: '"+name+"'");
125         getStringRepository().removeStringResource(name);
126     }
127 
128     @Override
tearDown()129     public void tearDown()
130     {
131         engine = null;
132         context = null;
133     }
134 
info(String msg)135     protected void info(String msg)
136     {
137         info(msg, null);
138     }
139 
info(String msg, Throwable t)140     protected void info(String msg, Throwable t)
141     {
142         if (DEBUG)
143         {
144             try
145             {
146                 if (engine == null)
147                 {
148                     Velocity.getLog().info(msg, t);
149                 }
150                 else
151                 {
152                     engine.getLog().info(msg, t);
153                 }
154             }
155             catch (Throwable t2)
156             {
157                 System.out.println("Failed to log: "+msg+(t!=null?" - "+t: ""));
158                 System.out.println("Cause: "+t2);
159                 t2.printStackTrace();
160             }
161         }
162     }
163 
164     /**
165      * Compare an expected string with the given loaded template
166      */
assertTmplEquals(String expected, String template)167     protected void assertTmplEquals(String expected, String template)
168     {
169         info("Expected:  " + expected + " from '" + template + "'");
170 
171         StringWriter writer = new StringWriter();
172         try
173         {
174             engine.mergeTemplate(template, "utf-8", context, writer);
175         }
176         catch (RuntimeException re)
177         {
178             info("RuntimeException!", re);
179             throw re;
180         }
181         catch (Exception e)
182         {
183             info("Exception!", e);
184             throw new RuntimeException(e);
185         }
186 
187         info("Result:  " + writer.toString());
188         assertEquals(expected, writer.toString());
189     }
190 
191     /**
192      * Ensure that a context value is as expected.
193      */
assertContextValue(String key, Object expected)194     protected void assertContextValue(String key, Object expected)
195     {
196         info("Expected value of '"+key+"': "+expected);
197         Object value = context.get(key);
198         info("Result: "+value);
199         assertEquals(expected, value);
200     }
201 
202     /**
203      * Ensure that a template renders as expected.
204      */
assertEvalEquals(String expected, String template)205     protected void assertEvalEquals(String expected, String template)
206     {
207         info("Expectation: "+expected);
208         assertEquals(expected, evaluate(template));
209     }
210 
211     /**
212      * Ensure that the given string renders as itself when evaluated.
213      */
assertSchmoo(String templateIsExpected)214     protected void assertSchmoo(String templateIsExpected)
215     {
216         assertEvalEquals(templateIsExpected, templateIsExpected);
217     }
218 
219     /**
220      * Ensure that an exception occurs when the string is evaluated.
221      */
assertEvalException(String evil)222     protected Exception assertEvalException(String evil)
223     {
224         return assertEvalException(evil, null);
225     }
226 
227     /**
228      * Ensure that a specified type of exception occurs when evaluating the string.
229      */
assertEvalException(String evil, Class<?> exceptionType)230     protected Exception assertEvalException(String evil, Class<?> exceptionType)
231     {
232         try
233         {
234             if (!DEBUG)
235             {
236                 log.off();
237             }
238             if (exceptionType != null)
239             {
240                 info("Expectation: "+exceptionType.getName());
241             }
242             else
243             {
244                 info("Expectation: "+Exception.class.getName());
245             }
246             evaluate(evil);
247             String msg = "Template '"+evil+"' should have thrown an exception.";
248             info("Fail: "+msg);
249             fail(msg);
250         }
251         catch (Exception e)
252         {
253             if (exceptionType != null && !exceptionType.isAssignableFrom(e.getClass()))
254             {
255                 String msg = "Was expecting template '"+evil+"' to throw "+exceptionType+" not "+e;
256                 info("Fail: "+msg);
257                 fail(msg);
258             }
259             return e;
260         }
261         finally
262         {
263             if (!DEBUG)
264             {
265                 log.on();
266             }
267         }
268         return null;
269     }
270 
271     /**
272      * Ensure that the error message of the expected exception has the proper location info.
273      */
assertEvalExceptionAt(String evil, String template, int line, int col)274     protected Exception assertEvalExceptionAt(String evil, String template,
275                                               int line, int col)
276     {
277         String loc = template+"[line "+line+", column "+col+"]";
278         info("Expectation: Exception at "+loc);
279         Exception e = assertEvalException(evil);
280 
281         info("Result: "+e.getClass().getName()+" - "+e.getMessage());
282         if (e.getMessage().indexOf(loc) < 1)
283         {
284             fail("Was expecting exception at "+loc+" instead of "+e.getMessage());
285         }
286         return e;
287     }
288 
289     /**
290      * Only ensure that the error message of the expected exception
291      * has the proper line and column info.
292      */
assertEvalExceptionAt(String evil, int line, int col)293     protected Exception assertEvalExceptionAt(String evil, int line, int col)
294     {
295          return assertEvalExceptionAt(evil, "", line, col);
296     }
297 
298     /**
299      * Evaluate the specified String as a template and return the result as a String.
300      */
evaluate(String template)301     protected String evaluate(String template)
302     {
303         StringWriter writer = new StringWriter();
304         try
305         {
306             info("Template: "+template);
307 
308             // use template as its own name, since our templates are short
309             // unless it's not that short, then shorten it...
310             String name = (template.length() <= 15) ? template : template.substring(0,15);
311             engine.evaluate(context, writer, name, template);
312 
313             String result = writer.toString();
314             info("Result: "+result);
315             return result;
316         }
317         catch (RuntimeException re)
318         {
319             info("RuntimeException!", re);
320             throw re;
321         }
322         catch (Exception e)
323         {
324             info("Exception!", e);
325             throw new RuntimeException(e);
326         }
327     }
328 
329     /**
330      * Concatenates the file name parts together appropriately.
331      *
332      * @return The full path to the file.
333      */
getFileName(final String dir, final String base, final String ext)334     protected String getFileName(final String dir, final String base, final String ext)
335     {
336         return getFileName(dir, base, ext, false);
337     }
338 
getFileName(final String dir, final String base, final String ext, final boolean mustExist)339     protected String getFileName(final String dir, final String base, final String ext, final boolean mustExist)
340     {
341         StringBuilder buf = new StringBuilder();
342         try
343         {
344             File baseFile = new File(base);
345             if (dir != null)
346             {
347                 if (!baseFile.isAbsolute())
348                 {
349                     baseFile = new File(dir, base);
350                 }
351 
352                 buf.append(baseFile.getCanonicalPath());
353             }
354             else
355             {
356                 buf.append(baseFile.getPath());
357             }
358 
359             if (org.apache.commons.lang3.StringUtils.isNotEmpty(ext))
360             {
361                 buf.append('.').append(ext);
362             }
363 
364             if (mustExist)
365             {
366                 File testFile = new File(buf.toString());
367 
368                 if (!testFile.exists())
369                 {
370                     String msg = "getFileName() result " + testFile.getPath() + " does not exist!";
371                     info(msg);
372                     fail(msg);
373                 }
374 
375                 if (!testFile.isFile())
376                 {
377                     String msg = "getFileName() result " + testFile.getPath() + " is not a file!";
378                     info(msg);
379                     fail(msg);
380                 }
381             }
382         }
383         catch (IOException e)
384         {
385             fail("IO Exception while running getFileName(" + dir + ", " + base + ", "+ ext + ", " + mustExist + "): " + e.getMessage());
386         }
387 
388         return buf.toString();
389     }
390 
391     /**
392      * Assures that the results directory exists.  If the results directory
393      * cannot be created, fails the test.
394      */
assureResultsDirectoryExists(String resultsDirectory)395     protected void assureResultsDirectoryExists(String resultsDirectory)
396     {
397         File dir = new File(resultsDirectory);
398         if (!dir.exists())
399         {
400             info("Template results directory ("+resultsDirectory+") does not exist");
401             if (dir.mkdirs())
402             {
403                 info("Created template results directory");
404                 if (DEBUG)
405                 {
406                     info("Created template results directory: "+resultsDirectory);
407                 }
408             }
409             else
410             {
411                 String errMsg = "Unable to create '"+resultsDirectory+"'";
412                 info(errMsg);
413                 fail(errMsg);
414             }
415         }
416     }
417 
418 
419     /**
420      * Normalizes lines to account for platform differences.  Macs use
421      * a single \r, DOS derived operating systems use \r\n, and Unix
422      * uses \n.  Replace each with a single \n.
423      *
424      * @return source with all line terminations changed to Unix style
425      */
normalizeNewlines(String source)426     protected String normalizeNewlines (String source)
427     {
428         return source.replaceAll("\r\n?", "\n");
429     }
430 
431     /**
432      * Returns whether the processed template matches the
433      * content of the provided comparison file.
434      *
435      * @return Whether the output matches the contents
436      *         of the comparison file.
437      *
438      * @exception Exception Test failure condition.
439      */
isMatch(String resultsDir, String compareDir, String baseFileName, String resultExt, String compareExt)440     protected boolean isMatch (String resultsDir,
441                                String compareDir,
442                                String baseFileName,
443                                String resultExt,
444                                String compareExt) throws Exception
445     {
446         if (DEBUG)
447         {
448             info("Result: "+resultsDir+'/'+baseFileName+'.'+resultExt);
449         }
450         String result = getFileContents(resultsDir, baseFileName, resultExt);
451         return isMatch(result,compareDir,baseFileName,compareExt);
452     }
453 
454 
getFileContents(String dir, String baseFileName, String ext)455     protected String getFileContents(String dir, String baseFileName, String ext)
456     {
457         String fileName = getFileName(dir, baseFileName, ext, true);
458         return getFileContents(fileName);
459     }
460 
getFileContents(String file)461     protected String getFileContents(String file)
462     {
463         String contents = null;
464 
465         try
466         {
467             contents = new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8);
468         }
469         catch (Exception e)
470         {
471             e.printStackTrace();
472         }
473         return contents;
474     }
475 
476     /**
477      * Returns whether the processed template matches the
478      * content of the provided comparison file.
479      *
480      * @return Whether the output matches the contents
481      *         of the comparison file.
482      *
483      * @exception Exception Test failure condition.
484      */
isMatch(String result, String compareDir, String baseFileName, String compareExt)485     protected boolean isMatch (String result,
486                                String compareDir,
487                                String baseFileName,
488                                String compareExt) throws Exception
489     {
490         String compare = getFileContents(compareDir, baseFileName, compareExt);
491 
492         // normalize each wrt newline
493         result = normalizeNewlines(result);
494         compare = normalizeNewlines(compare);
495         if (DEBUG)
496         {
497             info("Expection: "+compareDir+'/'+baseFileName+'.'+compareExt);
498         }
499         return result.equals(compare);
500     }
501 
502     /**
503      * Turns a base file name into a test case name.
504      *
505      * @param s The base file name.
506      * @return  The test case name.
507      */
getTestCaseName(String s)508     protected static String getTestCaseName(String s)
509     {
510         StringBuilder name = new StringBuilder();
511         name.append(Character.toTitleCase(s.charAt(0)));
512         name.append(s.substring(1, s.length()).toLowerCase(Locale.ROOT));
513         return name.toString();
514     }
515 }
516