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.StringWriter;
23  import java.lang.reflect.Array;
24  import java.util.Arrays;
25  import java.util.ArrayList;
26  import java.util.List;
27  import junit.framework.Test;
28  import junit.framework.TestCase;
29  import junit.framework.TestSuite;
30  import org.apache.velocity.VelocityContext;
31  import org.apache.velocity.app.VelocityEngine;
32  import org.apache.velocity.runtime.RuntimeConstants;
33  import org.apache.velocity.runtime.log.SystemLogChute;
34  
35  /**
36   * Used to check that method calls on Array references work properly
37   * and that they produce the same results as the same methods would on
38   * a fixed-size {@link List}.
39   */
40  public class ArrayMethodsTestCase extends TestCase
41  {
42      private VelocityEngine engine;
43      private VelocityContext context;
44  
45      private final static boolean PRINT_RESULTS = true;
46  
47      public ArrayMethodsTestCase(final String name)
48      {
49          super(name);
50      }
51  
52      public void setUp() throws Exception
53      {
54          engine = new VelocityEngine();
55  
56          // make the engine's log output go to the test-report
57          SystemLogChute log = new SystemLogChute();
58          log.setEnabledLevel(SystemLogChute.INFO_ID);
59          log.setSystemErrLevel(SystemLogChute.WARN_ID);
60          engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, log);
61  
62          context = new VelocityContext();
63      }
64  
65      public void tearDown()
66      {
67          engine = null;
68          context = null;
69      }
70  
71      public static Test suite ()
72      {
73          return new TestSuite(ArrayMethodsTestCase.class);
74      }
75  
76      /**
77       * Runs the test.
78       */
79      public void testArrayMethods() throws Exception
80      {
81          // test an array of string objects
82          Object array = new String[] { "foo", "bar", "baz" };
83          checkResults(array, "woogie", true);
84  
85          // test an array of primitive ints
86          array = new int[] { 1, 3, 7 };
87          checkResults(array, new Integer(11), false);
88  
89          // test an array of mixed objects, including null
90          array = new Object[] { new Double(2.2), null };
91          checkResults(array, "whatever", true);
92          // then set all the values to null
93          checkResults(array, null, true);
94  
95          // then try an empty array
96          array = new Object[] {};
97          checkResults(array, null, true);
98  
99          // while we have an empty array and list in the context,
100         // make sure $array.get(0) and $list.get(0) throw
101         // the same type of exception (MethodInvocationException)
102         Throwable lt = null;
103         Throwable at = null;
104         try
105         {
106             evaluate("$list.get(0)");
107         }
108         catch (Throwable t)
109         {
110             lt = t;
111         }
112         try
113         {
114             evaluate("$array.get(0)");
115         }
116         catch (Throwable t)
117         {
118             at = t;
119         }
120         assertEquals(lt.getClass(), at.getClass());
121     }
122 
123     private void checkResults(Object array, Object setme,
124                               boolean compareToList) throws Exception
125     {
126         context.put("array", array);
127         if (compareToList)
128         {
129             // create a list to match...
130             context.put("list", new ArrayList(Arrays.asList((Object[])array)));
131         }
132 
133         // if the object to be set is null, then remove instead of put
134         if (setme != null)
135         {
136             context.put("setme", setme);
137         }
138         else
139         {
140             context.remove("setme");
141         }
142 
143         if (PRINT_RESULTS)
144         {
145             System.out.println("Changing to an array of: " + array.getClass().getComponentType());
146             System.out.println("Changing setme to: " + setme);
147         }
148 
149         int size = Array.getLength(array);
150         checkResult("size()", String.valueOf(size), compareToList);
151 
152         boolean isEmpty = (size == 0);
153         checkResult("isEmpty()", String.valueOf(isEmpty), compareToList);
154 
155         for (int i=0; i < size; i++)
156         {
157             // put the index in the context, so we can try
158             // both an explicit index and a reference index
159             context.put("index", new Integer(i));
160 
161             Object value = Array.get(array, i);
162             String get = "get($index)";
163             String set = "set("+i+", $setme)";
164             if (value == null)
165             {
166                 checkEmptyResult(get, compareToList);
167                 // set should return null
168                 checkEmptyResult(set, compareToList);
169             }
170             else
171             {
172                 checkResult(get, value.toString(), compareToList);
173                 // set should return the old get value
174                 checkResult(set, value.toString(), compareToList);
175             }
176 
177             // check that set() actually changed the value
178             assertEquals(setme, Array.get(array, i));
179 
180             // and check that get() now returns setme
181             if (setme == null)
182             {
183                 checkEmptyResult(get, compareToList);
184             }
185             else
186             {
187                 checkResult(get, setme.toString(), compareToList);
188             }
189         }
190     }
191 
192     private void checkEmptyResult(String method, boolean compareToList)
193         throws Exception
194     {
195         checkResult(method, "", compareToList);
196     }
197 
198     private void checkResult(String method, String expected,
199                              boolean compareToList) throws Exception
200     {
201         String result = evaluate("$!array."+method);
202         assertEquals(expected, result);
203 
204         String listResult = null;
205         if (compareToList)
206         {
207             listResult = evaluate("$!list."+method);
208             assertEquals(result, listResult);
209         }
210 
211         if (PRINT_RESULTS)
212         {
213             System.out.println("    <$!array."+method+"> resolved to <"+result+">");
214             if (compareToList)
215             {
216                 System.out.println("    <$!list."+method+"> resolved to "+listResult+">");
217             }
218         }
219     }
220 
221     private String evaluate(String template) throws Exception
222     {
223         StringWriter writer = new StringWriter();
224         // use template as its own name, since our templates are short
225         engine.evaluate(context, writer, template, template);
226         return writer.toString();
227     }
228 
229 }
230 
231