001: /*
002: * Copyright 2002,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jexl;
017:
018: import java.io.StringReader;
019: import java.math.BigDecimal;
020: import java.math.BigInteger;
021: import java.util.ArrayList;
022: import java.util.BitSet;
023: import java.util.Calendar;
024: import java.util.Collections;
025: import java.util.GregorianCalendar;
026: import java.util.HashMap;
027: import java.util.HashSet;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import junit.framework.Test;
034: import junit.framework.TestCase;
035: import junit.framework.TestSuite;
036:
037: import org.apache.commons.jexl.parser.ParseException;
038: import org.apache.commons.jexl.parser.Parser;
039: import org.apache.commons.jexl.resolver.FlatResolver;
040:
041: /**
042: * Simple testcases
043: *
044: * @since 1.0
045: * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
046: * @version $Id: JexlTest.java 391888 2006-04-06 03:34:59Z dion $
047: */
048: public class JexlTest extends TestCase {
049: protected static final String METHOD_STRING = "Method string";
050: protected static final String GET_METHOD_STRING = "GetMethod string";
051:
052: protected static final String[] GET_METHOD_ARRAY = new String[] {
053: "One", "Two", "Three" };
054:
055: protected static final String[][] GET_METHOD_ARRAY2 = new String[][] {
056: { "One", "Two", "Three" }, { "Four", "Five", "Six" } };
057:
058: public static Test suite() {
059: return new TestSuite(JexlTest.class);
060: }
061:
062: public JexlTest(String testName) {
063: super (testName);
064: }
065:
066: /**
067: * test a simple property expression
068: */
069: public void testProperty() throws Exception {
070: /*
071: * tests a simple property expression
072: */
073:
074: Expression e = ExpressionFactory.createExpression("foo.bar");
075: JexlContext jc = JexlHelper.createContext();
076:
077: jc.getVars().put("foo", new Foo());
078: Object o = e.evaluate(jc);
079:
080: assertTrue("o not instanceof String", o instanceof String);
081: assertEquals("o incorrect", GET_METHOD_STRING, o);
082: }
083:
084: /**
085: * test a simple method expression
086: */
087: public void testMethod() throws Exception {
088: /*
089: * tests a simple method expression
090: */
091: JexlContext jc = JexlHelper.createContext();
092: jc.getVars().put("foo", new Foo());
093: assertExpression(jc, "foo.bar()", METHOD_STRING);
094: }
095:
096: /**
097: * test a simple method expression
098: */
099: public void testArrayAccess() throws Exception {
100: JexlContext jc = JexlHelper.createContext();
101:
102: /*
103: * test List access
104: */
105:
106: List l = new ArrayList();
107: l.add(new Integer(1));
108: l.add(new Integer(2));
109: l.add(new Integer(3));
110:
111: jc.getVars().put("list", l);
112:
113: assertExpression(jc, "list[1]", new Integer(2));
114: assertExpression(jc, "list[1+1]", new Integer(3));
115: jc.getVars().put("loc", new Integer(1));
116: assertExpression(jc, "list[loc+1]", new Integer(3));
117:
118: /*
119: * test array access
120: */
121:
122: String[] args = { "hello", "there" };
123: jc.getVars().put("array", args);
124: assertExpression(jc, "array[0]", "hello");
125:
126: /*
127: * to think that this was an intentional syntax...
128: */
129: assertExpression(jc, "array.0", "hello");
130:
131: /*
132: * test map access
133: */
134: Map m = new HashMap();
135: m.put("foo", "bar");
136:
137: jc.getVars().put("map", m);
138: jc.getVars().put("key", "foo");
139:
140: assertExpression(jc, "map[\"foo\"]", "bar");
141: assertExpression(jc, "map[key]", "bar");
142:
143: /*
144: * test bean access
145: */
146: jc.getVars().put("foo", new Foo());
147: assertExpression(jc, "foo[\"bar\"]", GET_METHOD_STRING);
148: assertExpression(jc, "foo[\"bar\"] == foo.bar", Boolean.TRUE);
149:
150: }
151:
152: public void testMulti() throws Exception {
153: /*
154: * tests a simple property expression
155: */
156: JexlContext jc = JexlHelper.createContext();
157: jc.getVars().put("foo", new Foo());
158: assertExpression(jc, "foo.innerFoo.bar()", METHOD_STRING);
159: }
160:
161: public void testBoolean() throws Exception {
162: JexlContext jc = JexlHelper.createContext();
163: jc.getVars().put("foo", new Foo());
164: jc.getVars().put("a", Boolean.TRUE);
165: jc.getVars().put("b", Boolean.FALSE);
166:
167: assertExpression(jc, "foo.convertBoolean(a==b)",
168: "Boolean : false");
169: assertExpression(jc, "foo.convertBoolean(a==true)",
170: "Boolean : true");
171: assertExpression(jc, "foo.convertBoolean(a==false)",
172: "Boolean : false");
173: assertExpression(jc, "foo.convertBoolean(true==false)",
174: "Boolean : false");
175: assertExpression(jc, "true eq false", Boolean.FALSE);
176: assertExpression(jc, "true ne false", Boolean.TRUE);
177: }
178:
179: public void testStringLit() throws Exception {
180: /*
181: * tests a simple property expression
182: */
183: JexlContext jc = JexlHelper.createContext();
184: jc.getVars().put("foo", new Foo());
185: assertExpression(jc, "foo.get(\"woogie\")", "Repeat : woogie");
186: }
187:
188: public void testExpression() throws Exception {
189: JexlContext jc = JexlHelper.createContext();
190: jc.getVars().put("foo", new Foo());
191: jc.getVars().put("a", Boolean.TRUE);
192: jc.getVars().put("b", Boolean.FALSE);
193: jc.getVars().put("num", new Integer(5));
194: jc.getVars().put("now", Calendar.getInstance().getTime());
195: GregorianCalendar gc = new GregorianCalendar(5000, 11, 20);
196: jc.getVars().put("now2", gc.getTime());
197:
198: assertExpression(jc, "a == b", Boolean.FALSE);
199: assertExpression(jc, "a==true", Boolean.TRUE);
200: assertExpression(jc, "a==false", Boolean.FALSE);
201: assertExpression(jc, "true==false", Boolean.FALSE);
202:
203: assertExpression(jc, "2 < 3", Boolean.TRUE);
204: assertExpression(jc, "num < 5", Boolean.FALSE);
205: assertExpression(jc, "num < num", Boolean.FALSE);
206: assertExpression(jc, "num < null", Boolean.FALSE);
207: assertExpression(jc, "num < 2.5", Boolean.FALSE);
208: assertExpression(jc, "now2 < now", Boolean.FALSE); // test comparable
209: //
210: assertExpression(jc, "'6' <= '5'", Boolean.FALSE);
211: assertExpression(jc, "num <= 5", Boolean.TRUE);
212: assertExpression(jc, "num <= num", Boolean.TRUE);
213: assertExpression(jc, "num <= null", Boolean.FALSE);
214: assertExpression(jc, "num <= 2.5", Boolean.FALSE);
215: assertExpression(jc, "now2 <= now", Boolean.FALSE); // test comparable
216:
217: //
218: assertExpression(jc, "'6' >= '5'", Boolean.TRUE);
219: assertExpression(jc, "num >= 5", Boolean.TRUE);
220: assertExpression(jc, "num >= num", Boolean.TRUE);
221: assertExpression(jc, "num >= null", Boolean.FALSE);
222: assertExpression(jc, "num >= 2.5", Boolean.TRUE);
223: assertExpression(jc, "now2 >= now", Boolean.TRUE); // test comparable
224:
225: assertExpression(jc, "'6' > '5'", Boolean.TRUE);
226: assertExpression(jc, "num > 4", Boolean.TRUE);
227: assertExpression(jc, "num > num", Boolean.FALSE);
228: assertExpression(jc, "num > null", Boolean.FALSE);
229: assertExpression(jc, "num > 2.5", Boolean.TRUE);
230: assertExpression(jc, "now2 > now", Boolean.TRUE); // test comparable
231:
232: assertExpression(jc, "\"foo\" + \"bar\" == \"foobar\"",
233: Boolean.TRUE);
234:
235: }
236:
237: public void testEmpty() throws Exception {
238: JexlContext jc = JexlHelper.createContext();
239: jc.getVars().put("string", "");
240: jc.getVars().put("array", new Object[0]);
241: jc.getVars().put("map", new HashMap());
242: jc.getVars().put("list", new ArrayList());
243: jc.getVars().put("set", (new HashMap()).keySet());
244: jc.getVars().put("longstring", "thingthing");
245:
246: /*
247: * I can't believe anyone thinks this is a syntax.. :)
248: */
249: assertExpression(jc, "empty nullthing", Boolean.TRUE);
250: assertExpression(jc, "empty string", Boolean.TRUE);
251: assertExpression(jc, "empty array", Boolean.TRUE);
252: assertExpression(jc, "empty map", Boolean.TRUE);
253: assertExpression(jc, "empty set", Boolean.TRUE);
254: assertExpression(jc, "empty list", Boolean.TRUE);
255: assertExpression(jc, "empty longstring", Boolean.FALSE);
256: assertExpression(jc, "not empty longstring", Boolean.TRUE);
257: }
258:
259: public void testSize() throws Exception {
260: JexlContext jc = JexlHelper.createContext();
261: jc.getVars().put("s", "five!");
262: jc.getVars().put("array", new Object[5]);
263:
264: Map map = new HashMap();
265:
266: map.put("1", new Integer(1));
267: map.put("2", new Integer(2));
268: map.put("3", new Integer(3));
269: map.put("4", new Integer(4));
270: map.put("5", new Integer(5));
271:
272: jc.getVars().put("map", map);
273:
274: List list = new ArrayList();
275:
276: list.add("1");
277: list.add("2");
278: list.add("3");
279: list.add("4");
280: list.add("5");
281:
282: jc.getVars().put("list", list);
283:
284: // 30652 - support for set
285: Set set = new HashSet();
286: set.addAll(list);
287: set.add("1");
288:
289: jc.getVars().put("set", set);
290:
291: // support generic int size() method
292: BitSet bitset = new BitSet(5);
293: jc.getVars().put("bitset", bitset);
294:
295: assertExpression(jc, "size(s)", new Integer(5));
296: assertExpression(jc, "size(array)", new Integer(5));
297: assertExpression(jc, "size(list)", new Integer(5));
298: assertExpression(jc, "size(map)", new Integer(5));
299: assertExpression(jc, "size(set)", new Integer(5));
300: assertExpression(jc, "size(bitset)", new Integer(64));
301: assertExpression(jc, "list.size()", new Integer(5));
302: assertExpression(jc, "map.size()", new Integer(5));
303: assertExpression(jc, "set.size()", new Integer(5));
304: assertExpression(jc, "bitset.size()", new Integer(64));
305:
306: assertExpression(jc, "list.get(size(list) - 1)", "5");
307: assertExpression(jc, "list[size(list) - 1]", "5");
308: assertExpression(jc, "list.get(list.size() - 1)", "5");
309: }
310:
311: public void testSizeAsProperty() throws Exception {
312: JexlContext jc = JexlHelper.createContext();
313:
314: jc.getVars().put("map",
315: Collections.singletonMap("size", "cheese"));
316: jc.getVars().put("foo", new Foo());
317:
318: assertExpression(jc, "map['size']", "cheese");
319: // PR - unsure whether or not we should support map.size or force usage of the above 'escaped' version
320: // assertExpression(jc, "map.size", "cheese");
321: assertExpression(jc, "foo.getSize()", new Integer(22));
322: // failing assertion for size property
323: //assertExpression(jc, "foo.size", new Integer(22));
324: }
325:
326: /**
327: * test some String method calls
328: */
329: public void testStringMethods() throws Exception {
330: JexlContext jc = JexlHelper.createContext();
331:
332: jc.getVars().put("foo", "abcdef");
333:
334: assertExpression(jc, "foo.substring(3)", "def");
335: assertExpression(jc, "foo.substring(0,(size(foo)-3))", "abc");
336: assertExpression(jc, "foo.substring(0,size(foo)-3)", "abc");
337: assertExpression(jc, "foo.substring(0,foo.length()-3)", "abc");
338: assertExpression(jc, "foo.substring(0, 1+1)", "ab");
339: }
340:
341: /**
342: * test some simple mathematical calculations
343: */
344: public void testUnaryMinus() throws Exception {
345: JexlContext jc = JexlHelper.createContext();
346:
347: jc.getVars().put("aByte", new Byte((byte) 1));
348: jc.getVars().put("aShort", new Short((short) 2));
349: jc.getVars().put("anInteger", new Integer(3));
350: jc.getVars().put("aLong", new Long(4));
351: jc.getVars().put("aFloat", new Float(5.5));
352: jc.getVars().put("aDouble", new Double(6.6));
353: jc.getVars().put("aBigInteger", new BigInteger("7"));
354: jc.getVars().put("aBigDecimal", new BigDecimal("8.8"));
355: assertExpression(jc, "-3", new Integer("-3"));
356: assertExpression(jc, "-3.0", new Float("-3.0"));
357: assertExpression(jc, "-aByte", new Byte((byte) -1));
358: assertExpression(jc, "-aShort", new Short((short) -2));
359: assertExpression(jc, "-anInteger", new Integer(-3));
360: assertExpression(jc, "-aLong", new Long(-4));
361: assertExpression(jc, "-aFloat", new Float(-5.5));
362: assertExpression(jc, "-aDouble", new Double(-6.6));
363: assertExpression(jc, "-aBigInteger", new BigInteger("-7"));
364: assertExpression(jc, "-aBigDecimal", new BigDecimal("-8.8"));
365: }
366:
367: /**
368: * test some simple mathematical calculations
369: */
370: public void testCalculations() throws Exception {
371: JexlContext jc = JexlHelper.createContext();
372:
373: jc.getVars().put("foo", new Integer(2));
374:
375: assertExpression(jc, "foo + 2", new Long(4));
376: assertExpression(jc, "3 + 3", new Long(6));
377: assertExpression(jc, "3 + 3 + foo", new Long(8));
378: assertExpression(jc, "3 * 3", new Long(9));
379: assertExpression(jc, "3 * 3 + foo", new Long(11));
380: assertExpression(jc, "3 * 3 - foo", new Long(7));
381:
382: /*
383: * test some floaty stuff
384: */
385: assertExpression(jc, "3 * \"3.0\"", new Double(9));
386: assertExpression(jc, "3 * 3.0", new Double(9));
387:
388: /*
389: * test / and %
390: */
391: assertExpression(jc, "6 / 3", new Double(6 / 3));
392: assertExpression(jc, "6.4 / 3", new Double(6.4 / 3));
393: assertExpression(jc, "0 / 3", new Double(0 / 3));
394: assertExpression(jc, "3 / 0", new Double(0));
395: assertExpression(jc, "4 % 3", new Long(1));
396: assertExpression(jc, "4.8 % 3", new Double(4.8 % 3));
397:
398: /*
399: * test to ensure new string cat works
400: */
401: jc.getVars().put("stringy", "thingy");
402: assertExpression(jc, "stringy + 2", "thingy2");
403:
404: /*
405: * test new null coersion
406: */
407: jc.getVars().put("imanull", null);
408: assertExpression(jc, "imanull + 2", new Long(2));
409: assertExpression(jc, "imanull + imanull", new Long(0));
410:
411: /* test for bugzilla 31577 */
412: jc.getVars().put("n", new Integer(0));
413: assertExpression(jc, "n != null && n != 0", Boolean.FALSE);
414: }
415:
416: /**
417: * test some simple conditions
418: */
419: public void testConditions() throws Exception {
420: JexlContext jc = JexlHelper.createContext();
421: jc.getVars().put("foo", new Integer(2));
422: jc.getVars().put("aFloat", new Float(1));
423: jc.getVars().put("aDouble", new Double(2));
424: jc.getVars().put("aChar", new Character('A'));
425: jc.getVars().put("aBool", Boolean.TRUE);
426: StringBuffer buffer = new StringBuffer("abc");
427: List list = new ArrayList();
428: List list2 = new LinkedList();
429: jc.getVars().put("aBuffer", buffer);
430: jc.getVars().put("aList", list);
431: jc.getVars().put("bList", list2);
432:
433: assertExpression(jc, "foo == 2", Boolean.TRUE);
434: assertExpression(jc, "2 == 3", Boolean.FALSE);
435: assertExpression(jc, "3 == foo", Boolean.FALSE);
436: assertExpression(jc, "3 != foo", Boolean.TRUE);
437: assertExpression(jc, "foo != 2", Boolean.FALSE);
438: // test float and double equality
439: assertExpression(jc, "aFloat eq aDouble", Boolean.FALSE);
440: assertExpression(jc, "aFloat ne aDouble", Boolean.TRUE);
441: assertExpression(jc, "aFloat == aDouble", Boolean.FALSE);
442: assertExpression(jc, "aFloat != aDouble", Boolean.TRUE);
443: // test number and character equality
444: assertExpression(jc, "foo == aChar", Boolean.FALSE);
445: assertExpression(jc, "foo != aChar", Boolean.TRUE);
446: // test string and boolean
447: assertExpression(jc, "aBool == 'true'", Boolean.TRUE);
448: assertExpression(jc, "aBool == 'false'", Boolean.FALSE);
449: assertExpression(jc, "aBool != 'false'", Boolean.TRUE);
450: // test null and boolean
451: assertExpression(jc, "aBool == notThere", Boolean.FALSE);
452: assertExpression(jc, "aBool != notThere", Boolean.TRUE);
453: // anything and string as a string comparison
454: assertExpression(jc, "aBuffer == 'abc'", Boolean.TRUE);
455: assertExpression(jc, "aBuffer != 'abc'", Boolean.FALSE);
456: // arbitrary equals
457: assertExpression(jc, "aList == bList", Boolean.TRUE);
458: assertExpression(jc, "aList != bList", Boolean.FALSE);
459: }
460:
461: /**
462: * test some simple conditions
463: */
464: public void testNotConditions() throws Exception {
465: JexlContext jc = JexlHelper.createContext();
466:
467: Foo foo = new Foo();
468: jc.getVars().put("x", Boolean.TRUE);
469: jc.getVars().put("foo", foo);
470: jc.getVars().put("bar", "true");
471:
472: assertExpression(jc, "!x", Boolean.FALSE);
473: assertExpression(jc, "x", Boolean.TRUE);
474: assertExpression(jc, "!bar", Boolean.FALSE);
475: assertExpression(jc, "!foo.isSimple()", Boolean.FALSE);
476: assertExpression(jc, "foo.isSimple()", Boolean.TRUE);
477: assertExpression(jc, "!foo.simple", Boolean.FALSE);
478: assertExpression(jc, "foo.simple", Boolean.TRUE);
479: assertExpression(jc, "foo.getCheeseList().size() == 3",
480: Boolean.TRUE);
481: assertExpression(jc, "foo.cheeseList.size() == 3", Boolean.TRUE);
482:
483: jc.getVars().put("string", "");
484: assertExpression(jc, "not empty string", Boolean.FALSE);
485: assertExpression(jc, "not(empty string)", Boolean.FALSE);
486: assertExpression(jc, "not empty(string)", Boolean.FALSE);
487: assertExpression(jc, "! empty string", Boolean.FALSE);
488: assertExpression(jc, "!(empty string)", Boolean.FALSE);
489: assertExpression(jc, "!empty(string)", Boolean.FALSE);
490:
491: }
492:
493: /**
494: * GMJ : disabled - need to fix
495: *
496: * test some simple conditions
497: */
498: public void testNotConditionsWithDots() throws Exception {
499: JexlContext jc = JexlHelper.createContext();
500:
501: jc.getVars().put("x.a", Boolean.TRUE);
502: jc.getVars().put("x.b", Boolean.FALSE);
503:
504: assertExpression(jc, "x.a", Boolean.TRUE);
505: assertExpression(jc, "!x.a", Boolean.FALSE);
506: assertExpression(jc, "!x.b", Boolean.TRUE);
507: }
508:
509: /**
510: * test some simple conditions
511: */
512: public void testComparisons() throws Exception {
513: JexlContext jc = JexlHelper.createContext();
514: jc.getVars().put("foo", "the quick and lazy fox");
515:
516: assertExpression(jc, "foo.indexOf('quick') > 0", Boolean.TRUE);
517: assertExpression(jc, "foo.indexOf('bar') >= 0", Boolean.FALSE);
518: assertExpression(jc, "foo.indexOf('bar') < 0", Boolean.TRUE);
519: }
520:
521: /**
522: * test some null conditions
523: */
524: public void testNull() throws Exception {
525: JexlContext jc = JexlHelper.createContext();
526: jc.getVars().put("bar", new Integer(2));
527:
528: assertExpression(jc, "empty foo", Boolean.TRUE);
529: assertExpression(jc, "bar == null", Boolean.FALSE);
530: assertExpression(jc, "foo == null", Boolean.TRUE);
531: assertExpression(jc, "bar != null", Boolean.TRUE);
532: assertExpression(jc, "foo != null", Boolean.FALSE);
533: assertExpression(jc, "empty(bar)", Boolean.FALSE);
534: assertExpression(jc, "empty(foo)", Boolean.TRUE);
535: }
536:
537: /**
538: * test some blank strings
539: */
540: public void testBlankStrings() throws Exception {
541: JexlContext jc = JexlHelper.createContext();
542: jc.getVars().put("bar", "");
543:
544: assertExpression(jc, "foo == ''", Boolean.FALSE);
545: assertExpression(jc, "bar == ''", Boolean.TRUE);
546: assertExpression(jc, "barnotexist == ''", Boolean.FALSE);
547: assertExpression(jc, "empty bar", Boolean.TRUE);
548: assertExpression(jc, "bar.length() == 0", Boolean.TRUE);
549: assertExpression(jc, "size(bar) == 0", Boolean.TRUE);
550: }
551:
552: /**
553: * test some blank strings
554: */
555: public void testLogicExpressions() throws Exception {
556: JexlContext jc = JexlHelper.createContext();
557: jc.getVars().put("foo", "abc");
558: jc.getVars().put("bar", "def");
559:
560: assertExpression(jc, "foo == 'abc' || bar == 'abc'",
561: Boolean.TRUE);
562: assertExpression(jc, "foo == 'abc' or bar == 'abc'",
563: Boolean.TRUE);
564: assertExpression(jc, "foo == 'abc' && bar == 'abc'",
565: Boolean.FALSE);
566: assertExpression(jc, "foo == 'abc' and bar == 'abc'",
567: Boolean.FALSE);
568:
569: assertExpression(jc, "foo == 'def' || bar == 'abc'",
570: Boolean.FALSE);
571: assertExpression(jc, "foo == 'def' or bar == 'abc'",
572: Boolean.FALSE);
573: assertExpression(jc, "foo == 'abc' && bar == 'def'",
574: Boolean.TRUE);
575: assertExpression(jc, "foo == 'abc' and bar == 'def'",
576: Boolean.TRUE);
577: }
578:
579: /**
580: * test some simple double array lookups
581: */
582: public void testDoubleArrays() throws Exception {
583: JexlContext jc = JexlHelper.createContext();
584:
585: Object[][] foo = new Object[2][2];
586: foo[0][0] = "one";
587: foo[0][1] = "two";
588:
589: jc.getVars().put("foo", foo);
590:
591: assertExpression(jc, "foo[0][1]", "two");
592: }
593:
594: /**
595: * test variables with underscore names
596: */
597: public void testVariableNames() throws Exception {
598: JexlContext jc = JexlHelper.createContext();
599: jc.getVars().put("foo_bar", "123");
600:
601: assertExpression(jc, "foo_bar", "123");
602: }
603:
604: /**
605: * test the use of dot notation to lookup map entries
606: */
607: public void testMapDot() throws Exception {
608: Map foo = new HashMap();
609: foo.put("bar", "123");
610:
611: JexlContext jc = JexlHelper.createContext();
612: jc.getVars().put("foo", foo);
613:
614: assertExpression(jc, "foo.bar", "123");
615: }
616:
617: /**
618: * Tests string literals
619: */
620: public void testStringLiterals() throws Exception {
621: JexlContext jc = JexlHelper.createContext();
622: jc.getVars().put("foo", "bar");
623:
624: assertExpression(jc, "foo == \"bar\"", Boolean.TRUE);
625: assertExpression(jc, "foo == 'bar'", Boolean.TRUE);
626: }
627:
628: /**
629: * test the use of an int based property
630: */
631: public void testIntProperty() throws Exception {
632: Foo foo = new Foo();
633:
634: // lets check the square function first..
635: assertEquals(4, foo.square(2));
636: assertEquals(4, foo.square(-2));
637:
638: JexlContext jc = JexlHelper.createContext();
639: jc.getVars().put("foo", foo);
640:
641: assertExpression(jc, "foo.count", new Integer(5));
642: assertExpression(jc, "foo.square(2)", new Integer(4));
643: assertExpression(jc, "foo.square(-2)", new Integer(4));
644: }
645:
646: /**
647: * test the -1 comparison bug
648: */
649: public void testNegativeIntComparison() throws Exception {
650: JexlContext jc = JexlHelper.createContext();
651: Foo foo = new Foo();
652: jc.getVars().put("foo", foo);
653:
654: assertExpression(jc, "foo.count != -1", Boolean.TRUE);
655: assertExpression(jc, "foo.count == 5", Boolean.TRUE);
656: assertExpression(jc, "foo.count == -1", Boolean.FALSE);
657: }
658:
659: public void testArrayProperty() throws Exception {
660: Foo foo = new Foo();
661:
662: JexlContext jc = JexlHelper.createContext();
663: jc.getVars().put("foo", foo);
664:
665: assertExpression(jc, "foo.array[1]", GET_METHOD_ARRAY[1]);
666: assertExpression(jc, "foo.array.1", GET_METHOD_ARRAY[1]);
667: assertExpression(jc, "foo.array2[1][1]",
668: GET_METHOD_ARRAY2[1][1]);
669: //assertExpression(jc, "foo.array2.1.1", GET_METHOD_ARRAY2[1][1]);
670: }
671:
672: /**
673: * Attempts to recreate bug http://jira.werken.com/ViewIssue.jspa?key=JELLY-8
674: */
675: public void testCharAtBug() throws Exception {
676: JexlContext jc = JexlHelper.createContext();
677:
678: jc.getVars().put("foo", "abcdef");
679:
680: assertExpression(jc, "foo.substring(2,4)", "cd");
681: assertExpression(jc, "foo.charAt(2)", new Character('c'));
682:
683: try {
684: assertExpression(jc, "foo.charAt(-2)", null);
685: fail("this test should have thrown an exception");
686: } catch (IndexOutOfBoundsException e) {
687: // expected behaviour
688: } catch (Exception e) {
689: throw e;
690: }
691: }
692:
693: public void testEmptyDottedVariableName() throws Exception {
694: JexlContext jc = JexlHelper.createContext();
695:
696: jc.getVars().put("this.is.a.test", "");
697:
698: assertExpression(jc, "empty(this.is.a.test)", Boolean.TRUE);
699: }
700:
701: public void testEmptySubListOfMap() throws Exception {
702: JexlContext jc = JexlHelper.createContext();
703: Map m = Collections.singletonMap("aList",
704: Collections.EMPTY_LIST);
705:
706: jc.getVars().put("aMap", m);
707:
708: assertExpression(jc, "empty( aMap.aList )", Boolean.TRUE);
709: }
710:
711: public void testCoercionWithComparisionOperators() throws Exception {
712: JexlContext jc = JexlHelper.createContext();
713:
714: assertExpression(jc, "'2' > 1", Boolean.TRUE);
715: assertExpression(jc, "'2' >= 1", Boolean.TRUE);
716: assertExpression(jc, "'2' >= 2", Boolean.TRUE);
717: assertExpression(jc, "'2' < 1", Boolean.FALSE);
718: assertExpression(jc, "'2' <= 1", Boolean.FALSE);
719: assertExpression(jc, "'2' <= 2", Boolean.TRUE);
720:
721: assertExpression(jc, "2 > '1'", Boolean.TRUE);
722: assertExpression(jc, "2 >= '1'", Boolean.TRUE);
723: assertExpression(jc, "2 >= '2'", Boolean.TRUE);
724: assertExpression(jc, "2 < '1'", Boolean.FALSE);
725: assertExpression(jc, "2 <= '1'", Boolean.FALSE);
726: assertExpression(jc, "2 <= '2'", Boolean.TRUE);
727: }
728:
729: public void testResolver() throws Exception {
730: /*
731: * first, a simple override
732: */
733:
734: Expression expr = ExpressionFactory.createExpression("foo.bar");
735: expr.addPreResolver(new FlatResolver());
736:
737: JexlContext jc = JexlHelper.createContext();
738: Foo foo = new Foo();
739: jc.getVars().put("foo.bar", "flat value");
740: jc.getVars().put("foo", foo);
741:
742: Object o = expr.evaluate(jc);
743: assertEquals("flat override", "flat value", o);
744:
745: /*
746: * now, let the resolver not find it and have it drop to jexl
747: */
748: expr = ExpressionFactory.createExpression("foo.bar.length()");
749: expr.addPreResolver(new FlatResolver());
750: o = expr.evaluate(jc);
751: assertEquals("flat override 1", new Integer(GET_METHOD_STRING
752: .length()), o);
753:
754: /*
755: * now, let the resolver not find it and NOT drop to jexl
756: */
757:
758: expr = ExpressionFactory.createExpression("foo.bar.length()");
759: expr.addPreResolver(new FlatResolver(false));
760: o = expr.evaluate(jc);
761: assertEquals("flat override 2", o, null);
762:
763: // now for a post resolver
764: expr = ExpressionFactory.createExpression("foo.bar.baz");
765: Long result = new Long(1);
766: jc.getVars().put("foo.bar.baz", result);
767: expr.addPostResolver(new FlatResolver());
768: assertEquals("flat override", result, expr.evaluate(jc));
769:
770: }
771:
772: /**
773: * Test that 'and' only evaluates the second item if needed
774: * @throws Exception if there are errors
775: */
776: public void testBooleanShortCircuitAnd() throws Exception {
777: // handle false for the left arg of 'and'
778: Foo tester = new Foo();
779: JexlContext jc = JexlHelper.createContext();
780: jc.getVars().put("first", Boolean.FALSE);
781: jc.getVars().put("foo", tester);
782: Expression expr = ExpressionFactory
783: .createExpression("first and foo.trueAndModify");
784: expr.evaluate(jc);
785: assertTrue(
786: "Short circuit failure: rhs evaluated when lhs FALSE",
787: !tester.getModified());
788: // handle true for the left arg of 'and'
789: tester = new Foo();
790: jc.getVars().put("first", Boolean.TRUE);
791: jc.getVars().put("foo", tester);
792: expr.evaluate(jc);
793: assertTrue(
794: "Short circuit failure: rhs not evaluated when lhs TRUE",
795: tester.getModified());
796: }
797:
798: /**
799: * Test that 'or' only evaluates the second item if needed
800: * @throws Exception if there are errors
801: */
802: public void testBooleanShortCircuitOr() throws Exception {
803: // handle false for the left arg of 'or'
804: Foo tester = new Foo();
805: JexlContext jc = JexlHelper.createContext();
806: jc.getVars().put("first", Boolean.FALSE);
807: jc.getVars().put("foo", tester);
808: Expression expr = ExpressionFactory
809: .createExpression("first or foo.trueAndModify");
810: expr.evaluate(jc);
811: assertTrue(
812: "Short circuit failure: rhs not evaluated when lhs FALSE",
813: tester.getModified());
814: // handle true for the left arg of 'or'
815: tester = new Foo();
816: jc.getVars().put("first", Boolean.TRUE);
817: jc.getVars().put("foo", tester);
818: expr.evaluate(jc);
819: assertTrue(
820: "Short circuit failure: rhs evaluated when lhs TRUE",
821: !tester.getModified());
822: }
823:
824: /**
825: * Simple test of '+' as a string concatenation operator
826: * @throws Exception
827: */
828: public void testStringConcatenation() throws Exception {
829: JexlContext jc = JexlHelper.createContext();
830: jc.getVars().put("first", "Hello");
831: jc.getVars().put("second", "World");
832: assertExpression(jc, "first + ' ' + second", "Hello World");
833: }
834:
835: /**
836: * Ensures static methods on objects can be called.
837: */
838: public void testStaticMethodInvocation() throws Exception {
839: JexlContext jc = JexlHelper.createContext();
840: jc.getVars().put("aBool", Boolean.FALSE);
841: assertExpression(jc, "aBool.valueOf('true')", Boolean.TRUE);
842: }
843:
844: public void testStaticMethodInvocationOnClasses() throws Exception {
845: JexlContext jc = JexlHelper.createContext();
846: jc.getVars().put("Boolean", Boolean.class);
847: assertExpression(jc, "Boolean.valueOf('true')", Boolean.TRUE);
848: }
849:
850: public void testToString() throws Exception {
851: String code = "abcd";
852: Expression expr = ExpressionFactory.createExpression(code);
853: assertEquals("Bad expression value", code, expr.toString());
854: }
855:
856: /**
857: * Make sure bad syntax throws ParseException
858: * @throws Exception on errors
859: */
860: public void testBadParse() throws Exception {
861: try {
862: assertExpression(JexlHelper.createContext(), "empty()",
863: null);
864: fail("Bad expression didn't throw ParseException");
865: } catch (ParseException pe) {
866: // expected behaviour
867: }
868: }
869:
870: /**
871: * Test the ## comment in a string
872: * @throws Exception
873: */
874: public void testComment() throws Exception {
875: assertExpression(JexlHelper.createContext(),
876: "## double or nothing\n 1 + 1", Long.valueOf("2"));
877: }
878:
879: /**
880: * Test assignment.
881: * @throws Exception
882: */
883: public void testAssignment() throws Exception {
884: JexlContext jc = JexlHelper.createContext();
885: jc.getVars().put("aString", "Hello");
886: Foo foo = new Foo();
887: jc.getVars().put("foo", foo);
888: Parser parser = new Parser(new StringReader(";"));
889: parser.parse(new StringReader("aString = 'World';"));
890:
891: assertExpression(jc, "hello = 'world'", "world");
892: assertEquals("hello variable not changed", "world", jc
893: .getVars().get("hello"));
894: assertExpression(jc, "result = 1 + 1", new Long(2));
895: assertEquals("result variable not changed", new Long(2), jc
896: .getVars().get("result"));
897: // todo: make sure properties can be assigned to, fall back to flat var if no property
898: // assertExpression(jc, "foo.property1 = '99'", "99");
899: // assertEquals("property not set", "99", foo.getProperty1());
900: }
901:
902: public void testAntPropertiesWithMethods() throws Exception {
903: JexlContext jc = JexlHelper.createContext();
904: String value = "Stinky Cheese";
905: jc.getVars().put("maven.bob.food", value);
906: assertExpression(jc, "maven.bob.food.length()", new Integer(
907: value.length()));
908: assertExpression(jc, "empty(maven.bob.food)", Boolean.FALSE);
909: assertExpression(jc, "size(maven.bob.food)", new Integer(value
910: .length()));
911: assertExpression(jc, "maven.bob.food + ' is good'", value
912: + " is good");
913:
914: // DG: Note the following ant properties don't work
915: // String version = "1.0.3";
916: // jc.getVars().put("commons-logging", version);
917: // assertExpression(jc, "commons-logging", version);
918: }
919:
920: /**
921: * Asserts that the given expression returns the given value when applied to the
922: * given context
923: */
924: protected void assertExpression(JexlContext jc, String expression,
925: Object expected) throws Exception {
926: Expression e = ExpressionFactory.createExpression(expression);
927: Object actual = e.evaluate(jc);
928: assertEquals(expression, expected, actual);
929: }
930:
931: /**
932: * Helps in debugging the testcases when working with it
933: *
934: */
935: public static void main(String[] args) throws Exception {
936: JexlTest jt = new JexlTest("foo");
937: jt.testEmpty();
938: }
939:
940: }
|