1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.junit.jupiter.api.Assertions.fail;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.InputStream;
29 import java.math.BigDecimal;
30 import java.math.BigInteger;
31 import java.math.MathContext;
32 import java.nio.charset.StandardCharsets;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.Date;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.concurrent.CountDownLatch;
41 import java.util.concurrent.atomic.AtomicBoolean;
42 import java.util.concurrent.atomic.AtomicReference;
43
44 import javax.xml.parsers.DocumentBuilder;
45 import javax.xml.parsers.DocumentBuilderFactory;
46
47 import org.apache.commons.jexl3.junit.Asserter;
48 import org.apache.commons.lang3.SystemProperties;
49 import org.junit.jupiter.api.BeforeEach;
50 import org.junit.jupiter.api.Test;
51 import org.w3c.dom.Attr;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.NamedNodeMap;
54 import org.w3c.dom.Node;
55
56 @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
57 class ArithmeticTest extends JexlTestCase {
58 public static class Arithmetic132 extends JexlArithmetic {
59 public Arithmetic132() {
60 super(false);
61 }
62
63 @Override
64 public Object divide(final Object left, final Object right) {
65 if (left == null && right == null) {
66 return controlNullNullOperands(JexlOperator.DIVIDE);
67 }
68
69 if (left instanceof BigDecimal || right instanceof BigDecimal) {
70 final BigDecimal l = toBigDecimal(left);
71 final BigDecimal r = toBigDecimal(right);
72 if (BigDecimal.ZERO.equals(r)) {
73 return divideZero(l);
74 }
75 final BigDecimal result = l.divide(r, getMathContext());
76 return narrowBigDecimal(left, right, result);
77 }
78
79 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
80 final double l = toDouble(left);
81 final double r = toDouble(right);
82 return Double.valueOf(l / r);
83 }
84
85 final BigInteger l = toBigInteger(left);
86 final BigInteger r = toBigInteger(right);
87 if (BigInteger.ZERO.equals(r)) {
88 return divideZero(l);
89 }
90 final BigInteger result = l.divide(r);
91 return narrowBigInteger(left, right, result);
92 }
93
94 protected double divideZero(final BigDecimal x) {
95 final int ls = x.signum();
96 if (ls < 0) {
97 return Double.NEGATIVE_INFINITY;
98 }
99 if (ls > 0) {
100 return Double.POSITIVE_INFINITY;
101 }
102 return Double.NaN;
103 }
104
105 protected double divideZero(final BigInteger x) {
106 final int ls = x.signum();
107 if (ls < 0) {
108 return Double.NEGATIVE_INFINITY;
109 }
110 if (ls > 0) {
111 return Double.POSITIVE_INFINITY;
112 }
113 return Double.NaN;
114 }
115
116 @Override
117 public Object mod(final Object left, final Object right) {
118 if (left == null && right == null) {
119 return controlNullNullOperands(JexlOperator.MOD);
120 }
121
122 if (left instanceof BigDecimal || right instanceof BigDecimal) {
123 final BigDecimal l = toBigDecimal(left);
124 final BigDecimal r = toBigDecimal(right);
125 if (BigDecimal.ZERO.equals(r)) {
126 return divideZero(l);
127 }
128 final BigDecimal remainder = l.remainder(r, getMathContext());
129 return narrowBigDecimal(left, right, remainder);
130 }
131
132 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
133 final double l = toDouble(left);
134 final double r = toDouble(right);
135 return Double.valueOf(l % r);
136 }
137
138 final BigInteger l = toBigInteger(left);
139 final BigInteger r = toBigInteger(right);
140 final BigInteger result = l.mod(r);
141 if (BigInteger.ZERO.equals(r)) {
142 return divideZero(l);
143 }
144 return narrowBigInteger(left, right, result);
145 }
146 }
147
148 public static class ArithmeticFail extends JexlArithmetic {
149 public ArithmeticFail(final boolean strict) {
150 super(strict);
151 }
152
153 @Override
154 public Object add(final Object lhs, final Object rhs) {
155 throw new ArithmeticException(lhs + " o " + rhs);
156 }
157
158 @Override
159 public Object and(final Object lhs, final Object rhs) {
160 throw new ArithmeticException(lhs + " o " + rhs);
161 }
162
163 @Override
164 public Object complement(final Object arg) {
165 throw new ArithmeticException(Objects.toString(arg));
166 }
167
168 @Override
169 public Boolean contains(final Object lhs, final Object rhs) {
170 throw new ArithmeticException(lhs + " o " + rhs);
171 }
172
173 @Override
174 public Object decrement(final Object arg) {
175 throw new ArithmeticException(Objects.toString(arg));
176 }
177
178 @Override
179 public Object divide(final Object lhs, final Object rhs) {
180 throw new ArithmeticException(lhs + " o " + rhs);
181 }
182
183 @Override
184 public Boolean endsWith(final Object lhs, final Object rhs) {
185 throw new ArithmeticException(lhs + " o " + rhs);
186 }
187
188 @Override
189 public boolean equals(final Object lhs, final Object rhs) {
190 throw new ArithmeticException(lhs + " o " + rhs);
191 }
192
193 @Override
194 public boolean greaterThan(final Object lhs, final Object rhs) {
195 throw new ArithmeticException(lhs + " o " + rhs);
196 }
197
198 @Override
199 public boolean greaterThanOrEqual(final Object lhs, final Object rhs) {
200 throw new ArithmeticException(lhs + " o " + rhs);
201 }
202
203 @Override
204 public Object increment(final Object arg) {
205 throw new ArithmeticException(Objects.toString(arg));
206 }
207
208 @Override
209 public boolean lessThan(final Object lhs, final Object rhs) {
210 throw new ArithmeticException(lhs + " o " + rhs);
211 }
212
213 @Override
214 public boolean lessThanOrEqual(final Object lhs, final Object rhs) {
215 throw new ArithmeticException(lhs + " o " + rhs);
216 }
217
218 @Override
219 public Object mod(final Object lhs, final Object rhs) {
220 throw new ArithmeticException(lhs + " o " + rhs);
221 }
222
223 @Override
224 public Object multiply(final Object lhs, final Object rhs) {
225 throw new ArithmeticException(lhs + " o " + rhs);
226 }
227
228 @Override
229 public Object negate(final Object arg) {
230 throw new ArithmeticException(Objects.toString(arg));
231 }
232
233 @Override
234 public Object not(final Object arg) {
235 throw new ArithmeticException(Objects.toString(arg));
236 }
237
238 @Override
239 public Object or(final Object lhs, final Object rhs) {
240 throw new ArithmeticException(lhs + " o " + rhs);
241 }
242
243 @Override
244 public Object shiftLeft(final Object lhs, final Object rhs) {
245 throw new ArithmeticException(lhs + " o " + rhs);
246 }
247
248 @Override
249 public Object shiftRight(final Object lhs, final Object rhs) {
250 throw new ArithmeticException(lhs + " o " + rhs);
251 }
252
253 @Override
254 public Object shiftRightUnsigned(final Object lhs, final Object rhs) {
255 throw new ArithmeticException(lhs + " o " + rhs);
256 }
257
258 @Override
259 public Boolean startsWith(final Object lhs, final Object rhs) {
260 throw new ArithmeticException(lhs + " o " + rhs);
261 }
262
263 @Override
264 public boolean strictEquals(final Object lhs, final Object rhs) {
265 throw new ArithmeticException(lhs + " o " + rhs);
266 }
267
268 @Override
269 public Object subtract(final Object lhs, final Object rhs) {
270 throw new ArithmeticException(lhs + " o " + rhs);
271 }
272
273 @Override
274 public boolean toBoolean(final Object x) {
275 throw new ArithmeticException(Objects.toString(x));
276 }
277
278 @Override
279 public Object xor(final Object lhs, final Object rhs) {
280 throw new ArithmeticException(lhs + " o " + rhs);
281 }
282 }
283
284
285 public static class ArithmeticPlus extends JexlArithmetic {
286 public ArithmeticPlus(final boolean strict) {
287 super(strict);
288 }
289
290 public Var add(final Var lhs, final Var rhs) {
291 return new Var(lhs.value + rhs.value);
292 }
293
294 public Var and(final Var lhs, final Var rhs) {
295 return new Var(lhs.value & rhs.value);
296 }
297
298 public Var complement(final Var arg) {
299 return new Var(~arg.value);
300 }
301
302 public Boolean contains(final Var lhs, final Var rhs) {
303 return lhs.toString().contains(rhs.toString());
304 }
305
306 public Var divide(final Var lhs, final Var rhs) {
307 return new Var(lhs.value / rhs.value);
308 }
309
310 public Boolean endsWith(final Var lhs, final Var rhs) {
311 return lhs.toString().endsWith(rhs.toString());
312 }
313
314 public boolean equals(final Var lhs, final Var rhs) {
315 return lhs.value == rhs.value;
316 }
317
318 public boolean greaterThan(final Var lhs, final Var rhs) {
319 return lhs.value > rhs.value;
320 }
321
322 public boolean greaterThanOrEqual(final Var lhs, final Var rhs) {
323 return lhs.value >= rhs.value;
324 }
325
326 public boolean lessThan(final Var lhs, final Var rhs) {
327 return lhs.value < rhs.value;
328 }
329
330 public boolean lessThanOrEqual(final Var lhs, final Var rhs) {
331 return lhs.value <= rhs.value;
332 }
333
334 public Var mod(final Var lhs, final Var rhs) {
335 return new Var(lhs.value / rhs.value);
336 }
337
338 public Var multiply(final Var lhs, final Var rhs) {
339 return new Var(lhs.value * rhs.value);
340 }
341
342 public Object negate(final String str) {
343 final int length = str.length();
344 final StringBuilder strb = new StringBuilder(str.length());
345 for (int c = length - 1; c >= 0; --c) {
346 strb.append(str.charAt(c));
347 }
348 return strb.toString();
349 }
350
351 public Var negate(final Var arg) {
352 return new Var(-arg.value);
353 }
354
355 public Object not(final Var x) {
356 throw new NullPointerException("make it fail");
357 }
358
359 public Var or(final Var lhs, final Var rhs) {
360 return new Var(lhs.value | rhs.value);
361 }
362
363 public Var shiftLeft(final Var lhs, final Var rhs) {
364 return new Var(lhs.value << rhs.value);
365 }
366
367 public Var shiftRight(final Var lhs, final Var rhs) {
368 return new Var(lhs.value >> rhs.value);
369 }
370
371 public Var shiftRightUnsigned(final Var lhs, final Var rhs) {
372 return new Var(lhs.value >>> rhs.value);
373 }
374
375 public Boolean startsWith(final Var lhs, final Var rhs) {
376 return lhs.toString().startsWith(rhs.toString());
377 }
378
379 public Object subtract(final String x, final String y) {
380 final int ix = x.indexOf(y);
381 if (ix < 0) {
382 return x;
383 }
384 final StringBuilder strb = new StringBuilder(x.substring(0, ix));
385 strb.append(x.substring(ix + y.length()));
386 return strb.toString();
387 }
388
389 public Var subtract(final Var lhs, final Var rhs) {
390 return new Var(lhs.value - rhs.value);
391 }
392
393 public Var xor(final Var lhs, final Var rhs) {
394 return new Var(lhs.value ^ rhs.value);
395 }
396 }
397
398 public static class Callable173 {
399 public Object call(final Integer... arg) {
400 return arg[0] * arg[1];
401 }
402 public Object call(final String... arg) {
403 return 42;
404 }
405 }
406
407 public static class EmptyTestContext extends MapContext implements JexlContext.NamespaceResolver {
408 public static int log(final Object fmt, final int... arr) {
409
410 return arr == null ? 0 : arr.length;
411 }
412
413 public static int log(final Object fmt, final Object... arr) {
414
415 return arr == null ? 0 : arr.length;
416 }
417
418 @Override
419 public Object resolveNamespace(final String name) {
420 return this;
421 }
422 }
423 public static class InstanceofContext extends MapContext implements JexlContext.ClassNameResolver {
424 @Override
425 public String resolveClassName(final String name) {
426 if ("Double".equals(name)) {
427 return Double.class.getName();
428 }
429 return null;
430 }
431 }
432 public static class Var {
433 int value;
434
435 Var(final int v) {
436 value = v;
437 }
438
439 @Override
440 public String toString() {
441 return Integer.toString(value);
442 }
443 }
444
445
446
447
448 public static class XmlArithmetic extends JexlArithmetic {
449 public XmlArithmetic(final boolean astrict) {
450 super(astrict);
451 }
452
453 public XmlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
454 super(astrict, bigdContext, bigdScale);
455 }
456
457 public boolean empty(final org.w3c.dom.Element elt) {
458 return !elt.hasAttributes() && !elt.hasChildNodes();
459 }
460
461 public int size(final org.w3c.dom.Element elt) {
462 return elt.getChildNodes().getLength();
463 }
464
465 public Object propertyGet(final NamedNodeMap attrs, final String name) {
466 final Node node = attrs.getNamedItem(name);
467 return node == null ? JexlEngine.TRY_FAILED : node.getNodeValue();
468 }
469
470 public Object propertySet(final NamedNodeMap attrs, final String name, final Object value) {
471 final Node node = attrs.getNamedItem(name);
472 if (node == null) {
473 return JexlEngine.TRY_FAILED;
474 }
475 node.setNodeValue(value.toString());
476 return value;
477 }
478
479 public Object propertyGet(final Node elt, final String name) {
480 if ("attributes".equals(name)) {
481 return elt.getAttributes();
482 }
483 return JexlEngine.TRY_FAILED;
484 }
485 }
486
487
488 private static final double EPSILON = 1.e-6;
489
490 private static void assertArithmeticException(final java.util.function.Supplier<Object> fun) {
491 assertThrows(ArithmeticException.class, fun::get);
492 }
493
494 private static void assertNullOperand(final java.util.function.Supplier<Object> fun) {
495 try {
496 assertNull(fun.get());
497 } catch (final JexlArithmetic.NullOperand xany) {
498 assertNotNull(xany);
499 }
500 }
501
502 private static Document getDocument(final String xml) throws Exception {
503 final DocumentBuilder xmlBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
504 final InputStream stringInputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
505 return xmlBuilder.parse(stringInputStream);
506 }
507
508
509
510
511
512 private static int getJavaVersion() {
513 String version = SystemProperties.getJavaVersion();
514 if (version.startsWith("1.")) {
515 version = version.substring(2);
516 }
517 int sep = version.indexOf(".");
518 if (sep < 0) {
519 sep = version.indexOf("-");
520 }
521 if (sep > 0) {
522 version = version.substring(0, sep);
523 }
524 return Integer.parseInt(version);
525 }
526
527 private final Asserter asserter;
528
529 private final JexlArithmetic jexla;
530
531 private final JexlArithmetic jexlb;
532
533 private final Date date = new Date();
534
535 public ArithmeticTest() {
536 super("ArithmeticTest");
537 asserter = new Asserter(JEXL);
538 jexla = JEXL.getArithmetic();
539 final JexlOptions options = new JexlOptions();
540 options.setStrictArithmetic(false);
541 jexlb = jexla.options(options);
542 }
543
544 void checkEmpty(final Object x, final boolean expect) {
545 final JexlScript s0 = JEXL.createScript("empty(x)", "x");
546 boolean empty = (Boolean) s0.execute(null, x);
547 assertEquals(expect, empty);
548 final JexlScript s1 = JEXL.createScript("empty x", "x");
549 empty = (Boolean) s1.execute(null, x);
550 assertEquals(expect, empty);
551 final JexlScript s2 = JEXL.createScript("x.empty()", "x");
552 empty = (Boolean) s2.execute(null, x);
553 assertEquals(expect, empty);
554 }
555
556 private void runInstanceof(final JexlEngine jexl, final JexlContext ctxt) {
557 Object r = jexl.createExpression("3.0 instanceof 'Double'").evaluate(ctxt);
558 assertTrue((Boolean) r);
559 r = jexl.createExpression("'3.0' !instanceof 'Double'").evaluate(ctxt);
560 assertTrue((Boolean) r);
561 JexlScript script = jexl.createScript("x instanceof y", "x", "y");
562 r = script.execute(ctxt, "foo", String.class);
563 assertTrue((Boolean) r);
564 r = script.execute(ctxt, 42.0, Double.class);
565 assertTrue((Boolean) r);
566 script = jexl.createScript("x !instanceof y", "x", "y");
567 r = script.execute(ctxt, "foo", Double.class);
568 assertTrue((Boolean) r);
569 r = script.execute(ctxt, 42.0, String.class);
570 assertTrue((Boolean) r);
571 }
572
573 protected void runOverload(final JexlEngine jexl, final JexlContext jc) {
574 JexlScript script;
575 Object result;
576
577 script = jexl.createScript("(x, y)->{ x < y }");
578 result = script.execute(jc, 42, 43);
579 assertEquals(true, result);
580 result = script.execute(jc, new Var(42), new Var(43));
581 assertEquals(true, result);
582 result = script.execute(jc, new Var(42), new Var(43));
583 assertEquals(true, result);
584 result = script.execute(jc, 43, 42);
585 assertEquals(false, result);
586 result = script.execute(jc, new Var(43), new Var(42));
587 assertEquals(false, result);
588
589 script = jexl.createScript("(x, y)->{ x <= y }");
590 result = script.execute(jc, 42, 43);
591 assertEquals(true, result);
592 result = script.execute(jc, new Var(42), new Var(43));
593 assertEquals(true, result);
594 result = script.execute(jc, new Var(41), new Var(44));
595 assertEquals(true, result);
596 result = script.execute(jc, 43, 42);
597 assertEquals(false, result);
598 result = script.execute(jc, new Var(45), new Var(40));
599 assertEquals(false, result);
600
601 script = jexl.createScript("(x, y)->{ x > y }");
602 result = script.execute(jc, 42, 43);
603 assertEquals(false, result);
604 result = script.execute(jc, new Var(42), new Var(43));
605 assertEquals(false, result);
606 result = script.execute(jc, new Var(42), new Var(43));
607 assertEquals(false, result);
608 result = script.execute(jc, 43, 42);
609 assertEquals(true, result);
610 result = script.execute(jc, new Var(43), new Var(42));
611 assertEquals(true, result);
612
613 script = jexl.createScript("(x, y)->{ x >= y }");
614 result = script.execute(jc, 42, 43);
615 assertEquals(false, result);
616 result = script.execute(jc, new Var(42), new Var(43));
617 assertEquals(false, result);
618 result = script.execute(jc, new Var(41), new Var(44));
619 assertEquals(false, result);
620 result = script.execute(jc, 43, 42);
621 assertEquals(true, result);
622 result = script.execute(jc, new Var(45), new Var(40));
623 assertEquals(true, result);
624
625 script = jexl.createScript("(x, y)->{ x == y }");
626 result = script.execute(jc, 42, 43);
627 assertEquals(false, result);
628 result = script.execute(jc, new Var(42), new Var(43));
629 assertEquals(false, result);
630 result = script.execute(jc, new Var(41), new Var(44));
631 assertEquals(false, result);
632 result = script.execute(jc, 43, 42);
633 assertEquals(false, result);
634 result = script.execute(jc, new Var(45), new Var(40));
635 assertEquals(false, result);
636
637 script = jexl.createScript("(x, y)->{ x != y }");
638 result = script.execute(jc, 42, 43);
639 assertEquals(true, result);
640 result = script.execute(jc, new Var(42), new Var(43));
641 assertEquals(true, result);
642 result = script.execute(jc, new Var(44), new Var(44));
643 assertEquals(false, result);
644 result = script.execute(jc, 44, 44);
645 assertEquals(false, result);
646 result = script.execute(jc, new Var(45), new Var(40));
647 assertEquals(true, result);
648
649 script = jexl.createScript("(x, y)->{ x % y }");
650 result = script.execute(jc, 4242, 100);
651 assertEquals(42, result);
652 result = script.execute(jc, new Var(4242), new Var(100));
653 assertEquals(42, ((Var) result).value);
654
655 script = jexl.createScript("(x, y)->{ x * y }");
656 result = script.execute(jc, 6, 7);
657 assertEquals(42, result);
658 result = script.execute(jc, new Var(6), new Var(7));
659 assertEquals(42, ((Var) result).value);
660
661 script = jexl.createScript("(x, y)->{ x + y }");
662 result = script.execute(jc, 35, 7);
663 assertEquals(42, result);
664 result = script.execute(jc, new Var(35), new Var(7));
665 assertEquals(42, ((Var) result).value);
666
667 script = jexl.createScript("(x, y)->{ x - y }");
668 result = script.execute(jc, 49, 7);
669 assertEquals(42, result);
670 result = script.execute(jc, "foobarquux", "bar");
671 assertEquals("fooquux", result);
672 result = script.execute(jc, 50, 8);
673 assertEquals(42, result);
674 result = script.execute(jc, new Var(50), new Var(8));
675 assertEquals(42, ((Var) result).value);
676
677 script = jexl.createScript("(x)->{ -x }");
678 result = script.execute(jc, -42);
679 assertEquals(42, result);
680 result = script.execute(jc, new Var(-42));
681 assertEquals(42, ((Var) result).value);
682 result = script.execute(jc, "pizza");
683 assertEquals("azzip", result);
684 result = script.execute(jc, -142);
685 assertEquals(142, result);
686
687 script = jexl.createScript("(x)->{ ~x }");
688 result = script.execute(jc, -1);
689 assertEquals(0L, result);
690 result = script.execute(jc, new Var(-1));
691 assertEquals(0L, ((Var) result).value);
692 result = script.execute(jc, new Var(-42));
693 assertEquals(41, ((Var) result).value);
694
695 script = jexl.createScript("(x, y)->{ x ^ y }");
696 result = script.execute(jc, 35, 7);
697 assertEquals(36L, result);
698 result = script.execute(jc, new Var(35), new Var(7));
699 assertEquals(36L, ((Var) result).value);
700
701 script = jexl.createScript("(x, y)->bitwiseXor(x,y)");
702 result = script.execute(jc, 35, 7);
703 assertEquals(36L, result);
704
705 script = jexl.createScript("(x, y)->{ x | y }");
706 result = script.execute(jc, 35, 7);
707 assertEquals(39L, result);
708 result = script.execute(jc, new Var(35), new Var(7));
709 assertEquals(39L, ((Var) result).value);
710
711 script = jexl.createScript("(x, y)->bitwiseOr(x,y)");
712 result = script.execute(jc, 35, 7);
713 assertEquals(39L, result);
714
715 script = jexl.createScript("(x, y)->{ x << y }");
716 result = script.execute(jc, 35, 1);
717 assertEquals(70L, result);
718 result = script.execute(jc, new Var(35), new Var(1));
719 assertEquals(70L, ((Var) result).value);
720
721 script = jexl.createScript("(x, y)->{ x >> y }");
722 result = script.execute(jc, 42, 1);
723 assertEquals(21L, result);
724 result = script.execute(jc, new Var(42), new Var(1));
725 assertEquals(21, ((Var) result).value);
726
727 script = jexl.createScript("(x, y)->{ x >>> y }");
728 result = script.execute(jc, 84, 2);
729 assertEquals(21L, result);
730 result = script.execute(jc, new Var(84), new Var(2));
731 assertEquals(21, ((Var) result).value);
732
733 script = jexl.createScript("(x, y)->{ x & y }");
734 result = script.execute(jc, 35, 7);
735 assertEquals(3L, result);
736 result = script.execute(jc, new Var(35), new Var(7));
737 assertEquals(3L, ((Var) result).value);
738
739 script = jexl.createScript("(x, y)->bitwiseAnd(x,y)");
740 result = script.execute(jc, 35, 7);
741 assertEquals(3L, result);
742
743 script = jexl.createScript("(x, y)->{ x =^ y }");
744 result = script.execute(jc, 3115, 31);
745 assertFalse((Boolean) result);
746 result = script.execute(jc, new Var(3115), new Var(31));
747 assertTrue((Boolean) result);
748
749 script = jexl.createScript("(x, y)->{ x !^ y }");
750 result = script.execute(jc, 3115, 31);
751 assertTrue((Boolean) result);
752 result = script.execute(jc, new Var(3115), new Var(31));
753 assertFalse((Boolean) result);
754
755 script = jexl.createScript("(x, y)->{ x =$ y }");
756 result = script.execute(jc, 3115, 15);
757 assertFalse((Boolean) result);
758 result = script.execute(jc, new Var(3115), new Var(15));
759 assertTrue((Boolean) result);
760
761 script = jexl.createScript("(x, y)->{ x !$ y }");
762 result = script.execute(jc, 3115, 15);
763 assertTrue((Boolean) result);
764 result = script.execute(jc, new Var(3115), new Var(15));
765 assertFalse((Boolean) result);
766
767 script = jexl.createScript("(x, y)->{ x =~ y }");
768 result = script.execute(jc, 3155, 15);
769 assertFalse((Boolean) result);
770 result = script.execute(jc, new Var(3155), new Var(15));
771 assertFalse((Boolean) result);
772 result = script.execute(jc, new Var(15), new Var(3155));
773 assertTrue((Boolean) result);
774
775 script = jexl.createScript("(x, y)->{ x !~ y }");
776 result = script.execute(jc, 3115, 15);
777 assertTrue((Boolean) result);
778 result = script.execute(jc, new Var(3155), new Var(15));
779 assertTrue((Boolean) result);
780 result = script.execute(jc, new Var(15), new Var(3155));
781 assertFalse((Boolean) result);
782
783 final JexlScript script1 = jexl.createScript("(x)->{ !x }");
784 assertThrows(JexlException.Operator.class, () -> script1.execute(jc, new Var(-42)));
785 }
786
787 @BeforeEach
788 @Override
789 public void setUp() {
790 }
791
792
793 @Test
794 void test2DoubleLiterals() {
795 final JexlEvalContext ctxt = new JexlEvalContext();
796 final JexlOptions options = ctxt.getEngineOptions();
797 options.setStrictArithmetic(true);
798 final String stmt = "{a = 42.0e1D; b = 42.0E+2D; c = 42.0e-1d; d = 42.0E-2d; e=10e10; f= +1.e1; g=1e1; }";
799 final JexlScript expr = JEXL.createScript(stmt);
800 expr.execute(ctxt);
801 assertEquals(Double.valueOf("42.0e+1"), ctxt.get("a"));
802 assertEquals(Double.valueOf("42.0e+2"), ctxt.get("b"));
803 assertEquals(Double.valueOf("42.0e-1"), ctxt.get("c"));
804 assertEquals(Double.valueOf("42.0e-2"), ctxt.get("d"));
805 assertEquals(Double.valueOf("10e10"), ctxt.get("e"));
806 assertEquals(Double.valueOf("10"), ctxt.get("f"));
807 assertEquals(Double.valueOf("10"), ctxt.get("g"));
808 }
809
810 @Test
811 void testAddWithStringsLenient() {
812 final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(false)).create();
813 JexlScript script;
814 Object result;
815 script = jexl.createScript("'a' + 0");
816 result = script.execute(null);
817 assertEquals("a0", result);
818
819 script = jexl.createScript("0 + 'a' ");
820 result = script.execute(null);
821 assertEquals("0a", result);
822
823 script = jexl.createScript("0 + '1.2' ");
824 result = script.execute(null);
825 assertEquals(1.2d, (Double) result, EPSILON);
826
827 script = jexl.createScript("'1.2' + 1.2 ");
828 result = script.execute(null);
829 assertEquals(2.4d, (Double) result, EPSILON);
830
831 script = jexl.createScript("1.2 + 1.2 ");
832 result = script.execute(null);
833 assertEquals(2.4d, (Double) result, EPSILON);
834
835 script = jexl.createScript("1.2 + '1.2' ");
836 result = script.execute(null);
837 assertEquals(2.4d, (Double) result, EPSILON);
838
839 script = jexl.createScript("'1.2' + 0 ");
840 result = script.execute(null);
841 assertEquals(1.2d, (Double) result, EPSILON);
842
843 script = jexl.createScript("'1.2' + '1.2' ");
844 result = script.execute(null);
845 assertEquals("1.21.2", result);
846 }
847
848 @Test
849 void testAddWithStringsStrict() {
850 final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(true)).create();
851 JexlScript script;
852 Object result;
853 script = jexl.createScript("'a' + 0");
854 result = script.execute(null);
855 assertEquals("a0", result);
856
857 script = jexl.createScript("0 + 'a' ");
858 result = script.execute(null);
859 assertEquals("0a", result);
860
861 script = jexl.createScript("0 + '1.2' ");
862 result = script.execute(null);
863 assertEquals("01.2", result);
864
865 script = jexl.createScript("'1.2' + 1.2 ");
866 result = script.execute(null);
867 assertEquals("1.21.2", result);
868
869 script = jexl.createScript("1.2 + 1.2 ");
870 result = script.execute(null);
871 assertEquals(2.4d, (Double) result, EPSILON);
872
873 script = jexl.createScript("1.2 + '1.2' ");
874 result = script.execute(null);
875 assertEquals("1.21.2", result);
876
877 script = jexl.createScript("'1.2' + 0 ");
878 result = script.execute(null);
879 assertEquals("1.20", result);
880
881 script = jexl.createScript("'1.2' + '1.2' ");
882 result = script.execute(null);
883 assertEquals("1.21.2", result);
884
885 }
886
887 @Test
888 void testArithmeticPlus() {
889 final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new ArithmeticPlus(false)).create();
890 final JexlContext jc = new EmptyTestContext();
891 runOverload(jexl, jc);
892 runOverload(jexl, jc);
893 }
894
895 @Test
896 void testArithmeticPlusNoCache() {
897 final JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new ArithmeticPlus(false)).create();
898 final JexlContext jc = new EmptyTestContext();
899 runOverload(jexl, jc);
900 }
901
902 @Test
903 void testAtomicBoolean() {
904
905 JexlScript e = JEXL.createScript("if (x) 1 else 2;", "x");
906 final JexlArithmetic jexla = JEXL.getArithmetic();
907 final JexlContext jc = new MapContext();
908 final AtomicBoolean ab = new AtomicBoolean();
909 Object o;
910 o = e.execute(jc, ab);
911 assertEquals(Integer.valueOf(2), o);
912 ab.set(true);
913 o = e.execute(jc, ab);
914 assertEquals(Integer.valueOf(1), o);
915
916 e = JEXL.createScript("x && y", "x", "y");
917 ab.set(true);
918 o = e.execute(jc, ab, Boolean.FALSE);
919 assertFalse(jexla.toBoolean(o));
920 ab.set(true);
921 o = e.execute(jc, ab, Boolean.TRUE);
922 assertTrue(jexla.toBoolean(o));
923 ab.set(false);
924 o = e.execute(jc, ab, Boolean.FALSE);
925 assertFalse(jexla.toBoolean(o));
926 ab.set(false);
927 o = e.execute(jc, ab, Boolean.FALSE);
928 assertFalse(jexla.toBoolean(o));
929
930 e = JEXL.createScript("x + y", "x", "y");
931 ab.set(true);
932 o = e.execute(jc, ab, 10);
933 assertEquals(11, o);
934 o = e.execute(jc, 10, ab);
935 assertEquals(11, o);
936 o = e.execute(jc, ab, 10.d);
937 assertEquals(11.d, (Double) o, EPSILON);
938 o = e.execute(jc, 10.d, ab);
939 assertEquals(11.d, (Double) o, EPSILON);
940
941 final BigInteger bi10 = BigInteger.TEN;
942 ab.set(false);
943 o = e.execute(jc, ab, bi10);
944 assertEquals(bi10, o);
945 o = e.execute(jc, bi10, ab);
946 assertEquals(bi10, o);
947
948 final BigDecimal bd10 = BigDecimal.TEN;
949 ab.set(false);
950 o = e.execute(jc, ab, bd10);
951 assertEquals(bd10, o);
952 o = e.execute(jc, bd10, ab);
953 assertEquals(bd10, o);
954
955
956 e = JEXL.createScript("!x", "x");
957 ab.set(true);
958 o = e.execute(jc, ab);
959 assertFalse((Boolean) o);
960 ab.set(false);
961 o = e.execute(jc, ab);
962 assertTrue((Boolean) o);
963
964
965 e = JEXL.createScript("-x", "x");
966 ab.set(true);
967 o = e.execute(jc, ab);
968 assertFalse((Boolean) o);
969 ab.set(false);
970 o = e.execute(jc, ab);
971 assertTrue((Boolean) o);
972 }
973
974 @Test
975 void testBigDecimal() throws Exception {
976 asserter.setVariable("left", new BigDecimal(2));
977 asserter.setVariable("right", new BigDecimal(6));
978 asserter.assertExpression("left + right", new BigDecimal(8));
979 asserter.assertExpression("right - left", new BigDecimal(4));
980 asserter.assertExpression("right * left", new BigDecimal(12));
981 asserter.assertExpression("right / left", new BigDecimal(3));
982 asserter.assertExpression("right % left", new BigDecimal(0));
983 }
984
985 @Test
986 void testBigdOp() {
987 final BigDecimal sevendot475 = new BigDecimal("7.475");
988 final BigDecimal SO = new BigDecimal("325");
989 final JexlContext jc = new MapContext();
990 jc.set("SO", SO);
991
992 final String expr = "2.3*SO/100";
993
994 final Object evaluate = JEXL.createExpression(expr).evaluate(jc);
995 assertEquals(sevendot475, evaluate);
996 }
997
998
999 @Test
1000 void testBigExponentLiterals() {
1001 final JexlEvalContext ctxt = new JexlEvalContext();
1002 final JexlOptions options = ctxt.getEngineOptions();
1003 options.setStrictArithmetic(true);
1004 final String stmt = "{a = 42.0e1B; b = 42.0E+2B; c = 42.0e-1B; d = 42.0E-2b; e=4242.4242e1b}";
1005 final JexlScript expr = JEXL.createScript(stmt);
1006 expr.execute(ctxt);
1007 assertEquals(new BigDecimal("42.0e+1"), ctxt.get("a"));
1008 assertEquals(new BigDecimal("42.0e+2"), ctxt.get("b"));
1009 assertEquals(new BigDecimal("42.0e-1"), ctxt.get("c"));
1010 assertEquals(new BigDecimal("42.0e-2"), ctxt.get("d"));
1011 assertEquals(new BigDecimal("4242.4242e1"), ctxt.get("e"));
1012 }
1013
1014 @Test
1015 void testBigInteger() throws Exception {
1016 asserter.setVariable("left", new BigInteger("2"));
1017 asserter.setVariable("right", new BigInteger("6"));
1018 asserter.assertExpression("left + right", new BigInteger("8"));
1019 asserter.assertExpression("right - left", new BigInteger("4"));
1020 asserter.assertExpression("right * left", new BigInteger("12"));
1021 asserter.assertExpression("right / left", new BigInteger("3"));
1022 asserter.assertExpression("right % left", new BigInteger("0"));
1023 }
1024
1025
1026 @Test
1027 void testBigLiterals() {
1028 final JexlEvalContext ctxt = new JexlEvalContext();
1029 final JexlOptions options = ctxt.getEngineOptions();
1030 options.setStrictArithmetic(true);
1031 final String stmt = "{a = 10H; b = 10h; c = 42.0B; d = 42.0b;}";
1032 final JexlScript expr = JEXL.createScript(stmt);
1033 expr.execute(ctxt);
1034 assertEquals(new BigInteger("10"), ctxt.get("a"));
1035 assertEquals(new BigInteger("10"), ctxt.get("b"));
1036 assertEquals(new BigDecimal("42.0"), ctxt.get("c"));
1037 assertEquals(new BigDecimal("42.0"), ctxt.get("d"));
1038 }
1039
1040 @Test
1041 void testBigLiteralValue() {
1042 final JexlEvalContext ctxt = new JexlEvalContext();
1043 final JexlOptions options = ctxt.getEngineOptions();
1044 options.setStrictArithmetic(true);
1045 final JexlExpression e = JEXL.createExpression("9223372036854775806.5B");
1046 final String res = String.valueOf(e.evaluate(ctxt));
1047 assertEquals("9223372036854775806.5", res);
1048 }
1049
1050
1051
1052
1053 @Test
1054 void testCalculations() throws Exception {
1055 asserter.setStrict(true, false);
1056
1057
1058
1059 asserter.setVariable("imanull", null);
1060 asserter.assertExpression("imanull + 2", Integer.valueOf(2));
1061 asserter.assertExpression("imanull + imanull", Integer.valueOf(0));
1062 asserter.setVariable("foo", Integer.valueOf(2));
1063
1064 asserter.assertExpression("foo + 2", Integer.valueOf(4));
1065 asserter.assertExpression("3 + 3", Integer.valueOf(6));
1066 asserter.assertExpression("3 + 3 + foo", Integer.valueOf(8));
1067 asserter.assertExpression("3 * 3", Integer.valueOf(9));
1068 asserter.assertExpression("3 * 3 + foo", Integer.valueOf(11));
1069 asserter.assertExpression("3 * 3 - foo", Integer.valueOf(7));
1070
1071
1072
1073
1074 asserter.assertExpression("(4 + 3) * 6", Integer.valueOf(42));
1075 asserter.assertExpression("(8 - 2) * 7", Integer.valueOf(42));
1076
1077
1078
1079
1080 asserter.assertExpression("3 * \"3.0\"", Double.valueOf(9));
1081 asserter.assertExpression("3 * 3.0", Double.valueOf(9));
1082
1083
1084
1085
1086 asserter.setStrict(false, false);
1087 asserter.assertExpression("6 / 3", Integer.valueOf(6 / 3));
1088 asserter.assertExpression("6.4 / 3", Double.valueOf(6.4 / 3));
1089 asserter.assertExpression("0 / 3", Integer.valueOf(0 / 3));
1090 asserter.assertExpression("3 / 0", Double.valueOf(0));
1091 asserter.assertExpression("4 % 3", Integer.valueOf(1));
1092 asserter.assertExpression("4.8 % 3", Double.valueOf(4.8 % 3));
1093
1094 }
1095
1096 @Test
1097 void testCoerceBigDecimal() {
1098 final JexlArithmetic ja = JEXL.getArithmetic();
1099 final JexlEvalContext ctxt = new JexlEvalContext();
1100 final JexlOptions options = ctxt.getEngineOptions();
1101 options.setStrictArithmetic(true);
1102 final String stmt = "{a = 34L; b = 45.0D; c=56.0F; d=67B; e=78H; }";
1103 final JexlScript expr = JEXL.createScript(stmt);
1104 expr.execute(ctxt);
1105 assertEquals(BigDecimal.valueOf(34), ja.toBigDecimal(ctxt.get("a")));
1106 assertEquals(BigDecimal.valueOf(45.), ja.toBigDecimal(ctxt.get("b")));
1107 assertEquals(BigDecimal.valueOf(56.), ja.toBigDecimal(ctxt.get("c")));
1108 assertEquals(BigDecimal.valueOf(67), ja.toBigDecimal(ctxt.get("d")));
1109 assertEquals(BigDecimal.valueOf(78), ja.toBigDecimal(ctxt.get("e")));
1110 assertEquals(BigDecimal.valueOf(10), ja.toBigDecimal("10"));
1111 assertEquals(BigDecimal.valueOf(1.), ja.toBigDecimal(true));
1112 assertEquals(BigDecimal.valueOf(0.), ja.toBigDecimal(false));
1113
1114 final BigDecimal a42 = BigDecimal.valueOf(42);
1115 final BigDecimal a49 = BigDecimal.valueOf(49);
1116 JexlScript bde = JEXL.createScript("a * 6 / 7", "a");
1117 assertEquals(a42, bde.execute(null, a49));
1118 bde = JEXL.createScript("(a - 12) / 12", "a");
1119 final MathContext mc = ja.getMathContext();
1120 final BigDecimal b56 = BigDecimal.valueOf(56);
1121 final BigDecimal b12 = BigDecimal.valueOf(12);
1122 final BigDecimal b3dot666 = b56.subtract(b12, mc).divide(b12, mc);
1123 assertEquals(b3dot666, bde.execute(null, b56));
1124 }
1125
1126 @Test
1127 void testCoerceBigInteger() {
1128 final JexlArithmetic ja = JEXL.getArithmetic();
1129 final JexlEvalContext ctxt = new JexlEvalContext();
1130 final JexlOptions options = ctxt.getEngineOptions();
1131 options.setStrictArithmetic(true);
1132 final String stmt = "{a = 34L; b = 45.0D; c=56.0F; d=67B; e=78H; }";
1133 final JexlScript expr = JEXL.createScript(stmt);
1134 expr.execute(ctxt);
1135 assertEquals(BigInteger.valueOf(34), ja.toBigInteger(ctxt.get("a")));
1136 assertEquals(BigInteger.valueOf(45), ja.toBigInteger(ctxt.get("b")));
1137 assertEquals(BigInteger.valueOf(56), ja.toBigInteger(ctxt.get("c")));
1138 assertEquals(BigInteger.valueOf(67), ja.toBigInteger(ctxt.get("d")));
1139 assertEquals(BigInteger.valueOf(78), ja.toBigInteger(ctxt.get("e")));
1140 assertEquals(BigInteger.valueOf(10), ja.toBigInteger("10"));
1141 assertEquals(BigInteger.valueOf(1), ja.toBigInteger(true));
1142 assertEquals(BigInteger.valueOf(0), ja.toBigInteger(false));
1143 }
1144
1145 @Test
1146 void testCoerceDouble() {
1147 final JexlArithmetic ja = JEXL.getArithmetic();
1148 final JexlEvalContext ctxt = new JexlEvalContext();
1149 final JexlOptions options = ctxt.getEngineOptions();
1150 options.setStrictArithmetic(true);
1151 final String stmt = "{a = 34L; b = 45.0D; c=56.0F; d=67B; e=78H; }";
1152 final JexlScript expr = JEXL.createScript(stmt);
1153 expr.execute(ctxt);
1154 assertEquals(34, ja.toDouble(ctxt.get("a")), EPSILON);
1155 assertEquals(45, ja.toDouble(ctxt.get("b")), EPSILON);
1156 assertEquals(56, ja.toDouble(ctxt.get("c")), EPSILON);
1157 assertEquals(67, ja.toDouble(ctxt.get("d")), EPSILON);
1158 assertEquals(78, ja.toDouble(ctxt.get("e")), EPSILON);
1159 assertEquals(10d, ja.toDouble("10"), EPSILON);
1160 assertEquals(1.D, ja.toDouble(true), EPSILON);
1161 assertEquals(0.D, ja.toDouble(false), EPSILON);
1162 }
1163
1164 @Test
1165 void testCoerceInteger() {
1166 final JexlArithmetic ja = JEXL.getArithmetic();
1167 final JexlEvalContext ctxt = new JexlEvalContext();
1168 final JexlOptions options = ctxt.getEngineOptions();
1169 options.setStrictArithmetic(true);
1170 final String stmt = "a = 34L; b = 45.0D; c=56.0F; d=67B; e=78H;";
1171 final JexlScript expr = JEXL.createScript(stmt);
1172 expr.execute(ctxt);
1173 assertEquals(34, ja.toInteger(ctxt.get("a")));
1174 assertEquals(45, ja.toInteger(ctxt.get("b")));
1175 assertEquals(56, ja.toInteger(ctxt.get("c")));
1176 assertEquals(67, ja.toInteger(ctxt.get("d")));
1177 assertEquals(78, ja.toInteger(ctxt.get("e")));
1178 assertEquals(10, ja.toInteger("10"));
1179 assertEquals(1, ja.toInteger(true));
1180 assertEquals(0, ja.toInteger(false));
1181 }
1182
1183 @Test
1184 void testCoerceLong() {
1185 final JexlArithmetic ja = JEXL.getArithmetic();
1186 final JexlEvalContext ctxt = new JexlEvalContext();
1187 final JexlOptions options = ctxt.getEngineOptions();
1188 options.setStrictArithmetic(true);
1189 final String stmt = "a = 34L; b = 45.0D; c=56.0F; d=67B; e=78H;";
1190 final JexlScript expr = JEXL.createScript(stmt);
1191 expr.execute(ctxt);
1192 assertEquals(34L, ja.toLong(ctxt.get("a")));
1193 assertEquals(45L, ja.toLong(ctxt.get("b")));
1194 assertEquals(56L, ja.toLong(ctxt.get("c")));
1195 assertEquals(67L, ja.toLong(ctxt.get("d")));
1196 assertEquals(78L, ja.toLong(ctxt.get("e")));
1197 assertEquals(10L, ja.toLong("10"));
1198 assertEquals(1L, ja.toLong(true));
1199 assertEquals(0L, ja.toLong(false));
1200 }
1201
1202 @Test
1203 void testCoercions() throws Exception {
1204 asserter.assertExpression("1", Integer.valueOf(1));
1205 asserter.assertExpression("5L", Long.valueOf(5));
1206
1207 asserter.setVariable("I2", Integer.valueOf(2));
1208 asserter.setVariable("L2", Long.valueOf(2));
1209 asserter.setVariable("L3", Long.valueOf(3));
1210 asserter.setVariable("B10", BigInteger.TEN);
1211
1212
1213 asserter.assertExpression("I2 + 2", Integer.valueOf(4));
1214 asserter.assertExpression("I2 * 2", Integer.valueOf(4));
1215 asserter.assertExpression("I2 - 2", Integer.valueOf(0));
1216 asserter.assertExpression("I2 / 2", Integer.valueOf(1));
1217
1218
1219 asserter.assertExpression("I2 * L2", Long.valueOf(4));
1220 asserter.assertExpression("I2 / L2", Long.valueOf(1));
1221
1222
1223 asserter.assertExpression("L2 + 3", Long.valueOf(5));
1224 asserter.assertExpression("L2 + L3", Long.valueOf(5));
1225 asserter.assertExpression("L2 / L2", Long.valueOf(1));
1226 asserter.assertExpression("L2 / 2", Long.valueOf(1));
1227
1228
1229 asserter.assertExpression("B10 / 10", BigInteger.ONE);
1230 asserter.assertExpression("B10 / I2", new BigInteger("5"));
1231 asserter.assertExpression("B10 / L2", new BigInteger("5"));
1232 }
1233
1234 @Test
1235 void testCompare() {
1236
1237 final Object[] EXPRESSIONS = {
1238
1239 "1 == 1", true,
1240 "1 === 1", true,
1241 "1.d === 1", false,
1242 "1 != 1", false,
1243 "1 != 2", true,
1244 "1 > 2", false,
1245 "1 >= 2", false,
1246 "1 < 2", true,
1247 "1 <= 2", true,
1248
1249 "1.0 == 1", true,
1250 "1 == 1.0", true,
1251 "1.1 != 1", true,
1252 "1.1 < 2", true,
1253
1254 "1.0b == 1h", true,
1255 "1.0b !== 1h", true,
1256 "1h == 1.0b", true,
1257 "1.1b != 1h", true,
1258 "1.1b < 2h", true,
1259
1260 "1l == 1.0", true,
1261 "1l !== 1.0", true,
1262 "1.0d == 1.0f", true,
1263 "1l == 1.0b", true,
1264 "1l == 1h", true,
1265 "1.0d == 1.0b", true,
1266 "1.0f == 1.0b", true,
1267 "1.0d == 1h", true,
1268 "1.0f == 1h", true,
1269
1270 "'1' == 1", true,
1271 "'1' == 1l", true,
1272 "'1' == 1h", true,
1273 "'' == 0", true,
1274 "'1.0' == 1", true,
1275 "'1.0' == 1.0f", true,
1276 "'1.0' == 1.0d", true,
1277 "'1.0' == 1.0b", true,
1278 "'1.01' == 1.01", true,
1279 "'1.01' == 1", false,
1280 "'1.01' == 1b", false,
1281 "'1.01' == 1h", false,
1282 "'1.00001' == 1b", false,
1283 "'1.00001' == 1h", false,
1284 "'1.00000001' == 1", false,
1285 "'1.00000001' == 1b", false,
1286 "'1.00000001' == 1h", false,
1287 "1.0 >= '1'", true,
1288 "1.0 > '1'", false,
1289 "1.0 == 'a'", false,
1290 "10 == 'a'", false,
1291 "10 > 'a'", ArithmeticException.class,
1292 "10.0 > 'a'", ArithmeticException.class,
1293 "'a' <= 10b", ArithmeticException.class,
1294 "'a' >= 1h", ArithmeticException.class
1295 };
1296 final JexlEngine jexl = new JexlBuilder().create();
1297 final JexlContext jc = new EmptyTestContext();
1298
1299 for (int e = 0; e < EXPRESSIONS.length; e += 2) {
1300 final String stext = (String) EXPRESSIONS[e];
1301 final Object expected = EXPRESSIONS[e + 1];
1302 final JexlExpression expression = jexl.createExpression(stext);
1303 try {
1304 final Object result = expression.evaluate(jc);
1305 assertEquals(expected, result, () -> "failed on " + stext);
1306 } catch (final JexlException jexlException) {
1307 final Throwable cause = jexlException.getCause();
1308 if (cause == null || !cause.getClass().equals(expected)) {
1309 fail(stext);
1310 }
1311 }
1312 }
1313 }
1314
1315 @Test
1316 void testDivClass() {
1317 final JexlEngine jexl = new JexlBuilder().create();
1318 final JexlContext jc = new MapContext();
1319 final Object ra = jexl.createExpression("463.0d / 0.1").evaluate(jc);
1320 assertEquals(Double.class, ra.getClass());
1321 final Object r0 = jexl.createExpression("463.0B / 0.1").evaluate(jc);
1322 assertEquals(java.math.BigDecimal.class, r0.getClass());
1323 final Object r1 = jexl.createExpression("463.0B / 0.1B").evaluate(jc);
1324 assertEquals(java.math.BigDecimal.class, r1.getClass());
1325 }
1326
1327
1328
1329
1330
1331
1332 @Test
1333 void testDivideByZero() throws Exception {
1334 final Map<String, Object> vars = new HashMap<>();
1335 final JexlEvalContext context = new JexlEvalContext(vars);
1336 final JexlOptions options = context.getEngineOptions();
1337 options.setStrictArithmetic(true);
1338 vars.put("aByte", Byte.valueOf((byte) 1));
1339 vars.put("aShort", Short.valueOf((short) 2));
1340 vars.put("aInteger", Integer.valueOf(3));
1341 vars.put("aLong", Long.valueOf(4));
1342 vars.put("aFloat", Float.valueOf((float) 5.5));
1343 vars.put("aDouble", Double.valueOf(6.6));
1344 vars.put("aBigInteger", new BigInteger("7"));
1345 vars.put("aBigDecimal", new BigDecimal("8.8"));
1346
1347 vars.put("zByte", Byte.valueOf((byte) 0));
1348 vars.put("zShort", Short.valueOf((short) 0));
1349 vars.put("zInteger", Integer.valueOf(0));
1350 vars.put("zLong", Long.valueOf(0));
1351 vars.put("zFloat", Float.valueOf(0));
1352 vars.put("zDouble", Double.valueOf(0));
1353 vars.put("zBigInteger", new BigInteger("0"));
1354 vars.put("zBigDecimal", new BigDecimal("0"));
1355
1356 final String[] tnames = {
1357 "Byte", "Short", "Integer", "Long",
1358 "Float", "Double",
1359 "BigInteger", "BigDecimal"
1360 };
1361
1362 final int PERMS = tnames.length * tnames.length;
1363
1364 final JexlEngine jexl = JEXL;
1365
1366 for (int s = 0; s < 2; ++s) {
1367 final boolean strict = s != 0;
1368 options.setStrict(true);
1369 options.setStrictArithmetic(strict);
1370 int zthrow = 0;
1371 int zeval = 0;
1372
1373 for (final String vname : tnames) {
1374
1375 for (final String zname : tnames) {
1376
1377 final String expr = "a" + vname + " / " + "z" + zname;
1378 try {
1379 final JexlExpression zexpr = jexl.createExpression(expr);
1380 final Object nan = zexpr.evaluate(context);
1381
1382 if (nan instanceof Number) {
1383 final double zero = ((Number) nan).doubleValue();
1384 if (zero == 0.0) {
1385 zeval += 1;
1386 }
1387 }
1388 } catch (final Exception any) {
1389
1390 zthrow += 1;
1391 }
1392 }
1393 }
1394 if (strict) {
1395 assertEquals(zthrow, PERMS, "All expressions should have thrown " + zthrow + "/" + PERMS);
1396 } else {
1397 assertEquals(zeval, PERMS, "All expressions should have zeroed " + zeval + "/" + PERMS);
1398 }
1399 }
1400 debuggerCheck(jexl);
1401 }
1402
1403 @Test
1404 void testDivideEdges() {
1405 assertNullOperand(() -> jexla.divide(null, null));
1406 assertEquals(0, jexlb.divide(null, null));
1407 assertNullOperand(() -> jexla.divide(null, null));
1408 assertEquals(0, jexlb.mod(null, null));
1409 assertArithmeticException(() -> jexla.divide(1, 0));
1410 assertArithmeticException(() -> jexla.divide(1L, 0L));
1411 assertArithmeticException(() -> jexla.divide(1f, 0f));
1412 assertArithmeticException(() -> jexla.divide(1d, 0d));
1413 assertArithmeticException(() -> jexla.divide(BigInteger.ONE, BigInteger.ZERO));
1414 assertArithmeticException(() -> jexla.divide(BigInteger.ONE, BigDecimal.ZERO));
1415 }
1416
1417 @Test
1418 void testEmpty() throws Exception {
1419 final Object[] SCRIPTS = {
1420 "var x = null; log('x = %s', x);", 0,
1421 "var x = 'abc'; log('x = %s', x);", 1,
1422 "var x = 333; log('x = %s', x);", 1,
1423 "var x = [1, 2]; log('x = %s', x);", 2,
1424 "var x = ['a', 'b']; log('x = %s', x);", 2,
1425 "var x = {1:'A', 2:'B'}; log('x = %s', x);", 1,
1426 "var x = null; return empty(x);", true,
1427 "var x = ''; return empty(x);", true,
1428 "var x = 'abc'; return empty(x);", false,
1429 "var x = 0; return empty(x);", true,
1430 "var x = 333; return empty(x);", false,
1431 "var x = []; return empty(x);", true,
1432 "var x = [1, 2]; return empty(x);", false,
1433 "var x = ['a', 'b']; return empty(x);", false,
1434 "var x = [...]; return empty(x);", true,
1435 "var x = [1, 2,...]; return empty(x);", false,
1436 "var x = {:}; return empty(x);", true,
1437 "var x = {1:'A', 2:'B'}; return empty(x);", false,
1438 "var x = {}; return empty(x);", true,
1439 "var x = {'A','B'}; return empty(x);", false
1440 };
1441 final JexlEngine jexl = new JexlBuilder().create();
1442 final JexlContext jc = new EmptyTestContext();
1443 JexlScript script;
1444
1445 for (int e = 0; e < SCRIPTS.length; e += 2) {
1446 final String stext = (String) SCRIPTS[e];
1447 final Object expected = SCRIPTS[e + 1];
1448 script = jexl.createScript(stext);
1449 final Object result = script.execute(jc);
1450 assertEquals(expected, result, () -> "failed on " + stext);
1451 }
1452 }
1453
1454
1455
1456
1457
1458
1459 @Test
1460 void testEmptySizeStrictPropagatesError() {
1461 final JexlEngine strict = new JexlBuilder().strict(true).safe(false).create();
1462 assertThrows(JexlException.class, () -> strict.createScript("empty(x.y)", "x").execute(null, (Object) null));
1463 assertThrows(JexlException.class, () -> strict.createScript("size(x.y)", "x").execute(null, (Object) null));
1464 final JexlEngine lenient = new JexlBuilder().strict(false).safe(true).create();
1465 assertEquals(Boolean.TRUE, lenient.createScript("empty(x.y)", "x").execute(null, (Object) null));
1466 assertEquals(0, lenient.createScript("size(x.y)", "x").execute(null, (Object) null));
1467 }
1468
1469
1470
1471
1472
1473 @Test
1474 void testEmptySizeDoNotSwallowCancel() {
1475 final JexlEngine jexl = new JexlBuilder().strict(false).cancellable(true).create();
1476 final JexlScript empty = jexl.createScript("empty(x)", "x");
1477 final JexlScript size = jexl.createScript("size(x)", "x");
1478 try {
1479 Thread.currentThread().interrupt();
1480 assertThrows(JexlException.Cancel.class, () -> empty.execute(null, "abc"));
1481 } finally {
1482 Thread.interrupted();
1483 }
1484 try {
1485 Thread.currentThread().interrupt();
1486 assertThrows(JexlException.Cancel.class, () -> size.execute(null, "abc"));
1487 } finally {
1488 Thread.interrupted();
1489 }
1490 }
1491
1492 @Test
1493 void testEmptyDouble() {
1494 Object x;
1495 x = JEXL.createScript("4294967296.d").execute(null);
1496 assertEquals(4294967296.0d, (Double) x, EPSILON);
1497 checkEmpty(x, false);
1498 x = JEXL.createScript("4294967296.0d").execute(null);
1499 assertEquals(4294967296.0d, (Double) x, EPSILON);
1500 checkEmpty(x, false);
1501 x = JEXL.createScript("0.0d").execute(null);
1502 assertEquals(0.0d, (Double) x, EPSILON);
1503 checkEmpty(x, true);
1504 x = Double.NaN;
1505 checkEmpty(x, true);
1506
1507 }
1508
1509 @Test
1510 void testEmptyFloat() {
1511 Object x;
1512 x = JEXL.createScript("4294967296.f").execute(null);
1513 assertEquals(4294967296.0f, (Float) x, EPSILON);
1514 checkEmpty(x, false);
1515 x = JEXL.createScript("4294967296.0f").execute(null);
1516 assertEquals(4294967296.0f, (Float) x, EPSILON);
1517 checkEmpty(x, false);
1518 x = JEXL.createScript("0.0f").execute(null);
1519 assertEquals(0.0f, (Float) x, EPSILON);
1520 checkEmpty(x, true);
1521 x = Float.NaN;
1522 checkEmpty(x, true);
1523 }
1524
1525 @Test
1526 void testEmptyLong() {
1527 Object x;
1528 x = JEXL.createScript("new('java.lang.Long', 4294967296)").execute(null);
1529 assertEquals(4294967296L, ((Long) x).longValue());
1530 x = JEXL.createScript("new Long(4294967296)").execute(null);
1531 assertEquals(4294967296L, ((Long) x).longValue());
1532 x = JEXL.createScript("new('java.lang.Long', '4294967296')").execute(null);
1533 assertEquals(4294967296L, ((Long) x).longValue());
1534 x = JEXL.createScript("4294967296l").execute(null);
1535 assertEquals(4294967296L, ((Long) x).longValue());
1536 x = JEXL.createScript("4294967296L").execute(null);
1537 assertEquals(4294967296L, ((Long) x).longValue());
1538 checkEmpty(x, false);
1539 x = JEXL.createScript("0L").execute(null);
1540 assertEquals(0, ((Long) x).longValue());
1541 checkEmpty(x, true);
1542 }
1543
1544 @Test
1545 void testFailAllOperators() {
1546
1547 final String[] scripts = {
1548 "(x, y)->{ x < y }",
1549 "(x, y)->{ x <= y }",
1550 "(x, y)->{ x > y }",
1551 "(x, y)->{ x >= y }",
1552 "(x, y)->{ x == y }",
1553 "(x, y)->{ x != y }",
1554 "(x, y)->{ x === y }",
1555 "(x, y)->{ x !== y }",
1556 "(x, y)->{ x % y }",
1557 "(x, y)->{ x * y }",
1558 "(x, y)->{ x + y }",
1559 "(x, y)->{ x - y }",
1560 "(x, y)->{ x ^ y }",
1561 "(x, y)->bitwiseXor(x,y)",
1562 "(x, y)->{ x || y }",
1563 "(x, y)->{ x | y }",
1564 "(x, y)->bitwiseOr(x,y)",
1565 "(x, y)->{ x << y }",
1566 "(x, y)->{ x >> y }",
1567 "(x, y)->{ x >>> y }",
1568 "(x, y)->{ x & y }",
1569 "(x, y)->{ x && y }",
1570 "(x, y)->bitwiseAnd(x,y)",
1571 "(x, y)->{ x =^ y }",
1572 "(x, y)->{ x !^ y }",
1573 "(x, y)->{ x =$ y }",
1574 "(x, y)->{ x !$ y }",
1575 "(x, y)->{ x =~ y }",
1576 "(x, y)->{ x !~ y }",
1577 "(x, ignore)->{ -x }",
1578 "(x, ignore)->{ +x }",
1579 "(x, ignore)->{ --x }",
1580 "(x, ignore)->{ ++x }",
1581 "(x, ignore)->{ x-- }",
1582 "(x, ignore)->{ x++ }"
1583 };
1584
1585 final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new ArithmeticFail(true)).create();
1586 final JexlContext jc = new EmptyTestContext();
1587 for (final String src : scripts) {
1588 final JexlScript script = jexl.createScript(src);
1589 assertThrows(JexlException.class, () -> script.execute(jc, new Var(42), new Var(43)));
1590 }
1591 }
1592
1593 @Test
1594 void testInfiniteArithmetic() {
1595 final Map<String, Object> ns = new HashMap<>();
1596 ns.put("math", Math.class);
1597 final JexlEngine jexl = new JexlBuilder().arithmetic(new Arithmetic132()).namespaces(ns).create();
1598
1599 Object evaluate = jexl.createExpression("1/0").evaluate(null);
1600 assertTrue(Double.isInfinite((Double) evaluate));
1601
1602 evaluate = jexl.createExpression("-1/0").evaluate(null);
1603 assertTrue(Double.isInfinite((Double) evaluate));
1604
1605 evaluate = jexl.createExpression("1.0/0.0").evaluate(null);
1606 assertTrue(Double.isInfinite((Double) evaluate));
1607
1608 evaluate = jexl.createExpression("-1.0/0.0").evaluate(null);
1609 assertTrue(Double.isInfinite((Double) evaluate));
1610
1611 evaluate = jexl.createExpression("math:abs(-42)").evaluate(null);
1612 assertEquals(42, evaluate);
1613
1614 evaluate = jexl.createExpression("42B / 7").evaluate(null);
1615 assertEquals(6, evaluate);
1616
1617 evaluate = jexl.createExpression("42.7B / 7").evaluate(null);
1618 assertEquals(BigDecimal.valueOf(6.1d), evaluate);
1619 }
1620
1621 @Test
1622 void testInstanceOf0() {
1623 final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).create();
1624 final JexlContext ctxt = new InstanceofContext();
1625 runInstanceof(jexl, ctxt);
1626 }
1627
1628 @Test
1629 void testInstanceOf1() {
1630 final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).imports("java.lang").create();
1631 runInstanceof(jexl, null);
1632 }
1633
1634 @Test
1635 void testIntegerCoercionEdges() {
1636 assertNullOperand(() -> jexla.toBoolean(null));
1637 assertTrue(jexla.toBoolean(date));
1638
1639 assertNullOperand(() -> jexla.toInteger(null));
1640 assertEquals(0, jexlb.toInteger(null));
1641 assertArithmeticException(() -> jexla.toInteger(date));
1642 assertEquals(0, jexla.toInteger(Double.NaN));
1643 assertEquals(0, jexla.toInteger(""));
1644 assertEquals('b', jexla.toInteger('b'));
1645 assertEquals(1, jexla.toInteger(new AtomicBoolean(true)));
1646 assertEquals(0, jexla.toInteger(new AtomicBoolean()));
1647
1648
1649 assertNullOperand(() -> jexla.toLong(null));
1650 assertEquals(0L, jexlb.toLong(null));
1651 assertArithmeticException(() -> jexla.toLong(date));
1652 assertEquals(0L, jexla.toLong(Double.NaN));
1653 assertEquals(0L, jexla.toLong(""));
1654 assertEquals('b', jexla.toLong('b'));
1655 assertEquals(1L, jexla.toLong(new AtomicBoolean(true)));
1656 assertEquals(0L, jexla.toLong(new AtomicBoolean()));
1657 }
1658
1659 @Test
1660 void testIsFloatingPointPattern() {
1661 final JexlArithmetic ja = new JexlArithmetic(true);
1662
1663 assertFalse(ja.isFloatingPointNumber("floating point"));
1664 assertFalse(ja.isFloatingPointNumber("a1."));
1665 assertFalse(ja.isFloatingPointNumber("b1.2"));
1666 assertFalse(ja.isFloatingPointNumber("-10.2a-34"));
1667 assertFalse(ja.isFloatingPointNumber("+10.2a+34"));
1668 assertFalse(ja.isFloatingPointNumber("0"));
1669 assertFalse(ja.isFloatingPointNumber("1"));
1670 assertFalse(ja.isFloatingPointNumber("12A"));
1671 assertFalse(ja.isFloatingPointNumber("2F3"));
1672 assertFalse(ja.isFloatingPointNumber("23"));
1673 assertFalse(ja.isFloatingPointNumber("+3"));
1674 assertFalse(ja.isFloatingPointNumber("+34"));
1675 assertFalse(ja.isFloatingPointNumber("+3-4"));
1676 assertFalse(ja.isFloatingPointNumber("+3.-4"));
1677 assertFalse(ja.isFloatingPointNumber("3ee4"));
1678
1679 assertTrue(ja.isFloatingPointNumber("0."));
1680 assertTrue(ja.isFloatingPointNumber("1."));
1681 assertTrue(ja.isFloatingPointNumber("1.2"));
1682 assertTrue(ja.isFloatingPointNumber("1.2e3"));
1683 assertTrue(ja.isFloatingPointNumber("2e3"));
1684 assertTrue(ja.isFloatingPointNumber("+2e-3"));
1685 assertTrue(ja.isFloatingPointNumber("+23E-34"));
1686 assertTrue(ja.isFloatingPointNumber("+23.E-34"));
1687 assertTrue(ja.isFloatingPointNumber("-23.4E+45"));
1688 assertTrue(ja.isFloatingPointNumber("1.2e34"));
1689 assertTrue(ja.isFloatingPointNumber("10.2e34"));
1690 assertTrue(ja.isFloatingPointNumber("+10.2e34"));
1691 assertTrue(ja.isFloatingPointNumber("-10.2e34"));
1692 assertTrue(ja.isFloatingPointNumber("10.2e-34"));
1693 assertTrue(ja.isFloatingPointNumber("10.2e+34"));
1694 assertTrue(ja.isFloatingPointNumber("-10.2e-34"));
1695 assertTrue(ja.isFloatingPointNumber("+10.2e+34"));
1696 assertTrue(ja.isFloatingPointNumber("-10.2E-34"));
1697 assertTrue(ja.isFloatingPointNumber("+10.2E+34"));
1698 }
1699
1700 @Test
1701 void testJexl173() {
1702 final JexlEngine jexl = new JexlBuilder().create();
1703 final JexlContext jc = new MapContext();
1704 final Callable173 c173 = new Callable173();
1705 JexlScript e = jexl.createScript("c173(9, 6)", "c173");
1706 Object result = e.execute(jc, c173);
1707 assertEquals(54, result);
1708 e = jexl.createScript("c173('fourty', 'two')", "c173");
1709 result = e.execute(jc, c173);
1710 assertEquals(42, result);
1711
1712 }
1713
1714 @Test
1715 void testLeftNullOperand() throws Exception {
1716 asserter.setVariable("left", null);
1717 asserter.setVariable("right", Integer.valueOf(8));
1718 asserter.setStrict(true);
1719 asserter.failExpression("left + right", ".*null.*");
1720 asserter.failExpression("left - right", ".*null.*");
1721 asserter.failExpression("left * right", ".*null.*");
1722 asserter.failExpression("left / right", ".*null.*");
1723 asserter.failExpression("left % right", ".*null.*");
1724 asserter.failExpression("left & right", ".*null.*");
1725 asserter.failExpression("left | right", ".*null.*");
1726 asserter.failExpression("left ^ right", ".*null.*");
1727 asserter.failExpression("left < right", ".*null.*");
1728 asserter.failExpression("left <= right", ".*null.*");
1729 asserter.failExpression("left > right", ".*null.*");
1730 asserter.failExpression("left >= right", ".*null.*");
1731 }
1732
1733 @Test
1734 void testLeftNullOperand2() throws Exception {
1735 asserter.setVariable("x.left", null);
1736 asserter.setVariable("right", Integer.valueOf(8));
1737 asserter.setStrict(true);
1738 asserter.failExpression("x.left + right", ".*null.*");
1739 asserter.failExpression("x.left - right", ".*null.*");
1740 asserter.failExpression("x.left * right", ".*null.*");
1741 asserter.failExpression("x.left / right", ".*null.*");
1742 asserter.failExpression("x.left % right", ".*null.*");
1743 asserter.failExpression("x.left & right", ".*null.*");
1744 asserter.failExpression("x.left | right", ".*null.*");
1745 asserter.failExpression("x.left ^ right", ".*null.*");
1746 asserter.failExpression("x.left < right", ".*null.*");
1747 asserter.failExpression("x.left <= right", ".*null.*");
1748 asserter.failExpression("x.left > right", ".*null.*");
1749 asserter.failExpression("x.left >= right", ".*null.*");
1750 }
1751
1752
1753 @Test
1754 void testLongLiterals() {
1755 final JexlEvalContext ctxt = new JexlEvalContext();
1756 final JexlOptions options = ctxt.getEngineOptions();
1757 options.setStrictArithmetic(true);
1758 final String stmt = "{a = 10L; b = 10l; c = 42.0D; d = 42.0d; e=56.3F; f=56.3f; g=63.5; h=0x10; i=010; j=0x10L; k=010l}";
1759 final JexlScript expr = JEXL.createScript(stmt);
1760 expr.execute(ctxt);
1761 assertEquals(10L, ctxt.get("a"));
1762 assertEquals(10L, ctxt.get("b"));
1763 assertEquals(42.0D, ctxt.get("c"));
1764 assertEquals(42.0d, ctxt.get("d"));
1765 assertEquals(56.3f, ctxt.get("e"));
1766 assertEquals(56.3f, ctxt.get("f"));
1767 assertEquals(63.5d, ctxt.get("g"));
1768 assertEquals(0x10, ctxt.get("h"));
1769 assertEquals(010, ctxt.get("i"));
1770 assertEquals(0x10L, ctxt.get("j"));
1771 assertEquals(010L, ctxt.get("k"));
1772 }
1773
1774 @Test
1775 void testMinusClass() {
1776 final JexlEngine jexl = new JexlBuilder().create();
1777 final JexlContext jc = new MapContext();
1778 final Object ra = jexl.createExpression("463.0d - 0.1").evaluate(jc);
1779 assertEquals(Double.class, ra.getClass());
1780 final Object r0 = jexl.createExpression("463.0B - 0.1").evaluate(jc);
1781 assertEquals(java.math.BigDecimal.class, r0.getClass());
1782 final Object r1 = jexl.createExpression("463.0B - 0.1B").evaluate(jc);
1783 assertEquals(java.math.BigDecimal.class, r1.getClass());
1784 }
1785
1786 @Test
1787 void testMinusMinusPostfix() throws Exception {
1788 asserter.setVariable("aByte", Byte.valueOf((byte) 2));
1789 asserter.setVariable("aShort", Short.valueOf((short) 3));
1790 asserter.setVariable("anInteger", Integer.valueOf(4));
1791 asserter.setVariable("aLong", Long.valueOf(5));
1792 asserter.setVariable("aFloat", Float.valueOf((float) 6.6));
1793 asserter.setVariable("aDouble", Double.valueOf(7.7));
1794 asserter.setVariable("aBigInteger", new BigInteger("8"));
1795 asserter.setVariable("aBigDecimal", new BigDecimal("9.9"));
1796 asserter.setVariable("aString", "forty-two");
1797
1798 asserter.assertExpression("aByte--",Byte.valueOf((byte) 2));
1799 asserter.assertExpression("aShort--", Short.valueOf((short) 3));
1800 asserter.assertExpression("anInteger--", Integer.valueOf(4));
1801 asserter.assertExpression("aLong--", Long.valueOf(5));
1802 asserter.assertExpression("aFloat--", Float.valueOf((float) 6.6));
1803 asserter.assertExpression("aDouble--", Double.valueOf(7.7));
1804 asserter.assertExpression("aBigInteger--", new BigInteger("8"));
1805 asserter.assertExpression("aBigDecimal--", new BigDecimal("9.9"));
1806
1807 asserter.assertExpression("aByte", Byte.valueOf((byte) 1));
1808 asserter.assertExpression("aShort", Short.valueOf((short) 2));
1809 asserter.assertExpression("anInteger", Integer.valueOf(3));
1810 asserter.assertExpression("aLong", Long.valueOf(4));
1811 asserter.assertExpression("aFloat", Float.valueOf((float) 5.6));
1812 asserter.assertExpression("aDouble", Double.valueOf(6.7));
1813 asserter.assertExpression("aBigInteger", new BigInteger("7"));
1814 asserter.assertExpression("aBigDecimal", new BigDecimal("8.9"));
1815
1816 asserter.failExpression("aString--", "--", String::contains);
1817 }
1818
1819 @Test
1820 void testMinusMinusPrefix() throws Exception {
1821 asserter.setVariable("aByte", Byte.valueOf((byte) 2));
1822 asserter.setVariable("aShort", Short.valueOf((short) 3));
1823 asserter.setVariable("anInteger", Integer.valueOf(4));
1824 asserter.setVariable("aLong", Long.valueOf(5));
1825 asserter.setVariable("aFloat", Float.valueOf((float) 6.6));
1826 asserter.setVariable("aDouble", Double.valueOf(7.7));
1827 asserter.setVariable("aBigInteger", new BigInteger("8"));
1828 asserter.setVariable("aBigDecimal", new BigDecimal("9.9"));
1829 asserter.setVariable("aString", "forty-two");
1830
1831 asserter.assertExpression("--aByte", Byte.valueOf((byte) 1));
1832 asserter.assertExpression("--aShort", Short.valueOf((short) 2));
1833 asserter.assertExpression("--anInteger", Integer.valueOf(3));
1834 asserter.assertExpression("--aLong", Long.valueOf(4));
1835 asserter.assertExpression("--aFloat", Float.valueOf((float) 5.6));
1836 asserter.assertExpression("--aDouble", Double.valueOf(6.7));
1837 asserter.assertExpression("--aBigInteger", new BigInteger("7"));
1838 asserter.assertExpression("--aBigDecimal", new BigDecimal("8.9"));
1839
1840 asserter.failExpression("aString--", "--", String::contains);
1841 }
1842
1843 @Test
1844 void testModEdge() {
1845 assertNullOperand(() -> jexla.mod(null, null));
1846 assertEquals(0, jexlb.mod(null, null));
1847 assertArithmeticException(() -> jexla.mod(1, 0));
1848 assertArithmeticException(() -> jexla.mod(1L, 0L));
1849 assertArithmeticException(() -> jexla.mod(1f, 0f));
1850 assertArithmeticException(() -> jexla.mod(1d, 0d));
1851 assertArithmeticException(() -> jexla.mod(BigInteger.ONE, BigInteger.ZERO));
1852 assertArithmeticException(() -> jexla.mod(BigInteger.ONE, BigDecimal.ZERO));
1853 assertNullOperand(() -> jexla.divide(null, null));
1854 }
1855
1856
1857
1858
1859 @Test
1860 void testMultClass(){
1861 final JexlEngine jexl = new JexlBuilder().create();
1862 final JexlContext jc = new MapContext();
1863 final Object ra = jexl.createExpression("463.0d * 0.1").evaluate(jc);
1864 assertEquals(Double.class, ra.getClass());
1865 final Object r0 = jexl.createExpression("463.0B * 0.1").evaluate(jc);
1866 assertEquals(java.math.BigDecimal.class, r0.getClass());
1867 final Object r1 = jexl.createExpression("463.0B * 0.1B").evaluate(jc);
1868 assertEquals(java.math.BigDecimal.class, r1.getClass());
1869 }
1870
1871 @Test
1872 void testNaN() {
1873 final Map<String, Object> ns = new HashMap<>();
1874 ns.put("double", Double.class);
1875 final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
1876 JexlScript script;
1877 Object result;
1878 script = jexl.createScript("#NaN");
1879 result = script.execute(null);
1880 assertTrue(Double.isNaN((Double) result));
1881 script = jexl.createScript("NaN");
1882 result = script.execute(null);
1883 assertTrue(Double.isNaN((Double) result));
1884 script = jexl.createScript("double:isNaN(#NaN)");
1885 result = script.execute(null);
1886 assertTrue((Boolean) result);
1887 script = jexl.createScript("double:isNaN(NaN)");
1888 result = script.execute(null);
1889 assertTrue((Boolean) result);
1890 }
1891
1892 @Test
1893 void testNarrowBigDecimal() throws Exception {
1894 final List<String> ls = Arrays.asList("zero", "one", "two");
1895 asserter.setVariable("list", ls);
1896 asserter.assertExpression("a -> list.get(a)", "zero", BigDecimal.ZERO);
1897 asserter.assertExpression("a -> list.get(a)", "one", BigDecimal.ONE);
1898 asserter.assertExpression("a -> list.get(2B)", "two");
1899 final BigDecimal bd42 = BigDecimal.valueOf(42);
1900 asserter.setVariable("bd10", BigDecimal.valueOf(10d));
1901 asserter.setVariable("bd420",BigDecimal.valueOf(420d));
1902 asserter.assertExpression("420 / bd10", bd42);
1903 asserter.assertExpression("420l / bd10", bd42);
1904 asserter.assertExpression("420H / bd10", bd42);
1905 asserter.assertExpression("bd420 / 10", bd42);
1906 asserter.assertExpression("bd420 / 10H", bd42);
1907 asserter.assertExpression("bd420 / 10B", bd42);
1908 }
1909
1910 @Test
1911 void testNarrowBigInteger() throws Exception {
1912 final List<String> ls = Arrays.asList("zero", "one", "two");
1913 asserter.setVariable("list",ls);
1914 asserter.assertExpression("a -> list.get(a)", "zero", BigInteger.ZERO);
1915 asserter.assertExpression("a -> list.get(a)", "one", BigInteger.ONE);
1916 asserter.assertExpression("a -> list.get(2H)", "two");
1917 final BigInteger b42 = BigInteger.valueOf(42);
1918 asserter.setVariable("bi10", BigInteger.valueOf(10));
1919 asserter.setVariable("bi420", BigInteger.valueOf(420));
1920 asserter.assertExpression("420 / bi10", b42);
1921 asserter.assertExpression("420l / bi10", b42);
1922 asserter.assertExpression("bi420 / 420", BigInteger.ONE);
1923 asserter.assertExpression("bi420 / 420l", BigInteger.ONE);
1924 asserter.assertExpression("bi420 / 420H", BigInteger.ONE);
1925 }
1926
1927 @Test
1928 void testNullArgs() {
1929 final JexlEngine jexl = new JexlBuilder().arithmetic(new JexlArithmetic(true) {
1930 @Override public boolean isStrict(final JexlOperator op) {
1931 return JexlOperator.ADD != op && super.isStrict(op);
1932 }
1933 }).create();
1934 final JexlScript script = jexl.createScript("'1.2' + x ", "x");
1935 final Object result = script.execute(null);
1936 assertEquals("1.2", result);
1937 }
1938
1939 @Test
1940 void testNullOperand() throws Exception {
1941 asserter.setVariable("right", null);
1942 asserter.failExpression("~right", ".*null.*");
1943 }
1944
1945 @Test
1946 void testNullOperands() throws Exception {
1947 asserter.setVariable("left", null);
1948 asserter.setVariable("right", null);
1949 asserter.failExpression("left + right", ".*null.*");
1950 asserter.failExpression("left - right", ".*null.*");
1951 asserter.failExpression("left * right", ".*null.*");
1952 asserter.failExpression("left / right", ".*null.*");
1953 asserter.failExpression("left % right", ".*null.*");
1954 asserter.failExpression("left & right", ".*null.*");
1955 asserter.failExpression("left | right", ".*null.*");
1956 asserter.failExpression("left ^ right", ".*null.*");
1957 }
1958
1959 @Test
1960 void testOperatorsEdges() {
1961 assertNullOperand(() -> jexla.multiply(null, null));
1962 assertEquals(0, jexlb.multiply(null, null));
1963 assertNullOperand(() -> jexla.add(null, null));
1964 assertEquals(0, jexlb.add(null, null));
1965 assertNullOperand(() -> jexla.subtract(null, null));
1966 assertEquals(0, jexlb.subtract(null, null));
1967
1968 assertTrue(jexla.contains(null, null));
1969 assertFalse(jexla.contains(true, null));
1970 assertFalse(jexla.contains(null, true));
1971 assertTrue(jexla.endsWith(null, null));
1972 assertFalse(jexla.endsWith(true, null));
1973 assertFalse(jexla.endsWith(null, true));
1974 assertTrue(jexla.startsWith(null, null));
1975 assertFalse(jexla.startsWith(true, null));
1976 assertFalse(jexla.startsWith(null, true));
1977 assertTrue(jexla.isEmpty(null));
1978 }
1979
1980 @Test
1981 void testOption() {
1982 final Map<String, Object> vars = new HashMap<>();
1983 final JexlEvalContext context = new JexlEvalContext(vars);
1984 final JexlOptions options = context.getEngineOptions();
1985 options.setStrictArithmetic(true);
1986 final JexlScript script = JEXL.createScript("0 + '1.2' ");
1987 Object result;
1988
1989 options.setStrictArithmetic(true);
1990 result = script.execute(context);
1991 assertEquals("01.2", result);
1992
1993 options.setStrictArithmetic(false);
1994 result = script.execute(context);
1995 assertEquals(1.2d, (Double) result, EPSILON);
1996 }
1997
1998 @Test
1999 void testOverflows() throws Exception {
2000 asserter.assertExpression("1 + 2147483647", Long.valueOf("2147483648"));
2001 asserter.assertExpression("3 + " + (Long.MAX_VALUE - 2), BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE));
2002 asserter.assertExpression("-2147483648 - 1", Long.valueOf("-2147483649"));
2003 asserter.assertExpression("-3 + " + (Long.MIN_VALUE + 2), BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE));
2004 asserter.assertExpression("1 + 9223372036854775807", new BigInteger("9223372036854775808"));
2005 asserter.assertExpression("-1 + (-9223372036854775808)", new BigInteger("-9223372036854775809"));
2006 asserter.assertExpression("-9223372036854775808 - 1", new BigInteger("-9223372036854775809"));
2007 final BigInteger maxl = BigInteger.valueOf(Long.MAX_VALUE);
2008 asserter.assertExpression(maxl + " * " + maxl , maxl.multiply(maxl));
2009 }
2010
2011 @Test
2012 void testPlusClass() {
2013 final JexlEngine jexl = new JexlBuilder().create();
2014 final JexlContext jc = new MapContext();
2015 final Object ra = jexl.createExpression("463.0d + 0.1").evaluate(jc);
2016 assertEquals(Double.class, ra.getClass());
2017 final Object r0 = jexl.createExpression("463.0B + 0.1").evaluate(jc);
2018 assertEquals(java.math.BigDecimal.class, r0.getClass());
2019 final Object r1 = jexl.createExpression("463.0B + 0.1B").evaluate(jc);
2020 assertEquals(java.math.BigDecimal.class, r1.getClass());
2021 }
2022
2023 @Test
2024 void testPlusPlusPostfix() throws Exception {
2025 asserter.setVariable("aByte", Byte.valueOf((byte) 0));
2026 asserter.setVariable("aShort", Short.valueOf((short) 1));
2027 asserter.setVariable("anInteger", Integer.valueOf(2));
2028 asserter.setVariable("aLong", Long.valueOf(3));
2029 asserter.setVariable("aFloat", Float.valueOf((float) 4.4));
2030 asserter.setVariable("aDouble", Double.valueOf(5.5));
2031 asserter.setVariable("aBigInteger", new BigInteger("6"));
2032 asserter.setVariable("aBigDecimal", new BigDecimal("7.7"));
2033 asserter.setVariable("aString", "forty-two");
2034
2035 asserter.assertExpression("aByte++", Byte.valueOf((byte) 0));
2036 asserter.assertExpression("aShort++", Short.valueOf((short) 1));
2037 asserter.assertExpression("anInteger++", Integer.valueOf(2));
2038 asserter.assertExpression("aLong++", Long.valueOf(3));
2039 asserter.assertExpression("aFloat++", Float.valueOf((float) 4.4));
2040 asserter.assertExpression("aDouble++", Double.valueOf(5.5));
2041 asserter.assertExpression("aBigInteger++", new BigInteger("6"));
2042 asserter.assertExpression("aBigDecimal++", new BigDecimal("7.7"));
2043
2044 asserter.assertExpression("aByte", Byte.valueOf((byte) 1));
2045 asserter.assertExpression("aShort", Short.valueOf((short) 2));
2046 asserter.assertExpression("anInteger", Integer.valueOf(3));
2047 asserter.assertExpression("aLong", Long.valueOf(4));
2048 asserter.assertExpression("aFloat", Float.valueOf((float) 5.4));
2049 asserter.assertExpression("aDouble", Double.valueOf(6.5));
2050 asserter.assertExpression("aBigInteger", new BigInteger("7"));
2051 asserter.assertExpression("aBigDecimal", new BigDecimal("8.7"));
2052
2053 asserter.failExpression("aString++", "++", String::contains);
2054 }
2055
2056 @Test
2057 void testPlusPlusPrefix() throws Exception {
2058 asserter.setVariable("aByte", Byte.valueOf((byte) 0));
2059 asserter.setVariable("aShort", Short.valueOf((short) 1));
2060 asserter.setVariable("anInteger", Integer.valueOf(2));
2061 asserter.setVariable("aLong", Long.valueOf(3));
2062 asserter.setVariable("aFloat", Float.valueOf((float) 4.4));
2063 asserter.setVariable("aDouble", Double.valueOf(5.5));
2064 asserter.setVariable("aBigInteger", new BigInteger("6"));
2065 asserter.setVariable("aBigDecimal", new BigDecimal("7.7"));
2066 asserter.setVariable("aString", "forty-two");
2067
2068 asserter.assertExpression("++aByte", Byte.valueOf((byte) 1));
2069 asserter.assertExpression("++aShort", Short.valueOf((short) 2));
2070 asserter.assertExpression("++anInteger", Integer.valueOf(3));
2071 asserter.assertExpression("++aLong", Long.valueOf(4));
2072 asserter.assertExpression("++aFloat", Float.valueOf((float) 5.4));
2073 asserter.assertExpression("++aDouble", Double.valueOf(6.5));
2074 asserter.assertExpression("++aBigInteger", new BigInteger("7"));
2075 asserter.assertExpression("++aBigDecimal", new BigDecimal("8.7"));
2076
2077 asserter.failExpression("++aString", "++", String::contains);
2078 }
2079
2080 @Test
2081 void testRealCoercionEdges() throws Exception {
2082 assertNullOperand(() -> jexla.toDouble(null));
2083 assertEquals(0.0d, jexlb.toDouble(null), EPSILON);
2084 assertEquals(32.0d, jexlb.toDouble((char) 32), EPSILON);
2085 assertArithmeticException(() -> jexla.toDouble(date));
2086 assertTrue(Double.isNaN(jexla.toDouble("")));
2087 assertEquals("", jexla.toString(Double.NaN));
2088
2089 assertNullOperand(() -> jexla.toBigInteger(null));
2090 assertArithmeticException(() -> jexla.toBigInteger(date));
2091 assertEquals(BigInteger.ZERO, jexla.toBigInteger(Double.NaN));
2092 assertEquals(BigInteger.ZERO, jexla.toBigInteger(""));
2093 assertEquals(BigInteger.ZERO, jexla.toBigInteger((char) 0));
2094
2095 assertNullOperand(() -> jexla.toBigDecimal(null));
2096 assertArithmeticException(() -> jexla.toBigDecimal(date));
2097
2098 assertEquals(BigDecimal.ZERO, jexla.toBigDecimal(Double.NaN));
2099 assertEquals(BigDecimal.ZERO, jexla.toBigDecimal(""));
2100 assertEquals(BigDecimal.ZERO, jexla.toBigDecimal((char) 0));
2101
2102 final Double d64d3 = Double.valueOf(6.4 / 3);
2103 assertEquals(d64d3, ((Number) JEXL.createExpression("6.4 / 3").evaluate(null)).doubleValue(), EPSILON);
2104 asserter.assertExpression("6.4 / 3", d64d3);
2105 assertEquals(d64d3, ((Number) JEXL.createExpression("6.4 / 3d").evaluate(null)).doubleValue(), EPSILON);
2106 asserter.assertExpression("6.4 / 3d", d64d3);
2107 assertEquals(64d / 3, ((Number) JEXL.createExpression("64d / 3").evaluate(null)).doubleValue(), EPSILON);
2108 asserter.assertExpression("64 / 3d", 64 / 3d);
2109 }
2110
2111 @Test
2112 void testRightNullOperand() throws Exception {
2113 asserter.setVariable("left", Integer.valueOf(9));
2114 asserter.setVariable("right", null);
2115 asserter.failExpression("left + right", ".*null.*");
2116 asserter.failExpression("left - right", ".*null.*");
2117 asserter.failExpression("left * right", ".*null.*");
2118 asserter.failExpression("left / right", ".*null.*");
2119 asserter.failExpression("left % right", ".*null.*");
2120 asserter.failExpression("left & right", ".*null.*");
2121 asserter.failExpression("left | right", ".*null.*");
2122 asserter.failExpression("left ^ right", ".*null.*");
2123 asserter.failExpression("left < right", ".*null.*");
2124 asserter.failExpression("left <= right", ".*null.*");
2125 asserter.failExpression("left > right", ".*null.*");
2126 asserter.failExpression("left >= right", ".*null.*");
2127 }
2128
2129 @Test
2130 void testRightNullOperand2() throws Exception {
2131 asserter.setVariable("left", Integer.valueOf(9));
2132 asserter.setVariable("y.right", null);
2133 asserter.failExpression("left + y.right", ".*null.*");
2134 asserter.failExpression("left - y.right", ".*null.*");
2135 asserter.failExpression("left * y.right", ".*null.*");
2136 asserter.failExpression("left / y.right", ".*null.*");
2137 asserter.failExpression("left % y.right", ".*null.*");
2138 asserter.failExpression("left & y.right", ".*null.*");
2139 asserter.failExpression("left | y.right", ".*null.*");
2140 asserter.failExpression("left ^ y.right", ".*null.*");
2141 asserter.failExpression("left < y.right", ".*null.*");
2142 asserter.failExpression("left <= y.right", ".*null.*");
2143 asserter.failExpression("left > y.right", ".*null.*");
2144 asserter.failExpression("left >= y.right", ".*null.*");
2145 }
2146
2147
2148
2149
2150 @Test
2151 void testUnaryMinus() throws Exception {
2152 asserter.setVariable("aByte", Byte.valueOf((byte) 1));
2153 asserter.setVariable("aShort", Short.valueOf((short) 2));
2154 asserter.setVariable("anInteger", Integer.valueOf(3));
2155 asserter.setVariable("aLong", Long.valueOf(4));
2156 asserter.setVariable("aFloat", Float.valueOf((float) 5.5));
2157 asserter.setVariable("aDouble", Double.valueOf(6.6));
2158 asserter.setVariable("aBigInteger", new BigInteger("7"));
2159 asserter.setVariable("aBigDecimal", new BigDecimal("8.8"));
2160
2161
2162 for(int i = 0 ; i < 2; ++i) {
2163 asserter.assertExpression("-3", Integer.valueOf("-3"));
2164 asserter.assertExpression("-3.0", Double.valueOf("-3.0"));
2165 asserter.assertExpression("-aByte", Byte.valueOf((byte) -1));
2166 asserter.assertExpression("-aShort", Short.valueOf((short) -2));
2167 asserter.assertExpression("-anInteger", Integer.valueOf(-3));
2168 asserter.assertExpression("-aLong", Long.valueOf(-4));
2169 asserter.assertExpression("-aFloat", Float.valueOf((float) -5.5));
2170 asserter.assertExpression("-aDouble", Double.valueOf(-6.6));
2171 asserter.assertExpression("-aBigInteger", new BigInteger("-7"));
2172 asserter.assertExpression("-aBigDecimal", new BigDecimal("-8.8"));
2173 }
2174 }
2175
2176 @Test
2177 void testUnaryopsEdges() {
2178 assertArithmeticException(() -> jexla.positivize(date));
2179 assertNullOperand(() -> jexla.positivize(null));
2180 assertNull(jexlb.positivize(null));
2181 assertEquals(42, jexla.positivize((char) 42));
2182 assertEquals(Boolean.TRUE, jexla.positivize(Boolean.TRUE));
2183 assertEquals(Boolean.FALSE, jexla.positivize(Boolean.FALSE));
2184 assertEquals(Boolean.TRUE, jexla.positivize(new AtomicBoolean(true)));
2185 assertEquals(Boolean.FALSE, jexla.positivize(new AtomicBoolean()));
2186
2187 assertNullOperand(() -> jexla.negate(null));
2188 assertNull(jexlb.negate(null));
2189 assertArithmeticException(() -> jexla.negate(date));
2190 assertEquals(Boolean.FALSE, jexla.negate(Boolean.TRUE));
2191 assertEquals(Boolean.TRUE, jexla.negate(Boolean.FALSE));
2192 }
2193
2194
2195
2196
2197 @Test
2198 void testUnaryPlus() throws Exception {
2199 asserter.setVariable("aByte", Byte.valueOf((byte) 1));
2200 asserter.setVariable("aShort", Short.valueOf((short) 2));
2201 asserter.setVariable("anInteger", Integer.valueOf(3));
2202 asserter.setVariable("aLong", Long.valueOf(4));
2203 asserter.setVariable("aFloat", Float.valueOf((float) 5.5));
2204 asserter.setVariable("aDouble", Double.valueOf(6.6));
2205 asserter.setVariable("aBigInteger", new BigInteger("7"));
2206 asserter.setVariable("aBigDecimal", new BigDecimal("8.8"));
2207
2208
2209 for(int i = 0 ; i < 2; ++i) {
2210 asserter.assertExpression("+3", Integer.valueOf("3"));
2211 asserter.assertExpression("+3.0", Double.valueOf("3.0"));
2212 asserter.assertExpression("+aByte", Integer.valueOf(1));
2213 asserter.assertExpression("+aShort", Integer.valueOf(2));
2214 asserter.assertExpression("+anInteger", Integer.valueOf(3));
2215 asserter.assertExpression("+aLong", Long.valueOf(4));
2216 asserter.assertExpression("+aFloat", Float.valueOf((float) 5.5));
2217 asserter.assertExpression("+aDouble", Double.valueOf(6.6));
2218 asserter.assertExpression("+aBigInteger", new BigInteger("7"));
2219 asserter.assertExpression("+aBigDecimal", new BigDecimal("8.8"));
2220 }
2221 }
2222
2223 @Test
2224 void testUndefinedVar() throws Exception {
2225 asserter.failExpression("objects[1].status", ".*variable 'objects' is undefined.*");
2226 }
2227
2228
2229
2230
2231 @Test
2232 void testXmlArithmetic() throws Exception {
2233 Document xml;
2234 Node x;
2235 Boolean empty;
2236 int size;
2237 final JexlEvalContext ctxt = new JexlEvalContext();
2238 final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).arithmetic(new XmlArithmetic(false)).create();
2239 final JexlScript e0 = jexl.createScript("x.empty()", "x");
2240 final JexlScript e1 = jexl.createScript("empty(x)", "x");
2241 final JexlScript s0 = jexl.createScript("x.size()", "x");
2242 final JexlScript s1 = jexl.createScript("size(x)", "x");
2243
2244 empty = (Boolean) e1.execute(null, (Object) null);
2245 assertTrue(empty);
2246 size = (Integer) s1.execute(null, (Object) null);
2247 assertEquals(0, size);
2248
2249 try {
2250 final Object xx = e0.execute(null, (Object) null);
2251 assertNull(xx);
2252 } catch (final JexlException.Variable xvar) {
2253 assertNotNull(xvar);
2254 }
2255 try {
2256 final Object xx = s0.execute(null, (Object) null);
2257 assertNull(xx);
2258 } catch (final JexlException.Variable xvar) {
2259 assertNotNull(xvar);
2260 }
2261 final JexlOptions options = ctxt.getEngineOptions();
2262 options.setSafe(true);
2263 final Object x0 = e0.execute(ctxt, (Object) null);
2264 assertNull(x0);
2265 final Object x1 = s0.execute(ctxt, (Object) null);
2266 assertNull(x1);
2267
2268 xml = getDocument("<node info='123'/>");
2269 x = xml.getLastChild();
2270 empty = (Boolean) e0.execute(null, x);
2271 assertFalse(empty);
2272 empty = (Boolean) e1.execute(null, x);
2273 assertFalse(empty);
2274 size = (Integer) s0.execute(null, x);
2275 assertEquals(0, size);
2276 size = (Integer) s1.execute(null, x);
2277 assertEquals(0, size);
2278 xml = getDocument("<node><a/><b/></node>");
2279 x = xml.getLastChild();
2280 empty = (Boolean) e0.execute(null, x);
2281 assertFalse(empty);
2282 empty = (Boolean) e1.execute(null, x);
2283 assertFalse(empty);
2284 size = (Integer) s0.execute(null, x);
2285 assertEquals(2, size);
2286 size = (Integer) s1.execute(null, x);
2287 assertEquals(2, size);
2288 xml = getDocument("<node/>");
2289 x = xml.getLastChild();
2290 empty = (Boolean) e0.execute(null, x);
2291 assertTrue(empty);
2292 empty = (Boolean) e1.execute(null, x);
2293 assertTrue(empty);
2294 size = (Integer) s0.execute(null, x);
2295 assertEquals(0, size);
2296 size = (Integer) s1.execute(null, x);
2297 assertEquals(0, size);
2298 xml = getDocument("<node info='123'/>");
2299 NamedNodeMap nnm = xml.getLastChild().getAttributes();
2300 Attr info = (Attr) nnm.getNamedItem("info");
2301 assertEquals("123", info.getValue());
2302
2303
2304 final JexlContext jc = new MapContext();
2305 final Object xmlx = xml.getLastChild();
2306 jc.set("x", xmlx);
2307 final String y = "456";
2308 jc.set("y", y);
2309 final JexlScript s = jexl.createScript("x.attributes.info = y");
2310 Object r;
2311 try {
2312 nnm = xml.getLastChild().getAttributes();
2313 info = (Attr) nnm.getNamedItem("info");
2314 r = s.execute(jc);
2315 assertEquals(y, r);
2316 assertEquals(y, info.getValue());
2317 } catch (final JexlException.Property xprop) {
2318
2319 assertTrue(xprop.getMessage().contains("attribute"));
2320 assertTrue(getJavaVersion() > 11, getJavaVersion() + " >? 11");
2321 }
2322 }
2323
2324 @Test void testShortCircuitAnd() {
2325 final String src = "(x, y, z) -> x && y && z";
2326 final JexlBuilder builder = new JexlBuilder();
2327 final JexlEngine jexl = builder.create();
2328 JexlScript script;
2329 Object result;
2330 script = jexl.createScript(src);
2331 result = script.execute(null, true, "foo", 42);
2332 assertEquals(42, result);
2333 result = script.execute(null, true, "", 42);
2334 assertEquals("", result);
2335 }
2336
2337 @Test void testShortCircuitOr() {
2338 final OptContext optc = new OptContext();
2339 final String src = "(x, y, z) -> x || y || z";
2340 final JexlBuilder builder = new JexlBuilder();
2341 final JexlEngine jexl = builder.create();
2342 final JexlOptions options = builder.options();
2343 optc.setOptions(options);
2344 JexlScript script;
2345 Object result;
2346 script = jexl.createScript(src);
2347 result = script.execute(optc, 0, "", 42);
2348 assertEquals(42, result);
2349 result = script.execute(optc, true, 42, null);
2350 assertEquals(true, result);
2351
2352 options.setBooleanLogical(true);
2353 result = script.execute(optc, 0, "", Double.NaN);
2354 assertEquals(false, result);
2355 result = script.execute(optc, 0, "", Collections.emptySet());
2356 assertEquals(true, result);
2357
2358 }
2359
2360 @Test void testLogicalValue() {
2361 final String src = "function sanitize(const n) { n == 0 ? NaN : n }; sanitize(x) && 420 / x";
2362 final JexlEngine jexl = new JexlBuilder().create();
2363 JexlScript script;
2364 Object result;
2365 script = jexl.createScript(src, "x");
2366 result = script.execute(null, 10);
2367 assertEquals(42, result);
2368 result = script.execute(null, 0);
2369 assertTrue(Double.isNaN(((Number) result).doubleValue()));
2370 }
2371
2372 public static class OptContext extends MapContext implements JexlContext.OptionsHandle {
2373 private JexlOptions options;
2374
2375 @Override
2376 public JexlOptions getEngineOptions() {
2377 return options;
2378 }
2379
2380 void setOptions(final JexlOptions options) {
2381 this.options = options;
2382 }
2383 }
2384
2385 @Test void testLeadingDotFloatLiteral() {
2386 final JexlEngine jexl = new JexlBuilder().create();
2387 final JexlContext jc = new MapContext();
2388
2389 assertEquals(2.2d, jexl.createExpression("(1+.1)*2").evaluate(jc));
2390
2391 assertEquals(2.2d, jexl.createExpression("(1+0.1)*2").evaluate(jc));
2392
2393 assertEquals(0.1d, jexl.createExpression(".1").evaluate(jc));
2394 assertEquals(1.0d, jexl.createExpression(".5 + .5").evaluate(jc));
2395 assertEquals(0.55d, jexl.createExpression(".55").evaluate(jc));
2396 assertEquals(0.1d, jexl.createExpression("-.1 + .2").evaluate(jc));
2397 assertEquals(-0.1d, jexl.createExpression(".1 + -.2").evaluate(jc));
2398 assertEquals(0.1d, jexl.createExpression("-.1+.2").evaluate(jc));
2399 assertEquals(-0.1d, jexl.createExpression(".1+-.2").evaluate(jc));
2400 assertEquals(1.4d, jexl.createExpression(".5 - -.9").evaluate(jc));
2401 assertEquals(0.4d, jexl.createExpression("-.5 - -.9").evaluate(jc));
2402 assertEquals(-1.4d, jexl.createExpression("-.5+-.9").evaluate(jc));
2403
2404 assertEquals(-0.1d, jexl.createExpression("-.1").evaluate(jc));
2405 assertEquals(0.1d, jexl.createExpression("+.1").evaluate(jc));
2406
2407 final List<Object> array = new java.util.ArrayList<>();
2408 array.add("zero");
2409 array.add("one");
2410 jc.set("array", array);
2411 assertEquals("zero", jexl.createExpression("array.0").evaluate(jc));
2412 assertEquals("one", jexl.createExpression("array.1").evaluate(jc));
2413 }
2414
2415
2416
2417
2418
2419
2420 @Test
2421 void testBigIntegerLiteralTooLong() {
2422
2423 assertNotNull(JEXL.createScript("42H"));
2424
2425 final char[] digits = new char[JexlArithmetic.MAX_BIGINTEGER_DIGITS + 1];
2426 java.util.Arrays.fill(digits, '1');
2427 final String huge = new String(digits) + "H";
2428 assertThrows(JexlException.Parsing.class, () -> JEXL.createScript(huge));
2429 }
2430
2431
2432
2433
2434 @Test
2435 void testBigIntegerArithmeticPrecisionCap() {
2436
2437 final JexlArithmetic bounded = new JexlArithmetic(true, new MathContext(3), JexlArithmetic.BIGD_SCALE);
2438 final JexlEngine jexl = new JexlBuilder().arithmetic(bounded).create();
2439
2440 assertEquals(new BigInteger("3"), jexl.createScript("a + b", "a", "b")
2441 .execute(null, BigInteger.ONE, BigInteger.valueOf(2L)));
2442
2443 assertThrows(JexlException.class, () ->
2444 jexl.createScript("a + b", "a", "b")
2445 .execute(null, BigInteger.valueOf(1500L), BigInteger.valueOf(1000L)));
2446
2447 assertThrows(JexlException.class, () ->
2448 jexl.createScript("a * b", "a", "b")
2449 .execute(null, BigInteger.valueOf(64L), BigInteger.valueOf(64L)));
2450 }
2451
2452
2453
2454
2455 @Test
2456 void testRegexPatternTooLong() {
2457 final JexlEngine jexl = new JexlBuilder().strict(true).create();
2458 final JexlScript script = jexl.createScript("x =~ y", "x", "y");
2459 final char[] chars = new char[JexlArithmetic.REGEX_PATTERN_MAX_LENGTH + 1];
2460 java.util.Arrays.fill(chars, 'a');
2461 final String longPattern = new String(chars);
2462 assertThrows(JexlException.class, () -> script.execute(null, "abc", longPattern));
2463 }
2464
2465
2466
2467
2468
2469 @Test
2470 void testRegexMatchingInterruptible() throws InterruptedException {
2471 final JexlEngine jexl = new JexlBuilder().cancellable(true).create();
2472 final JexlScript script = jexl.createScript("x =~ y", "x", "y");
2473 final String evilPattern = "(a+)+b";
2474
2475 for (int size = 256; size <= 4096; size *= 2) {
2476 final char[] chars = new char[size];
2477 java.util.Arrays.fill(chars, 'a');
2478 final String evilValue = new String(chars) + "c";
2479
2480 final AtomicReference<Throwable> caught = new AtomicReference<>();
2481 final CountDownLatch started = new CountDownLatch(1);
2482 final Thread t = new Thread(() -> {
2483 try {
2484 started.countDown();
2485 script.execute(null, evilValue, evilPattern);
2486 } catch (final Throwable e) {
2487 caught.set(e);
2488 }
2489 });
2490
2491 t.start();
2492 started.await();
2493
2494 final long deadline = System.nanoTime() + java.util.concurrent.TimeUnit.SECONDS.toNanos(5);
2495 while (t.isAlive() && System.nanoTime() < deadline) {
2496 t.interrupt();
2497 Thread.yield();
2498 t.join(10L);
2499 }
2500
2501 assertFalse(t.isAlive(), "Thread should have completed after interruption (regex should be interruptible)");
2502
2503 final Throwable thrown = caught.get();
2504 if (thrown instanceof JexlException.Cancel) {
2505 return;
2506 }
2507 if (thrown != null) {
2508 fail("Expected JexlException.Cancel when interrupted during matching, got "
2509 + thrown.getClass().getSimpleName(), thrown);
2510 }
2511 }
2512
2513 fail("Did not observe JexlException.Cancel during interrupted regex matching");
2514 }
2515 }