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.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import org.apache.commons.jexl3.introspection.JexlMethod;
31 import org.apache.commons.jexl3.introspection.JexlPropertyGet;
32 import org.apache.commons.jexl3.introspection.JexlPropertySet;
33 import org.apache.commons.jexl3.introspection.JexlUberspect;
34 import org.apache.commons.jexl3.junit.Asserter;
35 import org.junit.jupiter.api.BeforeEach;
36 import org.junit.jupiter.api.Test;
37
38
39
40
41 @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
42 class MethodTest extends JexlTestCase {
43 public static class ContextualFunctor {
44 private final EnhancedContext context;
45
46 public ContextualFunctor(final EnhancedContext theContext) {
47 context = theContext;
48 }
49
50 public int ratio(final int n) {
51 context.factor -= 1;
52 return n / context.factor;
53 }
54 }
55 public static class Edge {
56 private Edge() {
57 }
58
59 public int exec(final Boolean x, final int arg) {
60 return 1;
61 }
62
63 public int exec(final Boolean x, final int[] arg) {
64 return 20;
65 }
66
67 public int exec(final Boolean x, final Object args) {
68 return 3;
69 }
70
71 public int exec(final Boolean x, final Object... args) {
72 return 4;
73 }
74
75 public int exec(final Boolean x, final String arg) {
76 return 2;
77 }
78
79 public int exec(final int arg) {
80 return 1;
81 }
82
83 public int exec(final int[] arg) {
84 return 20;
85 }
86
87 public int exec(final Object args) {
88 return 3;
89 }
90
91 public int exec(final Object... args) {
92 return 4;
93 }
94
95 public int exec(final String arg) {
96 return 2;
97 }
98
99 public int exec(final String... arg) {
100 return 200;
101 }
102
103 public Class<?>[] execute(final Object... args) {
104 final Class<?>[] clazz = new Class<?>[args.length];
105 for (int a = 0; a < args.length; ++a) {
106 clazz[a] = args[a] != null ? args[a].getClass() : Void.class;
107 }
108 return clazz;
109 }
110 }
111
112 public static class EnhancedContext extends JexlEvalContext {
113 int factor = 6;
114 final Map<String, Object> funcs;
115
116 EnhancedContext(final Map<String, Object> funcs) {
117 this.funcs = funcs;
118 }
119
120 @Override
121 public Object resolveNamespace(final String name) {
122 return funcs.get(name);
123 }
124 }
125
126 public static class Functor {
127 public static Class<?> NPEIfNull(final Object x) {
128 return x.getClass();
129 }
130 public static int PLUS20(final int num) {
131 return num + 20;
132 }
133
134 public static int TWENTY() {
135 return 20;
136 }
137
138 private boolean overKill;
139
140 private String under;
141
142 public String getUnder() {
143 if (overKill) {
144 throw new UnsupportedOperationException("kill " + under);
145 }
146 return under;
147 }
148
149 public Object over(final String f, final Date g) {
150 return f + " + " + g;
151 }
152
153 public Object over(final String f, final int i) {
154 if (overKill) {
155 throw new UnsupportedOperationException("kill " + f + " + " + i);
156 }
157 return f + " + " + i;
158 }
159
160 public Object over(final String f, final String g) {
161 return f + " + " + g;
162 }
163
164 public int plus10(final int num) {
165 return num + 10;
166 }
167
168 void setKill(final boolean ok) {
169 overKill = ok;
170 }
171
172 public void setUnder(final String str) {
173 if (overKill) {
174 throw new UnsupportedOperationException("kill " + str);
175 }
176 under = str;
177 }
178
179 public int ten() {
180 return 10;
181 }
182 }
183
184 public static class FunctorOver extends Functor {
185
186 public Object over(final Object f, final Object g) {
187 return f + " + " + g;
188 }
189 }
190
191 public static class MyMath {
192 public double cos(final double x) {
193 return Math.cos(x);
194 }
195 }
196
197 public static class ScriptContext extends MapContext implements JexlContext.NamespaceResolver {
198 Map<String, Object> nsScript;
199
200 ScriptContext(final Map<String, Object> ns) {
201 nsScript = ns;
202 }
203
204 @Override
205 public Object resolveNamespace(final String name) {
206 if (name == null) {
207 return this;
208 }
209 if ("script".equals(name)) {
210 return nsScript;
211 }
212 if ("functor".equals(name)) {
213 return (NamespaceFunctor) context -> {
214 final Map<String, Object> values = new HashMap<>();
215 if ("gin".equals(context.get("base"))) {
216 values.put("drink", "gin fizz");
217 } else {
218 values.put("drink", "champaign");
219 }
220 return values;
221 };
222 }
223 return null;
224 }
225 }
226
227 public static class VarArgs {
228 public String callInts() {
229 final int result = -5000;
230 return "Varargs:" + result;
231 }
232
233 public String callInts(final Integer... args) {
234 int result = 0;
235 if (args != null) {
236 for (final Integer arg : args) {
237 result += arg != null ? arg : -100;
238 }
239 } else {
240 result = -1000;
241 }
242 return "Varargs:" + result;
243 }
244
245 public String callMixed(final Integer fixed, final Integer... args) {
246 int result = fixed;
247 if (args != null) {
248 for (final Integer arg : args) {
249 result += arg != null ? arg : -100;
250 }
251 } else {
252 result -= 1000;
253 }
254 return "Mixed:" + result;
255 }
256
257 public String callMixed(final String mixed, final Integer... args) {
258 int result = 0;
259 if (args != null) {
260 for (final Integer arg : args) {
261 result += arg != null ? arg : -100;
262 }
263 } else {
264 result = -1000;
265 }
266 return mixed + ":" + result;
267 }
268
269 public String concat(final String... strs) {
270 if (strs.length <= 0) {
271 return "";
272 }
273 final StringBuilder strb = new StringBuilder(strs[0]);
274 for (int s = 1; s < strs.length; ++s) {
275 strb.append(", ");
276 strb.append(strs[s]);
277 }
278 return strb.toString();
279 }
280 }
281
282 public static class ZArithmetic extends JexlArithmetic {
283 public ZArithmetic(final boolean astrict) {
284 super(astrict);
285 }
286
287 public int zzzz(final int z) {
288 return 38 + z;
289 }
290 }
291
292 public static class ZContext extends MapContext {
293 public ZContext(final Map<String,Object> map) {
294 super(map);
295 }
296
297 public int z(final int z) {
298 return 181 + z;
299 }
300
301 public int zz(final int z) {
302 return 40 + z;
303 }
304 }
305
306 public static class ZSpace {
307 public int zzz(final int z) {
308 return 39 + z;
309 }
310 }
311
312 private static final String METHOD_STRING = "Method string";
313
314 private Asserter asserter;
315
316 public MethodTest() {
317 super("MethodTest");
318 }
319
320 private boolean eqExecute(final Object lhs, final Object rhs) {
321 if (lhs instanceof Class<?>[] && rhs instanceof Class<?>[]) {
322 final Class<?>[] lhsa = (Class<?>[]) lhs;
323 final Class<?>[] rhsa = (Class<?>[]) rhs;
324 return Arrays.deepEquals(lhsa, rhsa);
325 }
326 return false;
327 }
328
329 @BeforeEach
330 @Override
331 public void setUp() {
332 asserter = new Asserter(JEXL);
333 }
334
335 @Test
336 void testAmbiguousInvoke() throws Exception {
337
338 final Functor func = new Functor();
339 final JexlContext ctxt = new MapContext();
340 ctxt.set("func", func);
341 Object result;
342
343 result = JEXL.invokeMethod(func, "over", "foo", 42);
344 assertEquals("foo + 42", result);
345
346 JexlException.Method xinvoke = assertThrows(JexlException.Method.class, () -> JEXL.invokeMethod(func, "over", "not null", null));
347 assertEquals("over(String, Object)", xinvoke.getMethodSignature());
348
349
350 final String[] arg2 = { "more", "than", "one" };
351 xinvoke = assertThrows(JexlException.Method.class, () -> JEXL.invokeMethod(func, "over", "not null", arg2));
352 assertEquals("over(String, String[])", xinvoke.getMethodSignature());
353 }
354
355 @Test
356 void testCallJexlVarArgMethod() throws Exception {
357 final VarArgs test = new VarArgs();
358 asserter.setVariable("test", test);
359 assertEquals("jexl:0", test.callMixed("jexl"));
360 asserter.assertExpression("test.callMixed('jexl')", "jexl:0");
361
362
363 assertEquals("jexl:-1000", test.callMixed("jexl", (Integer[]) null));
364 asserter.assertExpression("test.callMixed('jexl', null)", "jexl:-1000");
365
366 asserter.assertExpression("test.callMixed('jexl', 2)", test.callMixed("jexl", 2));
367 asserter.assertExpression("test.callMixed('jexl',2,3,4,5)", test.callMixed("jexl", 2, 3, 4, 5));
368 }
369
370 @Test
371 void testCallMixedVarArgMethod() throws Exception {
372 final VarArgs test = new VarArgs();
373 asserter.setVariable("test", test);
374 assertEquals("Mixed:1", test.callMixed(Integer.valueOf(1)));
375 asserter.assertExpression("test.callMixed(1)", test.callMixed(1));
376
377
378 assertEquals("Mixed:-999", test.callMixed(Integer.valueOf(1), (Integer[]) null));
379 asserter.assertExpression("test.callMixed(1, null)", "Mixed:-999");
380
381 asserter.assertExpression("test.callMixed(1,2)", test.callMixed(1, 2));
382 asserter.assertExpression("test.callMixed(1,2,3,4,5)", test.callMixed(1, 2, 3, 4, 5));
383 }
384
385 @Test
386 void testCallVarArgMethod() throws Exception {
387 final VarArgs test = new VarArgs();
388 asserter.setVariable("test", test);
389 asserter.assertExpression("test.callInts()", test.callInts());
390 asserter.assertExpression("test.callInts(1)", test.callInts(1));
391 asserter.assertExpression("test.callInts(1,2,3,4,5)", test.callInts(1, 2, 3, 4, 5));
392 asserter.assertExpression("test.concat(['1', '2', '3'])", test.concat(new String[]{"1", "2", "3"}));
393 asserter.assertExpression("test.concat('1', '2', '3')", test.concat("1", "2", "3"));
394
395 }
396
397 @Test
398 void testFizzCall() throws Exception {
399 final ScriptContext context = new ScriptContext(new HashMap<>());
400
401 JexlScript bar = JEXL.createScript("functor:get('drink')");
402 Object o;
403 o = bar.execute(context);
404 assertEquals("champaign", o, "Wrong choice");
405 context.set("base", "gin");
406 o = bar.execute(context);
407 assertEquals("gin fizz", o, "Wrong choice");
408
409
410 context.set("base", "wine");
411 bar = JEXL.createScript("var glass = functor:get('drink'); base = 'gin'; functor:get('drink')");
412 o = bar.execute(context);
413 assertEquals("champaign", o, "Wrong choice");
414 }
415
416 @Test
417 void testInvoke() throws Exception {
418 final Functor func = new Functor();
419 assertEquals(Integer.valueOf(10), JEXL.invokeMethod(func, "ten"));
420 assertEquals(Integer.valueOf(42), JEXL.invokeMethod(func, "PLUS20", Integer.valueOf(22)));
421 assertThrows(Exception.class, () -> JEXL.invokeMethod(func, "nonExistentMethod"), "method does not exist!");
422 assertThrows(Exception.class, () -> JEXL.invokeMethod(func, "NPEIfNull", (Object[]) null), "method should have thrown!");
423 Object result = JEXL.invokeMethod(func, "over", "foo", 42);
424 assertEquals("foo + 42", result);
425 assertThrows(Exception.class, () -> JEXL.invokeMethod(func, "over", null, null));
426 final Functor func1 = new FunctorOver();
427 result = JEXL.invokeMethod(func1, "over", null, null);
428 assertEquals("null + null", result);
429 }
430
431
432
433
434 @Test
435 void testMethod() throws Exception {
436
437 asserter.setVariable("foo", new Foo());
438 asserter.assertExpression("foo.bar()", METHOD_STRING);
439 }
440
441 @Test
442 void testMulti() throws Exception {
443 asserter.setVariable("foo", new Foo());
444 asserter.assertExpression("foo.innerFoo.bar()", METHOD_STRING);
445 }
446
447 @Test
448 void testNamespaceCall() throws Exception {
449 final java.util.Map<String, Object> funcs = new java.util.HashMap<>();
450 funcs.put("func", new Functor());
451 funcs.put("FUNC", Functor.class);
452
453 JexlExpression e = JEXL.createExpression("func:ten()");
454 final JexlEvalContext jc = new EnhancedContext(funcs);
455
456 Object o = e.evaluate(jc);
457 assertEquals(Integer.valueOf(10), o);
458
459 e = JEXL.createExpression("func:plus10(10)");
460 o = e.evaluate(jc);
461 assertEquals(Integer.valueOf(20), o);
462
463 e = JEXL.createExpression("func:plus10(func:ten())");
464 o = e.evaluate(jc);
465 assertEquals(Integer.valueOf(20), o);
466
467 e = JEXL.createExpression("FUNC:PLUS20(10)");
468 o = e.evaluate(jc);
469 assertEquals(Integer.valueOf(30), o);
470
471 e = JEXL.createExpression("FUNC:PLUS20(FUNC:TWENTY())");
472 o = e.evaluate(jc);
473 assertEquals(Integer.valueOf(40), o);
474 }
475
476 @Test
477 void testNamespaceCallEdge() throws Exception {
478 final java.util.Map<String, Object> funcs = new java.util.HashMap<>();
479 final Edge func = new Edge();
480 funcs.put("func", func);
481
482 Object o;
483 Object c;
484 JexlExpression e;
485 final JexlEvalContext jc = new EnhancedContext(funcs);
486 for (int i = 0; i < 2; ++i) {
487 e = JEXL.createExpression("func:exec([1, 2])");
488 o = e.evaluate(jc);
489 assertEquals(20, o, "exec(int[] arg): " + i);
490
491 e = JEXL.createExpression("func:exec(1, 2)");
492 o = e.evaluate(jc);
493 assertEquals(4, o, "exec(Object... args): " + i);
494
495 e = JEXL.createExpression("func:exec([10.0, 20.0])");
496 o = e.evaluate(jc);
497 assertEquals(3, o, "exec(Object args): " + i);
498
499 e = JEXL.createExpression("func:exec('1', 2)");
500 o = e.evaluate(jc);
501 assertEquals(4, o, "exec(Object... args): " + i);
502
503
504 assertEquals(func.exec("1", "2"), func.exec(new String[] { "1", "2" }), "exec(String... args): " + i);
505 e = JEXL.createExpression("func:exec(['1', '2'])");
506 o = e.evaluate(jc);
507 assertEquals(func.exec(new String[] { "1", "2" }), o, "exec(String... args): " + i);
508 e = JEXL.createExpression("func:exec('1', '2')");
509 o = e.evaluate(jc);
510 assertEquals(func.exec("1", "2"), o, "exec(String... args): " + i);
511
512 e = JEXL.createExpression("func:exec(true, [1, 2])");
513 o = e.evaluate(jc);
514 assertEquals(20, o, "exec(int[] arg): " + i);
515
516 e = JEXL.createExpression("func:exec(true, 1, 2)");
517 o = e.evaluate(jc);
518 assertEquals(4, o, "exec(Object... args): " + i);
519
520 e = JEXL.createExpression("func:exec(true, ['1', '2'])");
521 o = e.evaluate(jc);
522 assertEquals(3, o, "exec(Object args): " + i);
523
524 e = JEXL.createExpression("func:exec(true, '1', '2')");
525 o = e.evaluate(jc);
526 assertEquals(4, o, "exec(Object... args): " + i);
527
528 e = JEXL.createExpression("func:execute(true, '1', '2')");
529 o = e.evaluate(jc);
530 c = func.execute(Boolean.TRUE, "1", "2");
531 assertTrue(eqExecute(o, c), "execute(Object... args): " + i);
532
533 e = JEXL.createExpression("func:execute([true])");
534 o = e.evaluate(jc);
535 c = func.execute(new boolean[] { true });
536 assertTrue(eqExecute(o, c), "execute(Object... args): " + i);
537 }
538 }
539
540 @Test
541 void testScriptCall() throws Exception {
542 JexlContext context = new MapContext();
543 final JexlScript plus = JEXL.createScript("a + b", new String[]{"a", "b"});
544 context.set("plus", plus);
545 JexlScript forty2 = JEXL.createScript("plus(4, 2) * plus(4, 3)");
546 Object o = forty2.execute(context);
547 assertEquals(Integer.valueOf(42), o);
548
549 final Map<String, Object> foo = new HashMap<>();
550 foo.put("plus", plus);
551 context.set("foo", foo);
552 forty2 = JEXL.createScript("foo.plus(4, 2) * foo.plus(4, 3)");
553 o = forty2.execute(context);
554 assertEquals(Integer.valueOf(42), o);
555
556 context = new ScriptContext(foo);
557 forty2 = JEXL.createScript("script:plus(4, 2) * script:plus(4, 3)");
558 o = forty2.execute(context);
559 assertEquals(Integer.valueOf(42), o);
560
561 final JexlArithmetic ja = JEXL.getArithmetic();
562 final JexlMethod mplus = new JexlMethod() {
563 @Override
564 public Class<?> getReturnType() {
565 return Object.class;
566 }
567
568 @Override
569 public Object invoke(final Object obj, final Object ... params) throws Exception {
570 if (obj instanceof Map<?, ?>) {
571 return ja.add(params[0], params[1]);
572 }
573 throw new Exception("not a script context");
574 }
575
576 @Override
577 public boolean isCacheable() {
578 return true;
579 }
580
581 @Override
582 public boolean tryFailed(final Object rval) {
583
584 return rval == this;
585 }
586
587 @Override
588 public Object tryInvoke(final String name, final Object obj, final Object ... params) {
589 try {
590 if ("plus".equals(name)) {
591 return invoke(obj, params);
592 }
593 } catch (final Exception xany) {
594
595 }
596 return this;
597 }
598 };
599
600 foo.put("PLUS", mplus);
601 forty2 = JEXL.createScript("script:PLUS(4, 2) * script:PLUS(4, 3)");
602 o = forty2.execute(context);
603 assertEquals(Integer.valueOf(42), o);
604
605 context.set("foo.bar", foo);
606 forty2 = JEXL.createScript("foo.'bar'.PLUS(4, 2) * foo.bar.PLUS(4, 3)");
607 o = forty2.execute(context);
608 assertEquals(Integer.valueOf(42), o);
609 }
610
611
612
613
614 @Test
615 void testStaticMethodInvocation() throws Exception {
616 asserter.setVariable("aBool", Boolean.FALSE);
617 asserter.assertExpression("aBool.valueOf('true')", Boolean.TRUE);
618 }
619
620 @Test
621 void testStaticMethodInvocationOnClasses() throws Exception {
622 asserter.setVariable("Boolean", Boolean.class);
623 asserter.assertExpression("Boolean.valueOf('true')", Boolean.TRUE);
624 }
625
626
627
628
629 @Test
630 void testStringMethods() throws Exception {
631 asserter.setVariable("foo", "abcdef");
632 asserter.assertExpression("foo.substring(3)", "def");
633 asserter.assertExpression("foo.substring(0,(size(foo)-3))", "abc");
634 asserter.assertExpression("foo.substring(0,size(foo)-3)", "abc");
635 asserter.assertExpression("foo.substring(0,foo.length()-3)", "abc");
636 asserter.assertExpression("foo.substring(0, 1+1)", "ab");
637 }
638
639 @Test
640 void testTopLevelCall() throws Exception {
641 final java.util.Map<String, Object> funcs = new java.util.HashMap<>();
642 funcs.put(null, new Functor());
643 funcs.put("math", new MyMath());
644 funcs.put("cx", ContextualFunctor.class);
645
646 final EnhancedContext jc = new EnhancedContext(funcs);
647
648 JexlExpression e = JEXL.createExpression("ten()");
649 Object o = e.evaluate(jc);
650 assertEquals(Integer.valueOf(10), o);
651
652 e = JEXL.createExpression("plus10(10)");
653 o = e.evaluate(jc);
654 assertEquals(Integer.valueOf(20), o);
655
656 e = JEXL.createExpression("plus10(ten())");
657 o = e.evaluate(jc);
658 assertEquals(Integer.valueOf(20), o);
659
660 jc.set("pi", Double.valueOf(Math.PI));
661 e = JEXL.createExpression("math:cos(pi)");
662 o = e.evaluate(jc);
663 assertEquals(Double.valueOf(-1), o);
664
665 e = JEXL.createExpression("cx:ratio(10) + cx:ratio(20)");
666 o = e.evaluate(jc);
667 assertEquals(Integer.valueOf(7), o);
668 }
669
670 @Test
671 void testTryFailed() throws Exception {
672
673 final Functor func = new Functor();
674 final JexlContext ctxt = new MapContext();
675 ctxt.set("func", func);
676 Object result;
677 final JexlUberspect uber = JEXL.getUberspect();
678
679 final JexlMethod method = uber.getMethod(func, "over", "foo", 42);
680 assertNotNull(method);
681
682 result = method.tryInvoke("over", func, "foo", 42);
683 assertEquals("foo + 42", result);
684
685 func.setKill(true);
686 JexlException.TryFailed xfail = assertThrows(JexlException.TryFailed.class, () -> method.tryInvoke("over", func, "foo", 42));
687 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
688
689 func.setKill(false);
690 final JexlPropertySet setter = uber.getPropertySet(func, "under", "42");
691 result = setter.tryInvoke(func, "under", "42");
692 assertFalse(setter.tryFailed(result));
693 assertEquals("42", result);
694
695 final JexlPropertyGet getter = uber.getPropertyGet(func, "under");
696 result = getter.tryInvoke(func, "under");
697 assertFalse(getter.tryFailed(result));
698 assertEquals("42", result);
699
700 func.setKill(true);
701 xfail = assertThrows(JexlException.TryFailed.class, () -> setter.tryInvoke(func, "under", "42"), "should throw TryFailed");
702 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
703
704 func.setKill(false);
705 result = setter.tryInvoke(func, "under", "-42");
706 assertEquals("-42", result);
707
708 func.setKill(true);
709 xfail = assertThrows(JexlException.TryFailed.class, () -> getter.tryInvoke(func, "under"), "should throw TryFailed");
710 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
711
712 func.setKill(false);
713 result = getter.tryInvoke(func, "under");
714 assertFalse(getter.tryFailed(result));
715 assertEquals("-42", result);
716 }
717
718 @Test
719 void testTryFailedScript() throws Exception {
720
721 final Functor func = new Functor();
722 final JexlContext ctxt = new MapContext();
723 ctxt.set("func", func);
724 Object result;
725 final JexlUberspect uber = JEXL.getUberspect();
726 final JexlScript method = JEXL.createScript("(x, y)->{ func.over(x, y) }");
727
728
729 assertNotNull(method);
730
731 result = method.execute(ctxt, "foo", 42);
732 assertEquals("foo + 42", result);
733
734 func.setKill(true);
735 JexlException xfail = assertThrows(JexlException.class, () -> method.execute(ctxt, "foo", 42), "should throw TryFailed");
736 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
737
738 func.setKill(false);
739 final JexlScript setter = JEXL.createScript("(x)->{ func.under = x }");
740
741 result = setter.execute(ctxt, "42");
742 assertEquals("42", result);
743
744 final JexlScript getter = JEXL.createScript("func.under");
745 assertEquals("42", result);
746
747 func.setKill(true);
748 xfail = assertThrows(JexlException.class, () -> setter.execute(ctxt, "42"), "should throw TryFailed");
749 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
750
751 func.setKill(false);
752 result = setter.execute(ctxt, "-42");
753 assertEquals("-42", result);
754
755 func.setKill(true);
756 xfail = assertThrows(JexlException.class, () -> getter.execute(ctxt), "should throw TryFailed");
757 assertEquals(UnsupportedOperationException.class, xfail.getCause().getClass());
758
759 func.setKill(false);
760 result = getter.execute(ctxt);
761 assertEquals("-42", result);
762 }
763
764 @Test
765 void testVariousFunctionLocation() throws Exception {
766
767 final Map<String, Object> vars = new HashMap<>();
768 final Map<String,Object> funcs = new HashMap<>();
769 funcs.put(null, new ZSpace());
770 final JexlEngine jexl = new JexlBuilder().namespaces(funcs).arithmetic(new ZArithmetic(true)).create();
771
772 final JexlContext zjc = new ZContext(vars);
773 final String z41 = "z(41)";
774 final JexlScript callz41 = jexl.createScript(z41);
775 Object onovar = callz41.execute(zjc);
776 assertEquals(222, onovar);
777
778
779 final JexlScript z241 = jexl.createScript("(x)->{ return x + 241}");
780 vars.put("z", z241);
781 final Object oglobal = callz41.execute(zjc);
782 assertEquals(282, oglobal);
783
784 vars.remove("z");
785 onovar = callz41.execute(zjc);
786 assertEquals(222, onovar);
787
788
789 final String slocal = "var z = (x)->{ return x + 141}; z(1)";
790 final JexlScript jlocal = jexl.createScript(slocal);
791 final Object olocal = jlocal.execute(zjc);
792 assertEquals(142, olocal);
793
794
795 assertEquals(42, jexl.createScript("zz(2)").execute(zjc));
796 assertEquals(42, jexl.createScript("zzz(3)").execute(zjc));
797 assertEquals(42, jexl.createScript("zzzz(4)").execute(zjc));
798 }
799
800 }