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.Writer;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.Hashtable;
29  import java.util.Vector;
30  
31  import org.apache.velocity.Template;
32  import org.apache.velocity.VelocityContext;
33  import org.apache.velocity.app.FieldMethodizer;
34  import org.apache.velocity.runtime.RuntimeSingleton;
35  import org.apache.velocity.test.provider.BoolObj;
36  import org.apache.velocity.test.provider.NullToStringObject;
37  import org.apache.velocity.test.provider.TestNumber;
38  import org.apache.velocity.test.provider.TestProvider;
39  
40  /**
41   * Easily add test cases which evaluate templates and check their output.
42   *
43   * NOTE:
44   * This class DOES NOT extend RuntimeTestCase because the TemplateTestSuite
45   * already initializes the Velocity runtime and adds the template
46   * test cases. Having this class extend RuntimeTestCase causes the
47   * Runtime to be initialized twice which is not good. I only discovered
48   * this after a couple hours of wondering why all the properties
49   * being setup were ending up as Vectors. At first I thought it
50   * was a problem with the Configuration class, but the Runtime
51   * was being initialized twice: so the first time the property
52   * is seen it's stored as a String, the second time it's seen
53   * the Configuration class makes a Vector with both Strings.
54   * As a result all the getBoolean(property) calls were failing because
55   * the Configurations class was trying to create a Boolean from
56   * a Vector which doesn't really work that well. I have learned
57   * my lesson and now have to add some code to make sure the
58   * Runtime isn't initialized more then once :-)
59   *
60   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
61   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
62   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
63   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
64   * @version $Id: TemplateTestCase.java 463298 2006-10-12 16:10:32Z henning $
65   */
66  public class TemplateTestCase extends BaseTestCase implements TemplateTestBase
67  {
68      /**
69       * The base file name of the template and comparison file (i.e. array for
70       * array.vm and array.cmp).
71       */
72      protected String baseFileName;
73  
74      private TestProvider provider;
75      private ArrayList al;
76      private Hashtable h;
77      private VelocityContext context;
78      private VelocityContext context1;
79      private VelocityContext context2;
80      private Vector vec;
81  
82      /**
83       * Creates a new instance.
84       *
85       * @param baseFileName The base name of the template and comparison file to
86       *                     use (i.e. array for array.vm and array.cmp).
87       */
88      public TemplateTestCase (String baseFileName)
89      {
90          super(getTestCaseName(baseFileName));
91          this.baseFileName = baseFileName;
92      }
93  
94      public static junit.framework.Test suite()
95      {
96          return new TemplateTestSuite();
97      }
98  
99      /**
100      * Sets up the test.
101      */
102     protected void setUp ()
103     {
104         provider = new TestProvider();
105         al = provider.getCustomers();
106         h = new Hashtable();
107 
108         h.put("Bar", "this is from a hashtable!");
109         h.put("Foo", "this is from a hashtable too!");
110 
111         /*
112          *  lets set up a vector of objects to test late introspection. See ASTMethod.java
113          */
114 
115         vec = new Vector();
116 
117         vec.addElement(new String("string1"));
118         vec.addElement(new String("string2"));
119 
120         /*
121          *  set up 3 chained contexts, and add our data
122          *  throught the 3 of them.
123          */
124 
125         context2 = new VelocityContext();
126         context1 = new VelocityContext( context2 );
127         context = new VelocityContext( context1 );
128 
129         context.put("provider", provider);
130         context1.put("name", "jason");
131         context1.put("name2", new StringBuffer("jason"));
132         context1.put("name3", new StringBuffer("geoge"));
133         context2.put("providers", provider.getCustomers2());
134         context.put("list", al);
135         context1.put("hashtable", h);
136         context2.put("hashmap", new HashMap());
137         context2.put("search", provider.getSearch());
138         context.put("relatedSearches", provider.getRelSearches());
139         context1.put("searchResults", provider.getRelSearches());
140         context2.put("stringarray", provider.getArray());
141         context.put("vector", vec );
142         context.put("mystring", new String());
143         context.put("runtime", new FieldMethodizer( "org.apache.velocity.runtime.RuntimeSingleton" ));
144         context.put("fmprov", new FieldMethodizer( provider ));
145         context.put("Floog", "floogie woogie");
146         context.put("boolobj", new BoolObj() );
147 
148         /*
149          *  we want to make sure we test all types of iterative objects
150          *  in #foreach()
151          */
152 
153         Object[] oarr = { "a","b","c","d" } ;
154         int intarr[] = { 10, 20, 30, 40, 50 };
155 
156         context.put( "collection", vec );
157         context2.put("iterator", vec.iterator());
158         context1.put("map", h );
159         context.put("obarr", oarr );
160         context.put("enumerator", vec.elements());
161         context.put("intarr", intarr );
162 
163         // Add some Numbers
164         context.put ("int1", new Integer (1000));
165         context.put ("long1", new Long (10000000000l));
166         context.put ("float1", new Float (1000.1234));
167         context.put ("double1", new Double (10000000000d));
168 
169         // Add a TemplateNumber
170         context.put ("templatenumber1", new TestNumber (999.125));
171 
172         /**
173          * Test #foreach() with a list containing nulls
174          */
175         ArrayList nullList = new ArrayList();
176         nullList.add("a");
177         nullList.add("b");
178         nullList.add(null);
179         nullList.add("d");
180         context.put("nullList", nullList);
181 
182         // test silent references with a null tostring
183         context.put("nullToString",new NullToStringObject());
184     }
185 
186     /**
187      * Runs the test.
188      */
189     public void runTest ()
190         throws Exception
191     {
192         Template template = RuntimeSingleton.getTemplate
193             (getFileName(null, baseFileName, TMPL_FILE_EXT));
194 
195         assureResultsDirectoryExists(RESULT_DIR);
196 
197         /* get the file to write to */
198         FileOutputStream fos =
199             new FileOutputStream (getFileName(
200                 RESULT_DIR, baseFileName, RESULT_FILE_EXT));
201 
202         Writer writer = new BufferedWriter(new OutputStreamWriter(fos));
203 
204         /* process the template */
205         template.merge( context, writer);
206 
207         /* close the file */
208         writer.flush();
209         writer.close();
210 
211         if (!isMatch(RESULT_DIR,COMPARE_DIR,baseFileName,
212                 RESULT_FILE_EXT,CMP_FILE_EXT))
213         {
214             fail("Processed template did not match expected output");
215         }
216     }
217 }