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  
27  import junit.framework.Test;
28  import junit.framework.TestSuite;
29  
30  import org.apache.velocity.Template;
31  import org.apache.velocity.VelocityContext;
32  import org.apache.velocity.app.VelocityEngine;
33  import org.apache.velocity.app.event.EventCartridge;
34  import org.apache.velocity.app.event.IncludeEventHandler;
35  import org.apache.velocity.context.Context;
36  import org.apache.velocity.runtime.RuntimeConstants;
37  import org.apache.velocity.runtime.RuntimeServices;
38  import org.apache.velocity.test.misc.TestLogChute;
39  import org.apache.velocity.util.RuntimeServicesAware;
40  
41  /**
42   *  Tests event handling
43   *
44   * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
45   * @version $Id: IncludeEventHandlingTestCase.java 898032 2010-01-11 19:51:03Z nbubna $
46   */
47  public class IncludeEventHandlingTestCase extends BaseTestCase implements IncludeEventHandler,RuntimeServicesAware
48  {
49  
50       /**
51       * VTL file extension.
52       */
53      private static final String TMPL_FILE_EXT = "vm";
54  
55      /**
56       * Comparison file extension.
57       */
58      private static final String CMP_FILE_EXT = "cmp";
59  
60      /**
61       * Comparison file extension.
62       */
63      private static final String RESULT_FILE_EXT = "res";
64  
65      /**
66       * Path for templates. This property will override the
67       * value in the default velocity properties file.
68       */
69      private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/includeevent";
70  
71      /**
72       * Results relative to the build directory.
73       */
74      private static final String RESULTS_DIR = TEST_RESULT_DIR + "/includeevent";
75  
76      /**
77       * Results relative to the build directory.
78       */
79      private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/includeevent/compare";
80  
81  
82      private static final int PASS_THROUGH=0;
83      private static final int RELATIVE_PATH=1;
84      private static final int BLOCK=2;
85  
86      private int EventHandlerBehavior = PASS_THROUGH;
87  
88      VelocityEngine engine;
89      
90      /**
91       * Default constructor.
92       */
93      public IncludeEventHandlingTestCase(String name)
94      {
95          super(name);
96      }
97  
98      public void setUp()
99              throws Exception
100     {
101         assureResultsDirectoryExists(RESULTS_DIR);
102 
103         engine = new VelocityEngine();
104         
105         engine.addProperty(
106                 RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH);
107 
108         engine.setProperty(
109                 RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, TestLogChute.class.getName());
110 
111         engine.init();
112 
113 
114     }
115 
116 
117     public static Test suite ()
118     {
119         return new TestSuite(IncludeEventHandlingTestCase.class);
120     }
121 
122     /**
123      * Runs the test.
124      */
125     public void testIncludeEventHandlingPassThrough ()
126             throws Exception
127     {
128         Template template1 = engine.getTemplate(
129             getFileName(null, "test1", TMPL_FILE_EXT));
130 
131         FileOutputStream fos1 =
132             new FileOutputStream (
133                 getFileName(RESULTS_DIR, "test1", RESULT_FILE_EXT));
134 
135         Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1));
136 
137         // set up handler
138         Context context = new VelocityContext();
139         EventCartridge ec = new EventCartridge();
140         ec.addEventHandler(this);
141         ec.attachToContext( context );
142 
143         // BEHAVIOR A: pass through #input and #parse with no change
144         EventHandlerBehavior = PASS_THROUGH;
145 
146         template1.merge(context, writer1);
147         writer1.flush();
148         writer1.close();
149 
150         assertTrue("Output incorrect.", isMatch(RESULTS_DIR, COMPARE_DIR, "test1",
151                 RESULT_FILE_EXT, CMP_FILE_EXT));
152     }
153 
154     /**
155      * Runs the test.
156      */
157     public void testIncludeEventHandlingRelative()
158             throws Exception
159     {
160         Template template2 = engine.getTemplate(
161             getFileName(null, "subdir/test2", TMPL_FILE_EXT));
162 
163         FileOutputStream fos2 =
164             new FileOutputStream (
165                 getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT));
166 
167         Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2));
168 
169         // set up handler
170         Context context = new VelocityContext();
171         EventCartridge ec = new EventCartridge();
172         ec.addEventHandler(this);
173         ec.attachToContext( context );
174 
175         // BEHAVIOR B: pass through #input and #parse with using a relative path
176         EventHandlerBehavior = RELATIVE_PATH;
177 
178         template2.merge(context, writer2);
179         writer2.flush();
180         writer2.close();
181 
182         assertTrue("Output incorrect.", isMatch(RESULTS_DIR, COMPARE_DIR, "test2",
183                 RESULT_FILE_EXT, CMP_FILE_EXT));
184     }
185 
186     /**
187      * Runs the test.
188      */
189     public void testIncludeEventHandlingBlock()
190             throws Exception
191     {
192         Template template3 = engine.getTemplate(
193             getFileName(null, "test3", TMPL_FILE_EXT));
194 
195         FileOutputStream fos3 =
196             new FileOutputStream (
197                 getFileName(RESULTS_DIR, "test3", RESULT_FILE_EXT));
198 
199         Writer writer3 = new BufferedWriter(new OutputStreamWriter(fos3));
200 
201         // set up handler
202         Context context = new VelocityContext();
203         EventCartridge ec = new EventCartridge();
204         ec.addEventHandler(this);
205         ec.attachToContext( context );
206 
207         // BEHAVIOR C: refuse to pass through #input and #parse
208         EventHandlerBehavior = BLOCK;
209 
210         template3.merge(context, writer3);
211         writer3.flush();
212         writer3.close();
213 
214         assertTrue("Output incorrect.", isMatch(RESULTS_DIR, COMPARE_DIR, "test3",
215                 RESULT_FILE_EXT, CMP_FILE_EXT));
216     }
217 
218     /**
219      * Check bug VELOCITY-717.
220      */
221     public void testIncludeEventHandlingBlockMacros()
222             throws Exception
223     {
224         Template template = engine.getTemplate(
225             getFileName(null, "test7", TMPL_FILE_EXT));
226 
227         FileOutputStream fos =
228             new FileOutputStream (
229                 getFileName(RESULTS_DIR, "test7", RESULT_FILE_EXT));
230 
231         Writer writer = new BufferedWriter(new OutputStreamWriter(fos));
232 
233         // set up handler
234         Context context = new VelocityContext();
235         EventCartridge ec = new EventCartridge();
236         ec.addEventHandler(this);
237         ec.attachToContext( context );
238         
239         EventHandlerBehavior = BLOCK;
240         template.merge(context, writer);
241         writer.flush();
242         writer.close();
243 
244         assertTrue("Output incorrect.", isMatch(RESULTS_DIR, COMPARE_DIR, "test7",
245                 RESULT_FILE_EXT, CMP_FILE_EXT));
246     }
247 
248 
249     public void setRuntimeServices( RuntimeServices rs )
250     {
251     }
252 
253     /**
254      * Sample handler with different behaviors for the different tests.
255      */
256     public String includeEvent( String includeResourcePath, String currentResourcePath, String directiveName)
257     {
258         if (EventHandlerBehavior == PASS_THROUGH)
259             return includeResourcePath;
260 
261 
262         // treat as relative path
263         else if (EventHandlerBehavior == RELATIVE_PATH)
264         {
265             // if the resource name starts with a slash, it's not a relative path
266             if (includeResourcePath.startsWith("/") || includeResourcePath.startsWith("\\") ) {
267                 return includeResourcePath;
268             }
269 
270             int lastslashpos = Math.max(
271                     currentResourcePath.lastIndexOf("/"),
272                     currentResourcePath.lastIndexOf("\\")
273                     );
274 
275             // root of resource tree
276             if ( (lastslashpos == -1))
277                 return includeResourcePath;
278 
279             // prepend path to the input path
280             else
281                 return currentResourcePath.substring(0,lastslashpos) + "/" + includeResourcePath;
282 
283 
284 
285         } else if (EventHandlerBehavior == BLOCK)
286             return null;
287 
288         // should never happen
289         else
290             return null;
291 
292 
293     }
294 
295 
296 }