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.util.HashMap;
23  
24  import org.apache.velocity.app.VelocityEngine;
25  import org.apache.velocity.runtime.RuntimeConstants;
26  
27  /**
28   * This class tests the directive scope controls
29   */
30  public class ScopeTestCase extends BaseTestCase
31  {
32      public ScopeTestCase(String name)
33      {
34         super(name);
35      }
36  
37      protected void setUpEngine(VelocityEngine engine)
38      {
39          engine.setProperty("a.provide.scope.control", "true");
40          engine.setProperty("define.provide.scope.control", "true");
41          engine.setProperty("evaluate.provide.scope.control", "true");
42          engine.setProperty("foo.provide.scope.control", "true");
43          engine.setProperty("macro.provide.scope.control", "true");
44          engine.setProperty("template.provide.scope.control", "true");
45          engine.setProperty("vm.provide.scope.control", "true");
46          engine.setProperty(RuntimeConstants.SET_NULL_ALLOWED, Boolean.TRUE);
47      }
48  
49      public void testScopeGetLeakIntoInner()
50      {
51          addTemplate("foo", "#foreach($i in [1..1])#set($foreach.a=$i)"+
52                             "#foreach($j in [2..2])$foreach.a#set($foreach.a=$j)"+
53                             "#foreach($k in [3..3])$foreach.a#end#end$foreach.a#end");
54          assertTmplEquals("121", "foo");
55      }
56  
57      public void testScopeGetLeakDoesntHideNullset()
58      {
59          addTemplate("a", "#macro(a)#set($macro.a='a')#b()$macro.a#end"+
60                           "#macro(b)$macro.a#set($macro.a=$null)$!macro.a#end"+
61                           "#a()");
62          assertTmplEquals("aa", "a");
63      }
64  
65      public void testRootTemplateMergeScope()
66      {
67          addTemplate("foo", "foo#break($template)bar");
68          assertTmplEquals("foo", "foo");
69          assertNull(context.get("template"));
70      }
71  
72      public void testParseScope()
73      {
74          addTemplate("test", "$template.info.depth"+
75                              "$!parse.parent.info.depth"+
76                              "#set( $template.foo = 'bar' )"+
77                              "$template.foo"+
78                              "#break($template)"+
79                              "woogie");
80          assertEvalEquals("1bar", "#parse( 'test' )");
81          assertNull(context.get("template"));
82      }
83  
84      public void testNestedParseScope()
85      {
86          HashMap grab = new HashMap();
87          context.put("grab", grab);
88  
89          addTemplate("inner", "Inner depth: $template.info.depth"+
90                               "#set( $template.foo = '?' )"+
91                               "$!grab.put('inner',$template)"+
92                               "#break($template)$template.foo");
93          addTemplate("outer", "#set( $template.foo = '!' )"+
94                               "Outer depth: $template.info.depth "+
95                               "#parse('inner')"+
96                               "$!grab.put('outer', $template)"+
97                               "$template.foo");
98          assertEvalEquals("Outer depth: 1 Inner depth: 2!", "#parse('outer')");
99          // make extra sure that the outer control was restored after the stop
100         assertFalse(grab.get("inner") == grab.get("outer"));
101         // make sure the outer control was cleaned up
102         assertNull(context.get("template"));
103 
104         addTemplate("3", "$template.topmost.foo#set( $template.topmost.foo = 'bar' )");
105         addTemplate("2", "#parse( '3' )$!parse.foo");
106         addTemplate("1", "#set( $template.foo = 'foo' )#parse('2')$template.foo");
107         assertEvalEquals("foobar", "#parse('1')$!parse");
108         // make sure the top control was cleaned up
109         assertNull(context.get("template"));
110     }
111 
112     public void testForeachScope()
113     {
114         String template = "#foreach( $i in [0..2] )"+
115                           "#if( $i > 1 )#break($foreach)#end"+
116                           "$foreach.index:$foreach.count:$foreach.hasNext,"+
117                           "#end";
118         assertEvalEquals("0:1:true,1:2:true,", template);
119         assertNull(context.get("foreach"));
120     }
121 
122     public void testNestedForeachScope()
123     {
124         String template = "#foreach( $i in [1..5] )"+
125                             "#foreach( $j in [1..2] )"+
126                               "#if ( $i > $foreach.count + $foreach.index + $foreach.info.depth )#break($foreach.topmost)#end"+
127                             "#end"+
128                             "$i"+
129                           "#end";
130         assertEvalEquals("123", template);
131         assertNull(context.get("foreach"));
132     }
133 
134     public void testMacroScope()
135     {
136         String template = "#macro( foo $i )"+
137                           "#if($i > 2 )#break($macro)#end"+
138                           "$i#end"+
139                           "#foo( 0 )#foo( 1 )#foo( 2 )";
140         assertEvalEquals("012", template);
141         assertNull(context.get("macro"));
142     }
143 
144     public void testRecursiveMacroScope()
145     {
146         String template = "#macro( foo )$macro.info.depth"+
147                           "#if($macro.info.depth > 2 )#break($macro.topmost)#end"+
148                           "#foo()#end#foo()";
149         assertEvalEquals("123", template);
150         assertNull(context.get("macro"));
151     }
152 
153     public void testNestedMacroScope()
154     {
155         String template = "#macro( a )$macro.info.depth#set($macro.c = 'a')$macro.c#end"+
156                           "#macro( b )#set($macro.c = 'b' )#a()$macro.c#end"+
157                           "#b()";
158         assertEvalEquals("2ab", template);
159         assertNull(context.get("macro"));
160     }
161 
162     public void testBodyMacroScope()
163     {
164         String template = "#macro( foo $bar )$bodyContent$macro.bar#end"+
165                           "#@foo( 'bar' )#set( $macro.bar = 'foo'+$bar )"+
166                           "#set( $foo.d = $foo.info.depth )$foo.d #end";
167         assertEvalEquals("1 foobar", template);
168         assertNull(context.get("foo"));
169         assertNull(context.get("macro"));
170     }
171 
172     public void testRecursiveBodyMacroScope()
173     {
174         engine.setProperty(RuntimeConstants.VM_MAX_DEPTH, "5");
175         String template = "#macro( foo )$bodyContent$macro.i#end"+
176                           "#@foo()#set( $macro.i = \"$!macro.i$foo.info.depth,\" )"+
177                           "$!bodyContent#end";
178         assertEvalEquals("1,2,3,4,5,", template);
179         assertNull(context.get("foo"));
180         assertNull(context.get("macro"));
181     }
182 
183     public void testDefineScope()
184     {
185         String template = "#define( $foo )#set( $define.bar = 'bar'+$define.info.depth )$define.bar#end$foo";
186         assertEvalEquals("bar1", template);
187         assertNull(context.get("define"));
188     }
189 
190     public void testNestedDefineScope()
191     {
192         String template = "#define($a)$b c#end"+
193                           "#define($b)$define.info.depth#break($define.topmost)#end"+
194                           "$a";
195         assertEvalEquals("2", template);
196         assertNull(context.get("define"));
197     }
198 
199     public void testRecursiveDefineScope()
200     {
201         engine.setProperty(RuntimeConstants.DEFINE_DIRECTIVE_MAXDEPTH, "10");
202         String template = "#define($a)$define.info.depth"+
203                           "#if($define.info.depth == 5)#break($define)#end,$a#end$a";
204         assertEvalEquals("1,2,3,4,5", template);
205         assertNull(context.get("define"));
206     }
207 
208     public void testRootEvaluateScope()
209     {
210         assertEvalEquals("1", "$evaluate.info.depth");
211         assertEvalEquals("foo", "foo#break($evaluate)bar");
212         assertNull(context.get("evaluate"));
213     }
214 
215     public void testEvaluateScope()
216     {
217         context.put("h", "#");
218         context.put("d", "$");
219         String template = "${h}set( ${d}evaluate.foo = 'bar' )"+
220                           "${d}evaluate.foo ${d}evaluate.info.depth";
221         addTemplate("eval", "#evaluate(\""+template+"\")");
222         assertTmplEquals("bar 1", "eval");
223         assertNull(context.get("evaluate"));
224         assertNull(context.get("template"));
225     }
226 
227     public void testNestedEvaluateScope()
228     {
229         context.put("h", "#");
230         context.put("d", "$");
231         addTemplate("e", "#evaluate(\"${h}evaluate( '${d}evaluate.info.depth${h}stop(${d}evaluate) blah' )\")");
232         assertTmplEquals("2", "e");
233         assertNull(context.get("evaluate"));
234         assertNull(context.get("template"));
235     }
236 
237     public void testTurningOffTemplateScope()
238     {
239         engine.setProperty("template."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
240         // root
241         addTemplate("test", "$template.info.depth");
242         assertTmplEquals("$template.info.depth", "test");
243         // #parse
244         assertEvalEquals("$template.info.depth", "#parse('test')");
245     }
246 
247     public void testTurningOffEvaluateScope()
248     {
249         engine.setProperty("evaluate."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
250         // root
251         assertSchmoo("$evaluate.info.depth");
252         // #evaluate
253         assertEvalEquals("$evaluate.info.depth", "#evaluate( '$evaluate.info.depth' )");
254     }
255 
256     public void testTurningOffMacroScope()
257     {
258         engine.setProperty("macro."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
259         engine.setProperty("foo."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
260         // macro definition
261         assertEvalEquals("$macro", "#macro(a)$macro#end#a()");
262         // macro body
263         assertEvalEquals("$macro $foo", "#macro(foo)$bodyContent#end#@foo()$macro $foo#end");
264     }
265 
266     public void testTurningOffDefineScope()
267     {
268         engine.setProperty("define."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
269         assertEvalEquals("$define", "#define($a)$define#end$a");
270     }
271 
272     public void testTurningOffForeachScope()
273     {
274         engine.setProperty("foreach."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false");
275         assertEvalEquals("$foreach$foreach", "#foreach($i in [0..1])$foreach#end");
276     }
277 
278     public void testTemplateReplaced()
279     {
280         context.put("template", "foo");
281         addTemplate("test", "$template.replaced");
282         assertTmplEquals("foo", "test");
283         assertEvalEquals("foo", "#parse('test')");
284         assertContextValue("template", "foo");
285     }
286 
287     public void testEvaluateReplaced()
288     {
289         context.put("evaluate","foo");
290         assertEvalEquals("foo", "$evaluate.replaced");
291         assertEvalEquals("foo", "#evaluate('$evaluate.replaced')");
292         assertContextValue("evaluate", "foo");
293     }
294 
295     public void testMacroReplaced()
296     {
297         context.put("macro", "foo");
298         assertEvalEquals("foo foo foo", "$macro #macro(a)$macro.replaced#end#a() $macro");
299         assertContextValue("macro", "foo");
300     }
301 
302     public void testForeachReplaced()
303     {
304         context.put("foreach", "foo");
305         assertEvalEquals("foofoofoo", "$foreach#foreach($i in [1..1])$foreach.replaced#end$foreach");
306         assertEquals("foo", context.get("foreach"));
307         context.put("foreach", "a");
308         assertEvalEquals("a", "#foreach($i in [1..1])#foreach($j in [1..1])$foreach.replaced#end#end");
309         assertContextValue("foreach", "a");
310     }
311 
312     public void testDefineReplaced()
313     {
314         context.put("define", "a");
315         assertEvalEquals("a", "#define($a)$define.replaced#end$a");
316         assertContextValue("define", "a");
317     }
318 
319     public void testBodyContentReplaced()
320     {
321         context.put("vm", "a");
322         assertEvalEquals("a", "#macro(vm)$bodyContent#end#@vm()$vm.replaced#end");
323         assertContextValue("vm", "a");
324     }
325 
326     public void testInfoDepth()
327     {
328         String template = "#foreach($i in [1..1])"+
329                             "#foreach($j in [0..0])"+
330                                 "$foreach.info.depth"+
331                             "#end"+
332                           "#end";
333         assertEvalEquals("2", template);
334     }
335 
336     public void testInfoName()
337     {
338         String template = "#foreach($i in [1..1])"+
339                             "$foreach.info.name #evaluate('$evaluate.info.name')"+
340                           "#end";
341         assertEvalEquals("foreach evaluate", template);
342     }
343 
344     public void testInfoType()
345     {
346         addTemplate("info", "#foreach($i in [1..1])"+
347                                 "$foreach.info.type"+
348                             "#end "+
349                             "#evaluate('$evaluate.info.type') "+
350                             "$template.info.type");
351         assertTmplEquals("block line utf-8", "info");
352     }
353 
354     public void testInfoLineAndColumn()
355     {
356         String template = " #evaluate('$evaluate.info.line, $evaluate.info.column')";
357         assertEvalEquals(" 1, 2", template);
358         assertEvalEquals("\n\n   3, 4", "\n\n  "+template);
359     }
360 
361     public void testInfoTemplate()
362     {
363         addTemplate("test", "#evaluate('$evaluate.info.template')");
364         assertTmplEquals("test", "test");
365         assertEvalEquals("test", "#parse('test')");
366     }
367 
368 }