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