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 33bc10c1 JEXL-366: compare will try and convert a string to number when one argument is a number 33bc10c1 is described below commit 33bc10c109403639aca7ef22dd7a883468fd6e30 Author: henrib <hen...@apache.org> AuthorDate: Fri May 6 00:19:17 2022 +0200 JEXL-366: compare will try and convert a string to number when one argument is a number --- .../org/apache/commons/jexl3/JexlArithmetic.java | 46 ++++++++--- .../org/apache/commons/jexl3/ArithmeticTest.java | 92 ++++++++++++++++++---- 2 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java index b34d3678..54afcf93 100644 --- a/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java +++ b/src/main/java/org/apache/commons/jexl3/JexlArithmetic.java @@ -497,7 +497,16 @@ public class JexlArithmetic { } /** - * Given a Number, return back the value using the smallest type the result + * The last method called before returning a result from a script execution. + * @param returned the returned value + * @return the controlled returned value + */ + public Object controlReturn(Object returned) { + return returned; + } + + /** + * Given a Number, return the value using the smallest type the result * will fit into. * <p>This works hand in hand with parameter 'widening' in java * method calls, e.g. a call to substring(int,int) with an int and a long @@ -1347,6 +1356,21 @@ public class JexlArithmetic { return l >>> r; } + /** + * Converts an arg to a long for comparison purpose. + * @param arg the arg + * @return a long + * @throws NumberFormatException if the + */ + private long comparableLong(Object arg) throws NumberFormatException { + if (arg instanceof String) { + String s = (String) arg; + return s.isEmpty()? 0 :(long) Double.parseDouble((String) arg); + } else { + return toLong(arg); + } + } + /** * Performs a comparison. * @@ -1390,15 +1414,19 @@ public class JexlArithmetic { return 0; } if (isNumberable(left) || isNumberable(right)) { - final long lhs = toLong(left); - final long rhs = toLong(right); - if (lhs < rhs) { - return -1; - } - if (lhs > rhs) { - return +1; + try { + final long lhs = comparableLong(left); + final long rhs = comparableLong(right); + if (lhs < rhs) { + return -1; + } + if (lhs > rhs) { + return +1; + } + return 0; + } catch(NumberFormatException xformat) { + // ignore it, continue in sequence } - return 0; } if (left instanceof String || right instanceof String) { return toString(left).compareTo(toString(right)); diff --git a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java index 8b8cacc5..3eb611fb 100644 --- a/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java +++ b/src/test/java/org/apache/commons/jexl3/ArithmeticTest.java @@ -270,6 +270,7 @@ public class ArithmeticTest extends JexlTestCase { asserter.failExpression("left > y.right", ".*null.*"); asserter.failExpression("left >= y.right", ".*null.*"); } + @Test public void testNullOperands() throws Exception { asserter.setVariable("left", null); @@ -781,20 +782,20 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testNullArgs() throws Exception { + public void testNullArgs() { JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(true) { @Override public boolean isStrict(JexlOperator op) { return JexlOperator.ADD == op? false: super.isStrict(op); } }).create(); JexlScript script = jexl.createScript("'1.2' + x ", "x"); - Object result = script.execute(null, null); + Object result = script.execute(null); Assert.assertEquals("1.2", result); } @Test - public void testOption() throws Exception { - final Map<String, Object> vars = new HashMap<String, Object>(); + public void testOption() { + final Map<String, Object> vars = new HashMap<>(); final JexlEvalContext context = new JexlEvalContext(vars); final JexlOptions options = context.getEngineOptions(); options.setStrictArithmetic(true); @@ -811,7 +812,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testIsFloatingPointPattern() throws Exception { + public void testIsFloatingPointPattern() { final JexlArithmetic ja = new JexlArithmetic(true); Assert.assertFalse(ja.isFloatingPointNumber("floating point")); @@ -918,7 +919,7 @@ public class ArithmeticTest extends JexlTestCase { } } - // an arithmetic that know how to subtract strings + // an arithmetic that knows how to deal with vars public static class ArithmeticPlus extends JexlArithmetic { public ArithmeticPlus(final boolean strict) { super(strict); @@ -1041,7 +1042,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testArithmeticPlusNoCache() throws Exception { + public void testArithmeticPlusNoCache() { final JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new ArithmeticPlus(false)).create(); final JexlContext jc = new EmptyTestContext(); runOverload(jexl, jc); @@ -1258,7 +1259,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testJexl173() throws Exception { + public void testJexl173() { final JexlEngine jexl = new JexlBuilder().create(); final JexlContext jc = new MapContext(); final Callable173 c173 = new Callable173(); @@ -1522,7 +1523,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testEmptyLong() throws Exception { + public void testEmptyLong() { Object x; x = JEXL.createScript("new('java.lang.Long', 4294967296)").execute(null); Assert.assertEquals(4294967296L, ((Long) x).longValue()); @@ -1539,7 +1540,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testEmptyFloat() throws Exception { + public void testEmptyFloat() { Object x; x = JEXL.createScript("4294967296.f").execute(null); Assert.assertEquals(4294967296.0f, (Float) x, EPSILON); @@ -1555,7 +1556,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testEmptyDouble() throws Exception { + public void testEmptyDouble() { Object x; x = JEXL.createScript("4294967296.d").execute(null); Assert.assertEquals(4294967296.0d, (Double) x, EPSILON); @@ -1584,7 +1585,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testCoerceInteger() throws Exception { + public void testCoerceInteger() { final JexlArithmetic ja = JEXL.getArithmetic(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -1603,7 +1604,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testCoerceLong() throws Exception { + public void testCoerceLong() { final JexlArithmetic ja = JEXL.getArithmetic(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -1622,7 +1623,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testCoerceDouble() throws Exception { + public void testCoerceDouble() { final JexlArithmetic ja = JEXL.getArithmetic(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -1641,7 +1642,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testCoerceBigInteger() throws Exception { + public void testCoerceBigInteger() { final JexlArithmetic ja = JEXL.getArithmetic(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -1660,7 +1661,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testCoerceBigDecimal() throws Exception { + public void testCoerceBigDecimal() { final JexlArithmetic ja = JEXL.getArithmetic(); final JexlEvalContext ctxt = new JexlEvalContext(); final JexlOptions options = ctxt.getEngineOptions(); @@ -1679,7 +1680,7 @@ public class ArithmeticTest extends JexlTestCase { } @Test - public void testAtomicBoolean() throws Exception { + public void testAtomicBoolean() { // in a condition JexlScript e = JEXL.createScript("if (x) 1 else 2;", "x"); final JexlContext jc = new MapContext(); @@ -1748,4 +1749,61 @@ public class ArithmeticTest extends JexlTestCase { o = e.execute(jc, ab); Assert.assertTrue((Boolean) o); } + + @Test + public void testCompare() { + // JEXL doesn't support more than one operator in the same expression, for example: 1 == 1 == 1 + final Object[] EXPRESSIONS = { + // Basic compare + "1 == 1", true, + "1 != 1", false, + "1 != 2", true, + "1 > 2", false, + "1 >= 2", false, + "1 < 2", true, + "1 <= 2", true, + // Int <-> Float Coercion + "1.0 == 1", true, + "1 == 1.0", true, + "1.1 != 1", true, + "1.1 < 2", true, + // Big Decimal <-> Big Integer Coercion + "1.0b == 1h", true, + "1h == 1.0b", true, + "1.1b != 1h", true, + "1.1b < 2h", true, + // Mix all type of numbers + "1l == 1.0", true, // long and int + "1.0d == 1.0f", true, // double and float + "1l == 1.0b", true, + "1l == 1h", true, + "1.0d == 1.0b", true, + "1.0f == 1.0b", true, + "1.0d == 1h", true, + "1.0f == 1h", true, + // numbers and strings + "'1' == 1", true, + "'1' == 1l", true, + "'1' == 1h", true, + "'' == 0", true, // empty string is coerced to zero (ECMA compliance) + "'1.0' == 1", true, + "'1.0' == 1.0f", true, + "'1.0' == 1.0d", true, + "'1.0' == 1.0b", true, + "'1.01' == 1.01", true, + "1.0 >= '1'", true, + "1.0 > '1'", false, + }; + final JexlEngine jexl = new JexlBuilder().create(); + final JexlContext jc = new EmptyTestContext(); + JexlExpression expression; + + for (int e = 0; e < EXPRESSIONS.length; e += 2) { + final String stext = (String) EXPRESSIONS[e]; + final Object expected = EXPRESSIONS[e + 1]; + expression = jexl.createExpression(stext); + final Object result = expression.evaluate(jc); + Assert.assertEquals("failed on " + stext, expected, result); + } + } }