1   /*
2    * $Id: TestValidWhen.java 504715 2007-02-07 22:10:26Z bayard $
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  package org.apache.struts.validator;
22  
23  import junit.framework.Test;
24  import junit.framework.TestCase;
25  import junit.framework.TestSuite;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.commons.validator.util.ValidatorUtils;
30  import org.apache.struts.validator.validwhen.ValidWhenLexer;
31  import org.apache.struts.validator.validwhen.ValidWhenParser;
32  
33  import java.io.StringReader;
34  
35  /**
36   * Unit tests for the ValidWhen Parser/Lexer.
37   */
38  public class TestValidWhen extends TestCase {
39      /**
40       * All logging goes through this logger
41       */
42      private static Log log = LogFactory.getLog(TestValidWhen.class);
43      protected PojoBean testBean;
44  
45      /**
46       * Defines the testcase name for JUnit.
47       *
48       * @param theName the testcase's name.
49       */
50      public TestValidWhen(String theName) {
51          super(theName);
52      }
53  
54      /**
55       * Start the tests.
56       *
57       * @param theArgs the arguments. Not used
58       */
59      public static void main(String[] theArgs) {
60          junit.awtui.TestRunner.main(new String[] { TestValidWhen.class.getName() });
61      }
62  
63      /**
64       * @return a test suite (<code>TestSuite</code>) that includes all methods
65       *         starting with "test"
66       */
67      public static Test suite() {
68          // All methods starting with "test" will be executed in the test suite.
69          return new TestSuite(TestValidWhen.class);
70      }
71  
72      public void setUp() {
73          testBean = new PojoBean(123, 789);
74          testBean.setStringValue1("ABC");
75          testBean.setStringValue2(null);
76          testBean.setBeans(new PojoBean[] {
77                  new PojoBean(11, 12), new PojoBean(21, 22), new PojoBean(31, 42),
78                  new PojoBean(41, 52), new PojoBean(51, 62)
79              });
80          testBean.setMapped("testKey", "mappedValue");
81      }
82  
83      public void tearDown() {
84          testBean = null;
85      }
86  
87      /**
88       * Test Operators.
89       */
90      public void testProperty() {
91          // *this*
92          doParse("(*this* == 123)", testBean, 0, "intValue1", true);
93  
94          // Named property
95          doParse("(intValue2 == 789)", testBean, 0, "intValue1", true);
96  
97          // Indexed Property
98          doParse("(beans[].intValue1 == 21)", testBean, 1, "intValue1", true);
99          doParse("(beans[1].intValue1 == 21)", testBean, 4, "intValue1", true);
100 
101         // Mapped Property - *** NOT SUPPORTED ***
102         // doParse("(mapped(mappedValue) == 'testKey')", testBean , 0, "mappedValue", true);
103     }
104 
105     /**
106      * Test Operators.
107      */
108     public void testOperators() {
109         // Equal
110         doParse("(*this* == 123)", testBean, 0, "intValue1", true);
111 
112         // Not Equal
113         doParse("(*this* != 456)", testBean, 0, "intValue1", true);
114 
115         // Less Than
116         doParse("(*this* < 456)", testBean, 0, "intValue1", true);
117 
118         // Greater Than
119         doParse("(*this* > 100)", testBean, 0, "intValue1", true);
120 
121         // Less Than Equal
122         doParse("(*this* <= 123)", testBean, 0, "intValue1", true);
123 
124         // Greater Than Equal
125         doParse("(*this* >= 123)", testBean, 0, "intValue1", true);
126     }
127 
128     /**
129      * Test String values.
130      */
131     public void testString() {
132         doParse("(*this* != '--')", "XX", 0, "stringValue1", true);
133         doParse("(*this* == '--')", "--", 0, "stringValue1", true);
134 
135         String testValue = "dsgUOLMdLsdL";
136 
137         // single quote
138         doParse("(*this* == '" + testValue + "')", testValue, 0,
139             "stringValue1", true);
140 
141         // double quote
142         doParse("(*this* == \"" + testValue + "\")", testValue, 0,
143             "stringValue1", true);
144 
145         // obscure characters
146         doParse("(*this* == \":\")", ":", 0,
147             "stringValue1", true);
148         doParse("(*this* == \"foo:bar\")", "foo:bar", 0,
149             "stringValue1", true);
150     }
151 
152     /**
153      * Test Numeric values.
154      */
155     public void testNumeric() {
156         // Test Zero
157         PojoBean numberBean = new PojoBean(0, -50);
158 
159         doParse("(intValue1 == 0)", numberBean, 0, "intValue1", true);
160         doParse("(intValue2 != 0)", numberBean, 0, "intValue2", true);
161         doParse("(integerValue1 == 0)", numberBean, 0, "integerValue1", true);
162         doParse("(integerValue2 != 0)", numberBean, 0, "integerValue2", true);
163 
164         // int
165         doParse("(intValue1 == 123)", testBean, 0, "intValue1", true);
166 
167         // Integer
168         doParse("(integerValue1 == 123)", testBean, 0, "integerValue1", true);
169 
170         // Negative Numbers
171         doParse("((intValue2 < -10)     and (intValue2 > -60))", numberBean, 0,
172             "intValue2", true);
173         doParse("((integerValue2 < -10) and (integerValue2 > -60))",
174             numberBean, 0, "integerValue2", true);
175 
176         // Hex
177         doParse("(integerValue1 == 0x7B)", testBean, 0, "integerValue1", true);
178 
179         // Octal
180         doParse("(integerValue1 == 0173)", testBean, 0, "integerValue1", true);
181 
182         // Test 'String' numbers
183         PojoBean stringBean = new PojoBean("11", "2");
184 
185         doParse("(stringValue1 > stringValue2)", stringBean, 0, "stringValue1",
186             true);
187         doParse("(stringValue1 < stringValue2)", stringBean, 0, "stringValue1",
188             false);
189     }
190 
191     /**
192      * Test Null.
193      */
194     public void testNull() {
195         // Not Null
196         doParse("(*this* != null)", testBean, 0, "stringValue1", true);
197 
198         // Null
199         doParse("(*this* == null)", testBean, 0, "stringValue2", true);
200     }
201 
202     /**
203      * Test Joined expressions ('and' or 'or')
204      */
205     public void testJoined() {
206         // Join with 'or'
207         doParse("((*this* == 'ABC') or (stringValue2 == null))", testBean, 0,
208             "stringValue1", true);
209         doParse("((*this* != 'ABC') or (stringValue2 == null))", testBean, 0,
210             "stringValue1", true);
211         doParse("((*this* == 'ABC') or (stringValue2 != null))", testBean, 0,
212             "stringValue1", true);
213         doParse("((*this* != 'ABC') or (stringValue2 != null))", testBean, 0,
214             "stringValue1", false);
215 
216         // Join with 'and'
217         doParse("((*this* == 'ABC') and (stringValue2 == null))", testBean, 0,
218             "stringValue1", true);
219         doParse("((*this* != 'ABC') and (stringValue2 == null))", testBean, 0,
220             "stringValue1", false);
221         doParse("((*this* == 'ABC') and (stringValue2 != null))", testBean, 0,
222             "stringValue1", false);
223         doParse("((*this* != 'ABC') and (stringValue2 != null))", testBean, 0,
224             "stringValue1", false);
225     }
226 
227     /**
228      * Parse the expression and check that the expected result (either true or
229      * false) occurs - fail if an exception is thrown opr the wrong result
230      * occurs.
231      *
232      * @param test     Test expression
233      * @param bean     Test Bean
234      * @param index    index value
235      * @param property Bean property
236      * @param expected Expected Result
237      */
238     private void doParse(String test, Object bean, int index, String property,
239         boolean expected) {
240         boolean result = false;
241 
242         try {
243             result = doParse(test, bean, index, property);
244         } catch (Exception ex) {
245             log.error("Parsing " + test + " for property '" + property + "'", ex);
246             fail("Parsing " + test + " threw " + ex);
247         }
248 
249         if (expected) {
250             assertTrue(test + " didn't return TRUE for " + property, result);
251         } else {
252             assertFalse(test + " didn't return FALSE for " + property, result);
253         }
254     }
255 
256     /**
257      * Parse the expression and check that an Exception is throw. Failes if no
258      * expection is thrown.
259      *
260      * @param test     Test expression
261      * @param bean     Test Bean
262      * @param index    index value
263      * @param property Bean property
264      */
265     private void doParseFail(String test, Object bean, int index,
266         String property) {
267         try {
268             boolean result = doParse(test, bean, index, property);
269 
270             fail("Parsing " + test + " didn't throw exception as expected "
271                 + result);
272         } catch (Exception expected) {
273             // ignore exception - expected result
274         }
275     }
276 
277     /**
278      * Parse the expression returning the result
279      *
280      * @param test     Test expression
281      * @param bean     Test Bean
282      * @param index    index value
283      * @param property Bean property
284      */
285     private boolean doParse(String test, Object bean, int index, String property)
286         throws Exception {
287         if (bean == null) {
288             throw new NullPointerException("Bean is null for property '"
289                 + property + "'");
290         }
291 
292         String value =
293             String.class.isInstance(bean) ? (String) bean
294                                           : ValidatorUtils.getValueAsString(bean,
295                 property);
296 
297         ValidWhenLexer lexer = new ValidWhenLexer(new StringReader(test));
298 
299         ValidWhenParser parser = new ValidWhenParser(lexer);
300 
301         parser.setForm(bean);
302         parser.setIndex(index);
303         parser.setValue(value);
304 
305         parser.expression();
306 
307         return parser.getResult();
308     }
309 }