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