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 org.apache.velocity.exception.MethodInvocationException;
23  import org.apache.velocity.exception.VelocityException;
24  import org.apache.velocity.exception.ParseErrorException;
25  import org.apache.velocity.runtime.RuntimeConstants;
26  
27  /**
28   * Test strict reference mode turned on by the velocity property
29   * runtime.references.strict
30   */
31  public class StrictReferenceTestCase extends BaseTestCase
32  {
33      public StrictReferenceTestCase(String name)
34      {
35          super(name);
36      }
37  
38      public void setUp() throws Exception
39      {
40          super.setUp();
41          engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE);
42          context.put("NULL", null);
43          context.put("bar", null);
44          context.put("TRUE", Boolean.TRUE);
45      }
46      
47      /**
48       * Test the modified behavior of #if in strict mode.  Mainly, that
49       * single variables references in #if statements use non strict rules
50       */
51      public void testIfStatement()
52      {
53          Fargo fargo = new Fargo();
54          fargo.next = new Fargo();
55          context.put("fargo", fargo);
56          assertEvalEquals("", "#if($bogus)xxx#end");
57          assertEvalEquals("xxx", "#if($fargo)xxx#end");
58          assertEvalEquals("", "#if( ! $fargo)xxx#end");
59          assertEvalEquals("xxx", "#if($bogus || $fargo)xxx#end");
60          assertEvalEquals("", "#if($bogus && $fargo)xxx#end");
61          assertEvalEquals("", "#if($fargo != $NULL && $bogus)xxx#end");
62          assertEvalEquals("xxx", "#if($fargo == $NULL || ! $bogus)xxx#end");
63          assertEvalEquals("xxx", "#if(! $bogus1 && ! $bogus2)xxx#end");
64          assertEvalEquals("xxx", "#if($fargo.prop == \"propiness\" && ! $bogus && $bar == $NULL)xxx#end");
65          assertEvalEquals("", "#if($bogus && $bogus.foo)xxx#end");
66  
67          assertMethodEx("#if($bogus.foo)#end");
68          assertMethodEx("#if(!$bogus.foo)#end");
69      }
70      
71      
72      /**       
73       * We make sure that variables can actuall hold null
74       * values.
75       */
76      public void testAllowNullValues()
77          throws Exception
78      {
79          evaluate("$!bar");
80          assertEvalEquals("true", "#if($bar == $NULL)true#end");
81          assertEvalEquals("true", "#set($foobar = $NULL)#if($foobar == $NULL)true#end");
82          assertEvalEquals("13", "#set($list = [1, $NULL, 3])#foreach($item in $list)#if($item != $NULL)$item#end#end");
83      }
84      
85      /**
86       * Test that variables references that have not been defined throw exceptions 
87       */
88      public void testStrictVariableRef()
89          throws Exception
90      {
91          // We expect a Method exception on the following
92          assertMethodEx("$bogus");
93          assertMethodEx("#macro(test)$bogus#end #test()");
94  
95          assertMethodEx("#set($bar = $bogus)");
96  
97          assertMethodEx("#if($bogus == \"bar\") #end");
98          assertMethodEx("#if($bogus != \"bar\") #end");
99          assertMethodEx("#if(\"bar\" == $bogus) #end");
100         assertMethodEx("#if($bogus > 1) #end");
101         assertMethodEx("#foreach($item in $bogus)#end");
102 
103         // make sure no exceptions are thrown here    
104         evaluate("#set($foo = \"bar\") $foo");     
105         evaluate("#macro(test1 $foo1) $foo1 #end #test1(\"junk\")");
106         evaluate("#macro(test2) #set($foo2 = \"bar\") $foo2 #end #test2()");
107     }
108     
109     /**
110      * Test that exceptions are thrown when methods are called on
111      * references that contains objects that do not contains those
112      * methods.
113      */
114     public void testStrictMethodRef()
115     {
116         Fargo fargo = new Fargo();
117         fargo.next = new Fargo();
118         context.put("fargo", fargo);        
119 
120         // Mainly want to make sure no exceptions are thrown here
121         assertEvalEquals("propiness", "$fargo.prop");
122         assertEvalEquals("", "$!fargo.nullVal");
123         assertEvalEquals("propiness", "$fargo.next.prop");
124 
125         assertMethodEx("$fargo.foobar");
126         assertMethodEx("$fargo.next.foobar");
127         assertMethodEx("$fargo.foobar()");
128         assertMethodEx("#set($fargo.next.prop = $TRUE)");
129         assertMethodEx("$fargo.next.setProp($TRUE)");
130     }
131   
132     /**
133      * Make sure exceptions are thrown when when we attempt to call
134      * methods on null values.
135      */
136     public void testStrictMethodOnNull()
137     {
138         Fargo fargo = new Fargo();
139         fargo.next = new Fargo();
140         context.put("fargo", fargo);
141 
142         assertVelocityEx("$NULL.bogus");
143         assertVelocityEx("$fargo.nullVal.bogus");
144         assertVelocityEx("$fargo.next.nullVal.bogus");
145         assertVelocityEx("#if (\"junk\" == $fargo.nullVal.bogus)#end");
146         assertVelocityEx("#if ($fargo.nullVal.bogus > 2)#end");
147         assertVelocityEx("#set($fargo.next.nullVal.bogus = \"junk\")");
148         assertVelocityEx("#set($foo = $NULL.bogus)");
149         assertVelocityEx("#foreach($item in $fargo.next.nullVal.bogus)#end");
150 
151         evaluate("$fargo.prop.toString()");
152         assertVelocityEx("#set($fargo.prop = $NULL)$fargo.prop.next");
153 
154         // make sure no exceptions are thrown here
155         evaluate("$!fargo.next.next");
156         evaluate("$!fargo.next.nullVal");
157         evaluate("#foreach($item in $fargo.nullVal)#end");
158     }
159 
160     /**
161      * Make sure undefined macros throw exceptions
162      */
163     public void testMacros()
164     {
165         assertVelocityEx("#bogus()");
166         assertVelocityEx("#bogus (  )");
167         assertVelocityEx("#bogus( $a )");        
168         assertVelocityEx("abc#bogus ( $a )a ");
169 
170         assertEvalEquals(" true ", "#macro(test1) true #end#test1()");
171         assertEvalEquals(" true ", "#macro(test2 $a) $a #end#test2 ( \"true\")");
172         assertEvalEquals("#CCFFEE", "#CCFFEE");
173         assertEvalEquals("#F - ()", "#F - ()");
174         assertEvalEquals("#F{}", "#F{}");
175     }
176     
177     
178     public void testRenderingNull()
179     {
180         Fargo fargo = new Fargo();
181         fargo.next = new Fargo();
182         context.put("fargo", fargo);      
183       
184         assertVelocityEx("#set($foo = $NULL)$foo");
185         assertEvalEquals("", "#set($foo = $NULL)$!foo");
186         assertVelocityEx("$fargo.nullVal");
187         assertEvalEquals("", "$!fargo.nullVal");
188         assertVelocityEx("$fargo.next.next");
189         assertEvalEquals("", "$!fargo.next.next");
190         assertVelocityEx("$fargo.next.nullVal");
191         assertEvalEquals("", "$!fargo.next.nullVal");
192     }
193     
194     /**
195      * Assert that we get a MethodInvocationException when calling evaluate
196      */
197     public void assertMethodEx(String template)
198     {
199         assertEvalException(template, MethodInvocationException.class);
200     }
201 
202     /**
203      * Assert that we get a VelocityException when calling evaluate
204      */
205     public void assertVelocityEx(String template)
206     {
207         assertEvalException(template, VelocityException.class);
208     }
209 
210     /**
211      * Assert that we get a MethodInvocationException when calling evaluate
212      */
213     public void assertParseEx(String template)
214     {
215         assertEvalException(template, ParseErrorException.class);
216     }
217 
218 
219     public static class Fargo
220     {
221         String prop = "propiness";
222         Fargo next = null;
223       
224         public String getProp()
225         {
226             return prop;
227         }
228 
229         public void setProp(String val)
230         {
231             this.prop = val;
232         }
233 
234         public String getNullVal()
235         {
236             return null;
237         }
238 
239         public Fargo getNext()
240         {
241             return next;
242         }      
243     }  
244 }