This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git


The following commit(s) were added to refs/heads/master by this push:
     new 8e4f41d  JEXL-328: ensure creation of options before evaluation do 
call pragma processing, added tests Task #JEXL-328 - JXLT template scripts 
evaluation do not process pragmas
8e4f41d is described below

commit 8e4f41de2f8407bc3b9e42bbbac7749944c1d538
Author: henrib <hen...@apache.org>
AuthorDate: Wed Mar 4 17:44:54 2020 +0100

    JEXL-328: ensure creation of options before evaluation do call pragma 
processing, added tests
    Task #JEXL-328 - JXLT template scripts evaluation do not process pragmas
---
 RELEASE-NOTES.txt                                  |   1 +
 .../org/apache/commons/jexl3/internal/Engine.java  |  59 +++++++++-
 .../apache/commons/jexl3/internal/Interpreter.java |   6 +-
 .../commons/jexl3/internal/InterpreterBase.java    |  21 ++++
 .../org/apache/commons/jexl3/internal/Script.java  |  52 +--------
 .../commons/jexl3/internal/TemplateEngine.java     |  25 ++++-
 .../jexl3/internal/TemplateInterpreter.java        | 124 +++++++++++++++++----
 .../commons/jexl3/internal/TemplateScript.java     |  35 ++++--
 src/site/xdoc/changes.xml                          |   3 +
 .../org/apache/commons/jexl3/FeaturesTest.java     |   2 +-
 .../java/org/apache/commons/jexl3/JXLTTest.java    |  98 ++++++++++++++--
 11 files changed, 330 insertions(+), 96 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 27f7655..4249085 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -74,6 +74,7 @@ New Features in 3.2:
 
 Bugs Fixed in 3.2:
 ==================
+* JEXL-328:      JXLT template scripts evaluation do not process pragmas
 * JEXL-327:      map[null] does not work in assignment context
 * JEXL-326:      Link to "JavaCC" on syntax reference page is broken
 * JEXL-325:      Potential race-condition in NumberParser.toString()
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java 
b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
index 20da2a0..f470fd9 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
@@ -341,6 +341,62 @@ public class Engine extends JexlEngine {
     }
 
     /**
+     * Compute a script options for evaluation.
+     * <p>This calls processPragma(...).
+     * @param script the script
+     * @param context the context
+     * @return the options
+     */
+    protected JexlOptions options(ASTJexlScript script, JexlContext context) {
+        final JexlOptions opts = options(context);
+        if (script != null) {
+            // when parsing lexical, try hard to run lexical
+           JexlFeatures features = script.getFeatures();
+           if (features != null) {
+               if (features.isLexical()) {
+                   opts.setLexical(true);
+               }
+               if (features.isLexicalShade()) {
+                   opts.setLexicalShade(true);
+               }
+           }
+           // process script pragmas if any
+           processPragmas(script, context, opts);
+        }
+        return opts;
+    }
+    
+    /**
+     * Processes a script pragmas.
+     * <p>Only called from options(...)
+     * @param script the script
+     * @param context the context
+     * @param opts the options
+     */
+    protected void processPragmas(ASTJexlScript script, JexlContext context, 
JexlOptions opts) {
+        Map<String, Object> pragmas = script.getPragmas();
+        if (pragmas != null && !pragmas.isEmpty()) {
+            JexlContext.PragmaProcessor processor =
+                    context instanceof JexlContext.PragmaProcessor
+                    ? (JexlContext.PragmaProcessor) context
+                    : null;
+            for(Map.Entry<String, Object> pragma : pragmas.entrySet()) {
+                String key = pragma.getKey();
+                Object value = pragma.getValue();
+                if (PRAGMA_OPTIONS.equals(key)) {
+                    if (value instanceof String) {
+                        String[] vs = ((String) value).split(" ");
+                        opts.setFlags(vs);
+                    }
+                }
+                if (processor != null) {
+                    processor.processPragma(key, value);
+                }
+            }
+        }
+    }
+    
+    /**
      * Sets options from this engine options.
      * @param opts the options to set
      * @return the options
@@ -348,7 +404,7 @@ public class Engine extends JexlEngine {
     public JexlOptions optionsSet(JexlOptions opts) {
         if (opts != null) {
             opts.set(options);
-    }
+        }
         return opts;
     }
     
@@ -375,6 +431,7 @@ public class Engine extends JexlEngine {
         return new Interpreter(this, opts, context, frame);
     }
 
+    
     @Override
     public Script createExpression(JexlInfo info, String expression) {
         return createScript(expressionFeatures, info, expression, null);
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java 
b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
index 99a81c9..8d955eb 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
@@ -1223,8 +1223,8 @@ public class Interpreter extends InterpreterBase {
                 }
                 if (ant != null) {
                     String aname = ant.toString();
-                    boolean undefined = !(context.has(aname));
-                    return unsolvableVariable(node, aname, undefined);
+                    boolean defined = isVariableDefined(frame, block, aname);
+                    return unsolvableVariable(node, aname, !defined);
                 }
                 return unsolvableProperty(node,
                         stringifyProperty(ptyNode), ptyNode == objectNode, 
null);
@@ -1234,7 +1234,7 @@ public class Interpreter extends InterpreterBase {
                     return null;
                 }
                 String aname = ant != null ? ant.toString() : "?";
-                boolean defined = context.has(aname);
+                boolean defined = isVariableDefined(frame, block, aname);
                 if (defined && !arithmetic.isStrict()) {
                     return null;
                 }
diff --git 
a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java 
b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
index 1a69717..8655760 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
@@ -246,6 +246,27 @@ public abstract class InterpreterBase extends 
ParserVisitor {
     }
     
     /**
+     * Checks whether a variable is defined.
+     * <p>The var may be either a local variable declared in the frame and
+     * visible from the block or defined in the context.
+     * @param frame the frame
+     * @param block the block
+     * @param name the variable name
+     * @return true if variable is defined, false otherwise
+     */
+    protected boolean isVariableDefined(Frame frame, LexicalScope block, 
String name) {
+        if (frame != null && block != null) {
+            Integer ref = frame.getScope().getSymbol(name);
+            int symbol = ref != null? ref : -1;
+            if (symbol >= 0  && block.hasSymbol(symbol)) {
+                Object value = frame.get(symbol);
+                return value != Scope.UNDEFINED && value != Scope.UNDECLARED;
+            }
+        }
+        return context.has(name);
+    }
+    
+    /**
      * Gets a value of a defined local variable or from the context.
      * @param frame the local frame
      * @param block the lexical block if any
diff --git a/src/main/java/org/apache/commons/jexl3/internal/Script.java 
b/src/main/java/org/apache/commons/jexl3/internal/Script.java
index c458242..ed01345 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/Script.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/Script.java
@@ -17,6 +17,7 @@
 package org.apache.commons.jexl3.internal;
 
 import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlFeatures;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.JexlOptions;
 import org.apache.commons.jexl3.JexlEngine;
@@ -27,8 +28,6 @@ import org.apache.commons.jexl3.parser.ASTJexlScript;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.apache.commons.jexl3.JexlFeatures;
-
 /**
  * <p>A JexlScript implementation.</p>
  * @since 1.1
@@ -50,10 +49,6 @@ public class Script implements JexlScript, JexlExpression {
      * The engine version (as class loader change count) that last evaluated 
this script.
      */
     protected int version;
-    /**
-     * The name of the options pragma.
-     */
-    protected static final String PRAGMA_OPTIONS = "jexl.options";
 
     /**
      * @return the script AST
@@ -105,55 +100,14 @@ public class Script implements JexlScript, JexlExpression 
{
     }
     
     /**
-     * Compute this script options for evaluation.
-     * <p>This also calls the pragma processor 
-     * @param context the context
-     * @return the options
-     */
-    protected JexlOptions options(JexlContext context) {
-        JexlOptions opts = jexl.options(context);
-        // when parsing lexical, try hard to run lexical
-        JexlFeatures features = script.getFeatures();
-        if (features != null) {
-            if (features.isLexical()) {
-                opts.setLexical(true);
-            }
-            if (features.isLexicalShade()) {
-                opts.setLexicalShade(true);
-            }
-        }
-        // process script pragmas if any
-        Map<String, Object> pragmas = script.getPragmas();
-        if (pragmas != null) {
-            JexlContext.PragmaProcessor processor =
-                    context instanceof JexlContext.PragmaProcessor
-                    ? (JexlContext.PragmaProcessor) context
-                    : null;
-            for(Map.Entry<String, Object> pragma : pragmas.entrySet()) {
-                String key = pragma.getKey();
-                Object value = pragma.getValue();
-                if (PRAGMA_OPTIONS.equals(key)) {
-                    if (value instanceof String) {
-                        String[] vs = ((String) value).split(" ");
-                        opts.setFlags(vs);
-                    }
-                }
-                if (processor != null) {
-                    processor.processPragma(key, value);
-                }
-            }
-        }
-        return opts;
-    }
-    
-    /**
      * Creates this script interpreter.
      * @param context the context
      * @param frame the calling frame
      * @return  the interpreter
      */
     protected Interpreter createInterpreter(JexlContext context, Frame frame) {
-        return jexl.createInterpreter(context, frame, options(context));
+        JexlOptions opts = jexl.options(script, context);
+        return jexl.createInterpreter(context, frame, opts);
     }
 
     /**
diff --git 
a/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java 
b/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
index 8f1a7ea..fa2831b 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
@@ -18,6 +18,7 @@ package org.apache.commons.jexl3.internal;
 
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlOptions;
 import org.apache.commons.jexl3.JexlInfo;
 import org.apache.commons.jexl3.JxltEngine;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
@@ -291,7 +292,7 @@ public final class TemplateEngine extends JxltEngine {
          */
         protected final TemplateExpression prepare(Frame frame, JexlContext 
context) {
             try {
-                Interpreter interpreter = new TemplateInterpreter(jexl, 
context, frame, null, null);
+                Interpreter interpreter = jexl.createInterpreter(context, 
frame, jexl.options(context));
                 return prepare(interpreter);
             } catch (JexlException xjexl) {
                 JexlException xuel = createException(xjexl.getInfo(), 
"prepare", this, xjexl);
@@ -319,6 +320,15 @@ public final class TemplateEngine extends JxltEngine {
         }
 
         /**
+         * The options to use during evaluation.
+         * @param context the context
+         * @return the options
+         */
+        protected JexlOptions options(JexlContext context) {
+            return jexl.options(null, context);
+        }
+        
+        /**
          * Evaluates this expression.
          * @param frame the frame storing parameters and local variables
          * @param context the context storing global variables
@@ -327,7 +337,13 @@ public final class TemplateEngine extends JxltEngine {
          */
         protected final Object evaluate(Frame frame, JexlContext context) {
             try {
-                Interpreter interpreter = new TemplateInterpreter(jexl, 
context, frame, null, null);
+                JexlOptions options = options(context);
+                TemplateInterpreter.Arguments args = new TemplateInterpreter
+                        .Arguments(jexl)
+                        .context(context)
+                        .options(options)
+                        .frame(frame);
+                Interpreter interpreter = new TemplateInterpreter(args);
                 return evaluate(interpreter);
             } catch (JexlException xjexl) {
                 JexlException xuel = createException(xjexl.getInfo(), 
"evaluate", this, xjexl);
@@ -420,6 +436,11 @@ public final class TemplateEngine extends JxltEngine {
             strb.append("}");
             return strb;
         }
+        
+        @Override
+        protected JexlOptions options(JexlContext context) {
+            return jexl.options(node instanceof ASTJexlScript? (ASTJexlScript) 
node : null, context);
+        }
 
         @Override
         protected Object evaluate(Interpreter interpreter) {
diff --git 
a/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java 
b/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
index 7babe6f..d095625 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
@@ -18,14 +18,16 @@ package org.apache.commons.jexl3.internal;
 
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.JexlInfo;
+import org.apache.commons.jexl3.JexlOptions;
 import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
 import org.apache.commons.jexl3.introspection.JexlMethod;
 import org.apache.commons.jexl3.introspection.JexlUberspect;
 import org.apache.commons.jexl3.parser.ASTIdentifier;
-import org.apache.commons.jexl3.parser.JexlNode;
-import java.io.Writer;
 import org.apache.commons.jexl3.parser.ASTJexlLambda;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.parser.JexlNode;
+
+import java.io.Writer;
 
 /**
  * The type of interpreter to use during evaluation of templates.
@@ -39,18 +41,85 @@ public class TemplateInterpreter extends Interpreter {
     private final Writer writer;
 
     /**
+     * Helper ctor.
+     * <p>Stores the different properties required to create a Template 
interpreter.
+     */
+    static class Arguments {
+        /** The engine. */
+        Engine jexl;
+        /** The options. */
+        JexlOptions options;
+        /** The context. */
+        JexlContext jcontext;
+        /** The frame. */
+        Frame jframe;
+        /** The expressions. */
+        TemplateExpression[] expressions;
+        /** The writer. */
+        Writer out;
+        
+        /**
+         * Sole ctor.
+         * @param e the JEXL engine
+         */  
+        Arguments(Engine e) {
+            this.jexl = e;
+        } 
+        /**
+         * Sets the options.
+         * @param o the options
+         * @return this instance
+         */         
+        Arguments options(JexlOptions o) {
+            this.options = o;
+            return this;
+        } 
+        /**
+         * Sets the context.
+         * @param j the context
+         * @return this instance
+         */      
+        Arguments context(JexlContext j) {
+            this.jcontext = j;
+            return this;
+        } 
+        /**
+         * Sets the frame.
+         * @param f the frame
+         * @return this instance
+         */        
+        Arguments frame(Frame f) {
+            this.jframe = f;
+            return this;
+        }  
+        /**
+         * Sets the expressions.
+         * @param e the expressions
+         * @return this instance
+         */  
+        Arguments expressions(TemplateExpression[] e) {
+            this.expressions = e;
+            return this;
+        }   
+        /**
+         * Sets the writer.
+         * @param o the writer
+         * @return this instance
+         */
+        Arguments writer(Writer o) {
+            this.out = o;
+            return this;
+        }
+    }
+    
+    /**
      * Creates a template interpreter instance.
-     * @param jexl        the engine instance
-     * @param jcontext    the base context
-     * @param jframe      the calling frame
-     * @param expressions the list of TemplateExpression from the 
TemplateScript to evaluate
-     * @param out         the output writer
+     * @param args the template interpreter arguments
      */
-    TemplateInterpreter(Engine jexl,
-            JexlContext jcontext, Frame jframe, TemplateExpression[] 
expressions, Writer out) {
-        super(jexl, null, jcontext, jframe);
-        exprs = expressions;
-        writer = out;
+    TemplateInterpreter(Arguments args) {
+        super(args.jexl, args.options, args.jcontext, args.jframe);
+        exprs = args.expressions;
+        writer = args.out;
         block = new LexicalFrame(frame, null);
     }
 
@@ -145,24 +214,31 @@ public class TemplateInterpreter extends Interpreter {
     }
 
     @Override
-    protected Object visit(ASTJexlScript node, Object data) {
-        if (node instanceof ASTJexlLambda && !((ASTJexlLambda) 
node).isTopLevel()) {
-            return new Closure(this, (ASTJexlLambda) node) {
+    protected Object visit(ASTJexlScript script, Object data) {
+        if (script instanceof ASTJexlLambda && !((ASTJexlLambda) 
script).isTopLevel()) {
+            return new Closure(this, (ASTJexlLambda) script) {
                 @Override
                 protected Interpreter createInterpreter(JexlContext context, 
Frame local) {
-                    return new TemplateInterpreter(jexl, context, local, 
exprs, writer);
+                    JexlOptions opts = jexl.options(script, context);
+                    TemplateInterpreter.Arguments targs = new 
TemplateInterpreter.Arguments(jexl)
+                            .context(context)
+                            .options(opts)
+                            .frame(local)
+                            .expressions(exprs)
+                            .writer(writer);
+                    return new TemplateInterpreter(targs);
                 }
             };
         }
         // otherwise...
-        final int numChildren = node.jjtGetNumChildren();
-        Object result = null;
-        for (int i = 0; i < numChildren; i++) {
-            JexlNode child = node.jjtGetChild(i);
-            result = child.jjtAccept(this, data);
-            cancelCheck(child);
+        final int numChildren = script.jjtGetNumChildren();
+            Object result = null;
+            for (int i = 0; i < numChildren; i++) {
+            JexlNode child = script.jjtGetChild(i);
+                result = child.jjtAccept(this, data);
+                cancelCheck(child);
+            }
+            return result;
         }
-        return result;    
-    }
 
 }
diff --git 
a/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java 
b/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
index eed231c..88f4ccc 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/TemplateScript.java
@@ -23,6 +23,14 @@ import 
org.apache.commons.jexl3.internal.TemplateEngine.Block;
 import org.apache.commons.jexl3.internal.TemplateEngine.BlockType;
 import org.apache.commons.jexl3.internal.TemplateEngine.TemplateExpression;
 import org.apache.commons.jexl3.parser.ASTJexlScript;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.JexlOptions;
+import org.apache.commons.jexl3.parser.ASTArguments;
+import org.apache.commons.jexl3.parser.ASTFunctionNode;
+import org.apache.commons.jexl3.parser.ASTIdentifier;
+import org.apache.commons.jexl3.parser.ASTNumberLiteral;
+import org.apache.commons.jexl3.parser.JexlNode;
+
 import java.io.Reader;
 import java.io.Writer;
 import java.util.ArrayList;
@@ -30,12 +38,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
-import org.apache.commons.jexl3.JexlException;
-import org.apache.commons.jexl3.parser.ASTArguments;
-import org.apache.commons.jexl3.parser.ASTFunctionNode;
-import org.apache.commons.jexl3.parser.ASTIdentifier;
-import org.apache.commons.jexl3.parser.ASTNumberLiteral;
-import org.apache.commons.jexl3.parser.JexlNode;
 
 /**
  * A Template instance.
@@ -246,9 +248,15 @@ public final class TemplateScript implements 
JxltEngine.Template {
     
     @Override
     public TemplateScript prepare(JexlContext context) {
-        Engine jexl = jxlt.getEngine();
+        final Engine jexl = jxlt.getEngine();
+        JexlOptions options = jexl.options(script, context);
         Frame frame = script.createFrame((Object[]) null);
-        Interpreter interpreter = new TemplateInterpreter(jexl, context, 
frame, null, null);
+        TemplateInterpreter.Arguments targs = new TemplateInterpreter
+                .Arguments(jxlt.getEngine())
+                .context(context)
+                .options(options)
+                .frame(frame);
+        Interpreter interpreter = new TemplateInterpreter(targs);
         TemplateExpression[] immediates = new TemplateExpression[exprs.length];
         for (int e = 0; e < exprs.length; ++e) {
             try {
@@ -272,8 +280,17 @@ public final class TemplateScript implements 
JxltEngine.Template {
 
     @Override
     public void evaluate(JexlContext context, Writer writer, Object... args) {
+        final Engine jexl = jxlt.getEngine();
+        JexlOptions options = jexl.options(script, context);
         Frame frame = script.createFrame(args);
-        Interpreter interpreter = new TemplateInterpreter(jxlt.getEngine(), 
context, frame, exprs, writer);
+        TemplateInterpreter.Arguments targs = new TemplateInterpreter
+                .Arguments(jexl)
+                .context(context)
+                .options(options)
+                .frame(frame)
+                .expressions(exprs)
+                .writer(writer);
+        Interpreter interpreter = new TemplateInterpreter(targs);
         interpreter.interpret(script);
     }
 
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 8d80239..83c6b23 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -26,6 +26,9 @@
     </properties>
     <body>
         <release version="3.2" date="unreleased">
+            <action dev="henrib" type="fix" issue="JEXL-328">
+                JXLT template scripts evaluation do not process pragmas
+            </action>
             <action dev="henrib" type="fix" issue="JEXL-327" due-to="David 
Costanzo">
                 map[null] does not work in assignment context
             </action>
diff --git a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java 
b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
index 02256ad..01fbf5e 100644
--- a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
+++ b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java
@@ -46,7 +46,7 @@ public class FeaturesTest extends JexlTestCase {
             JexlScript ctl = JEXL.createScript(script);
             Assert.assertNotNull(ctl);
             try {
-                JexlScript e = jexl.createScript(features, null, script, null);
+                JexlScript e = jexl.createScript(features, null, script);
                 Assert.fail("should fail parse: " + script);
             } catch (JexlException.Feature xfeature) {
                 String msg = xfeature.getMessage();
diff --git a/src/test/java/org/apache/commons/jexl3/JXLTTest.java 
b/src/test/java/org/apache/commons/jexl3/JXLTTest.java
index 95d1dd3..9f91d3c 100644
--- a/src/test/java/org/apache/commons/jexl3/JXLTTest.java
+++ b/src/test/java/org/apache/commons/jexl3/JXLTTest.java
@@ -17,7 +17,6 @@
 package org.apache.commons.jexl3;
 
 import org.apache.commons.jexl3.internal.Debugger;
-import org.apache.commons.jexl3.internal.Engine;
 import org.apache.commons.jexl3.internal.TemplateDebugger;
 import org.apache.commons.jexl3.internal.TemplateScript;
 import org.apache.commons.logging.Log;
@@ -28,7 +27,6 @@ import java.io.StringReader;
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -95,8 +93,7 @@ public class JXLTTest extends JexlTestCase {
         if (options.isLexicalShade()) {
             return true;
         }
-        options = new JexlOptions();
-        ((Engine) ENGINE).optionsSet(options);
+        options = new JexlOptions().set(ENGINE);
         return options.isLexicalShade();
     }
 
@@ -161,12 +158,14 @@ public class JXLTTest extends JexlTestCase {
 
     @Test
     public void testAssign() throws Exception {
-        JxltEngine.Expression assign = JXLT.createExpression("${froboz.value = 
10}");
+        Froboz froboz = new Froboz(32);
+        context.set("froboz", froboz);
+        JxltEngine.Expression assign = JXLT.createExpression("${froboz.value = 
42}");
         JxltEngine.Expression check = JXLT.createExpression("${froboz.value}");
         Object o = assign.evaluate(context);
-        Assert.assertEquals("Result is not 10", new Integer(10), o);
+        Assert.assertEquals("Result is not 10", new Integer(42), o);
         o = check.evaluate(context);
-        Assert.assertEquals("Result is not 10", new Integer(10), o);
+        Assert.assertEquals("Result is not 10", new Integer(42), o);
     }
 
     @Test
@@ -1001,5 +1000,90 @@ public class JXLTTest extends JexlTestCase {
         output = strw.toString();
         Assert.assertEquals(s315, output);
     }
+    
+        // define mode pro50
+    static final JexlOptions MODE_PRO50 = new JexlOptions();
+    static {
+        MODE_PRO50.setFlags( "+strict +cancellable +lexical +lexicalShade 
-safe".split(" "));
+    }
+
+    public static class PragmaticContext extends MapContext implements 
JexlContext.PragmaProcessor, JexlContext.OptionsHandle {
+        private final JexlOptions options;
+
+        public PragmaticContext(JexlOptions o) {
+            this.options = o;
+        }
+
+        @Override
+        public void processPragma(String key, Object value) {
+            if ("script.mode".equals(key) && "pro50".equals(value)) {
+                options.set(MODE_PRO50);
+            }
+        }
+
+        @Override
+        public Object get(String name) {
+            if ("$options".equals(name)) {
+                return options;
+            }
+            return super.get(name);
+        }
+
+        @Override
+        public JexlOptions getEngineOptions() {
+            return options;
+        }
+    }
+    @Test
+    public void testLexicalTemplate() throws Exception {
+        JexlOptions opts = new JexlOptions();
+        JexlContext ctxt = new PragmaticContext(opts);
+        opts.setCancellable(false);
+        opts.setStrict(false);
+        opts.setSafe(true);
+        opts.setLexical(false);
+        opts.setLexicalShade(false);
+        String src0 = "${$options.strict?'+':'-'}strict"
+                + " ${$options.cancellable?'+':'-'}cancellable"
+                + " ${$options.lexical?'+':'-'}lexical"
+                + " ${$options.lexicalShade?'+':'-'}lexicalShade"
+                + " ${$options.safe?'+':'-'}safe";
+        
+        JxltEngine.Template tmplt0 = JXLT.createTemplate("$$", new 
StringReader(src0));
+        Writer strw0 = new StringWriter();
+        tmplt0.evaluate(ctxt, strw0);
+        String output0 = strw0.toString();
+        Assert.assertEquals( "-strict -cancellable -lexical -lexicalShade 
+safe", output0);
+                
+        String src = "$$ #pragma script.mode pro50\n"
+                + "${$options.strict?'+':'-'}strict"
+                + " ${$options.cancellable?'+':'-'}cancellable"
+                + " ${$options.lexical?'+':'-'}lexical"
+                + " ${$options.lexicalShade?'+':'-'}lexicalShade"
+                + " ${$options.safe?'+':'-'}safe";
+            
+        JxltEngine.Template tmplt = JXLT.createTemplate("$$", new 
StringReader(src));
+        Writer strw = new StringWriter();
+        tmplt.evaluate(ctxt, strw);
+        String output = strw.toString();
+        Assert.assertEquals("+strict +cancellable +lexical +lexicalShade 
-safe", output);
+    }
 
+    @Test
+    public void testTemplatePragmaPro50() throws Exception {
+        JexlOptions opts = new JexlOptions();
+        JexlContext ctxt = new PragmaticContext(opts);
+        String src = "$$ #pragma script.mode pro50\n"
+                + "$$ var tab = null;\n"
+                + "$$ tab.dummy();";
+        JxltEngine.Template tmplt = JXLT.createTemplate("$$", new 
StringReader(src));
+        Writer strw = new StringWriter();
+        try {
+            tmplt.evaluate(ctxt, strw);
+            Assert.fail("tab var is null");
+        } catch (JexlException.Variable xvar) {
+            Assert.assertTrue("tab".equals(xvar.getVariable()));
+            Assert.assertFalse(xvar.isUndefined());
+        }
+    }
 }

Reply via email to