@Override
    public void run() {
      System.out.println("dog is running");
    }
  }

  public static class Cat extends Pet {
    @Override
    public void run() {
      System.out.println("cat is running");
    }
  }

  public void testSetExpressions2() {
    Foo foo = new Foo();
    Collection col = new ArrayList();
    final Serializable fooExpr = compileSetExpression("collectionTest");
    executeSetExpression(fooExpr,
        foo,
        col);
    assertEquals(col,
        foo.getCollectionTest());
  }

  public class Fruit {
    public class Apple {

    }
  }

  public void testInnerClassReference() {
    assertEquals(Fruit.Apple.class,
        test("import " + CoreConfidenceTests.class.getName() + "; CoreConfidenceTests.Fruit.Apple"));
  }

  public void testEdson() {
    assertEquals("foo",
        test("list = new java.util.ArrayList(); list.add(new String('foo')); list[0]"));
  }

  public void testEnumSupport() {
    MyInterface myInterface = new MyClass();
    myInterface.setType(MyInterface.MY_ENUM.TWO,
        true);
    boolean isType = MVEL.eval("isType(org.mvel2.tests.core.res.MyInterface$MY_ENUM.ONE)",
        myInterface,
        Boolean.class);
    System.out.println(isType);

  }

  public void testOperatorPrecedenceOrder() {
    Serializable compiled =
        compileExpression("bean1.successful && bean2.failed || bean1.failed && bean2.successful");
    Map context = new HashMap();

    BeanB bean1 = new BeanB(true);
    BeanB bean2 = new BeanB(false);

    context.put("bean1",
        bean1);
    context.put("bean2",
        bean2);

    System.out.println("interpreted: "
        + MVEL.eval("bean1.successful && bean2.failed || bean1.failed && bean2.successful",
        context));

    assertEquals(bean1.isSuccessful() && bean2.isFailed() || bean1.isFailed() && bean2.isSuccessful(),
        (boolean) executeExpression(compiled,
            context,
            Boolean.class));
  }

  public static class BeanB {
    private boolean successful;

    public BeanB(boolean successful) {
      this.successful = successful;
    }

    public boolean isSuccessful() {
      return successful;
    }

    public boolean isFailed() {
      return !successful;
    }
  }

  public void testJIRA139() {
    ParserContext ctx = new ParserContext();
    ctx.addImport("ReflectionUtil",
        ReflectionUtil.class);
    Serializable s = compileExpression("ReflectionUtil.getGetter('foo')",
        ctx);
    assertEquals(ReflectionUtil.getGetter("foo"),
        executeExpression(s));
  }

  public void testJIRA140() {
    ParserContext ctx = new ParserContext();
    Serializable s = compileExpression("import org.mvel2.tests.core.res.*;"
        + "cols = new Column[] { new Column('name', 20), new Column('age', 2) };"
        + "grid = new Grid(new Model(cols));",
        ctx);

    Grid g = (Grid) executeExpression(s,
        new HashMap());

    assertEquals(g.getModel().getColumns()[0].getName(),
        "name");
    assertEquals(g.getModel().getColumns()[0].getLength(),
        20);
    assertEquals(g.getModel().getColumns()[1].getName(),
        "age");
    assertEquals(g.getModel().getColumns()[1].getLength(),
        2);
  }

  public void testVerifierWithIndexedProperties() {
    ParserContext ctx = new ParserContext();
    ctx.setStrictTypeEnforcement(true);
    ctx.addInput("base",
        Base.class);

    Serializable s = compileExpression("base.fooMap['foo'].setName('coffee')",
        ctx);

    Map vars = new HashMap();
    vars.put("base",
        new Base());

    executeExpression(s,
        vars);

    assertEquals("coffee",
        ((Base) vars.get("base")).fooMap.get("foo").getName());
  }


  public void testEmpty() {
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);

    Serializable s = compileExpression("list = new java.util.ArrayList(); list == empty",
        ctx);

    Map vars = new HashMap();

    Boolean x = (Boolean) executeExpression(s,
        vars);

    assertNotNull(x);
    assertTrue(x.booleanValue());
  }

  public void testMapsAndLists() {
    OptimizerFactory.setDefaultOptimizer("ASM");

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addImport(HashMap.class);
    ctx.addImport(ArrayList.class);
    ctx.addInput("list",
        List.class);

    String expression = "m = new HashMap();\n" + "l = new ArrayList();\n" + "l.add(\"first\");\n" +
        "m.put(\"content\", l);\n" + "list.add(((ArrayList)m[\"content\"])[0]);";

    Serializable s = compileExpression(expression,
        ctx);

    Map vars = new HashMap();
    List list = new ArrayList();
    vars.put("list",
        list);

    Boolean result = (Boolean) executeExpression(s,
        vars);

    assertNotNull(result);
    assertTrue(result);
    assertEquals(1,
        list.size());
    assertEquals("first",
        list.get(0));
  }

  public void testMapsAndLists2() {
    OptimizerFactory.setDefaultOptimizer("reflective");

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addImport(HashMap.class);
    ctx.addImport(ArrayList.class);
    ctx.addInput("list",
        List.class);

    String expression = "m = new HashMap();\n" + "l = new ArrayList();\n" + "l.add(\"first\");\n" +
        "m.put(\"content\", l);\n" + "list.add(((ArrayList)m[\"content\"])[0]);";

    Serializable s = compileExpression(expression,
        ctx);

    Map vars = new HashMap();
    List list = new ArrayList();
    vars.put("list",
        list);

    Boolean result = (Boolean) executeExpression(s,
        vars);

    assertNotNull(result);
    assertTrue(result);
    assertEquals(1,
        list.size());
    assertEquals("first",
        list.get(0));
  }

  public void testReturnBoolean() {
    String ex = "list = new java.util.ArrayList(); return list != null";

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    Serializable s = compileExpression(ex,
        ctx);

    assertEquals(true,
        executeExpression(s,
            new HashMap()));
  }

  public void testComaProblemStrikesBack() {
    String ex = "a.explanation = \"There is a coma, in here\"";

    ParserContext ctx = new ParserContext();
    ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);
    Serializable s = compiler.compile();

    Base a = new Base();
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("a",
        a);

    executeExpression(s,
        variables);
    assertEquals("There is a coma, in here",
        a.data);
  }


  public static interface Services {
    public final static String A_CONST = "Hello World";

    public void log(String text);
  }

  public void testStringConcatenation() {
    // debugging MVEL code, it seems that MVEL 'thinks' that the result of the expression:
    // "Drop +5%: "+$sb+" avg: $"+$av+" price: $"+$pr
    // is a double, and as so, he looks for a method:
    // Services.log( double );
    // but finds only:
    // Services.log( String );
    // raising the error.
    String ex = "services.log((String) \"Drop +5%: \"+$sb+\" avg: $\"+$av+\" price: $\"+$pr );";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("$sb",
        String.class);
    ctx.addInput("$av",
        double.class);
    ctx.addInput("$pr",
        double.class);
    ctx.addInput("services",
        Services.class);
    try {
      ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);
      compiler.compile();
    }
    catch (Throwable e) {
      e.printStackTrace();
      fail("Should not raise exception: " + e.getMessage());
    }
  }

  public void testStringConcatenation2() {
    String ex = "services.log( $cheese + \" some string \" );";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("$cheese",
        Cheese.class);
    ctx.addInput("services",
        Services.class);
    try {
      ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);
      compiler.compile();
    }
    catch (Throwable e) {
      e.printStackTrace();
      fail("Should not raise exception: " + e.getMessage());
    }
  }

  public void testStringConcatenation3() {
    // BUG: return type of the string concatenation is inferred as double instead of String
    String ex = "services.log($av + \"Drop +5%: \"+$sb+\" avg: $\"+percent($av)+\" price: $\"+$pr );";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.setStrictTypeEnforcement(true);
    ctx.addInput("$sb",
        String.class);
    ctx.addInput("$av",
        double.class);
    ctx.addInput("$pr",
        double.class);
    ctx.addInput("services",
        Services.class);
    ctx.addImport("percent", MVEL.getStaticMethod(String.class, "valueOf", new Class[]{double.class}));
    try {
      Serializable compiledExpression = MVEL.compileExpression(ex, ctx);

      Services services = new Services() {
        public void log(String text) {
        }
      };
      Map<String, Object> vars = new HashMap<String, Object>();
      vars.put("services", services);
      vars.put("$sb", "RHT");
      vars.put("$av", 15.0);
      vars.put("$pr", 10.0);

      MVEL.executeExpression(compiledExpression, vars);
    }
    catch (Throwable e) {
      e.printStackTrace();
      fail("Should not raise exception: " + e.getMessage());
    }
  }

  public void testMapsWithVariableAsKey() {
    String ex = "aMap[aKey] == 'aValue'";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(false);

    ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);
    compiler.setVerifyOnly(true);
    compiler.compile();

    Set<String> requiredInputs = compiler.getParserContextState().getInputs().keySet();
    assertTrue(requiredInputs.contains("aMap"));
    assertTrue(requiredInputs.contains("aKey"));
  }

  public void testMapsWithVariableAsKey2() {
    String ex = "objectKeyMaptributes[$aPerson] == foo";
    Foo foo = new Foo();
    Person person = new Person();
    person.setObjectKeyMaptributes(new HashMap<Object, Foo>());
    person.getObjectKeyMaptributes().put(person, foo);
    Map<String, Class> inputs = new HashMap<String, Class>();
    inputs.put("this", Person.class);
    inputs.put("foo", Foo.class);
    inputs.put("$aPerson", Person.class);
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.setInputs(inputs);

    Serializable expression = MVEL.compileExpression(ex, ctx);
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("foo", foo);
    variables.put("$aPerson", person);

    Boolean result = (Boolean) MVEL.executeExpression(expression, person, variables);
    assertTrue(result);
  }

  public static void testProjectionUsingThis() {
    Set records = new HashSet();
    for (int i = 0; i < 53; i++) {
      Bean2 record = new Bean2(i);
      records.add(record);
    }

    Object result = MVEL.eval("(_prop in this)",
        records);
    System.out.println("result: " + result);
  }

  public static final class Bean2 {
    public final int _prop;

    public Bean2(int prop_) {
      _prop = prop_;
    }

    public int getProp() {
      return _prop;
    }

    public String toString() {
      return Integer.toString(_prop);
    }
  }

  public void testUnaryOpNegation1() {
    assertEquals(false,
        test("!new Boolean(true)"));
  }

  public void testUnaryOpNegation2() {
    assertEquals(true,
        test("!isdef _foozy_"));
  }

  public class Az {
    public void foo(String s) {
    }
  }

  public class Bz extends Az {
  }

  public void testJIRA151() {
    OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE);
    Bz b = new Bz();
    ParserContext context = new ParserContext();
    Object expression = MVEL.compileExpression("a.foo(value)",
        context);
    Map<String, Object> variables = new HashMap<String, Object>();

    variables.put("a",
        b);
    variables.put("value",
        123);
    for (int i = 0; i < 100; i++) {
      System.out.println("i: " + i);
      System.out.flush();
      executeExpression(expression,
          variables);
    }
  }

  public void testJIRA151b() {
    OptimizerFactory.setDefaultOptimizer("ASM");
    Bz b = new Bz();
    ParserContext context = new ParserContext();
    Object expression = MVEL.compileExpression("a.foo(value)",
        context);
    Map<String, Object> variables = new HashMap<String, Object>();

    variables.put("a",
        b);
    variables.put("value",
        123);
    for (int i = 0; i < 100; i++) {
      System.out.println("i: " + i);
      System.out.flush();
      executeExpression(expression,
          variables);
    }
  }


  public void testJIRA153() {
    assertEquals(false,
        MVEL.eval("!(true)"));
    assertEquals(false,
        executeExpression(MVEL.compileExpression("!(true)")));
  }

  public void testMultipleNegations() {
    assertEquals(true,
        executeExpression(MVEL.compileExpression("!false")));
    assertEquals(false,
        executeExpression(MVEL.compileExpression("!!false")));
    assertEquals(true,
        executeExpression(MVEL.compileExpression("!!!false")));
    assertEquals(false,
        executeExpression(MVEL.compileExpression("!!!!false")));
  }

  public void testJIRA154() {
    Map m = createTestMap();
    m.put("returnTrue",
        MVEL.getStaticMethod(CoreConfidenceTests.class,
            "returnTrue",
            new Class[0]));

    assertEquals(false,
        MVEL.eval("!returnTrue()",
            m));
  }

  public void testJIRA154b() {
    ParserContext pctx = new ParserContext();
    pctx.addImport("returnTrue",
        MVEL.getStaticMethod(CoreConfidenceTests.class,
            "returnTrue",
            new Class[0]));

    assertEquals(false,
        executeExpression(MVEL.compileExpression("!(returnTrue())",
            pctx)));
  }

  public void testJIRA155() {
    ParserContext pctx = new ParserContext();
    pctx.addImport("returnTrue",
        MVEL.getStaticMethod(CoreConfidenceTests.class,
            "returnTrue",
            new Class[0]));

    assertEquals(true,
        executeExpression(MVEL.compileExpression("!true || returnTrue()",
            pctx)));
  }

  public void testJIRA155b() {
    ParserContext pctx = new ParserContext();
    pctx.addImport("returnTrue",
        MVEL.getStaticMethod(CoreConfidenceTests.class,
            "returnTrue",
            new Class[0]));

    assertEquals(true,
        executeExpression(MVEL.compileExpression("!(!true || !returnTrue())",
            pctx)));
  }

  public void testJIRA156() throws Throwable {
    ClassProvider provider = new ClassProvider();
    provider.getPrivate().foo();

    PublicClass.class.getMethod("foo").invoke(provider.getPrivate());

    String script = "provider.getPrivate().foo()";
    HashMap<String, Object> vars = new HashMap<String, Object>();
    vars.put("provider",
        provider);
    MVEL.eval(script,
        vars);
  }

  public void testJIRA156b() throws Throwable {
    ClassProvider provider = new ClassProvider();
    provider.getPrivate().foo();

    PublicClass.class.getMethod("foo").invoke(provider.getPrivate());

    String script = "provider.getPrivate().foo()";

    Serializable s = MVEL.compileExpression(script);

    HashMap<String, Object> vars = new HashMap<String, Object>();
    vars.put("provider",
        provider);

    OptimizerFactory.setDefaultOptimizer("reflective");
    executeExpression(s,
        vars);
    OptimizerFactory.setDefaultOptimizer("ASM");
    executeExpression(s,
        vars);
  }

  public void testJIRA156c() throws Throwable {
    ClassProvider provider = new ClassProvider();
    provider.getPublic().foo();

    PublicClass.class.getMethod("foo").invoke(provider.getPublic());

    String script = "provider.getPublic().foo()";

    Serializable s = MVEL.compileExpression(script);

    HashMap<String, Object> vars = new HashMap<String, Object>();
    vars.put("provider",
        provider);

    MVEL.eval(script,
        vars);
    OptimizerFactory.setDefaultOptimizer("reflective");
    executeExpression(s,
        vars);
    OptimizerFactory.setDefaultOptimizer("ASM");
    executeExpression(s,
        vars);
  }

  public static boolean returnTrue() {
    return true;
  }

  public static class TestHelper {
    public static void method(int id,
                              Object[] arr) {
      System.out.println(id + " -> " + arr.length);
    }

    public static void method(Object obj1, Object obj2) {
      System.out.println(obj1 + "-> " + obj2);
    }

    public static Calendar minDate() {
      return Calendar.getInstance();
    }

    public static Calendar maxDate() {
      return Calendar.getInstance();
    }
  }

  public static class Fooz {
    public Fooz(String id) {
    }
  }

  public void testArray() {
    String ex = " TestHelper.method(1, new String[]{\"a\", \"b\"});\n"
        + " TestHelper.method(2, new String[]{new String(\"a\"), new String(\"b\")});\n"
        + " TestHelper.method(3, new Fooz[]{new Fooz(\"a\"), new Fooz(\"b\")});";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addImport(TestHelper.class);
    ctx.addImport(Fooz.class);
    ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);

    OptimizerFactory.setDefaultOptimizer("ASM");
    CompiledExpression expr = compiler.compile();
    executeExpression(expr);

    OptimizerFactory.setDefaultOptimizer("reflective");
    expr = compiler.compile();
    executeExpression(expr);
  }

  public void testArray2() {
    String ex = " TestHelper.method(1, {\"a\", \"b\"});\n"
        + " TestHelper.method(2, {new String(\"a\"), new String(\"b\")});\n"
        + " TestHelper.method(3, {new Fooz(\"a\"), new Fooz(\"b\")});";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addImport(TestHelper.class);
    ctx.addImport(Fooz.class);
    ExpressionCompiler compiler = new ExpressionCompiler(ex, ctx);

    OptimizerFactory.setDefaultOptimizer("ASM");
    CompiledExpression expr = compiler.compile();
    executeExpression(expr);

    OptimizerFactory.setDefaultOptimizer("reflective");
    expr = compiler.compile();
    executeExpression(expr);
  }


  public void testJIRA166() {
    Object v = MVEL.eval("import java.util.regex.Matcher; import java.util.regex.Pattern;"
        + " if (Pattern.compile(\"hoge\").matcher(\"hogehogehoge\").find()) { 'foo' } else { 'bar' }",
        new HashMap());
    assertEquals("foo",
        v);
  }

  public static class Beano {
    public String getProperty1() {
      return null;
    }

    public boolean isProperty2() {
      return true;
    }

    public boolean isProperty3() {
      return false;
    }
  }

  public void testJIRA167() {
    Map context = new HashMap();
    context.put("bean",
        new Beano());
    MVEL.eval("bean.property1==null?bean.isProperty2():bean.isProperty3()",
        context);
  }

  public void testJIRA168() {
    boolean before = MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL;
    try {
      Map<String, Object> st = new HashMap<String, Object>();
      st.put("__fact__", new ArrayList());
      st.put("__expected__", 0);

      String expressionNaked = "__fact__.size == __expected__";
      String expressionNonNaked = "__fact__.size() == __expected__";
      MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;

      // the following works fine
      ParserContext ctx = new ParserContext();
      for (Map.Entry<String, Object> entry : st.entrySet()) {
        ctx.addInput(entry.getKey(),
            entry.getValue().getClass());
      }
      CompiledExpression expr = new ExpressionCompiler(expressionNaked, ctx).compile();

      Boolean result = (Boolean) executeExpression(expr,
          st);
      assertTrue(result);

      // the following works fine
      result = (Boolean) MVEL.eval(expressionNonNaked, st);
      assertTrue(result);

      // the following fails
      result = (Boolean) MVEL.eval(expressionNaked, st);
      assertTrue(result);
    }
    finally {
      MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = before;
    }
  }

  public void testJIRA170() {
    OptimizerFactory.setDefaultOptimizer("reflective");

    List<Integer> staticDispatch = Arrays.asList(2, 1, 0);
    List<Integer> multimethodDispatch = Arrays.asList(3, 2, 1);

    //      invokeJIRA170("Dynamic", ctxJIRA170(false, false), varsJIRA170(), multimethodDispatch);
    //      invokeJIRA170("Strict", ctxJIRA170(true, false), varsJIRA170(), multimethodDispatch);
    invokeJIRA170("Strong", ctxJIRA170(false, true), varsJIRA170(), staticDispatch);
  }

  public void testJIRA170b() {
    OptimizerFactory.setDefaultOptimizer("ASM");

    List<Integer> staticDispatch = Arrays.asList(2, 1, 0);
    List<Integer> multimethodDispatch = Arrays.asList(3, 2, 1);

    //       invokeJIRA170("Dynamic", ctxJIRA170(false, false), varsJIRA170(), multimethodDispatch);
    //       invokeJIRA170("Strict", ctxJIRA170(true, false), varsJIRA170(), multimethodDispatch);
    invokeJIRA170("Strong", ctxJIRA170(false, true), varsJIRA170(), staticDispatch);
  }

  public void invokeJIRA170(String name, ParserContext pctx, Map<String, ?> vars, Collection<Integer> expected) {
    Serializable expression = MVEL.compileExpression("x.remove((Object) y); x ", pctx);
    Object result = executeExpression(expression, vars);

    assertTrue(String.format("%s Expected %s, Got %s", name, expected, result), expected.equals(result));
    result = executeExpression(expression, vars);

    assertTrue(String.format("%s Expected %s, Got %s", name, expected, result), expected.equals(result));
  }


  private Map<String, ?> varsJIRA170() {
    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("x", new ArrayList<Integer>(Arrays.asList(3, 2, 1, 0)));
    vars.put("y", 3);
    return vars;
  }

  private ParserContext ctxJIRA170(boolean strictTypeEnforcement, boolean strongTyping) {
    ParserContext ctx = new ParserContext();
    //    ctx.setStrictTypeEnforcement(strictTypeEnforcement);
    ctx.setStrongTyping(strongTyping);
    ctx.addInput("x", Collection.class, new Class[]{Integer.class});
    ctx.addInput("y", Integer.class);
    return ctx;
  }


  public static class JIRA167Step {
    public String getParent() {
      return null;
    }
  }

  public static class JIRA167Node {
    public boolean isServer() {
      return true;
    }
  }

  public void testJIRA167b() {
    Map context = new HashMap();
    context.put("current", new JIRA167Step());
    context.put("node", new JIRA167Node());
    MVEL.eval("current.parent==null?node.isServer():(node==current.parent.node)", context);
  }

  public void testJIRA167c() {
    MVEL.eval("true?true:(false)");
  }


  public void testJIRA176() {
    Map innerMap = new HashMap();
    innerMap.put("testKey[MyValue=newValue]", "test");

    Map vars = new HashMap();
    vars.put("mappo", innerMap);

    assertEquals("test", MVEL.eval("mappo['testKey[MyValue=newValue]']", vars));
  }

  public void testJIRA176b() {
    Map innerMap = new HashMap();
    innerMap.put("testKey[MyValue=newValue]", "test");

    Map vars = new HashMap();
    vars.put("mappo", innerMap);

    Serializable s = MVEL.compileExpression("mappo['testKey[MyValue=newValue]']");
    OptimizerFactory.setDefaultOptimizer("reflective");

    assertEquals("test", executeExpression(s, vars));

    s = MVEL.compileExpression("mappo['testKey[MyValue=newValue]']");
    OptimizerFactory.setDefaultOptimizer("ASM");

    assertEquals("test", executeExpression(s, vars));
  }

  public void testRandomSomething() {

    Foo foo = new Foo();
    foo.setName("foo1");

    Foo foo2 = new Foo();
    foo2.setName("foo2");

    MVEL.setProperty(foo, "name", 5);

    Serializable s = MVEL.compileExpression("name.toUpperCase()", ParserContext.create().stronglyTyped().withInput("name", String.class));

    Object _return = executeExpression(s, foo);

    System.out.println("returned value: " + String.valueOf(_return));

    _return = executeExpression(s, foo2);

    System.out.println("returned value: " + String.valueOf(_return));

  }

  public static class ProcessManager {
    public void startProcess(String name, Map<String, Object> variables) {
      System.out.println("Process started");
    }
  }

  public static class KnowledgeRuntimeHelper {
    public ProcessManager getProcessManager() {
      return new ProcessManager();
    }
  }

  public void testDeepMethodNameResolution() {
    String expression = "variables = [ \"symbol\" : \"RHT\" ]; \n" +
        "drools.getProcessManager().startProcess(\"id\", variables );";

    // third pass
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("drools", KnowledgeRuntimeHelper.class);
    Map vars = new HashMap();
    vars.put("drools", new KnowledgeRuntimeHelper());
    Serializable expr = MVEL.compileExpression(expression, ctx);
    executeExpression(expr, vars);
  }

  public void testJIRA183() {
    String exp1 = "int end = 'attribute'.indexOf('@');  if(end == -1)" +
        " { end = 'attribute'.length()} 'attribute'.substring(0, end);";
    Object val1 = MVEL.eval(exp1, new HashMap<String, Object>());

    String exp2 = "int end = 'attribute'.indexOf('@');  if(end == -1)" +
        " { end = 'attribute'.length() } 'attribute'.substring(0, end);";
    Object val2 = MVEL.eval(exp2, new HashMap<String, Object>());
  }


  public void testContextAssignments() {
    Foo foo = new Foo();
    MVEL.eval("this.name = 'bar'", foo);

    assertEquals("bar", foo.getName());
  }

  public void testMVEL187() {
    ParserContext context = new ParserContext();
    context.addPackageImport("test");
    context.addInput("outer", Outer.class);

    Object compiled = MVEL.compileExpression(
        "outer.getInner().getValue()", context);

    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("outer", new Outer());
    VariableResolverFactory varsResolver = new MapVariableResolverFactory(vars);

    assertEquals(2, executeExpression(compiled, varsResolver));
  }

  public void testMVEL190() {
    ParserContext context = new ParserContext();
    context.addImport(Ship.class);
    context.addImport(MapObject.class);

    context.addInput("obj", MapObject.class);

    Object compiled = MVEL.compileExpression(
        "((Ship) obj).getName()", context);

    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("obj", new Ship());

    VariableResolverFactory varsResolver
        = new MapVariableResolverFactory(vars);

    System.out.println(
        executeExpression(compiled, varsResolver));
  }

  public void testMethodScoring() {
    OptimizerFactory.setDefaultOptimizer("ASM");
    ParserConfiguration pconf = new ParserConfiguration();
    for (Method m : StaticMethods.class.getMethods()) {
      if (Modifier.isStatic(m.getModifiers())) {
        pconf.addImport(m.getName(), m);

      }
    }
    pconf.addImport("TestCase", TestCase.class);
    ParserContext pctx = new ParserContext(pconf);

    Map<String, Object> vars = new HashMap<String, Object>();

    // this is successful
    TestCase.assertTrue(StaticMethods.is(StaticMethods.getList(java.util.Formatter.class)));

    // this also should be fine
    Serializable expr = MVEL.compileExpression("TestCase.assertTrue( is( getList( java.util.Formatter ) ) )", pctx);
    executeExpression(expr, vars);
  }

  public void testMethodWithNegativeIntParamMVEL313() {
    assertTrue((Boolean) runSingleTest("ord(true,-1)"));
  }

  public static class StaticMethods {
    public static <T> boolean is(List<T> arg) {
      return true;
    }

    public static boolean is(Collection arg) {
      throw new RuntimeException("Wrong method called");
    }

    public static List<Object> getList(Class<?> arg) {
      ArrayList<Object> result = new ArrayList<Object>();
      result.add(arg);
      return result;
    }

    public static String throwException() {
      throw new RuntimeException("this should throw an exception");
    }
  }

  public void testSetterViaDotNotation() {

    TestClass tc = new TestClass();
    tc.getExtra().put("test", "value");

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    String expression = "extra.test";
    Serializable compiled = MVEL.compileSetExpression(expression, ctx);
    MVEL.executeSetExpression(compiled, tc, "value2");
    assertEquals("value2", tc.getExtra().get("test"));
  }

  public void testSetterViaMapNotation() {

    TestClass tc = new TestClass();
    tc.getExtra().put("test", "value");

    ParserContext ctx = new ParserContext();
    ctx.withInput("this", TestClass.class);
    ctx.setStrongTyping(true);
    String expression = "extra[\"test\"]";
    Serializable compiled = MVEL.compileSetExpression(expression, tc.getClass(), ctx);
    MVEL.executeSetExpression(compiled, tc, "value3");
    assertEquals("value3", tc.getExtra().get("test"));
  }


  public void testGetterViaDotNotation() {
    TestClass tc = new TestClass();
    tc.getExtra().put("test", "value");

    Map vars = new HashMap();
    vars.put("tc", tc);

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("tc", tc.getClass());
    String expression = "tc.extra.test";
    Serializable compiled = MVEL.compileExpression(expression, ctx);
    String val = (String) executeExpression(compiled, vars);
    assertEquals("value", val);
  }

  public void testGetterViaMapNotation() {
    TestClass tc = new TestClass();
    tc.getExtra().put("test", "value");

    Map vars = new HashMap();
    vars.put("tc", tc);

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("tc", tc.getClass());
    String expression = "tc.extra[\"test\"]";
    Serializable compiled = MVEL.compileExpression(expression, ctx);
    String val = (String) executeExpression(compiled, vars);
    assertEquals("value", val);
  }

  public void testGetterViaMapGetter() {
    TestClass tc = new TestClass();
    tc.getExtra().put("test", "value");

    Map vars = new HashMap();
    vars.put("tc", tc);

    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addInput("tc", tc.getClass());
    String expression = "tc.extra.get(\"test\")";
    Serializable compiled = MVEL.compileExpression(expression, ctx);
    String val = (String) executeExpression(compiled, vars);
    assertEquals("value", val);
  }


  public void testJIRA209() {
    Map vars = new LinkedHashMap();
    vars.put("bal", new BigDecimal("999.99"));

    String[] testCases = {
        //        "bal < 100 or bal > 200",
        //        "bal < 100 || bal > 200",
        "bal > 200 or bal < 100",
        "bal > 200 || bal < 100",
        "bal < 100 and bal > 200",
        "bal < 100 && bal > 200",
        "bal > 200 and bal < 100",
        "bal > 200 && bal < 100"
    };

    Object val1, val2;
    for (String expr : testCases) {
      System.out.println("Evaluating '" + expr + "': ......");
      val1 = MVEL.eval(expr, vars);
      assertNotNull(val1);
      Serializable compiled = MVEL.compileExpression(expr);
      val2 = executeExpression(compiled, vars);
      assertNotNull(val2);
      assertEquals("expression did not evaluate correctly: " + expr, val1, val2);
    }
  }

  public void testBigDecimalOutput() {
    String str = "import java.math.BigDecimal; BigDecimal test = new BigDecimal(\"50000\"); System.out.println(test / new BigDecimal(\"1.13\"));";
    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.setStrictTypeEnforcement(true);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    MVEL.executeExpression(stmt, new HashMap());
  }

  public void testConstructor() {
    String ex = " TestHelper.method(new Person('bob', 30), new Person('mark', 40, 999, 55, 10));\n";
    ParserContext ctx = new ParserContext();
    ctx.setStrongTyping(true);
    ctx.addImport(TestHelper.class);
    ctx.addImport(Person.class);

    // un-comment the following line to see how MVEL is converting the int argument 40 into a
    // string and then executing the wrong constructor on the Person class
    try {
      MVEL.compileExpression(ex, ctx);
      fail("Constructor should not have been found.");
    }
    catch (CompileException e) {
      // yay.
    }
    // fail( "The Person constructor used in the expression does not exist, so an error should have been raised during compilation." );
  }

  public void testAmbiguousGetName() {
    Map<String, Object> vars = createTestMap();
    vars.put("Foo244", Foo.class);

    OptimizerFactory.setDefaultOptimizer("ASM");
    Serializable s = MVEL.compileExpression("foo.getClass().getName()");

    System.out.println(MVEL.executeExpression(s, vars));

    s = MVEL.compileExpression("Foo244.getName()");

    System.out.println(MVEL.executeExpression(s, vars));
  }

  public void testBindingNullToPrimitiveTypes() {
    Map<String, Object> vars = createTestMap();
    ((Foo) vars.get("foo")).setCountTest(10);

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.countTest");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCountTest(), 0);

    OptimizerFactory.setDefaultOptimizer("ASM");
    s = MVEL.compileSetExpression("foo.countTest");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCountTest(), 0);

    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCountTest(), 0);
  }

  public void testBindingNullToPrimitiveTypes2() {
    Map<String, Object> vars = createTestMap();
    ((Foo) vars.get("foo")).setCountTest(10);

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.boolTest");
    MVEL.executeSetExpression(s, vars, null);

    assertFalse(((Foo) vars.get("foo")).isBoolTest());

    OptimizerFactory.setDefaultOptimizer("ASM");
    s = MVEL.compileSetExpression("foo.boolTest");
    MVEL.executeSetExpression(s, vars, null);

    assertFalse(((Foo) vars.get("foo")).isBoolTest());

    MVEL.executeSetExpression(s, vars, null);

    assertFalse(((Foo) vars.get("foo")).isBoolTest());
  }

  public void testBindingNullToPrimitiveTypes3() {
    Map<String, Object> vars = createTestMap();
    ((Foo) vars.get("foo")).setCharTest('a');

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.charTest");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCharTest(), 0);

    OptimizerFactory.setDefaultOptimizer("ASM");
    s = MVEL.compileSetExpression("foo.charTest");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCharTest(), 0);

    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).getCharTest(), 0);
  }


  public void testBindingNullToPrimitiveTypes4() {
    Map<String, Object> vars = createTestMap();
    ((Foo) vars.get("foo")).charTestFld = 'a';

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.charTestFld");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).charTestFld, 0);

    OptimizerFactory.setDefaultOptimizer("ASM");
    s = MVEL.compileSetExpression("foo.charTestFld");
    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).charTestFld, 0);

    MVEL.executeSetExpression(s, vars, null);

    assertEquals(((Foo) vars.get("foo")).charTestFld, 0);
  }

  public void testBindListToArray() {
    Map<String, Object> vars = createTestMap();

    ArrayList<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.charArray");

    MVEL.executeSetExpression(s, vars, list);

    assertEquals(((Foo) vars.get("foo")).getCharArray().length, 3);
  }

  public void testBindListToMultiArray() {
    Map<String, Object> vars = createTestMap();

    ArrayList<List<String>> list = new ArrayList<List<String>>();

    List<String> l1 = new ArrayList<String>();
    l1.add("a");
    l1.add("b");
    l1.add("c");

    List<String> l2 = new ArrayList<String>();
    l2.add("d");
    l2.add("e");
    l2.add("f");

    List<String> l3 = new ArrayList<String>();
    l3.add("g");
    l3.add("h");
    l3.add("i");

    list.add(l1);
    list.add(l2);
    list.add(l3);

    OptimizerFactory.setDefaultOptimizer("reflective");
    Serializable s = MVEL.compileSetExpression("foo.charArrayMulti");

    MVEL.executeSetExpression(s, vars, list);

    Foo foo = (Foo) vars.get("foo");

    assertEquals(foo.getCharArrayMulti().length, 3);
    assertEquals(foo.getCharArrayMulti()[2][2], 'i');
  }

  public void testMVEL224() {
    ParserContext ctx = new ParserContext();
    MVEL.compileExpression("(pin == 1)", ctx);
  }


  public static class A221 {

    public B221 b;
  }

  public static class B221 {

    public String c = "something";
  }

  public void testMVEL221() {
    A221 a1 = new A221();
    a1.b = new B221();

    A221 a2 = new A221();

    OptimizerFactory.setDefaultOptimizer("ASM");

    String expression = "this.?b.c";
    Serializable compiledExpression = MVEL.compileExpression(expression);

    assertEquals(null, MVEL.executeExpression(compiledExpression, a2, String.class));
    assertEquals("something", MVEL.executeExpression(compiledExpression, a1, String.class));

    OptimizerFactory.setDefaultOptimizer("reflective");

    compiledExpression = MVEL.compileExpression(expression);

    assertEquals(null, MVEL.executeExpression(compiledExpression, a2, String.class));
    assertEquals("something", MVEL.executeExpression(compiledExpression, a1, String.class));
  }

  public void testMVEL222() throws IOException {
    String script = "for (int i= 0; i < 10; i++ ){ values[i] = 1.0; }";
    Map<String, Object> scriptVars = new HashMap<String, Object>();
    double[] values = new double[10];
    scriptVars.put("values", values);
    Serializable expression = MVEL.compileExpression(script);
    for (int i = 0; i < 6; i++) {
      scriptVars.put("values", values);
      MVEL.executeExpression(expression, scriptVars);
    }
  }

  public void testMVEL238() throws IOException {
    String expr = new String(loadFromFile(new File("src/test/java/org/mvel2/tests/MVEL238.mvel")));

    Serializable s = MVEL.compileExpression(expr);

    System.out.println(MVEL.executeExpression(s, new HashMap()));
    System.out.println(MVEL.executeExpression(s, new HashMap()));
  }

  public void testParsingRegression() {
    String expr = "if (false) {System.out.println(\" foo\")} else {System.out.println(\" bar\")}";
    MVEL.eval(expr);
  }


  public static class StaticClassWithStaticMethod {
    public static String getString() {
      return "hello";
    }
  }

//    public void testStaticImportWithWildcard() {
//        // this isn't supported yet
//        assertEquals("hello",
//                test("import_static " + getClass().getName() + ".StaticClassWithStaticMethod.*; getString()"));
//    }

  public void testArrayLength() {
    ParserContext context = new ParserContext();
    context.setStrongTyping(true);
    context.addInput("x",
        String[].class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression("x.length", context);
  }

  public void testEmptyConstructorWithSpace() throws Exception {
    ParserConfiguration pconf = new ParserConfiguration();
    pconf.addImport("getString", StaticClassWithStaticMethod.class.getMethod("getString", null));

    String text = "getString( )";

    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.setStrictTypeEnforcement(true);


    MVEL.compileExpression(text, pctx);
  }

  public void testJavaLangImport() throws Exception {
    String s = "Exception e = null;";
    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    MVEL.compileExpression(s, pctx);
  }


  public void testContextFieldNotFound() {
    String str = "'stilton'.equals( type );";

    ParserConfiguration pconf = new ParserConfiguration();

    ParserContext pctx = new ParserContext(pconf);
    pctx.addInput("this", Cheese.class);
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);

    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    MVEL.executeExpression(stmt, new Cheese(), new HashMap());
  }

  public void testVarArgs() throws Exception {
    ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);

    MVEL.analyze("String.format(\"\");", parserContext);
  }


  public void testOperatorPrecedence() throws IOException {
    String script = "list = [1, 2, 3]; x = 10; list contains x || x == 20";
    Serializable expression = MVEL.compileExpression(script);
    Object result = MVEL.executeExpression(expression, new HashMap());

    assertEquals(Boolean.FALSE, result);
  }


  public void testNestedEnum() throws Exception {
//        assertEquals(Triangle.Foo.class, MVEL.analyze("import " + Triangle.class.getCanonicalName() +"; Triangle.Foo.OBTUSE" , ParserContext.create()));

    //       Serializable o = MVEL.compileExpression( "import " + Triangle.class.getCanonicalName() +"; Triangle.Foo.OBTUSE" );

    //     assertEquals( Triangle.Foo.OBTUSE, MVEL.executeExpression(o, new HashMap()) );

    MVEL.eval("import " + Triangle.class.getCanonicalName() + "; Triangle.Foo.OBTUSE", new HashMap());
  }

  public void testNestedNumInMapKey() {
    String str = "objectKeyMaptributes[Triangle.Foo.OBTUSE]";

    ParserConfiguration pconf = new ParserConfiguration();
    pconf.addImport("Triangle", Triangle.class);
    ParserContext pctx = new ParserContext(pconf);
    pctx.addInput("this", Person.class);
    pctx.setStrongTyping(true);

    Foo foo = new Foo();
    Person p = new Person();
    Map<Object, Foo> map = new HashMap<Object, Foo>();
    map.put(Triangle.Foo.OBTUSE, foo);
    p.setObjectKeyMaptributes(map);

    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    Object o = MVEL.executeExpression(stmt, p, new HashMap());
  }

  public void testNestedClassWithNestedGenericsOnNakedMethod() {
    String str = "deliveries.size";

    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.addInput("this", Triangle.class);
    pctx.setStrongTyping(true);

    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    assertEquals(Integer.valueOf(0), (Integer) MVEL.executeExpression(stmt, new Triangle(), new HashMap()));

    str = "deliveries.size == 0";

    stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    assertTrue((Boolean) MVEL.executeExpression(stmt, new Triangle(), new HashMap()));

    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = false;
  }

  public static class Triangle {
    public static enum Foo {
      INCOMPLETE, UNCLASSIFIED,
      EQUILATERAL, ISOSCELES, RECTANGLED, ISOSCELES_RECTANGLED, ACUTE, OBTUSE;
    }

    private List<Map<String, Object>> deliveries = new ArrayList<Map<String, Object>>();

    public List<Map<String, Object>> getDeliveries() {
      return deliveries;
    }

    private Object objLabel = "Triangle";
    private String strLabel = "Triangle";
    private Double doubleVal = 29.0;

    public Object getObjLabel() {
      return objLabel;
    }

    public void setObjLabel(Object objLabel) {
      this.objLabel = objLabel;
    }

    public String getStrLabel() {
      return strLabel;
    }

    public void setStrLabel(String strLabel) {
      this.strLabel = strLabel;
    }

    public Double getDoubleVal() {
      return doubleVal;
    }

    public void setDoubleVal(Double doubleVal) {
      this.doubleVal = doubleVal;
    }
  }

  public void testStrictModeAddAll() {
    String str = "list.addAll( o );";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("o", Object.class);
    pctx.addInput("list", ArrayList.class);
    try {
      ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
      fail("This should not compileShared, as o is not of a type Collection");
    }
    catch (Exception e) {

    }
  }

  public void testNestedEnumFromJar() throws ClassNotFoundException,
      SecurityException,
      NoSuchFieldException {
    String expr = "EventRequest.Status.ACTIVE";

    // creating a classloader for the jar
    URL resource = getClass().getResource("/eventing-example.jar");
    assertNotNull(resource);
    URLClassLoader loader = new URLClassLoader(new URL[]{resource},
        getClass().getClassLoader());

    // loading the class to prove it works
    Class<?> er = loader.loadClass("org.drools.examples.eventing.EventRequest");
    assertNotNull(er);
    assertEquals("org.drools.examples.eventing.EventRequest",
        er.getCanonicalName());

    // getting the value of the enum to prove it works:
    Class<?> st = er.getDeclaredClasses()[0];
    assertNotNull(st);
    Field active = st.getField("ACTIVE");
    assertNotNull(active);

    // now, trying with MVEL
    ParserConfiguration pconf = new ParserConfiguration();
    pconf.setClassLoader(loader);
    pconf.addImport(er);
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);

    Serializable compiled = MVEL.compileExpression(expr, pctx);
    Object result = MVEL.executeExpression(compiled);

    assertNotNull(result);
  }

  public void testContextObjMethodCall() {
    String str = "getName() == \"bob\"";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", Bar.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    Bar ctx = new Bar();
    ctx.setName("bob");
    Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx);
    assertTrue(result);
  }

  public void testMapAccessWithNestedMethodCall() {
    String str = "map[aMethod(1)] == \"one\"";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", POJO.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);

    POJO ctx = new POJO();
    ctx.getMap().put("1", "one");
    Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx);
    assertTrue(result);
  }

  public void testMapAccessWithNestedProperty() {
    String str = "map[key] == \"one\"";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", POJO.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);

    POJO ctx = new POJO();
    ctx.getMap().put("1", "one");
    Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx);
    assertTrue(result);
  }

  public void testArrays() {
    String str = "Object[] a = new Object[3]; a[0] = \"a\"; a[1] = \"b\"; a[2] = \"c\"; System.out.println(java.util.Arrays.toString(a));";
    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    MVEL.executeExpression(stmt, new HashMap());
  }

  public void testFullyQualifiedEnums() {
    String str = "System.out.println( STATIC_ENUM.FOO ); \n" +
        "System.out.println( org.mvel2.tests.core.res.MyInterface$STATIC_ENUM.BAR );\n" +
        "System.out.println( org.mvel2.tests.core.res.MyInterface.MyInnerInterface.INNER_STATIC_ENUM.BAR );\n" +
        "System.out.println( RoundingMode.UP );\n" +
        "System.out.println( java.math.RoundingMode.DOWN );";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", MyInterface.class);
    pctx.addImport(MyInterface.STATIC_ENUM.class);
    pctx.addImport(java.math.RoundingMode.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
  }

  public void testGenericsMap() throws Exception {
    try {
      String str = "triangle.deliveries[0].containsKey( \"x\" )";

      ParserConfiguration pconf = new ParserConfiguration();
      ParserContext pctx = new ParserContext(pconf);
      pctx.setStrongTyping(true);
      pctx.addInput("triangle", Triangle.class);
      ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    }
    catch (Exception e) {
      // it should not raise CCE
      e.printStackTrace();
      throw e;
    }
  }

  public void testWithInsideBlock() {
    String str = "Foo f = new Foo(); with(f) { setBoolTest( true ) }; f.isBoolTest()";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", Bar.class);
    pctx.addImport(Foo.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    Bar ctx = new Bar();
    Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx, new HashMap());
    assertTrue(result);
  }

  public void testMethodCallWithSpaces() {
    String[] str = new String[]{
        "Foo f = new Foo(); f.setBoolTest( true )   ; f.isBoolTest()",
        "Foo f = new Foo(); f . setBoolTest( true ) ; f.isBoolTest()",
        "Foo f = new Foo(); f. setBoolTest( true )  ; f.isBoolTest()",
        "Foo f = new Foo(); f .setBoolTest( true )  ; f.isBoolTest()",
        "Foo f = new Foo(); f.boolTest = true   ; f.isBoolTest()",
        "Foo f = new Foo(); f . boolTest = true ; f.isBoolTest()",
        "Foo f = new Foo(); f. boolTest = true  ; f.isBoolTest()",
        "Foo f = new Foo(); f .boolTest = true  ; f.isBoolTest()"
    };

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("this", Bar.class);
    pctx.addImport(Foo.class);
    List<String> errors = new ArrayList<String>();
    for (String s : str) {
      try {
        ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(s, pctx);
        Bar ctx = new Bar();
        Boolean result = (Boolean) MVEL.executeExpression(stmt, ctx, new HashMap());
        assertTrue(result);
      }
      catch (Exception e) {
        e.printStackTrace();
        errors.add("**** Error on expression: " + s + "\n" + e.getMessage());
      }
    }
    assertTrue(errors.toString(), errors.isEmpty());
  }

  public void testInlineConstructor() {
    String str = "cheese = new Cheese().{ type = $c.type };";
    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);
    pctx.addInput("$c", Cheese.class);
    pctx.addImport(Cheese.class);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    Cheese $c = new Cheese();
    $c.setType("stilton");
    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("$c", $c);
    Cheese cheese = (Cheese) MVEL.executeExpression(stmt, vars);
    assertEquals("stilton", cheese.getType());
  }

  public void testStrTriangleEqualsEquals() {

    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;

    try {
      ParserConfiguration pconf = new ParserConfiguration();
      ParserContext pctx = new ParserContext(pconf);
      pctx.addInput("this", Triangle.class);
      pctx.setStrongTyping(true);

      String str = "this.strLabel == this";

      try {
        ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
        fail("should have failed");
      }
      catch (CompileException e) {

        System.out.println();
        return;
      }
    }
    finally {
      MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = false;
    }
  }

  //public void testSysoutNullVariable() {
  //  // Create our root Map object
  //  Map<String, String> map = new HashMap<String, String>();
  //  map.put("foo", null);
  //
  //  VariableResolverFactory factory = new MapVariableResolverFactory(new HashMap<String, Object>());
  //  factory.createVariable("this", map);
  //
  //  org.mvel2.MVEL.executeExpression(org.mvel2.MVEL.compileExpression("System.out.println(foo);"), map, factory);
  //}

  public void testPackageImportEnum() {
    String str = "new Status( START )";
    ParserConfiguration pconf = new ParserConfiguration();
    pconf.addPackageImport("org.mvel2.tests.core.res");
    pconf.addPackageImport("org.mvel2.tests.core.res.Status");
    ParserContext context = new ParserContext(pconf);
    context.setStrongTyping(true);

    Serializable s = MVEL.compileExpression(str.trim(), context);
    assertEquals(new Status(Status.START), MVEL.executeExpression(s));
    assertFalse(new Status(Status.STOP).equals(MVEL.executeExpression(s)));
  }

//  public void testStrDoubleEqualsEquals() {
//
//    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
//    try {
//      ParserConfiguration pconf = new ParserConfiguration();
//      ParserContext pctx = new ParserContext(pconf);
//      pctx.addInput("this", Triangle.class);
//      pctx.setStrongTyping(true);
//
//      String str = "strLabel == doubleVal";
//
//      try {
//        ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
//      }
//      catch (CompileException e) {
//        fail("should have failed");
//
//      }
//    }
//    finally {
//      MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = false;
//    }
//  }

  public void testNarrowToWideCompare() {
    Serializable s = MVEL.compileExpression("new String('foo') == new Object()",
        ParserContext.create().stronglyTyped());

    assertFalse((Boolean) MVEL.executeExpression(s));
  }

  public void testPrimitiveArray() {
    Map vars = new HashMap();
    vars.put("array", new boolean[]{true, false});
    String expression = "a = true; array contains a";
    Serializable compiled = MVEL.compileExpression(expression);
    boolean result = (Boolean) MVEL.executeExpression(compiled, vars);
    assertEquals(true, result);

    vars = new HashMap();
    vars.put("array", new int[]{1, 3, 4});
    expression = "a = 2; array contains a";
    compiled = MVEL.compileExpression(expression);
    result = (Boolean) MVEL.executeExpression(compiled, vars);
    assertEquals(false, result);

    expression = "a = 3; array contains a";
    compiled = MVEL.compileExpression(expression);
    result = (Boolean) MVEL.executeExpression(compiled, vars);
    assertEquals(true, result);

    expression = "a = false; array contains a";
    compiled = MVEL.compileExpression(expression);
    result = (Boolean) MVEL.executeExpression(compiled, vars);
    assertEquals(false, result);
  }

  public void testPrimitiveArrayWithStrongTyping() {
    String expression = "a = true; new boolean[] { true, false } contains a";
    boolean result = (Boolean) compileAndExecuteWithStrongTyping(expression);
    assertEquals(true, result);

    expression = "a = 2; new int[] { 1, 3 } contains a";
    result = (Boolean) compileAndExecuteWithStrongTyping(expression);
    assertEquals(false, result);

    expression = "a = true; array = new boolean[] { true, false }; array contains a";
    result = (Boolean) compileAndExecuteWithStrongTyping(expression);
    assertEquals(true, result);
  }

  public void testVarArgsParams() {

    assertEquals(String.format("null"),
                   runSingleTest("import org.mvel2.tests.core.res.AStatic; a = null; AStatic.process(a)"));
    assertEquals(String.format("hello,world,"),
                   runSingleTest("import org.mvel2.tests.core.res.AStatic; AStatic.process(\"hello\",\"world\")"));

      assertEquals(String.format(""),
                   runSingleTest("import org.mvel2.tests.core.res.AStatic; AStatic.process()"));
      assertEquals(String.format("null"),
                   runSingleTest("import org.mvel2.tests.core.res.AStatic; AStatic.process(null)"));



    assertEquals(String.format("xxx"),
        runSingleTest("String.format(\"xxx\")"));

    assertEquals(String.format("%010d", 123),
        runSingleTest("String.format(\"%010d\", 123)"));

    assertEquals(String.format("%010d", 123),
        runSingleTest("a = new Object[1]; a[0] = 123; String.format(\"%010d\", a)"));

    assertEquals(String.format("%010d", 123),
        runSingleTest("a = 123; String.format(\"%010d\", a)"));

    assertEquals(String.format("%010d -- %010d", 123, 456),
        runSingleTest("a = 123; b = 456; String.format(\"%010d -- %010d\", {a, b})"));

    assertEquals(String.format("%010d -- %010d", 123, 456),
        runSingleTest("a = new Object[2]; a[0] = 123; a[1] = 456; String.format(\"%010d -- %010d\", a)"));

    assertEquals(String.format("%010d -- %010d", 123, 456),
        runSingleTest("String.format(\"%010d -- %010d\", 123, 456)"));

    assertEquals(String.format("%010d -- %010d", 123, 456),
        runSingleTest("a = 123; b = 456; String.format(\"%010d -- %010d\", a, b)"));
  }

  public static class A {
    public int invoke(String s1, String s2, B... bs) {
      return bs.length;
    }

    public static int invokeSum(int start, B... bs) {
      for (B b : bs) start += b.getValue();
      return start;
    }
  }

  public static class B {
    private int value;

    public B() {
    }

    public B(int value) {
      this.value = value;
    }

    public int getValue() {
      return value;
    }

    public boolean equals(Object other) {
      return other != null && other instanceof B && value == ((B) other).value;
    }
  }

  public static class MySet {
    private Set<String> set = new HashSet<String>();

    public MySet(String... strings) {
      add(strings);
    }

    public void add(String... strings) {
      for (String s : strings) {
        set.add(s);
      }
    }

    public boolean contains(String s) {
      return set.contains(s);
    }

    public String toString() {
      return set.toString();
    }
  }

  public void testTypedVarArgsParams() {
    String imports = "import org.mvel2.tests.core.CoreConfidenceTests.A;\nimport org.mvel2.tests.core.CoreConfidenceTests.B;\n";

    String invoke0 = imports + "new A().invoke(\"s1\", \"s2\")";
    int result = (Integer) compileAndExecuteWithStrongTyping(invoke0);
    assertEquals(0, result);
    assertEquals(0, runSingleTest(invoke0));

    String invokeSum0 = imports + "A.invokeSum(3)";
    result = (Integer) compileAndExecuteWithStrongTyping(invokeSum0);
    assertEquals(3, result);
    assertEquals(3, runSingleTest(invokeSum0));

    String invoke3 = imports + "new A().invoke(\"s1\", \"s2\", new B(), new B(), new B())";
    result = (Integer) compileAndExecuteWithStrongTyping(invoke3);
    assertEquals(3, result);
    assertEquals(3, runSingleTest(invoke3));

    String invokeSum2 = imports + "A.invokeSum(3, new B(4), new B(5))";
    result = (Integer) compileAndExecuteWithStrongTyping(invokeSum2);
    assertEquals(12, result);
    assertEquals(12, runSingleTest(invokeSum2));
  }

  public void testTypedVarArgsConstructor() {
    String imports = "import org.mvel2.tests.core.CoreConfidenceTests.MySet;\n";
    String constructor = imports + "new MySet(\"s1\", \"s2\")";
    MySet result = (MySet) compileAndExecuteWithStrongTyping(constructor);
    assertTrue(result.contains("s1"));
    assertTrue(result.contains("s2"));
  }

  private <T> T compileAndExecuteWithStrongTyping(String expression) {
    return (T) compileAndExecuteWithStrongTyping(expression, new HashMap());
  }

  private <T> T compileAndExecuteWithStrongTyping(String expression, Map vars) {
    ParserContext context = new ParserContext();
    context.setStrongTyping(true);
    context.setStrictTypeEnforcement(true);
    Serializable compiled = MVEL.compileExpression(expression, context);
    return (T) MVEL.executeExpression(compiled, vars);
  }

  public void testArrayCreation() {
    assertTrue(Arrays.deepEquals(new Object[0], (Object[]) compileAndExecuteWithStrongTyping("{}")));
    assertTrue(Arrays.deepEquals(new String[0], (String[]) compileAndExecuteWithStrongTyping("new String[] {}")));
    assertTrue(Arrays.deepEquals(new String[]{"xyz"}, (String[]) compileAndExecuteWithStrongTyping("new String[] { \"xyz\" }")));
    assertTrue(Arrays.deepEquals(new String[]{"xyz"}, (String[]) compileAndExecuteWithStrongTyping("new String[] { new String(\"xyz\") }")));
    assertTrue(Arrays.deepEquals(new String[]{"xyz", "abc"}, (String[]) compileAndExecuteWithStrongTyping("new String[] { new String(\"xyz\"), new String(\"abc\") }")));
    assertTrue(Arrays.deepEquals(new B[0], (B[]) compileAndExecuteWithStrongTyping("import org.mvel2.tests.core.CoreConfidenceTests.B;\nnew B[] { }")));
    assertTrue(Arrays.deepEquals(new B[]{new B(5)}, (B[]) compileAndExecuteWithStrongTyping("import org.mvel2.tests.core.CoreConfidenceTests.B;\nnew B[] { new B(5) }")));
    assertTrue(Arrays.deepEquals(new B[]{new B(), new B(), new B()}, (B[]) compileAndExecuteWithStrongTyping("import org.mvel2.tests.core.CoreConfidenceTests.B;\nnew B[] {new B(),new B(),new B()}")));
  }

  public static class Bean1 {
    private String Field1;
    private String FIELD2;
    private int intField;

    public String getField1() {
      return Field1;
    }

    public void setField1(String Field1) {
      this.Field1 = Field1;
    }

    public String getFIELD2() {
      return FIELD2;
    }

    public void setFIELD2(String FIELD2) {
      this.FIELD2 = FIELD2;
    }

    public int getIntField() {
      return intField;
    }

    public void setIntField(int intField) {
      this.intField = intField;
    }

    public Option<String> getField1Option() {
      return new Option(Field1);
    }
  }

  public static class Option<T> {
    public final T t;

    public Option(T t) {
      this.t = t;
    }

    public boolean isDefined() {
      return t != null;
    }

    public T get() {
      return t;
    }
  }

  public void testUppercaseField() {
    String ex = "Field1 == \"foo\" || FIELD2 == \"bar\"";
    final ParserContext parserContext2 = new ParserContext();
    parserContext2.setStrictTypeEnforcement(true);
    parserContext2.setStrongTyping(true);
    parserContext2.addInput("this", Bean1.class);
    MVEL.analyze(ex, parserContext2);
  }

  public void testExpressionReturnType() {
    assertEquals(String.class, expressionReturnType("Field1"));
    assertEquals(String.class, expressionReturnType("Field1 + FIELD2"));
    assertEquals(String.class, expressionReturnType("Field1 + 3"));
    assertEquals(String.class, expressionReturnType("Field1 + 3 + FIELD2"));
    assertEquals(int.class, expressionReturnType("intField"));
    assertEquals(Integer.class, expressionReturnType("intField = 3"));
    assertEquals(Boolean.class, expressionReturnType("intField == 3"));
    assertEquals(Boolean.class, expressionReturnType("intField == \"3\""));
    assertEquals(Boolean.class, expressionReturnType("intField == 1 || Field1 == \"xxx\""));
    assertEquals(Boolean.class, expressionReturnType("FIELD2 == \"yyy\" && intField == 1 + 2 || Field1 == \"xxx\""));
  }

  public void testConstantOnLeftExpression() {
    assertEquals(Boolean.class, expressionReturnType("3 == intField"));
    assertEquals(Boolean.class, expressionReturnType("\"xxx\" == Field1"));
    assertEquals(Boolean.class, expressionReturnType("null == Field1"));
  }

  public void testExpressionReturnTypeWithGenerics() {
    assertEquals(String.class, expressionReturnType("Field1Option.get"));
    assertEquals(String.class, expressionReturnType("Field1Option.t"));
  }

  public void testWrongExpressions() {
    wrongExpressionMustFail("Field1 == 3");
    wrongExpressionMustFail("Field1 - 3");
    wrongExpressionMustFail("intField == 3 || Field1");
  }

  private void wrongExpressionMustFail(String expr) {
    try {
      expressionReturnType(expr);
      fail("wrong expression '" + expr + "' must fail");
    }
    catch (Exception e) {
    }
  }

  private Class<?> expressionReturnType(String expr) {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("this", Bean1.class);
    MVEL.compileExpression(expr, parserContext);
    return MVEL.analyze(expr, parserContext);
  }

  public void testExponentialNotation() {
    assertEquals(110.0, runSingleTest("10 + 1.0E+2"));
    assertEquals(90.0, runSingleTest("1.0E+2 - 10"));
    assertEquals(10.01, runSingleTest("10 + 1.0E-2"));
  }

  public void testShiftOperator() {
    String expression = "1 << 65536L";
    Serializable compiled = MVEL.compileExpression(expression, context);
    Object result = MVEL.executeExpression(compiled, new HashMap());
    assertEquals(1 << 65536L, result);

    expression = "one << shift";
    Map map = new HashMap() {{
      put("one", 1);
      put("shift", 65536L);
    }};
    compiled = MVEL.compileExpression(expression, context);
    result = MVEL.executeExpression(compiled, map);
    assertEquals(1 << 65536L, result);
    System.out.println(result);
  }

  public void testSystemOutOnPrivateClass() {
    PrintStream originalSystemOut = System.out;
    System.setOut(new MyPrivatePrintStream(System.out));
    String expression = "System.out.println(\"Hello World\");";
    runSingleTest(expression);
    System.setOut(originalSystemOut);
  }

  private static class MyPrivatePrintStream extends PrintStream {
    public MyPrivatePrintStream(OutputStream os) {
      super(os);
    }

    public void println(String s) {
      super.println(s);
    }
  }

  public void testSystemOutWithActualInstanceMethod() {
    PrintStream originalSystemOut = System.out;
    System.setOut(new MyPublicPrintStream(System.out));
    String expression = "System.out.myPrintln(\"Hello World\");";
    runSingleTest(expression);
    System.setOut(originalSystemOut);
  }

  public static class MyPublicPrintStream extends PrintStream {
    public MyPublicPrintStream(OutputStream os) {
      super(os);
    }

    public void println(String s) {
      super.println(s);
    }

    public void myPrintln(String s) {
      super.println(s);
    }
  }

  public void testMinusOperatorWithoutSpace() {
    String str = "length == $c.length -1";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    ExecutableStatement stmt = (ExecutableStatement) MVEL.compileExpression(str, pctx);
    Column col1 = new Column("x", 0);
    Column col2 = new Column("x", 0);
    Map<String, Object> vars = new HashMap<String, Object>();
    vars.put("$c", col2);
    Boolean result = (Boolean) MVEL.executeExpression(stmt, col1, vars);
    assertFalse(result);
  }

  public void testDhanji2() {
    String ex =
        "name = null;\n" +
            "$_1 = ?name.?toLowerCase();\n";


    Serializable s = MVEL.compileExpression(ex);

    MVEL.executeExpression(s, new HashMap());
  }

  public void testPrimitiveNumberCoercion() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", int.class);
    parserContext.addInput("b", double.class);
    Class<?> clazz = MVEL.analyze("a > b", parserContext);
    assertEquals(Boolean.class, clazz);
  }

  public void testClassLiteral() {
    try {
      MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS = true;
      final ParserContext parserContext = new ParserContext();
      parserContext.setStrictTypeEnforcement(true);
      parserContext.setStrongTyping(true);
      parserContext.addInput("a", Class.class);
      MVEL.compileExpression("a == String", parserContext);
    }
    finally {
      MVEL.COMPILER_OPT_SUPPORT_JAVA_STYLE_CLASS_LITERALS = false;
    }
  }

  public void testBigIntegerWithZeroValue() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", BigInteger.class);
    Serializable expression = MVEL.compileExpression("a == 0I", parserContext);
    boolean result = (Boolean) MVEL.executeExpression(expression, new HashMap() {{
      put("a", new BigInteger("0"));
    }});
    assertTrue(result);
  }

  public void testBigDecimalWithZeroValue() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", BigDecimal.class);
    Serializable expression = MVEL.compileExpression("a == 0B", parserContext);
    boolean result = (Boolean) MVEL.executeExpression(expression, new HashMap() {{
      put("a", new BigDecimal("0.0"));
    }});
    assertTrue(result);
  }

  public void testMethodReturningPrimitiveTypeAnalysis() {
    String str = "value";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.addInput("this", MyObj.class);
    pctx.setStrongTyping(true);

    Class<?> returnType = MVEL.analyze(str, pctx);
    assertEquals(long.class, returnType);
  }

  public static class MyObj {
    public long valueField;

    public MyObj(long value) {
      this.valueField = value;
    }

    public long getValue() {
      return valueField;
    }

    public static String doSomething(MyObj s1, String s2) {
      return s1 + s2;
    }
  }

  public void testStaticMethodsInvocationWithNullArg() {
    String str = "org.mvel2.tests.core.CoreConfidenceTests$MyObj.doSomething(null, \"abc\")";

    ParserConfiguration pconf = new ParserConfiguration();
    ParserContext pctx = new ParserContext(pconf);
    pctx.setStrongTyping(true);

    assertEquals(null + "abc", MVEL.executeExpression(MVEL.compileExpression(str, pctx)));
  }

  public interface InterfaceA {
    InterfaceB getB();
  }

  public interface InterfaceB {
  }

  public static class ImplementationA implements InterfaceA {
    public ImplementationB getB() {
      return new ImplementationB();
    }

    public void setB(InterfaceB b) {
    }
  }

  public static class ImplementationB implements InterfaceB {
    public int getValue() {
      return 42;
    }
  }

  public void testCovariance() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("this", ImplementationA.class);
    assertEquals(int.class, MVEL.analyze("b.value", parserContext));
    assertEquals(42, MVEL.executeExpression(MVEL.compileExpression("b.value", parserContext), new ImplementationA()));
  }

  public void testDivisionType() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", BigDecimal.class);
    Serializable expression = MVEL.compileExpression("(a / 3).setScale(2, java.math.BigDecimal.ROUND_HALF_UP)", parserContext);
    Object result = MVEL.executeExpression(expression, new HashMap() {{
      put("a", new BigDecimal("3.0"));
    }});
    System.out.println(result);
  }

  public void testUntypedClone() {
    String expression = "obj.clone();";
    ParserContext context = new ParserContext();
    context.setStrongTyping(false);
    context.setStrictTypeEnforcement(false);
    MVEL.analyze(expression, context);

    try {
      context.addInput("obj", Object.class);
      context.setStrongTyping(true);
      context.setStrictTypeEnforcement(true);
      MVEL.analyze(expression, context);
      fail("Must fail with strong typing");
    }
    catch (CompileException e) {
    }
  }

  public void testOverloading() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("this", Overloaded.class);
    Overloaded overloaded = new Overloaded();

    assertEquals(15, MVEL.executeExpression(MVEL.compileExpression("method(5, 9, \"x\")", parserContext), overloaded));
    assertEquals(-3, MVEL.executeExpression(MVEL.compileExpression("method(5, \"x\", 9)", parserContext), overloaded));
    assertEquals(-13, MVEL.executeExpression(MVEL.compileExpression("method(\"x\", 5, 9)", parserContext), overloaded));
  }

  public static class Overloaded {
    public int method(int i, int j, String s) {
      return i + j + s.length();
    }

    public int method(int i, String s, int j) {
      return i + s.length() - j;
    }

    public int method(String s, int i, int j) {
      return s.length() - i - j;
    }
  }


  public void testPippo() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrongTyping(true);
    assertEquals(String.class, MVEL.analyze("new String(\"b)ar\")", parserContext));
  }

  public void testReturnTypeExtendingGeneric() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrongTyping(true);
    parserContext.addInput("this", StringConcrete.class);
    assertEquals(String.class, MVEL.analyze("foo.concat(\"bar\")", parserContext));
    assertEquals(String.class, MVEL.analyze("getFoo().concat(\"bar\")", parserContext));
  }

  public static abstract class AbstractBase<T> {
    protected T foo;
    public T getFoo() { return foo; }
  }

  public static class StringConcrete extends AbstractBase<String> {
    public StringConcrete() { this.foo = new String(); }
  }

  public void testNullCollection() throws CompileException {
    boolean allowCompilerOverride = MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING;
    MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;

    String[] names  = { "missing" };
    String[] values = { null };

    try {
      MVEL.executeExpression( (CompiledExpression) MVEL.compileExpression("1; missing[3]"),
                              new IndexedVariableResolverFactory(names, values) );
      fail("Should throw a NullPointerExcption");
    } catch (Exception e) {
    } finally {
      MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = allowCompilerOverride;
    }
  }

  public void testRegExWithCast() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrongTyping(true);
    parserContext.addInput("this", Foo.class);
    assertEquals(Boolean.class, MVEL.analyze("(String)bar.name ~= '[a-z].+'", parserContext));
  }

  public void testUnwantedImport() {
    ParserConfiguration conf = new ParserConfiguration();
    conf.addPackageImport("java.util");
    conf.addPackageImport("org.mvel2.tests.core.res");
    ParserContext pctx = new ParserContext( conf );
    MVEL.analysisCompile( "ScenarioType.Set.ADD", pctx );
    assertNull(conf.getImports().get("Set"));
  }

  public void testUnaryNegative() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", int.class);
    Map vars = new HashMap() {{ put("value", 42); }};
    assertEquals(-42, MVEL.executeExpression(MVEL.compileExpression("-value", pctx), vars));
  }

  public void testUnaryNegativeWithSpace() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", int.class);
    Map vars = new HashMap() {{ put("value", 42); }};
    assertEquals(-42, MVEL.executeExpression(MVEL.compileExpression("- value", pctx), vars));
  }

  public static class ARef {
    public static int getSize(String s) {
      return 0;
    }
  }

  public static class BRef extends ARef {
    public static int getSize(String s) {
      return s.length();
    }
  }

  public void testStaticMethodInvocation() {
    ParserConfiguration conf = new ParserConfiguration();
    conf.addImport(ARef.class);
    conf.addImport(BRef.class);
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", String.class);
    Map vars = new HashMap() {{ put("value", "1234"); }};
    assertEquals(0, MVEL.executeExpression(MVEL.compileExpression("ARef.getSize(value)", pctx), vars));
    assertEquals(4, MVEL.executeExpression(MVEL.compileExpression("BRef.getSize(value)", pctx), vars));
  }

  public void testMultiplyIntByDouble() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("i", Integer.class);
    pctx.addInput("d", Double.class);
    Map vars = new HashMap() {{ put("i", 10); put("d", 0.3); }};
    assertEquals(3.0, MVEL.executeExpression(MVEL.compileExpression("i*d", pctx), vars));
    assertEquals(3.0, MVEL.executeExpression(MVEL.compileExpression("i*0.3", pctx), vars));
  }

  public void testCharToStringCoercionForComparison() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("ch", Character.class);
    Map vars = new HashMap() {{ put("ch", 'a'); }};
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("ch == \"a\"", pctx), vars));
    assertEquals(false, MVEL.executeExpression(MVEL.compileExpression("ch == \"b\"", pctx), vars));
  }

  public void testFieldNameWithUnderscore() {
      final ParserContext parserContext = new ParserContext();
      parserContext.setStrictTypeEnforcement(true);
      parserContext.setStrongTyping(true);
      parserContext.addInput("this", Underscore.class);
      Underscore underscore = new Underscore();

      assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("_id == \"test\"", parserContext), underscore));
  }

    public static class Underscore {
        public String get_id() {
            return "test";
        }
    }

  public void testEmptyOperatorOnStrings() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);

    pctx.addInput("nullString", String.class);
    pctx.addInput("emptyString", String.class);
    pctx.addInput("blankString", String.class);
    pctx.addInput("nonEmptyString", String.class);
    Map vars = new HashMap() {{
        put("nullString", null);
        put("emptyString", "");
        put("blankString", "   ");
        put("nonEmptyString", "abc");
    }};

    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("nullString == empty", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("emptyString == empty", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("blankString == empty", pctx), vars));
    assertEquals(false, MVEL.executeExpression(MVEL.compileExpression("nonEmptyString == empty", pctx), vars));
  }

  public void testEmptyOperatorOnBoolean() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);

    pctx.addInput("bNull", Boolean.class);
    pctx.addInput("bTrue", Boolean.class);
    pctx.addInput("bFalse", Boolean.class);
    Map vars = new HashMap() {{
        put("bNull", null);
        put("bTrue", true);
        put("bFalse", false);
    }};

    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("bNull == empty", pctx), vars));
    assertEquals(false, MVEL.executeExpression(MVEL.compileExpression("bTrue == empty", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("bFalse == empty", pctx), vars));
  }

  public void testEmptyOperatorOnInteger() {
    ParserConfiguration conf = new ParserConfiguration();
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);

    pctx.addInput("nullInt", Integer.class);
    pctx.addInput("zero", Integer.class);
    pctx.addInput("nonZero", Integer.class);
    Map vars = new HashMap() {{
        put("nullInt", null);
        put("zero", 0);
        put("nonZero", 42);
    }};

    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("nullInt == empty", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("zero == empty", pctx), vars));
    assertEquals(false, MVEL.executeExpression(MVEL.compileExpression("nonZero == empty", pctx), vars));
  }

  public void testInstanceofOnInnerClass() {
    ParserConfiguration conf = new ParserConfiguration();
    conf.addImport(ARef.class);
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", Object.class);
    Map vars = new HashMap() {{ put("value", new ARef()); }};
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof ARef", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + ARef.class.getCanonicalName(), pctx), vars));
  }

  public void testInstanceofWithPackageImport() {
    ParserConfiguration conf = new ParserConfiguration();
    conf.addPackageImport( "org.mvel2.tests.core" );
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", Object.class);
    Map vars = new HashMap() {{ put("value", new CoreConfidenceTests()); }};
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof CoreConfidenceTests", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + CoreConfidenceTests.class.getCanonicalName(), pctx), vars));
  }

  public void testInstanceofWithPackageImportAndInnerClass() {
    ParserConfiguration conf = new ParserConfiguration();
    conf.addPackageImport( "org.mvel2.tests.core.CoreConfidenceTests" );
    ParserContext pctx = new ParserContext( conf );
    pctx.setStrictTypeEnforcement(true);
    pctx.setStrongTyping(true);
    pctx.addInput("value", Object.class);
    Map vars = new HashMap() {{ put("value", new ARef()); }};
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof ARef", pctx), vars));
    assertEquals(true, MVEL.executeExpression(MVEL.compileExpression("value instanceof " + ARef.class.getCanonicalName(), pctx), vars));
  }

  public void testCompilerExceptionFormatting() throws Exception {
    try {
      Object value = test("\n2x * 3\n");
      fail("Invalid expression should fail");
    } catch (Exception e) {
      // Invalid expression should fail to compile
    }
  }

  public void testHandleNumericConversionBug() {
    String[] testLiterals = {"0x20","020",};
    String baseExpression = "int foo = ";

    for( String literal : testLiterals ) {
      char[] decExpr = ( baseExpression + literal ).toCharArray();
      assertEquals( Integer.decode( literal ),
                    ParseTools.handleNumericConversion( decExpr, baseExpression.length(), literal.length() ) );
    }
  }

  public static class Parent {
    public Object getSomething() {
      return null;
    }
  }

  public static class Child extends Parent {
    @Override
    public String getSomething() {
      return null;
    }
  }

  public void testNoArgMethodInheritance() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", Parent.class);
    parserContext.addInput("b", Child.class);
    assertEquals(Object.class, MVEL.analyze("a.getSomething()", parserContext));
    assertEquals(String.class, MVEL.analyze("b.getSomething()", parserContext));
  }
  
  
  public void testMethodOverloadMatch() throws Exception {
	  OverloadedClass c = new OverloadedClass();
	  Method found  = ParseTools.getExactMatch("putXX", new Class[]{int.class, String.class}, void.class, OverloadedInterface.class);
	  Method correct = OverloadedInterface.class.getMethod("putXX", new Class[]{int.class, String.class});
	  assertEquals(correct, found);
  }

  public static class O1 {
    public O2 getObj() {
      return new O2();
    }
  }
  public static class O2 extends O3 { }
  public abstract static class O3  {
    public String getValue() {
      return "value";
    }
  }

  public void testInvokeMethodInAbstractClass() {
    final ParserContext parserContext = new ParserContext();
    parserContext.setStrictTypeEnforcement(true);
    parserContext.setStrongTyping(true);
    parserContext.addInput("a", O1.class);
    assertEquals(String.class, MVEL.analyze("a.getObj().getValue()", parserContext));

    Map vars = new HashMap() {{ put("a", new O1()); }}