From ca83d6bcb403eb0dcb624509646de56a3c0e35ad Mon Sep 17 00:00:00 2001 From: Henrib Date: Fri, 30 Aug 2024 19:23:32 +0200 Subject: [PATCH] JEXL-425, JEXL-426, JEXL-427 : added flag for logical expressions 3.4 compatibility; - javadoc, nitpicks, light code refactoring; --- src/changes/changes.xml | 9 ++ .../org/apache/commons/jexl3/JexlBuilder.java | 57 ++++++--- .../apache/commons/jexl3/JexlFeatures.java | 5 +- .../org/apache/commons/jexl3/JexlOptions.java | 44 ++++++- .../apache/commons/jexl3/internal/Frame.java | 47 +++---- .../commons/jexl3/internal/Interpreter.java | 54 ++++---- .../commons/jexl3/internal/LexicalFrame.java | 7 +- .../apache/commons/jexl3/internal/Scope.java | 3 +- .../commons/jexl3/parser/ASTIdentifier.java | 1 - .../apache/commons/jexl3/parser/JexlNode.java | 10 +- .../commons/jexl3/parser/JexlParser.java | 32 +++-- .../apache/commons/jexl3/parser/Parser.jjt | 8 +- .../apache/commons/jexl3/FeaturesTest.java | 60 ++++----- .../apache/commons/jexl3/Issues400Test.java | 87 +++++++++---- .../org/apache/commons/jexl3/LexicalTest.java | 119 +++++++++--------- .../org/apache/commons/jexl3/SpreadCache.java | 4 +- .../jexl3/introspection/SandboxTest.java | 62 +++++---- .../jexl3/jexl342/ReferenceUberspect.java | 2 +- 18 files changed, 369 insertions(+), 242 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index ae72546d5..61f9150f4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -29,8 +29,17 @@ + + Multiline format literals does not always return string + Replace NumberParser use of Locale.ENGLISH with Locale.ROOT. + + Avoid coercing logical expressions to boolean + + + Enable pass-by-reference for Captured Variables + Bump commons-logging:commons-logging from 1.3.2 to 1.3.4 #267, #280. Bump org.codehaus.mojo:animal-sniffer-maven-plugin from 1.23 to 1.24 #266. diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java index 03146109e..a8cb6ee5b 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java +++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java @@ -187,15 +187,15 @@ public boolean antish() { } /** - * Sets whether the engine will resolve antish variable names. - * - * @param flag true means antish resolution is enabled, false disables it - * @return this builder - */ - public JexlBuilder antish(final boolean flag) { - options.setAntish(flag); - return this; - } + * Sets whether the engine will resolve antish variable names. + * + * @param flag true means antish resolution is enabled, false disables it + * @return this builder + */ + public JexlBuilder antish(final boolean flag) { + options.setAntish(flag); + return this; + } /** @return the arithmetic */ public JexlArithmetic arithmetic() { @@ -216,6 +216,16 @@ public JexlBuilder arithmetic(final JexlArithmetic a) { return this; } + /** + * Sets whether logical expressions ("" , ||) coerce their result to boolean. + * @param flag true or false + * @return this builder + */ + public JexlBuilder booleanLogical(final boolean flag) { + options.setBooleanLogical(flag); + return this; + } + /** * @return the cache size */ @@ -431,7 +441,12 @@ public JexlBuilder imports(final String... imports) { return imports(Arrays.asList(imports)); } - /** @return whether lexical scope is enabled */ + /** + * @see JexlOptions#isLexical() + * @return whether lexical scope is enabled + * @deprecated 3.4.1 + */ + @Deprecated public boolean lexical() { return options.isLexical(); } @@ -448,7 +463,12 @@ public JexlBuilder lexical(final boolean flag) { return this; } - /** @return whether lexical shading is enabled */ + /** + * @see JexlOptions#isLexicalShade() + * @return whether lexical shading is enabled + * @deprecated 3.4.1 + */ + @Deprecated public boolean lexicalShade() { return options.isLexicalShade(); } @@ -546,9 +566,11 @@ public JexlBuilder namespaces(final Map ns) { return this; } - /** @return the current set of options */ + /** + * @return the current set of options + */ public JexlOptions options() { - return options; + return options; } /** @return the permissions */ @@ -675,15 +697,16 @@ public JexlBuilder strict(final boolean flag) { return this; } + /** + * @see JexlOptions#setStrictInterpolation(boolean) + * @param flag strict interpolation flag + * @return this builder + */ public JexlBuilder strictInterpolation(final boolean flag) { options.setStrictInterpolation(flag); return this; } - public boolean strictInterpolation() { - return options.isStrictInterpolation(); - } - /** @return the uberspect */ public JexlUberspect uberspect() { return this.uberspect; diff --git a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java index 73f65068d..7ec7f1a2b 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlFeatures.java +++ b/src/main/java/org/apache/commons/jexl3/JexlFeatures.java @@ -59,6 +59,7 @@ *
  • Pragma anywhere: whether pragma, that are not statements and handled before execution begins, * can appear anywhere in the source or before any statements - ie at the beginning of a script.
  • *
  • Const Capture: whether variables captured by lambdas are read-only (aka const, same as Java) or read-write.
  • + *
  • Reference Capture: whether variables captured by lambdas are pass-by-reference or pass-by-value.
  • * * @since 3.2 */ @@ -341,7 +342,7 @@ public JexlFeatures comparatorNames(final boolean flag) { } /** - * Sets whether lambda captured-variables are const or not. + * Sets whether lambda captured-variables are constant or mutable. *

    * When disabled, lambda-captured variables are implicitly converted to read-write local variable (let), * when enabled, those are implicitly converted to read-only local variables (const). @@ -355,7 +356,7 @@ public JexlFeatures constCapture(final boolean flag) { } /** - * Sets whether lambda captured-variables are references or not. + * Sets whether lambda captured-variables are references or values. *

    When variables are pass-by-reference, side-effects are visible from inner lexical scopes * to outer-scope.

    *

    diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java b/src/main/java/org/apache/commons/jexl3/JexlOptions.java index 3ca5c7efa..a20bb0f5a 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java +++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java @@ -38,12 +38,15 @@ *

  • sharedInstance: whether these options can be modified at runtime during execution (expert)
  • *
  • constCapture: whether captured variables will throw an error if an attempt is made to change their value
  • *
  • strictInterpolation: whether interpolation strings always return a string or attempt to parse and return integer
  • + *
  • booleanLogical: whether logical expressions ("" , ||) coerce their result to boolean
  • * * The sensible default is cancellable, strict and strictArithmetic. *

    This interface replaces the now deprecated JexlEngine.Options. * @since 3.2 */ public final class JexlOptions { + /** The boolean logical flag. */ + private static final int BOOLEAN_LOGICAL = 10; /** The interpolation string bit. */ private static final int STRICT_INTERPOLATION= 9; /** The const capture bit. */ @@ -67,10 +70,12 @@ public final class JexlOptions { /** The flag names ordered. */ private static final String[] NAMES = { "cancellable", "strict", "silent", "safe", "lexical", "antish", - "lexicalShade", "sharedInstance", "constCapture", "strictInterpolation" + "lexicalShade", "sharedInstance", "constCapture", "strictInterpolation", + "booleanShortCircuit" }; /** Default mask .*/ private static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1 << ANTISH | 1 << SAFE; + /** * Checks the value of a flag in the mask. * @param ordinal the flag ordinal @@ -80,6 +85,7 @@ public final class JexlOptions { private static boolean isSet(final int ordinal, final int mask) { return (mask & 1 << ordinal) != 0; } + /** * Parses flags by name. *

    A '+flag' or 'flag' will set flag as true, '-flag' set as false. @@ -115,6 +121,7 @@ public static int parseFlags(final int initial, final String... flags) { } return mask; } + /** * Sets the value of a flag in a mask. * @param ordinal the flag ordinal @@ -125,6 +132,7 @@ public static int parseFlags(final int initial, final String... flags) { private static int set(final int ordinal, final int mask, final boolean value) { return value? mask | 1 << ordinal : mask & ~(1 << ordinal); } + /** * Sets the default (static, shared) option flags. *

    @@ -140,8 +148,10 @@ private static int set(final int ordinal, final int mask, final boolean value) { public static void setDefaultFlags(final String...flags) { DEFAULT = parseFlags(DEFAULT, flags); } + /** The arithmetic math context. */ private MathContext mathContext; + /** The arithmetic math scale. */ private int mathScale = Integer.MIN_VALUE; @@ -212,6 +222,17 @@ public boolean isAntish() { return isSet(ANTISH, flags); } + /** + * Gets whether logical expressions ("" , ||) coerce their result to boolean; if set, + * an expression like (3 "" 4 "" 5) will evaluate to true. If not, it will evaluate to 5. + * To preserve strict compatibility with 3.4, set the flag to true. + * @return true if short-circuit logicals coerce their result to boolean, false otherwise + * @since 3.4.1 + */ + public boolean isBooleanLogical() { + return isSet(BOOLEAN_LOGICAL, flags); + } + /** * Checks whether evaluation will throw JexlException.Cancel (true) or * return null (false) if interrupted. @@ -339,6 +360,14 @@ public void setAntish(final boolean flag) { flags = set(ANTISH, flags, flag); } + /** + * Sets whether logical expressions ("" , ||) coerce their result to boolean. + * @param flag true or false + */ + public void setBooleanLogical(final boolean flag) { + flags = set(BOOLEAN_LOGICAL, flags, flag); + } + /** * Sets whether the engine will throw JexlException.Cancel (true) or return * null (false) when interrupted during evaluation. @@ -473,10 +502,15 @@ public void setStrictArithmetic(final boolean stricta) { /** * Sets the strict interpolation flag. - * @param flag true or false - */ - public void setStrictInterpolation(final boolean flag) { - flags = set(STRICT_INTERPOLATION, flags, flag); + *

    When strict, interpolation strings composed only of an expression (ie `${...}`) are evaluated + * as strings; when not strict, integer results are left untouched.

    + * This can affect the results of expressions like map.`${key}` when key is + * an integer (or a string); it is almost always possible to use map[key] to ensure + * that the key type is not altered. + * @param strict true or false + */ + public void setStrictInterpolation(final boolean strict) { + flags = set(STRICT_INTERPOLATION, flags, strict); } @Override public String toString() { diff --git a/src/main/java/org/apache/commons/jexl3/internal/Frame.java b/src/main/java/org/apache/commons/jexl3/internal/Frame.java index e83876948..5602433ee 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Frame.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Frame.java @@ -65,7 +65,7 @@ Frame assign(final Object... values) { } /** - * Creates a new from of this frame"e;s class. + * Creates a new from of this frame"s class. * @param s the scope * @param r the arguments * @param c the number of curried parameters @@ -149,6 +149,9 @@ Object[] nocycleStack(final Closure closure) { } } +/** + * Pass-by-reference frame. + */ class ReferenceFrame extends Frame { ReferenceFrame(Scope s, Object[] r, int c) { super(s, r, c); @@ -160,42 +163,40 @@ Frame newFrame(final Scope s, final Object[] r, final int c) { } @Override - CaptureReference capture(int s) { - synchronized(stack) { - Object o = stack[s]; - if (o instanceof CaptureReference) { - return (CaptureReference) o; - } else { - CaptureReference captured = new CaptureReference(o); - stack[s] = captured; - return captured; - } + CaptureReference capture(final int s) { + final Object o = stack[s]; + if (o instanceof CaptureReference) { + return (CaptureReference) o; + } else { + // change the type of the captured register, wrap the value in a reference + CaptureReference captured = new CaptureReference(o); + stack[s] = captured; + return captured; } } @Override Object get(final int s) { - synchronized(stack) { - Object o = stack[s]; - return o instanceof CaptureReference ? ((CaptureReference) o).get() : o; - } + final Object o = stack[s]; + return o instanceof CaptureReference ? ((CaptureReference) o).get() : o; } @Override void set(final int r, final Object value) { - synchronized (stack) { - Object o = stack[r]; - if (o instanceof CaptureReference) { - if (value != Scope.UNDEFINED && value != Scope.UNDECLARED) { - ((CaptureReference) o).set(value); - } - } else { - stack[r] = value; + final Object o = stack[r]; + if (o instanceof CaptureReference) { + if (value != Scope.UNDEFINED && value != Scope.UNDECLARED) { + ((CaptureReference) o).set(value); } + } else { + stack[r] = value; } } } +/** + * Captured variable reference. + */ class CaptureReference extends AtomicReference { CaptureReference(Object o) { super(o); 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 cfc2fd54e..3479c92a8 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java @@ -489,10 +489,11 @@ private Object evalJxltHandle(NODE if (expr instanceof TemplateEngine.TemplateExpression ) { Object eval = ((TemplateEngine.TemplateExpression ) expr).evaluate(context, frame, options); if (eval != null) { + String inter = eval.toString(); if (options.isStrictInterpolation()) { - return eval.toString(); + return inter; } - final Integer id = ASTIdentifierAccess.parseIdentifier(eval.toString()); + final Integer id = ASTIdentifierAccess.parseIdentifier(inter); return id != null ? id : eval; } } @@ -1076,8 +1077,14 @@ protected Object visit(final ASTAddNode node, final Object data) { } } - @Override - protected Object visit(final ASTAndNode node, final Object data) { + /** + * Short-circuit evaluation of logical expression. + * @param check the fuse value that will stop evaluation, true for OR, false for AND + * @param node a ASTAndNode or a ASTOrNode + * @param data + * @return true or false if boolean logical option is true, the last evaluated argument otherwise + */ + private Object shortCircuit(final boolean check, final JexlNode node, final Object data) { /* * The pattern for exception mgmt is to let the child*.jjtAccept out of the try/catch loop so that if one fails, * the ex will traverse up to the interpreter. In cases where this is not convenient/possible, JexlException @@ -1085,20 +1092,33 @@ protected Object visit(final ASTAndNode node, final Object data) { */ final int last = node.jjtGetNumChildren(); Object argument = null; + boolean result = false; for (int c = 0; c < last; ++c) { argument = node.jjtGetChild(c).jjtAccept(this, data); try { // short-circuit - if (!arithmetic.toBoolean(argument)) { + result = arithmetic.toBoolean(argument); + if (result == check) { break; } } catch (final ArithmeticException xrt) { throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt); } } - return argument; + return options.isBooleanLogical()? result : argument; + } + + @Override + protected Object visit(final ASTAndNode node, final Object data) { + return shortCircuit(false, node, data); } + @Override + protected Object visit(final ASTOrNode node, final Object data) { + return shortCircuit(true, node, data); + } + + @Override protected Object visit(final ASTAnnotatedStatement node, final Object data) { return processAnnotation(node, 0, data); @@ -1786,24 +1806,6 @@ protected Object visit(final ASTNumberLiteral node, final Object data) { return node.getLiteral(); } - @Override - protected Object visit(final ASTOrNode node, final Object data) { - final int last = node.jjtGetNumChildren(); - Object argument = null; - for (int c = 0; c < last; ++c) { - argument = node.jjtGetChild(c).jjtAccept(this, data); - try { - // short-circuit - if (arithmetic.toBoolean(argument)) { - break; - } - } catch (final ArithmeticException xrt) { - throw new JexlException(node.jjtGetChild(0), "boolean coercion error", xrt); - } - } - return argument; - } - @Override protected Object visit(final ASTQualifiedIdentifier node, final Object data) { return resolveClassName(node.getName()); @@ -2113,13 +2115,13 @@ protected Object visit(final ASTTernaryNode node, final Object data) { } // ternary as in "x ? y : z" if (node.jjtGetNumChildren() == 3) { - if (condition != null && arithmetic.toBoolean(condition)) { + if (condition != null && arithmetic.testPredicate(condition)) { return node.jjtGetChild(1).jjtAccept(this, data); } return node.jjtGetChild(2).jjtAccept(this, data); } // elvis as in "x ?: z" - if (condition != null && arithmetic.toBoolean(condition)) { + if (condition != null && arithmetic.testPredicate(condition)) { return condition; } return node.jjtGetChild(1).jjtAccept(this, data); diff --git a/src/main/java/org/apache/commons/jexl3/internal/LexicalFrame.java b/src/main/java/org/apache/commons/jexl3/internal/LexicalFrame.java index 13a0715ed..822c0dc2c 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/LexicalFrame.java +++ b/src/main/java/org/apache/commons/jexl3/internal/LexicalFrame.java @@ -21,7 +21,9 @@ /** * The set of valued symbols defined in a lexical frame. - *

    The symbol identifiers are determined by the functional scope. + *

    The symbol identifiers are determined by the functional scope. Since the frame contains values of + * all symbols in the functional scope, the lexical frame preserves values of symbols reused for local + * definition. */ public class LexicalFrame extends LexicalScope { /** @@ -34,6 +36,7 @@ public class LexicalFrame extends LexicalScope { protected final LexicalFrame previous; /** * The stack of values in the lexical frame. + *

    [symbol identifier, value] are stacked in pairs

    */ private Deque stack; @@ -105,7 +108,7 @@ public boolean defineSymbol(final int symbol, final boolean capture) { */ public LexicalFrame pop() { // undefine all symbols - clearSymbols(s -> frame.set(s, Scope.UNDEFINED) ); + clearSymbols(s -> frame.set(s, Scope.UNDEFINED) ); // restore values of captured symbols that were overwritten if (stack != null) { while (!stack.isEmpty()) { diff --git a/src/main/java/org/apache/commons/jexl3/internal/Scope.java b/src/main/java/org/apache/commons/jexl3/internal/Scope.java index 1f671e63b..d407fc82b 100644 --- a/src/main/java/org/apache/commons/jexl3/internal/Scope.java +++ b/src/main/java/org/apache/commons/jexl3/internal/Scope.java @@ -70,7 +70,6 @@ public final class Scope { * The map of local captured variables to parent scope variables, ie closure. */ private Map capturedVariables; - /** * Let symbols. */ @@ -125,7 +124,7 @@ public Frame createFrame(boolean ref, final Frame frame, final Object...args) { for (final Map.Entry capture : capturedVariables.entrySet()) { final Integer target = capture.getKey(); final Integer source = capture.getValue(); - final Object arg = frame.capture(source); //frame.get(source); + final Object arg = frame.capture(source); arguments[target] = arg; } newFrame = frame.newFrame(this, arguments, 0); diff --git a/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java b/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java index dca516a03..94fb90339 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java +++ b/src/main/java/org/apache/commons/jexl3/parser/ASTIdentifier.java @@ -29,7 +29,6 @@ public class ASTIdentifier extends JexlNode { private static final int SHADED = 1; /** The captured variable flag. */ private static final int CAPTURED = 2; - /** The lexical variable flag. */ private static final int LEXICAL = 3; /** The const variable flag. */ diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java index 3171e41a6..2b505913e 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlNode.java @@ -42,11 +42,19 @@ public interface Constant { public interface Funcall {} /** - * Marker interface for nodes hosting a JxltExpression + * Marker interface for nodes hosting a JxltExpression. */ public interface JxltHandle { + /** @return the expression source. */ String getExpressionSource(); + + /**@return the expression instance, should be a TemplateEngine.TemplateExpression. */ JxltEngine.Expression getExpression(); + + /** + * Sets the template expression. + * @param expr a TemplateEngine.TemplateExpression instance + */ void setExpression(JxltEngine.Expression expr); } diff --git a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java index 50d7b972a..0db5e377f 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java +++ b/src/main/java/org/apache/commons/jexl3/parser/JexlParser.java @@ -301,11 +301,11 @@ protected String checkVariable(final ASTIdentifier identifier, final String name } identifier.setSymbol(symbol, name); if (!declared) { - identifier.setShaded(true); - if (/*identifier.isLexical() ||*/ getFeatures().isLexicalShade()) { + if (getFeatures().isLexicalShade()) { // can not reuse a local as a global throw new JexlException.Parsing(info, name + ": variable is not declared").clean(); } + identifier.setShaded(true); } } } @@ -480,9 +480,9 @@ private boolean declareSymbol(final int symbol) { *

    * * @param variable the identifier used to declare - * @param lexical whether the symbol is lexical + * @param lexical whether the symbol is lexical * @param constant whether the symbol is constant - * @param token the variable name toekn + * @param token the variable name token */ protected void declareVariable(final ASTVar variable, final Token token, final boolean lexical, final boolean constant) { final String name = token.image; @@ -717,10 +717,26 @@ protected void jjtreeCloseNodeScope(final JexlNode node) { * @param node the node */ protected void jjtreeOpenNodeScope(final JexlNode node) { -// if (node instanceof ASTBlock || node instanceof ASTForeachStatement) { -// final LexicalUnit unit = (LexicalUnit) node; -// unit.setScope(scope); -// } + // nothing + } + + /** + * Starts the definition of a lambda. + * @param jjtThis the script + */ + protected void beginLambda(final ASTJexlScript jjtThis) { + jjtThis.setFeatures(this.getFeatures()); + pushScope(); + pushUnit(jjtThis); + } + + /** + * Ends the definition of a lambda. + * @param jjtThis the script + */ + protected void endLambda(final ASTJexlScript jjtThis) { + popUnit(jjtThis); + popScope(); } /** diff --git a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt index a8ddf22f8..4dd4fee69 100644 --- a/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt +++ b/src/main/java/org/apache/commons/jexl3/parser/Parser.jjt @@ -426,7 +426,7 @@ void Block() #Block : {} void FunctionStatement() #JexlLambda : {} { - DeclareFunction() { pushScope(); jjtThis.setFeatures(this.getFeatures()); pushUnit(jjtThis); } Parameters() ( LOOKAHEAD(3) Block() | Expression()) { popUnit(jjtThis); popScope(); } + DeclareFunction() { beginLambda(jjtThis); } Parameters() ( LOOKAHEAD(3) Block() | Expression()) { endLambda(jjtThis); } } void ExpressionStatement() #void : {} @@ -1058,11 +1058,11 @@ void Lambda() #JexlLambda : } { (LOOKAHEAD() DeclareFunction())? { - pushScope(); jjtThis.setFeatures(this.getFeatures()); pushUnit(jjtThis); } Parameters() ( LOOKAHEAD(3) Block() | Expression()) { popUnit(jjtThis); popScope(); } + beginLambda(jjtThis); } Parameters() ( LOOKAHEAD(3) Block() | Expression()) { endLambda(jjtThis); } | - { pushScope(); jjtThis.setFeatures(this.getFeatures()); pushUnit(jjtThis); } Parameters() (arrow= | arrow=) ( LOOKAHEAD(3) Block() | Expression()) { checkLambda(arrow); popUnit(jjtThis); popScope(); } + { beginLambda(jjtThis); } Parameters() (arrow= | arrow=) ( LOOKAHEAD(3) Block() | Expression()) { checkLambda(arrow); endLambda(jjtThis); } | - { pushScope(); jjtThis.setFeatures(this.getFeatures()); pushUnit(jjtThis); } Parameter() (arrow= | arrow=)( LOOKAHEAD(3) Block() | Expression()) { checkLambda(arrow); popUnit(jjtThis); popScope(); } + { beginLambda(jjtThis); } Parameter() (arrow= | arrow=)( LOOKAHEAD(3) Block() | Expression()) { checkLambda(arrow); endLambda(jjtThis); } } diff --git a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java index dc3923ec4..2b83ad60a 100644 --- a/src/test/java/org/apache/commons/jexl3/FeaturesTest.java +++ b/src/test/java/org/apache/commons/jexl3/FeaturesTest.java @@ -42,7 +42,7 @@ public FeaturesTest() { super("FeaturesTest"); } - private void assertOk(final JexlFeatures features, final String[] scripts) { + private void assertOk(final String[] scripts) { for(final String str : scripts) { try { final JexlScript e = jexl.createScript(str); @@ -55,8 +55,8 @@ private void assertOk(final JexlFeatures features, final String[] scripts) { /** * Checks that the script is valid with all features on then verifies it * throws a feature exception with the given set (in features param). - * @param features - * @param scripts + * @param features the features + * @param scripts the scripts * @throws Exception */ private void checkFeature(final JexlFeatures features, final String[] scripts) throws Exception { @@ -69,7 +69,7 @@ private void checkFeature(final JexlFeatures features, final String[] scripts) t } @Test - public void test410a() { + void test410a() { final long x = JexlFeatures.createAll().getFlags(); assertEquals(REF_CAPTURE + 1, Long.bitCount(x)); assertTrue((x & 1L << REF_CAPTURE) != 0); @@ -82,7 +82,7 @@ public void test410a() { } @Test - public void test410b() { + void test410b() { final JexlFeatures features = JexlFeatures.createScript(); assertTrue(features.isLexical()); assertTrue(features.isLexicalShade()); @@ -113,7 +113,7 @@ public void test410b() { } @Test - public void testAnnotations() throws Exception { + void testAnnotations() throws Exception { final JexlFeatures f = new JexlFeatures().annotation(false); final String[] scripts = { "@synchronized(2) { return 42; }", @@ -123,7 +123,7 @@ public void testAnnotations() throws Exception { } @Test - public void testArrayRefs() throws Exception { + void testArrayRefs() throws Exception { final JexlFeatures f = new JexlFeatures().arrayReferenceExpr(false); final String[] scripts = { @@ -133,7 +133,7 @@ public void testArrayRefs() throws Exception { "x.y['a'][b]" }; checkFeature(f, scripts); - assertOk(f, scripts); + assertOk(scripts); // same ones with constant array refs should work final String[] scriptsOk = { "x['y']", @@ -141,11 +141,11 @@ public void testArrayRefs() throws Exception { "x()['a']['b']", "x.y['a']['b']" }; - assertOk(f, scriptsOk); + assertOk(scriptsOk); } @Test - public void testConstCapture() throws Exception { + void testConstCapture() throws Exception { final JexlFeatures f = new JexlFeatures().constCapture(true); final String[] scripts = { "let x = 0; const f = y -> x += y; f(42)", @@ -153,11 +153,11 @@ public void testConstCapture() throws Exception { }; checkFeature(f, scripts); final JexlFeatures nof = new JexlFeatures().constCapture(true); - assertOk(nof, scripts); + assertOk(scripts); } @Test - public void testCreate() { + void testCreate() { final JexlFeatures f = JexlFeatures.createNone(); assertTrue(f.supportsExpression()); @@ -187,7 +187,7 @@ public void testCreate() { } @Test - public void testIssue409() { + void testIssue409() { final JexlFeatures baseFeatures = JexlFeatures.createDefault(); assertFalse(baseFeatures.isLexical()); assertFalse(baseFeatures.isLexicalShade()); @@ -202,7 +202,7 @@ public void testIssue409() { } @Test - public void testMethodCalls() throws Exception { + void testMethodCalls() throws Exception { final JexlFeatures f = new JexlFeatures().methodCall(false); final String[] scripts = { "x.y(z)", @@ -217,11 +217,11 @@ public void testMethodCalls() throws Exception { "x('a')[1]", "x()['a']['b']", }; - assertOk(f, scriptsOk); + assertOk(scriptsOk); } @Test - public void testMixedFeatures() throws Exception { + void testMixedFeatures() throws Exception { // no new, no local, no lambda, no loops, no-side effects final JexlFeatures f = new JexlFeatures() .newInstance(false) @@ -241,7 +241,7 @@ public void testMixedFeatures() throws Exception { checkFeature(f, scripts); } @Test - public void testNoComparatorNames() throws Exception { + void testNoComparatorNames() throws Exception { final JexlFeatures f = new JexlFeatures().comparatorNames(false); final String[] scripts = { "1 eq 1", @@ -255,7 +255,7 @@ public void testNoComparatorNames() throws Exception { } @Test - public void testNoLambda() throws Exception { + void testNoLambda() throws Exception { final JexlFeatures f = new JexlFeatures().lambda(false); final String[] scripts = { "var x = ()->{ return 0 };", @@ -269,7 +269,7 @@ public void testNoLambda() throws Exception { } @Test - public void testNoLocals() throws Exception { + void testNoLocals() throws Exception { final JexlFeatures f = new JexlFeatures().localVar(false); final String[] scripts = { "var x = 0;", @@ -279,7 +279,7 @@ public void testNoLocals() throws Exception { } @Test - public void testNoLoop() throws Exception { + void testNoLoop() throws Exception { final JexlFeatures f = new JexlFeatures().loops(false); final String[] scripts = { "while(true);", @@ -288,7 +288,7 @@ public void testNoLoop() throws Exception { checkFeature(f, scripts); } @Test - public void testNoNew() throws Exception { + void testNoNew() throws Exception { final JexlFeatures f = new JexlFeatures().newInstance(false); final String[] scripts = { "return new(clazz);", @@ -298,7 +298,7 @@ public void testNoNew() throws Exception { } @Test - public void testNoScript() throws Exception { + void testNoScript() throws Exception { final JexlFeatures f = new JexlFeatures().script(false); assertTrue(f.supportsExpression()); final String[] scripts = { @@ -311,7 +311,7 @@ public void testNoScript() throws Exception { } @Test - public void testNoSideEffects() throws Exception { + void testNoSideEffects() throws Exception { final JexlFeatures f = new JexlFeatures().sideEffect(false); final String[] scripts = { "x = 1", @@ -335,7 +335,7 @@ public void testNoSideEffects() throws Exception { } @Test - public void testNoSideEffectsGlobal() throws Exception { + void testNoSideEffectsGlobal() throws Exception { final JexlFeatures f = new JexlFeatures().sideEffectGlobal(false); final String[] scripts = { "x = 1", @@ -366,7 +366,7 @@ public void testNoSideEffectsGlobal() throws Exception { } @Test - public void testPragma() throws Exception { + void testPragma() throws Exception { final JexlFeatures f = new JexlFeatures().pragma(false); final String[] scripts = { "#pragma foo 42", @@ -376,7 +376,7 @@ public void testPragma() throws Exception { } @Test - public void testPragmaAnywhere() throws Exception { + void testPragmaAnywhere() throws Exception { final JexlFeatures f = new JexlFeatures().pragmaAnywhere(false); final String[] scripts = { "var x = 3;\n#pragma foo 42", @@ -385,7 +385,7 @@ public void testPragmaAnywhere() throws Exception { } @Test - public void testReservedVars() throws Exception { + void testReservedVars() throws Exception { final JexlFeatures f = new JexlFeatures().reservedNames(Arrays.asList("foo", "bar")); final String[] scripts = { "var foo = 0;", @@ -398,11 +398,11 @@ public void testReservedVars() throws Exception { "(bar1)->{ bar }", "var f = function(bar2) { bar2; }" }; - assertOk(f, scriptsOk); + assertOk(scriptsOk); } @Test - public void testStructuredLiterals() throws Exception { + void testStructuredLiterals() throws Exception { final JexlFeatures f = new JexlFeatures().structuredLiteral(false); final String[] scripts = { "{1, 2, 3}", @@ -411,6 +411,6 @@ public void testStructuredLiterals() throws Exception { "(1 .. 5)" }; checkFeature(f, scripts); - assertOk(f, scripts); + assertOk(scripts); } } diff --git a/src/test/java/org/apache/commons/jexl3/Issues400Test.java b/src/test/java/org/apache/commons/jexl3/Issues400Test.java index 54a99ffb7..8ec230e40 100644 --- a/src/test/java/org/apache/commons/jexl3/Issues400Test.java +++ b/src/test/java/org/apache/commons/jexl3/Issues400Test.java @@ -100,7 +100,7 @@ private static void run404(final JexlEngine jexl, final String src, final Object } @Test - public void test402() { + void test402() { final JexlContext jc = new MapContext(); // @formatter:off final String[] sources = { @@ -118,7 +118,7 @@ public void test402() { } @Test - public void test403() { + void test403() { // @formatter:off final String[] strings = { " map1.`${item.a}` = 1;\n", @@ -150,7 +150,7 @@ public void test403() { } @Test - public void test404a() { + void test404a() { final JexlEngine jexl = new JexlBuilder().cache(64).strict(true).safe(false).create(); Map a = Collections.singletonMap("b", 42); // access is constant @@ -172,7 +172,7 @@ public void test404a() { } @Test - public void test404b() { + void test404b() { // @formatter:off final JexlEngine jexl = new JexlBuilder() .cache(64) @@ -213,7 +213,7 @@ public void test404b() { } @Test - public void test406a() { + void test406a() { // @formatter:off final JexlEngine jexl = new JexlBuilder() .cache(64) @@ -251,7 +251,7 @@ public void test406a() { } @Test - public void test407() { + void test407() { // Java version final double r = 99.0d + 7.82d - 99.0d - 7.82d; assertEquals(0d, r, 8.e-15); // Not zero, IEEE 754 @@ -267,7 +267,7 @@ public void test407() { } @Test - public void test412() { + void test412() { final Map ctl = new HashMap<>(); ctl.put("one", 1); ctl.put("two", 2); @@ -292,7 +292,7 @@ public void test412() { } @Test - public void test413a() { + void test413a() { final JexlBuilder builder = new JexlBuilder(); final JexlEngine jexl = builder.create(); final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z"); @@ -301,7 +301,7 @@ public void test413a() { } @Test - public void test413b() { + void test413b() { final JexlBuilder builder = new JexlBuilder(); final JexlOptions options = builder.options(); options.setConstCapture(true); @@ -313,7 +313,7 @@ public void test413b() { } @Test - public void test413c() { + void test413c() { final JexlBuilder builder = new JexlBuilder(); final JexlEngine jexl = builder.create(); final JexlScript script = jexl.createScript("#pragma jexl.options '+constCapture'\nvar c = 42; var f = y -> c += y; f(z)", "z"); @@ -322,7 +322,7 @@ public void test413c() { } @Test - public void test413d() { + void test413d() { final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true)); final JexlEngine jexl = builder.create(); final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z"), @@ -331,7 +331,7 @@ public void test413d() { } @Test - public void test415() { + void test415() { final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true)); final JexlEngine jexl = builder.create(); JexlScript script; @@ -354,7 +354,7 @@ public void test415() { } @Test - public void test419() throws NoSuchMethodException { + void test419() throws NoSuchMethodException { // check RESTRICTED permissions denies call to System::currentTimeMillis() final Method currentTimeMillis = System.class.getMethod("currentTimeMillis"); assertFalse(RESTRICTED.allow(currentTimeMillis)); @@ -382,7 +382,7 @@ public void test419() throws NoSuchMethodException { } @Test - public void testDocBreakContinue() { + void testDocBreakContinue() { final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true)); final JexlEngine jexl = builder.create(); JexlScript script; @@ -406,7 +406,7 @@ public void testDocBreakContinue() { } @Test - public void testNamespaceVsTernary0() { + void testNamespaceVsTernary0() { final VinzContext ctxt = new VinzContext(); ctxt.set("Users", "USERS"); final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create(); @@ -425,7 +425,7 @@ public void testNamespaceVsTernary0() { } @Test - public void testNamespaceVsTernary1() { + void testNamespaceVsTernary1() { final VinzContext ctxt = new VinzContext(); ctxt.set("Users", "USERS"); ctxt.set("vinz", new VinzCaller(ctxt)); @@ -465,7 +465,7 @@ public int compare(Object o1, Object o2) { } @Test - public void testSortArray() { + void testSortArray() { final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create(); // test data, json like String src = "[{'id':1,'name':'John','type':9},{'id':2,'name':'Doe','type':7},{'id':3,'name':'Doe','type':10}]"; @@ -482,7 +482,7 @@ public void testSortArray() { assertEquals(9, m[1].get("type")); } - @Test public void test425() { + @Test void test425() { final JexlBuilder builder = new JexlBuilder().strictInterpolation(true); final JexlEngine jexl = builder.create(); JexlScript script; @@ -493,7 +493,7 @@ public void testSortArray() { assertEquals("42", result); } - @Test public void test426a() { + @Test void test426a() { String src = "let x = 10;\n" + "let foo = () -> {\n" + "x += 2;\n" + @@ -510,7 +510,7 @@ public void testSortArray() { assertEquals(42, result); } - @Test public void test426b() { + @Test void test426b() { String src = "let x = 10; let f = () -> { x + 2 }; x = 40; f()"; final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true).referenceCapture(true)); final JexlEngine jexl = builder.create(); @@ -521,7 +521,7 @@ public void testSortArray() { assertEquals(42, result); } - @Test public void test426c() { + @Test void test426c() { String src = "let x = 10; let f = () -> { x + 2 }; x = 40; f"; final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true).referenceCapture(true)); final JexlEngine jexl = builder.create(); @@ -535,7 +535,7 @@ public void testSortArray() { assertEquals(42, result); } - @Test public void test426d() { + @Test void test426d() { String src = "let x = 10; let f = () -> { let x = 142; x }; x = 40; f"; final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().referenceCapture(true)); final JexlEngine jexl = builder.create(); @@ -550,7 +550,7 @@ public void testSortArray() { } - @Test public void test427a() { + @Test void test427a() { String src = "(x, y, z) -> x && y && z"; final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true)); final JexlEngine jexl = builder.create(); @@ -563,16 +563,51 @@ public void testSortArray() { assertEquals("", result); } - @Test public void test427b() { + @Test void test427b() { + OptContext optc = new OptContext(); String src = "(x, y, z) -> x || y || z"; final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true)); final JexlEngine jexl = builder.create(); + JexlOptions options = builder.options(); + optc.setOptions(options); JexlScript script; Object result; script = jexl.createScript(src); - result = script.execute(null, 0, "", 42); + result = script.execute(optc, 0, "", 42); assertEquals(42, result); - result = script.execute(null, true, 42, null); + result = script.execute(optc, true, 42, null); assertEquals(true, result); + + options.setBooleanLogical(true); + result = script.execute(optc, 0, "", Double.NaN); + assertEquals(false, result); + result = script.execute(optc, 0, "", Collections.emptySet()); + assertEquals(true, result); + + } + + @Test void test427c() { + String src = "function sanitize(const n) { n == 0 ? NaN : n }; sanitize(x) && 420 / x"; + final JexlEngine jexl = new JexlBuilder().create(); + JexlScript script; + Object result; + script = jexl.createScript(src, "x"); + result = script.execute(null, 10); + assertEquals(42, result); + result = script.execute(null, 0); + assertTrue(Double.isNaN(((Number) result).doubleValue())); + } + + public static class OptContext extends MapContext implements JexlContext.OptionsHandle { + private JexlOptions options; + + @Override + public JexlOptions getEngineOptions() { + return options; + } + + void setOptions(JexlOptions options) { + this.options = options; + } } } diff --git a/src/test/java/org/apache/commons/jexl3/LexicalTest.java b/src/test/java/org/apache/commons/jexl3/LexicalTest.java index 8d596462b..f541a760b 100644 --- a/src/test/java/org/apache/commons/jexl3/LexicalTest.java +++ b/src/test/java/org/apache/commons/jexl3/LexicalTest.java @@ -157,7 +157,7 @@ void runLexical0(final boolean feature) { // ensure errors will throw options.setLexical(true); runLexical0(jexl, ctxt, "var x = 0; var x = 1;", feature); - runLexical0(jexl, ctxt, "var x = 0; for(var y : null) { var y = 1;", feature); + runLexical0(jexl, ctxt, "var x = 0; for(var y : null) { let y = 1; }", feature); runLexical0(jexl, ctxt, "var x = 0; for(var x : null) {};", feature); runLexical0(jexl, ctxt, "(x)->{ var x = 0; x; }", feature); runLexical0(jexl, ctxt, "var x; if (true) { if (true) { var x = 0; x; } }", feature); @@ -170,9 +170,10 @@ void runLexical0(final boolean feature) { }); assertNotNull(xany.toString()); // no fail - final JexlScript script = jexl.createScript("var x = 32; (()->{ for(var x : null) { x; }})();"); + final JexlScript script = jexl.createScript("var x = 32; y = (()->{ for(var x : [42]) { x; }})(); x"); if (!feature) { - script.execute(ctxt, 42); + assertEquals(32, script.execute(ctxt, 42)); + assertEquals(42, ctxt.get("y")); } } @@ -315,7 +316,7 @@ private JexlFeatures runVarLoop(final boolean flag, final String src) { } @Test - public void testAnnotation() { + void testAnnotation() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); final JexlEngine jexl = new JexlBuilder().strict(true).features(f).create(); @@ -326,7 +327,7 @@ public void testAnnotation() { } @Test - public void testCaptured0() { + void testCaptured0() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); final JexlEngine jexl = new JexlBuilder().strict(true).features(f).create(); @@ -338,7 +339,7 @@ public void testCaptured0() { } @Test - public void testCaptured1() { + void testCaptured1() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); final JexlEngine jexl = new JexlBuilder().strict(true).features(f).create(); @@ -351,7 +352,7 @@ public void testCaptured1() { } @Test - public void testConst0a() { + void testConst0a() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlScript script = jexl.createScript( @@ -362,7 +363,7 @@ public void testConst0a() { } @Test - public void testConst0b() { + void testConst0b() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlScript script = jexl.createScript( @@ -373,7 +374,7 @@ public void testConst0b() { } @Test - public void testConst1() { + void testConst1() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript("const foo; foo"), @@ -383,7 +384,7 @@ public void testConst1() { } @Test - public void testConst2a() { + void testConst2a() { final JexlEngine jexl = new JexlBuilder().strict(true).create(); for (final String op : Arrays.asList("=", "+=", "-=", "/=", "*=", "%=", "<<=", ">>=", ">>>=", "^=", "&=", "|=")) { final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript("const foo = 42; foo " + op + " 1;"), @@ -393,7 +394,7 @@ public void testConst2a() { } @Test - public void testConst2b() { + void testConst2b() { final JexlEngine jexl = new JexlBuilder().strict(true).create(); for (final String op : Arrays.asList("=", "+=", "-=", "/=", "*=", "%=", "<<=", ">>=", ">>>=", "^=", "&=", "|=")) { final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, @@ -403,7 +404,7 @@ public void testConst2b() { } @Test - public void testConst2c() { + void testConst2c() { final JexlEngine jexl = new JexlBuilder().strict(true).create(); for (final String op : Arrays.asList("=", "+=", "-=", "/=", "*=", "%=", "<<=", ">>=", ">>>=", "^=", "&=", "|=")) { final JexlScript script = jexl.createScript("{ const foo = 42; } { let foo = 0; foo " + op + " 1; }"); @@ -412,7 +413,7 @@ public void testConst2c() { } @Test - public void testConst3a() { + void testConst3a() { final JexlEngine jexl = new JexlBuilder().create(); // @formatter:off final List srcs = Arrays.asList( @@ -430,7 +431,7 @@ public void testConst3a() { } @Test - public void testConst3b() { + void testConst3b() { final JexlEngine jexl = new JexlBuilder().create(); // @formatter:off final List srcs = Arrays.asList( @@ -447,7 +448,7 @@ public void testConst3b() { } @Test - public void testConstCaptures() { + void testConstCaptures() { // @formatter:off final List srcsFalse = Arrays.asList( "const x = 0; x = 1;", @@ -475,7 +476,7 @@ public void testConstCaptures() { } @Test - public void testContextualOptions0() { + void testContextualOptions0() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().features(f).strict(true).create(); final JexlEvalContext ctxt = new JexlEvalContext(); @@ -489,7 +490,7 @@ public void testContextualOptions0() { } @Test - public void testContextualOptions1() { + void testContextualOptions1() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().features(f).strict(true).create(); final JexlEvalContext ctxt = new TestContext(); @@ -518,7 +519,7 @@ public void testContextualOptions1() { } @Test - public void testForVariable0a() { + void testForVariable0a() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); f.lexicalShade(true); @@ -527,7 +528,7 @@ public void testForVariable0a() { } @Test - public void testForVariable0b() { + void testForVariable0b() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); f.lexicalShade(true); @@ -536,7 +537,7 @@ public void testForVariable0b() { } @Test - public void testForVariable1a() { + void testForVariable1a() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); f.lexicalShade(true); @@ -546,7 +547,7 @@ public void testForVariable1a() { } @Test - public void testForVariable1b() { + void testForVariable1b() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); f.lexicalShade(true); @@ -556,7 +557,7 @@ public void testForVariable1b() { } @Test - public void testInnerAccess0() { + void testInnerAccess0() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); final JexlEngine jexl = new JexlBuilder().strict(true).features(f).create(); @@ -570,14 +571,14 @@ public void testInnerAccess0() { } @Test - public void testInnerAccess1a() { + void testInnerAccess1a() { final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).create(); final JexlScript script = jexl.createScript("var x = 32; (()->{ for(var x : null) { var c = 0; {return x; }} })();"); assertNotNull(script); } @Test - public void testInnerAccess1b() { + void testInnerAccess1b() { final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlScript script = jexl.createScript("let x = 32; (()->{ for(let x : null) { let c = 0; { return x; } } } )(); "); assertNotNull(script); @@ -587,7 +588,7 @@ public void testInnerAccess1b() { } @Test - public void testInternalLexicalFeatures() { + void testInternalLexicalFeatures() { final String str = "42"; final JexlFeatures f = new JexlFeatures(); f.lexical(true); @@ -609,7 +610,7 @@ public void testInternalLexicalFeatures() { } @Test - public void testLet0() { + void testLet0() { final JexlFeatures f = new JexlFeatures(); final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlScript script = jexl.createScript( @@ -622,7 +623,7 @@ public void testLet0() { } @Test - public void testLetFail() { + void testLetFail() { final List srcs = Arrays.asList( "let x = 0; var x = 1;", "var x = 0; let x = 1;", @@ -636,7 +637,7 @@ public void testLetFail() { } @Test - public void testLetSucceed() { + void testLetSucceed() { final List srcs = Arrays.asList( "var x = 1; var x = 0;", "{ let x = 0; } var x = 1;", @@ -651,17 +652,17 @@ public void testLetSucceed() { } @Test - public void testLexical0a() { + void testLexical0a() { runLexical0(false); } @Test - public void testLexical0b() { + void testLexical0b() { runLexical0(true); } @Test - public void testLexical1() { + void testLexical1() { final JexlEngine jexl = new JexlBuilder().strict(true).create(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -670,11 +671,11 @@ public void testLexical1() { Object result; final JexlScript script = jexl.createScript("var x = 0; for(var y : [1]) { var x = 42; return x; };"); - JexlException xany = assertThrows(JexlException.class, () -> script.execute(ctxt)); + JexlException xany = assertThrows(JexlException.Variable.class, () -> script.execute(ctxt)); assertNotNull(xany.toString()); final JexlScript script1 = jexl.createScript("(x)->{ if (x) { var x = 7 * (x + x); x; } }"); - xany = assertThrows(JexlException.class, () -> script.execute(ctxt, 3)); + xany = assertThrows(JexlException.Variable.class, () -> script.execute(ctxt, 3)); assertNotNull(xany.toString()); final JexlScript script3 = jexl.createScript("{ var x = 0; } var x = 42; x"); @@ -683,27 +684,27 @@ public void testLexical1() { } @Test - public void testLexical1a() { + void testLexical1a() { runLexical1(false); } @Test - public void testLexical1b() { + void testLexical1b() { runLexical1(true); } @Test - public void testLexical2a() { + void testLexical2a() { runLexical2(true); } @Test - public void testLexical2b() { + void testLexical2b() { runLexical2(false); } @Test - public void testLexical3() { + void testLexical3() { final String str = "var s = {}; for (var i : [1]) s.add(i); s"; final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).create(); JexlScript e = jexl.createScript(str); @@ -717,7 +718,7 @@ public void testLexical3() { } @Test - public void testLexical4() { + void testLexical4() { final JexlEngine Jexl = new JexlBuilder().silent(false).strict(true).lexical(true).create(); final JxltEngine Jxlt = Jexl.createJxltEngine(); final JexlContext ctxt = new MapContext(); @@ -735,7 +736,7 @@ public void testLexical4() { } @Test - public void testLexical5() { + void testLexical5() { final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).create(); final JexlContext ctxt = new DebugContext(); Object result; @@ -745,7 +746,7 @@ public void testLexical5() { } @Test - public void testLexical6a() { + void testLexical6a() { final String str = "i = 0; { var i = 32; }; i"; final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).create(); final JexlScript e = jexl.createScript(str); @@ -755,7 +756,7 @@ public void testLexical6a() { } @Test - public void testLexical6a1() { + void testLexical6a1() { final String str = "i = 0; { var i = 32; }; i"; final JexlFeatures f = new JexlFeatures(); f.lexical(true); @@ -767,7 +768,7 @@ public void testLexical6a1() { } @Test - public void testLexical6b() { + void testLexical6b() { final String str = "i = 0; { var i = 32; }; i"; final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).lexicalShade(true).create(); final JexlScript e = jexl.createScript(str); @@ -777,7 +778,7 @@ public void testLexical6b() { } @Test - public void testLexical6c() { + void testLexical6c() { final String str = "i = 0; for (var i : [42]) i; i"; final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).lexicalShade(false).create(); final JexlScript e = jexl.createScript(str); @@ -787,7 +788,7 @@ public void testLexical6c() { } @Test - public void testLexical6d() { + void testLexical6d() { final String str = "i = 0; for (var i : [42]) i; i"; final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).lexicalShade(true).create(); final JexlScript e = jexl.createScript(str); @@ -796,7 +797,7 @@ public void testLexical6d() { assertNotNull(xany.toString()); } - @Test public void testManyConst() { + @Test void testManyConst() { final String text = "const x = 1, y = 41; x + y"; final JexlEngine jexl = new JexlBuilder().safe(true).create(); final JexlScript script = jexl.createScript(text); @@ -807,7 +808,7 @@ public void testLexical6d() { assertNotEquals(s0, s1); } - @Test public void testManyLet() { + @Test void testManyLet() { final String text = "let x = 1, y = 41, z; x + y"; final JexlEngine jexl = new JexlBuilder().safe(true).create(); final JexlScript script = jexl.createScript(text); @@ -819,7 +820,7 @@ public void testLexical6d() { } @Test - public void testNamed() { + void testNamed() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); final JexlEngine jexl = new JexlBuilder().strict(true).features(f).create(); @@ -830,7 +831,7 @@ public void testNamed() { } @Test - public void testOptionsPragma() { + void testOptionsPragma() { try { JexlOptions.setDefaultFlags("+safe", "-lexical", "-lexicalShade"); final VarContext vars = new VarContext(); @@ -864,7 +865,7 @@ public void testOptionsPragma() { } @Test - public void testParameter0() { + void testParameter0() { final String str = "function(u) {}"; final JexlEngine jexl = new JexlBuilder().create(); JexlScript e = jexl.createScript(str); @@ -874,7 +875,7 @@ public void testParameter0() { } @Test - public void testParameter1() { + void testParameter1() { final JexlEngine jexl = new JexlBuilder().strict(true).lexical(true).create(); final JexlContext jc = new MapContext(); final String strs = "var s = function(x) { for (var i : 1..3) {if (i > 2) return x}}; s(42)"; @@ -884,7 +885,7 @@ public void testParameter1() { } @Test - public void testPragmaNoop() { + void testPragmaNoop() { // unknow pragma final String str = "#pragma jexl.options 'no effect'\ni = -42; for (var i : [42]) i; i"; final JexlEngine jexl = new JexlBuilder().lexical(false).strict(true).create(); @@ -895,7 +896,7 @@ public void testPragmaNoop() { } @Test - public void testPragmaOptions() { + void testPragmaOptions() { // same as 6d but using a pragma final String str = "#pragma jexl.options '+strict +lexical +lexicalShade -safe'\n" + "i = 0; for (var i : [42]) i; i"; @@ -907,7 +908,7 @@ public void testPragmaOptions() { } @Test - public void testScopeFrame() { + void testScopeFrame() { final LexicalScope scope = new LexicalScope(); runTestScope(scope, 0, 128, 2); runTestScope(scope, 33, 55, 1); @@ -916,7 +917,7 @@ public void testScopeFrame() { } @Test - public void testSingleStatementDeclFail() { + void testSingleStatementDeclFail() { final List srcs = Arrays.asList( "if (true) let x ;", "if (true) let x = 1;", @@ -941,7 +942,7 @@ public void testSingleStatementDeclFail() { } @Test - public void testSingleStatementVarSucceed() { + void testSingleStatementVarSucceed() { final List srcs = Arrays.asList( "if (true) var x = 1;", "if (true) { 1 } else var x = 1;", @@ -954,7 +955,7 @@ public void testSingleStatementVarSucceed() { } @Test - public void testUndeclaredVariable() { + void testUndeclaredVariable() { final JexlFeatures f = new JexlFeatures(); f.lexical(true); f.lexicalShade(true); @@ -963,7 +964,7 @@ public void testUndeclaredVariable() { } @Test - public void testVarFail() { + void testVarFail() { final List srcs = Arrays.asList( "var x = 0; var x = 1;", "var x = 0; let x = 1;", @@ -979,7 +980,7 @@ public void testVarFail() { } @Test - public void testVarLoop0() { + void testVarLoop0() { final String src0 = "var count = 10;\n" + "for (var i : 0 .. count-1) {\n" + " $out.add(i);\n" diff --git a/src/test/java/org/apache/commons/jexl3/SpreadCache.java b/src/test/java/org/apache/commons/jexl3/SpreadCache.java index c2a3e4489..356797161 100644 --- a/src/test/java/org/apache/commons/jexl3/SpreadCache.java +++ b/src/test/java/org/apache/commons/jexl3/SpreadCache.java @@ -28,8 +28,8 @@ * Creates a cache using an array of synchronized LinkedHashMap as backing store to spread contention. *

    Just meant as a contention reducing mechanism for cache tests.

    * - * @param the cached element"e;s key - * @param the cached element"e;s value + * @param the cached element"s key + * @param the cached element"s value * @return the cache instance */ public class SpreadCache extends SoftCache { diff --git a/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java b/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java index 17980c3bb..229d21c5a 100644 --- a/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java +++ b/src/test/java/org/apache/commons/jexl3/introspection/SandboxTest.java @@ -46,7 +46,7 @@ * Tests sandbox features. */ @SuppressWarnings({ "UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes" }) -public class SandboxTest extends JexlTestCase { +class SandboxTest extends JexlTestCase { public abstract static class AbstractCallMeNot { public @NoJexl String NONO = "should not be accessible!"; @@ -213,7 +213,7 @@ public SandboxTest() { } @Test - public void testCantSeeMe() throws Exception { + void testCantSeeMe() { final JexlContext jc = new MapContext(); final String expr = "foo.doIt()"; JexlScript script; @@ -233,7 +233,7 @@ public void testCantSeeMe() throws Exception { } @Test - public void testCtorAllow() throws Exception { + void testCtorAllow() { final String expr = "new('" + Foo.class.getName() + "', '42')"; JexlScript script; Object result; @@ -248,7 +248,7 @@ public void testCtorAllow() throws Exception { } @Test - public void testCtorBlock() throws Exception { + void testCtorBlock() { final String expr = "new('" + Foo.class.getName() + "', '42')"; final JexlScript script = JEXL.createScript(expr); Object result; @@ -265,7 +265,7 @@ public void testCtorBlock() throws Exception { } @Test - public void testGetAllow() throws Exception { + void testGetAllow() { final Foo foo = new Foo("42"); final String expr = "foo.alias"; JexlScript script; @@ -286,7 +286,7 @@ public void testGetAllow() throws Exception { } @Test - public void testGetBlock() throws Exception { + void testGetBlock() { final String expr = "foo.alias"; final JexlScript script = JEXL.createScript(expr, "foo"); final Foo foo = new Foo("42"); @@ -303,7 +303,7 @@ public void testGetBlock() throws Exception { } @Test - public void testGetNullKeyAllowed0() throws Exception { + void testGetNullKeyAllowed0() { final JexlEngine jexl = new JexlBuilder().sandbox(new JexlSandbox(true)).create(); final JexlExpression expression = jexl.createExpression("{null : 'foo'}[null]"); final Object o = expression.evaluate(null); @@ -311,7 +311,7 @@ public void testGetNullKeyAllowed0() throws Exception { } @Test - public void testGetNullKeyAllowed1() throws Exception { + void testGetNullKeyAllowed1() { final JexlSandbox sandbox = new JexlSandbox(true, true); final JexlSandbox.Permissions p = sandbox.permissions("java.util.Map", false, true, true); p.read().add("quux"); @@ -330,7 +330,7 @@ public void testGetNullKeyAllowed1() throws Exception { } @Test - public void testGetNullKeyBlocked() throws Exception { + void testGetNullKeyBlocked() { final JexlSandbox sandbox = new JexlSandbox(true, true); final JexlSandbox.Permissions p = sandbox.permissions("java.util.Map", false, true, true); p.read().add(null); @@ -349,7 +349,7 @@ public void testGetNullKeyBlocked() throws Exception { } @Test - public void testInheritedPermission0() { + void testInheritedPermission0() { final Foo386 foo = new Foo386(); final JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(SomeInterface.class.getName(), true, true, true, true); @@ -359,7 +359,7 @@ public void testInheritedPermission0() { } @Test - public void testInheritedPermission1() { + void testInheritedPermission1() { final Quux386 foo = new Quux386(); final JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(Foo386.class.getName(), true, true, true, true); @@ -369,7 +369,7 @@ public void testInheritedPermission1() { } @Test - public void testMethodAllow() throws Exception { + void testMethodAllow() { final Foo foo = new Foo("42"); final String expr = "foo.Quux()"; JexlScript script; @@ -385,7 +385,7 @@ public void testMethodAllow() throws Exception { } @Test - public void testMethodBlock() throws Exception { + void testMethodBlock() { final String expr = "foo.Quux()"; final JexlScript script = JEXL.createScript(expr, "foo"); final Foo foo = new Foo("42"); @@ -402,7 +402,7 @@ public void testMethodBlock() throws Exception { } @Test - public void testMethodNoJexl() throws Exception { + void testMethodNoJexl() { final Foo foo = new Foo("42"); // @formatter:off final String[] exprs = { @@ -421,7 +421,7 @@ public void testMethodNoJexl() throws Exception { } @Test - public void testNoJexl312() throws Exception { + void testNoJexl312() { final JexlContext ctxt = new MapContext(); final JexlEngine sjexl = new JexlBuilder().safe(false).strict(true).create(); final JexlScript foo = sjexl.createScript("x.getFoo()", "x"); @@ -429,7 +429,7 @@ public void testNoJexl312() throws Exception { } @Test - public void testNonInheritedPermission0() { + void testNonInheritedPermission0() { final Foo386 foo = new Foo386(); final JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(SomeInterface.class.getName(), false, true, true, true); @@ -439,7 +439,7 @@ public void testNonInheritedPermission0() { } @Test - public void testNonInheritedPermission1() { + void testNonInheritedPermission1() { final Quux386 foo = new Quux386(); final JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(Foo386.class.getName(), false, true, true, true); @@ -449,11 +449,11 @@ public void testNonInheritedPermission1() { } @Test - public void testRestrict() throws Exception { + void testRestrict() { final JexlContext context = new MapContext(); context.set("System", System.class); final JexlSandbox sandbox = new JexlSandbox(); - // only allow call to currentTimeMillis (avoid exit, gc, loadLibrary, etc) + // only allow call to currentTimeMillis (avoid exit, gc, loadLibrary, etc.) sandbox.allow(System.class.getName()).execute("currentTimeMillis"); // can not create a new file sandbox.block(java.io.File.class.getName()).execute(""); @@ -471,7 +471,7 @@ public void testRestrict() throws Exception { } @Test - public void testSandboxInherit0() throws Exception { + void testSandboxInherit0() { Object result; final JexlContext ctxt = null; final List foo = new ArrayList<>(); @@ -485,20 +485,16 @@ public void testSandboxInherit0() throws Exception { result = method.execute(ctxt, foo, "nothing"); assertTrue((boolean) result); - result = null; result = get.execute(null, foo, Integer.valueOf(0)); assertEquals("nothing", result); - result = null; result = set.execute(null, foo, Integer.valueOf(0), "42"); assertEquals("42", result); - - result = null; result = get.execute(null, foo, Integer.valueOf(0)); assertEquals("42", result); } @Test - public void testSandboxInherit1() throws Exception { + void testSandboxInherit1() { Object result; final JexlContext ctxt = null; final Operation2 foo = new Operation2(12); @@ -515,7 +511,7 @@ public void testSandboxInherit1() throws Exception { } @Test - public void testSetAllow() throws Exception { + void testSetAllow() { final Foo foo = new Foo("42"); final String expr = "foo.alias = $0"; JexlScript script; @@ -532,7 +528,7 @@ public void testSetAllow() throws Exception { } @Test - public void testSetBlock() throws Exception { + void testSetBlock() { final String expr = "foo.alias = $0"; final JexlScript script1 = JEXL.createScript(expr, "foo", "$0"); final Foo foo = new Foo("42"); @@ -550,7 +546,7 @@ public void testSetBlock() throws Exception { } @Test - public void testSetNullKeyAllowed0() throws Exception { + void testSetNullKeyAllowed0() { final Arithmetic350 a350 = new Arithmetic350(true); final JexlEngine jexl = new JexlBuilder().arithmetic(a350).sandbox(new JexlSandbox(true)).create(); final JexlContext jc = new MapContext(); @@ -561,7 +557,7 @@ public void testSetNullKeyAllowed0() throws Exception { } @Test - public void testSetNullKeyAllowed1() throws Exception { + void testSetNullKeyAllowed1() { final Arithmetic350 a350 = new Arithmetic350(true); final JexlSandbox sandbox = new JexlSandbox(true, true); final JexlSandbox.Permissions p = sandbox.permissions("java.util.Map", true, false, true); @@ -584,7 +580,7 @@ public void testSetNullKeyAllowed1() throws Exception { } @Test - public void testSetNullKeyBlocked() throws Exception { + void testSetNullKeyBlocked() { final Arithmetic350 a350 = new Arithmetic350(true); final JexlSandbox sandbox = new JexlSandbox(true, true); final JexlSandbox.Permissions p = sandbox.permissions("java.util.Map", true, false, true); @@ -608,14 +604,14 @@ static class A implements I{} static class B extends A{} @Test - public void testPermission0() { + void testPermission0() { JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(I.class.getName(), true, true, true, false); System.out.println("permission A=" + sandbox.get(A.class.getName()).write()); System.out.println("permission B=" + sandbox.get(B.class.getName()).write()); } @Test - public void testPermission1() { + void testPermission1() { JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(I.class.getName(), true, true, true, false); System.out.println("permission B=" + sandbox.get(B.class.getName()).write()); @@ -623,7 +619,7 @@ public void testPermission1() { } @Test - public void testIssue424() { + void testIssue424() { JexlSandbox sandbox = new JexlSandbox(false, true); sandbox.permissions(Map.class.getName(), true, true, true, true); String jexlCode = "x.foo = 'bar'"; diff --git a/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java b/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java index ef7ee7547..9c25ed589 100644 --- a/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java +++ b/src/test/java/org/apache/commons/jexl3/jexl342/ReferenceUberspect.java @@ -37,7 +37,7 @@ /** * An Uberspect that handles references (java.lang.ref.Reference) and optionals (java.util.Optional). - *

    This illustrates JEXL"e;s low level customization capabilities.

    + *

    This illustrates JEXL"s low level customization capabilities.

    * see JEXL-342. */ public class ReferenceUberspect implements JexlUberspect {