Author: rahul
Date: Fri Jul 17 18:40:59 2009
New Revision: 795190

URL: http://svn.apache.org/viewvc?rev=795190&view=rev
Log:
UnifiedJEXL improvements:
 - Better names for inner classes
 - More test coverage, and some fixes
 - Factor String parsing utilities in new class (StringParser)
Slightly modified version of patch thanks to Henri Biestro <hbiestro at gmail 
dot com>.
JEXL-58

Added:
    
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
   (with props)
Modified:
    
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
    
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
    
commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/UnifiedJEXLTest.java

Modified: 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java?rev=795190&r1=795189&r2=795190&view=diff
==============================================================================
--- 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
 (original)
+++ 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/UnifiedJEXL.java
 Fri Jul 17 18:40:59 2009
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import org.apache.commons.jexl.parser.SimpleNode;
 import org.apache.commons.jexl.parser.ParseException;
+import org.apache.commons.jexl.util.StringParser;
 
 /**
  * An evaluator similar to the unified EL evaluator used in JSP/JSF based on 
JEXL.
@@ -173,7 +174,7 @@
             // if only one sub-expr, no need to create a composite
             return (expressions.size() == 1)?
                     expressions.get(0) :
-                    el.new Composite(counts, expressions, source);
+                    el.new CompositeExpression(counts, expressions, source);
         }
     }
 
@@ -199,21 +200,41 @@
      * The abstract base class for all expressions, immediate '${...}' and 
deferred '#{...}'.
      */
     public abstract class Expression {
-        final Expression source;
+        protected final Expression source;
 
         Expression(Expression source) {
             this.source = source != null ? source : this;
         }
 
+        @Override
+        public String toString() {
+            StringBuilder strb = new StringBuilder();
+            if (source != this) {
+                strb.append(source.toString());
+                strb.append(" /*= ");
+            }
+            asString(strb);
+            if (source != this) {
+                strb.append(" */");
+            }
+            return strb.toString();
+        }
         /**
-         * Generate the string corresponding to this expression.
+         * Generates this expression's string representation.
          * @return the string representation
          */
         public String asString() {
-            return toString();
+            StringBuilder strb = new StringBuilder();
+            asString(strb);
+            return strb.toString();
         }
 
         /**
+         * Adds this expression's string representation to a StringBuilder.
+         */
+        abstract void asString(StringBuilder strb);
+
+        /**
          * When the expression is dependant upon immediate and deferred 
sub-expressions,
          * evaluates the immediate sub-expressions with the context passed as 
parameter
          * and returns this expression deferred form.
@@ -294,49 +315,50 @@
 
 
     /** A constant expression. */
-    private class Constant extends Expression {
+    private class ConstantExpression extends Expression {
         private final Object value;
 
-        Constant(Object value, Expression source) {
+        ConstantExpression(Object value, Expression source) {
             super(source);
             if (value == null) {
                 throw new NullPointerException("constant can not be null");
             }
+            if (value instanceof String) {
+                value = StringParser.buildString((String) value, false);
+            }
             this.value = value;
         }
 
+        @Override
+        public String asString() {
+            StringBuilder strb = new StringBuilder();
+            strb.append('"');
+            asString(strb);
+            strb.append('"');
+            return strb.toString();
+        }
+
+        @Override
         ExpressionType getType() {
             return ExpressionType.CONSTANT;
         }
 
         @Override
-        public String toString() {
+        void asString(StringBuilder strb) {
             String str = value.toString();
             if (value instanceof String || value instanceof CharSequence) {
-                StringBuilder strb = new StringBuilder(str.length() + 2);
-                if (source != this) {
-                    strb.append(source.toString());
-                    strb.append(" /*= ");
-                }
-                strb.append('"');
                 for (int i = 0, size = str.length(); i < size; ++i) {
                     char c = str.charAt(i);
                     if (c == '"')
                         strb.append('\\');
+                    else if (c == '\\')
+                        strb.append("\\\\");
                     strb.append(c);
                 }
-                strb.append('"');
-                if (source != this) {
-                    strb.append(" */");
-                }
-                return strb.toString();
             }
-            return str;
-        }
-
-        @Override
-        public String asString() {
-            return value.toString();
+            else {
+                strb.append(str);
+            }
         }
 
         @Override
@@ -363,11 +385,11 @@
 
 
     /** The base for Jexl based expressions. */
-    abstract private class JexlBased extends Expression {
+    abstract private class JexlBasedExpression extends Expression {
         protected final CharSequence expr;
         protected final SimpleNode node;
 
-        JexlBased(CharSequence expr, SimpleNode node, Expression source) {
+        JexlBasedExpression(CharSequence expr, SimpleNode node, Expression 
source) {
             super(source);
             this.expr = expr;
             this.node = node;
@@ -391,8 +413,11 @@
         }
 
         @Override
-        public String asString() {
-            return expr.toString();
+        public void asString(StringBuilder strb) {
+            strb.append(isImmediate()? '$' : '#');
+            strb.append("{");
+            strb.append(expr);
+            strb.append("}");
         }
 
         @Override
@@ -418,8 +443,8 @@
     }
 
     /** An immediate expression: ${jexl}. */
-    private class Immediate extends JexlBased {
-        Immediate(CharSequence expr, SimpleNode node, Expression source) {
+    private class ImmediateExpression extends JexlBasedExpression {
+        ImmediateExpression(CharSequence expr, SimpleNode node, Expression 
source) {
             super(expr, node, source);
         }
 
@@ -435,8 +460,8 @@
     }
 
     /** An immediate expression: ${jexl}. */
-    private class Deferred extends JexlBased {
-        Deferred(CharSequence expr, SimpleNode node, Expression source) {
+    private class DeferredExpression extends JexlBasedExpression {
+        DeferredExpression(CharSequence expr, SimpleNode node, Expression 
source) {
             super(expr, node, source);
         }
 
@@ -456,8 +481,8 @@
      * #{...${jexl}...}
      * Note that the deferred syntax is JEXL's, not UnifiedJEXL.
      */
-    private class Nested extends Deferred {
-        Nested(CharSequence expr, SimpleNode node, Expression source) {
+    private class NestedExpression extends DeferredExpression {
+        NestedExpression(CharSequence expr, SimpleNode node, Expression 
source) {
             super(expr, node, source);
             if (this.source != this) {
                 throw new IllegalArgumentException("Nested expression can not 
have a source");
@@ -483,7 +508,7 @@
         public Expression prepare(Interpreter interpreter) throws 
ParseException {
             String value = interpreter.interpret(node).toString();
             SimpleNode dnode = toNode(value);
-            return new Deferred(value, dnode, this);
+            return new DeferredExpression(value, dnode, this);
         }
 
         @Override
@@ -494,13 +519,13 @@
 
 
     /** A composite expression: "... ${...} ... #{...} ...". */
-    private class Composite extends Expression {
+    private class CompositeExpression extends Expression {
         // bit encoded (deferred count > 0) bit 1, (immediate count > 0) bit 0
         final int meta;
         // the list of expression resulting from parsing
         final Expression[] exprs;
 
-        Composite(int[] counts, ArrayList<Expression> exprs, Expression 
source) {
+        CompositeExpression(int[] counts, ArrayList<Expression> exprs, 
Expression source) {
             super(source);
             this.exprs = exprs.toArray(new Expression[exprs.size()]);
             this.meta = (counts[ExpressionType.DEFERRED.index] > 0? 2 : 0) |
@@ -518,32 +543,14 @@
         @Override
         public boolean isImmediate() {
             // immediate if no deferred
-            return (meta & 2) != 0;
-        }
-        
-        @Override
-        public String toString() {
-            StringBuilder strb = new StringBuilder();
-            if (source != this) {
-                strb.append(source.toString());
-                strb.append(" /*= ");
-            }
-            for (Expression e : exprs) {
-                strb.append(e.toString());
-            }
-            if (source != this) {
-                strb.append(" */ ");
-            }
-            return strb.toString();
+            return (meta & 2) == 0;
         }
 
         @Override
-        public String asString() {
-            StringBuilder strb = new StringBuilder();
+        void asString(StringBuilder strb) {
             for (Expression e : exprs) {
-                strb.append(e.asString());
+                e.asString(strb);
             }
-            return strb.toString();
         }
 
         @Override
@@ -565,10 +572,10 @@
             for(int e = 0; e < size; ++e) {
                 Expression expr = exprs[e];
                 Expression prepared = expr.prepare(interpreter);
-                if (evalImmediate && prepared instanceof Immediate) {
+                if (evalImmediate && prepared instanceof ImmediateExpression) {
                     // evaluate immediate as constant
                     Object value = prepared.evaluate(interpreter);
-                    prepared = value == null? null : new Constant(value, 
prepared);
+                    prepared = value == null? null : new 
ConstantExpression(value, prepared);
                 }
                 // add it if not null
                 if (prepared != null) {
@@ -789,7 +796,7 @@
                         state = ParseState.IMMEDIATE1;
                         // if chars in buffer, create constant
                         if (strb.length() > 0) {
-                            Expression cexpr = new Constant(strb.toString(), 
null);
+                            Expression cexpr = new 
ConstantExpression(strb.toString(), null);
                             builder.add(cexpr);
                             strb.delete(0, Integer.MAX_VALUE);
                         }
@@ -806,7 +813,7 @@
                         state = ParseState.DEFERRED1;
                         // if chars in buffer, create constant
                         if (strb.length() > 0) {
-                            Expression cexpr = new Constant(strb.toString(), 
null);
+                            Expression cexpr = new 
ConstantExpression(strb.toString(), null);
                             builder.add(cexpr);
                             strb.delete(0, Integer.MAX_VALUE);
                         }
@@ -822,7 +829,7 @@
                     if (c == '}') {
                         // materialize the immediate expr
                         //Expression iexpr = 
createExpression(ExpressionType.IMMEDIATE, strb, null);
-                        Expression iexpr = new Immediate(strb.toString(), 
toNode(strb), null);
+                        Expression iexpr = new 
ImmediateExpression(strb.toString(), toNode(strb), null);
                         builder.add(iexpr);
                         strb.delete(0, Integer.MAX_VALUE);
                         state = ParseState.CONST;
@@ -836,7 +843,7 @@
                     // skip inner strings (for '}')
                     if (c == '"' || c == '\'') {
                         strb.append(c);
-                        i = readDeferredString(strb, expr, i + 1, c);
+                        i = StringParser.readString(strb, expr, i + 1, c);
                         continue;
                     }
                     // nested immediate in deferred; need to balance count of 
'{' & '}'
@@ -856,8 +863,8 @@
                         } else {
                             // materialize the nested/deferred expr
                             Expression dexpr = nested?
-                                               new 
Nested(expr.substring(inested, i+1), toNode(strb), null) :
-                                               new Deferred(strb.toString(), 
toNode(strb), null);
+                                               new 
NestedExpression(expr.substring(inested, i+1), toNode(strb), null) :
+                                               new 
DeferredExpression(strb.toString(), toNode(strb), null);
                             builder.add(dexpr);
                             strb.delete(0, Integer.MAX_VALUE);
                             nested = false;
@@ -883,42 +890,12 @@
         }
         // we should be in that state
         if (state != ParseState.CONST)
-            throw new IllegalStateException("malformed expression: " + expr);
+            throw new ParseException("malformed expression: " + expr);
         // if any chars were buffered, add them as a constant
         if (strb.length() > 0) {
-            Expression cexpr = new Constant(strb.toString(), null);
+            Expression cexpr = new ConstantExpression(strb.toString(), null);
             builder.add(cexpr);
         }
         return builder.build(this, null);
     }
-
-    /**
-     * Read the remainder of a string till a given separator,
-     * handles escaping through '\' syntax.
-     * @param strb the destination buffer to copy characters into
-     * @param str the origin
-     * @param index the offset into the origin
-     * @param sep the separator, single or double quote, marking end of string
-     * @return the offset in origin
-     */
-    static private int readDeferredString(StringBuilder strb, String str, int 
index, char sep) {
-        boolean escape = false;
-        for(;index < str.length();++index) {
-           char c = str.charAt(index);
-           if (escape) {
-               strb.append(c);
-               escape = false;
-               continue;
-           }
-           if (c == '\\') {
-               escape = true;
-               continue;
-           }
-           strb.append(c);
-           if (c == sep) {
-              break;
-           }
-        }
-        return index;
-    }
 }
\ No newline at end of file

Modified: 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt?rev=795190&r1=795189&r2=795190&view=diff
==============================================================================
--- 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
 (original)
+++ 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/parser/Parser.jjt
 Fri Jul 17 18:40:59 2009
@@ -43,7 +43,7 @@
 
 import org.apache.commons.jexl.util.introspection.Uberspect;
 
-public class Parser
+public class Parser extends StringParser
 {
 
     public SimpleNode parse(Reader reader)
@@ -349,7 +349,7 @@
 {
  (
   t=<STRING_LITERAL>
-  { jjtThis.image = t.image.substring(1, t.image.length() -1); }
+  { jjtThis.image = Parser.buildString(t.image, true); }
  )
 }
 
@@ -484,8 +484,8 @@
 TOKEN :
 {
     <STRING_LITERAL :
-        ("\"" ( ~["\"","\n","\r"] )* "\"" )
+        ("\"" ( ~["\"","\n","\r"] | "\\" ["n","t","b","r","f","\\","\""] )* 
"\"" )
      |
-        ("\'" ( ~["\'","\n","\r"] )* "\'" )
+        ("\'" ( ~["\'","\n","\r"] | "\\" ["n","t","b","r","f","\\","\'"])* 
"\'" )
     >
 }
\ No newline at end of file

Added: 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java?rev=795190&view=auto
==============================================================================
--- 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
 (added)
+++ 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
 Fri Jul 17 18:40:59 2009
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.jexl.util;
+
+/**
+ * Common constant strings utilities.
+ */
+public class StringParser {
+    /**
+     * Builds a string, handles escaping through '\' syntax.
+     * @param str the string to build from
+     * @param eatsep whether the separator, the first character, should be 
considered
+     * @return the built string
+     */
+    public static String buildString(CharSequence str, boolean eatsep) {
+        StringBuilder strb = new StringBuilder(str.length());
+        char sep = eatsep ? str.charAt(0) : 0;
+        int end = str.length() - (eatsep ? 1 : 0);
+        int begin = (eatsep ? 1 : 0);
+        read(strb, str, begin, end, sep);
+        return strb.toString();
+    }
+
+    /**
+     * Read the remainder of a string till a given separator,
+     * handles escaping through '\' syntax.
+     * @param strb the destination buffer to copy characters into
+     * @param str the origin
+     * @param index the offset into the origin
+     * @param sep the separator, single or double quote, marking end of string
+     * @return the offset in origin
+     */
+    public static int readString(StringBuilder strb, CharSequence str, int 
index, char sep) {
+        return read(strb, str, index, str.length(), sep);
+    }
+    
+    /**
+     * Read the remainder of a string till a given separator,
+     * handles escaping through '\' syntax.
+     * @param strb the destination buffer to copy characters into
+     * @param str the origin
+     * @param begin the relative offset in str to begin reading
+     * @param end the relative offset in str to end reading
+     * @param sep the separator, single or double quote, marking end of string
+     * @return the last character offset handled in origin
+     */
+    private static int read(StringBuilder strb, CharSequence str, int begin, 
int end, char sep) {
+        boolean escape = false;
+        int index = begin;
+        for (; index < end; ++index) {
+            char c = str.charAt(index);
+            if (escape) {
+                strb.append(c);
+                if (c == '\\')
+                    strb.append('\\');
+                escape = false;
+                continue;
+            }
+            if (c == '\\') {
+                escape = true;
+                continue;
+            }
+            strb.append(c);
+            if (c == sep) {
+                break;
+            }
+        }
+        return index;
+    }
+}
\ No newline at end of file

Propchange: 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/jexl/branches/2.0/src/java/org/apache/commons/jexl/util/StringParser.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: 
commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/UnifiedJEXLTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/UnifiedJEXLTest.java?rev=795190&r1=795189&r2=795190&view=diff
==============================================================================
--- 
commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/UnifiedJEXLTest.java
 (original)
+++ 
commons/proper/jexl/branches/2.0/src/test/org/apache/commons/jexl/UnifiedJEXLTest.java
 Fri Jul 17 18:40:59 2009
@@ -15,7 +15,9 @@
  * limitations under the License.
  */
 package org.apache.commons.jexl;
-
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import junit.framework.TestCase;
 /**
  * Test cases for the UnifiedEL.
@@ -28,10 +30,16 @@
         JEXL.setCache(128);
     }
     static UnifiedJEXL EL = new UnifiedJEXL(JEXL);
-    
+    static Log LOG = LogFactory.getLog(UnifiedJEXL.class);
+    JexlContext context = null;
+    Map<String,Object> vars =null;
+
+    @Override
     public void setUp() throws Exception {
         // ensure jul logging is only error
         
java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
+        context = JexlHelper.createContext();
+        vars = context.getVars();
     }
     
     public static class Froboz {
@@ -80,79 +88,154 @@
     public void testAssign() throws Exception {
         UnifiedJEXL.Expression assign = EL.parse("${froboz.value = 10}");
         UnifiedJEXL.Expression check = EL.parse("${froboz.value}");
-        JexlContext jc = JexlHelper.createContext();
-        Object o = assign.evaluate(jc);
+        Object o = assign.evaluate(context);
         assertEquals("Result is not 10", new Integer(10), o);
-        o = check.evaluate(jc);
+        o = check.evaluate(context);
         assertEquals("Result is not 10", new Integer(10), o);
     }
     
-    public void testDear() throws Exception {
-        UnifiedJEXL.Expression assign = EL.parse("Dear ${p} ${name};");
-        JexlContext jc = JexlHelper.createContext();
-        jc.getVars().put("p", "Mr");
-        jc.getVars().put("name", "Doe");
-        Object o = assign.evaluate(jc);
+    public void testComposite() throws Exception {
+        UnifiedJEXL.Expression expr = EL.parse("Dear ${p} ${name};");
+        vars.put("p", "Mr");
+        vars.put("name", "Doe");
+        assertTrue("expression should be immediate", expr.isImmediate());
+        Object o = expr.evaluate(context);
         assertEquals("Dear Mr Doe;", o);
-        jc.getVars().put("p", "Ms");
-        jc.getVars().put("name", "Jones");
-        o = assign.evaluate(jc);
+        vars.put("p", "Ms");
+        vars.put("name", "Jones");
+        o = expr.evaluate(context);
         assertEquals("Dear Ms Jones;", o);
     }
 
-    public void testDear2Phase() throws Exception {
-        UnifiedJEXL.Expression assign = EL.parse("Dear #{p} ${name};");
-        JexlContext jc = JexlHelper.createContext();
-        jc.getVars().put("name", "Doe");
-        UnifiedJEXL.Expression  phase1 = assign.prepare(jc);
-        jc.getVars().put("p", "Mr");
-        jc.getVars().put("name", "Should not be used in 2nd phase");
-        Object o = phase1.evaluate(jc);
+    public void testPrepareEvaluate() throws Exception {
+        UnifiedJEXL.Expression expr = EL.parse("Dear #{p} ${name};");
+        assertTrue("expression should be deferred", expr.isDeferred());
+        vars.put("name", "Doe");
+        UnifiedJEXL.Expression  phase1 = expr.prepare(context);
+        String as = phase1.asString();
+        assertEquals("Dear #{p} Doe;", as);
+        vars.put("p", "Mr");
+        vars.put("name", "Should not be used in 2nd phase");
+        Object o = phase1.evaluate(context);
         assertEquals("Dear Mr Doe;", o);
     }
     
     public void testNested() throws Exception {
         UnifiedJEXL.Expression expr = EL.parse("#{${hi}+'.world'}");
-        JexlContext jc = JexlHelper.createContext();
-        jc.getVars().put("hi", "hello");
-        jc.getVars().put("hello.world", "Hello World!");
-        Object o = expr.evaluate(jc);
+        vars.put("hi", "hello");
+        vars.put("hello.world", "Hello World!");
+        Object o = expr.evaluate(context);
+        assertTrue("source should not be expression", expr.getSource() != 
expr.prepare(context));
+        assertTrue("expression should be deferred", expr.isDeferred());
         assertEquals("Hello World!", o);
     }
 
     public void testImmediate() throws Exception {
+        JexlContext none = null;
         UnifiedJEXL.Expression expr = EL.parse("${'Hello ' + 'World!'}");
-        JexlContext jc = null;
-        Object o = expr.evaluate(jc);
+        assertTrue("prepare should return same expression", expr.prepare(none) 
== expr);
+        Object o = expr.evaluate(none);
+        assertTrue("expression should be immediate", expr.isImmediate());
+        assertEquals("Hello World!", o);
+    }
+
+    public void testConstant() throws Exception {
+        JexlContext none = null;
+        UnifiedJEXL.Expression expr = EL.parse("Hello World!");
+        assertTrue("prepare should return same expression", expr.prepare(none) 
== expr);
+        Object o = expr.evaluate(none);
+        assertTrue("expression should be immediate", expr.isImmediate());
         assertEquals("Hello World!", o);
     }
 
     public void testDeferred() throws Exception {
+        JexlContext none = null;
         UnifiedJEXL.Expression expr = EL.parse("#{'world'}");
-        JexlContext jc = null;
-        Object o = expr.evaluate(jc);
+        assertTrue("prepare should return same expression", expr.prepare(none) 
== expr);
+        Object o = expr.evaluate(none);
+        assertTrue("expression should be deferred", expr.isDeferred());
         assertEquals("world", o);
     }
+
+    public void testEscape() throws Exception {
+        UnifiedJEXL.Expression expr = EL.parse("#\\{'world'\\}");
+        JexlContext none = null;
+        Object o = expr.evaluate(none);
+        assertEquals("#{'world'}", o);
+    }
+
+    public void testEscapeString() throws Exception {
+        UnifiedJEXL.Expression expr = EL.parse("\\\"${'world\\'s 
finest'}\\\"");
+        JexlContext none = null;
+        Object o = expr.evaluate(none);
+        assertEquals("\"world's finest\"", o);
+    }
+
+    public void testMalformed() throws Exception {
+        try {
+            UnifiedJEXL.Expression expr = EL.parse("${'world'");
+            JexlContext none = null;
+            Object o = expr.evaluate(none);
+            fail("should be malformed");
+        }
+        catch(UnifiedJEXL.Exception xjexl) {
+            // expected
+            String xmsg = xjexl.getMessage();
+            LOG.warn(xmsg);
+        }
+    }
+    
+    public void testMalformedNested() throws Exception {
+        try {
+            UnifiedJEXL.Expression expr = EL.parse("#{${hi} world}");
+            JexlContext none = null;
+            Object o = expr.evaluate(none);
+            fail("should be malformed");
+        }
+        catch(UnifiedJEXL.Exception xjexl) {
+            // expected
+            String xmsg = xjexl.getMessage();
+            LOG.warn(xmsg);
+        }
+    }
+    
+    public void testBadContextNested() throws Exception {
+        try {
+            UnifiedJEXL.Expression expr = EL.parse("#{${hi}+'.world'}");
+            JexlContext none = null;
+            Object o = expr.evaluate(none);
+            fail("should be malformed");
+        }
+        catch(UnifiedJEXL.Exception xjexl) {
+            // expected
+            String xmsg = xjexl.getMessage();
+            LOG.warn(xmsg);
+        }
+    }
     
     public void testCharAtBug() throws Exception {
-        JexlContext jc = JexlHelper.createContext();
-
-        jc.getVars().put("foo", "abcdef");
+        vars.put("foo", "abcdef");
         UnifiedJEXL.Expression expr = 
EL.parse("${foo.substring(2,4)/*comment*/}");
-        Object o = expr.evaluate(jc);
+        Object o = expr.evaluate(context);
         assertEquals("cd", o);
         
-        jc.getVars().put("bar", "foo");
-        EL.getEngine().setSilent(true);
-        expr = EL.parse("#{${bar}+'.charAt(-2)'}");
-        expr = expr.prepare(jc);
-        o = expr.evaluate(jc);
-        assertEquals(null, o);
+        vars.put("bar", "foo");
+        try {
+            JEXL.setSilent(true);
+            expr = EL.parse("#{${bar}+'.charAt(-2)'}");
+            expr = expr.prepare(context);
+            o = expr.evaluate(context);
+            assertEquals(null, o);
+        }
+        finally {
+            JEXL.setSilent(false);
+        }
 
     }
- 
+
     public static void main(String[] args) throws Exception {
-        //new UnifiedELTest("debug").testClassHash();
-        new UnifiedJEXLTest("debug").testAssign();
+        UnifiedJEXLTest test = new UnifiedJEXLTest("debug");
+        test.setUp();
+        test.testBadContextNested();
     }
 }
\ No newline at end of file


Reply via email to