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.apache.commons.jexl3.introspection.JexlPermissions.RESTRICTED;
20 import static org.apache.commons.jexl3.introspection.JexlPermissions.UNRESTRICTED;
21 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
25 import static org.junit.jupiter.api.Assertions.assertNotNull;
26 import static org.junit.jupiter.api.Assertions.assertNull;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29 import static org.junit.jupiter.api.Assertions.fail;
30
31 import java.io.Closeable;
32 import java.io.File;
33 import java.io.StringWriter;
34 import java.lang.reflect.Method;
35 import java.math.BigDecimal;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.HashMap;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Objects;
43 import java.util.concurrent.atomic.AtomicLong;
44 import java.util.function.Function;
45
46 import org.apache.commons.jexl3.internal.Debugger;
47 import org.apache.commons.jexl3.internal.Engine32;
48 import org.apache.commons.jexl3.internal.Scope;
49 import org.apache.commons.jexl3.internal.TemplateEngine;
50 import org.apache.commons.jexl3.introspection.JexlPermissions;
51 import org.apache.commons.jexl3.introspection.JexlSandbox;
52 import org.apache.commons.jexl3.parser.ASTJexlScript;
53 import org.apache.commons.jexl3.parser.JexlScriptParser;
54 import org.apache.commons.jexl3.parser.Parser;
55 import org.apache.commons.jexl3.parser.StringProvider;
56 import org.junit.jupiter.api.BeforeAll;
57 import org.junit.jupiter.api.Test;
58
59
60
61
62 public class Issues400Test {
63
64 public static class VinzCaller {
65 private final JexlContext context;
66
67 VinzCaller(final JexlContext context) {
68 this.context = context;
69 }
70
71 public Object execute(final JexlScript script) {
72 return script.execute(context);
73 }
74 }
75
76 public static class VinzContext extends MapContext {
77 public String member(final String m, final String u) {
78 return m + '.' + u;
79 }
80 }
81
82
83
84
85 public static class XuContext extends MapContext {
86
87 public String join(final int[] list, final String str) {
88 return join(Arrays.stream(list).iterator(), str);
89 }
90
91 public String join(final Iterable<?> list, final String str) {
92 return join(list.iterator(), str);
93 }
94
95 public String join(final Iterator<?> iterator, final String str) {
96 if (!iterator.hasNext()) {
97 return "";
98 }
99 final StringBuilder strb = new StringBuilder(256);
100 strb.append(iterator.next().toString());
101 while (iterator.hasNext()) {
102 strb.append(str);
103 strb.append(Objects.toString(iterator.next(), "?"));
104 }
105 return strb.toString();
106 }
107 }
108
109 private static void run404(final JexlEngine jexl, final String src, final Object... a) {
110 final JexlScript script = jexl.createScript(src, "a", "b");
111 if (!src.endsWith(";")) {
112 assertEquals(script.getSourceText(), script.getParsedText());
113 }
114 final Object result = script.execute(null, a);
115 assertEquals(42, result);
116 }
117
118 @BeforeAll
119 static void setUpClass() {
120 JexlBuilder.setDefaultPermissions(JexlTestCase.TEST_PERMS);
121 }
122
123 @Test
124 void test402() {
125 final JexlContext jc = new MapContext();
126
127 final String[] sources = {
128 "if (true) { return }",
129 "if (true) { 3; return }",
130 "(x->{ 3; return })()"
131 };
132
133 final JexlEngine jexl = new JexlBuilder().create();
134 for (final String source : sources) {
135 final JexlScript e = jexl.createScript(source);
136 final Object o = e.execute(jc);
137 assertNull(o);
138 }
139 }
140
141 @Test
142 void test403() {
143
144 final String[] strings = {
145 " map1.`${item.a}` = 1;\n",
146 " map1[`${item.a}`] = 1;\n",
147 " map1[item.a] = 1;\n"
148 };
149
150 for (final String setmap : strings) {
151
152 final String src = "var a = {'a': 1};\n" +
153 "var list = [a, a];\n" +
154 "let map1 = {:};\n" +
155 "for (let item : list) {\n" +
156 setmap +
157 "}\n " +
158 "map1";
159
160 final JexlEngine jexl = new JexlBuilder().cache(64).create();
161 final JexlScript script = jexl.createScript(src);
162 for (int i = 0; i < 2; ++i) {
163 final Object result = script.execute(null);
164 assertInstanceOf(Map.class, result);
165 final Map<?, ?> map = (Map<?, ?>) result;
166 assertEquals(1, map.size());
167 final Object val = jexl.createScript("m -> m[1]").execute(null, map);
168 assertEquals(1, val);
169 }
170 }
171 }
172
173 @Test
174 void test404a() {
175 final JexlEngine jexl = new JexlBuilder().cache(64).strict(true).safe(false).create();
176 Map<String, Object> a = Collections.singletonMap("b", 42);
177
178 for (final String src : new String[]{"a.b", "a?.b", "a['b']", "a?['b']", "a?.`b`"}) {
179 run404(jexl, src, a);
180 run404(jexl, src + ";", a);
181 }
182
183 for (final String src : new String[]{"a[b]", "a?[b]", "a?.`${b}`"}) {
184 run404(jexl, src, a, "b");
185 run404(jexl, src + ";", a, "b");
186 }
187
188 final Map<String, Object> b = Collections.singletonMap("c", 42);
189 a = Collections.singletonMap("b", b);
190 for (final String src : new String[]{"a[b].c", "a?[b]?['c']", "a?.`${b}`.c"}) {
191 run404(jexl, src, a, "b");
192 }
193 }
194
195 @Test
196 void test404b() {
197
198 final JexlEngine jexl = new JexlBuilder()
199 .cache(64)
200 .strict(true)
201 .safe(false)
202 .create();
203
204 final Map<String, Object> b = Collections.singletonMap("c", 42);
205 final Map<String, Object> a = Collections.singletonMap("b", b);
206 JexlScript script;
207 Object result;
208 script = jexl.createScript("a?['B']?['C']", "a");
209 result = script.execute(null, a);
210 assertEquals(script.getSourceText(), script.getParsedText());
211 assertNull(result);
212 script = jexl.createScript("a?['b']?['C']", "a");
213 assertEquals(script.getSourceText(), script.getParsedText());
214 result = script.execute(null, a);
215 assertNull(result);
216 script = jexl.createScript("a?['b']?['c']", "a");
217 assertEquals(script.getSourceText(), script.getParsedText());
218 result = script.execute(null, a);
219 assertEquals(42, result);
220 script = jexl.createScript("a?['B']?['C']?: 1042", "a");
221 assertEquals(script.getSourceText(), script.getParsedText());
222 result = script.execute(null, a);
223 assertEquals(1042, result);
224
225 script = jexl.createScript("a? ['B']:['C']", "a");
226 result = script.execute(null, a);
227 assertArrayEquals(new String[]{"B"}, (String[]) result);
228 script = jexl.createScript("a?['b'] ?: ['C']", "a");
229 result = script.execute(null, a);
230 assertEquals(b, result);
231 script = jexl.createScript("a?['B'] ?: ['C']", "a");
232 result = script.execute(null, a);
233 assertArrayEquals(new String[]{"C"}, (String[]) result);
234 }
235
236
237
238
239
240
241
242 @Test
243 void testSafeNavBitIndexing() {
244
245 final JexlEngine jexl = new JexlBuilder()
246 .cache(64)
247 .strict(true)
248 .safe(false)
249 .create();
250
251
252 final String[] sources = {
253 "a[b]?[c]",
254 "a?[b][c]",
255 "a[b][c]?[d]",
256 "a?[b]?[c]",
257 "a[b][c]"
258 };
259 for (final String src : sources) {
260 final JexlScript script = jexl.createScript(src, "a", "b", "c", "d");
261 assertEquals(src, script.getParsedText(), src);
262 }
263
264
265 final Map<String, Object> a = Collections.singletonMap("x", 42);
266 final JexlScript shielded = jexl.createScript("a[b]?[c]", "a", "b", "c");
267 assertNull(shielded.execute(null, a, "missing", "c"));
268
269 final JexlScript unshielded = jexl.createScript("a[b]?[c]", "a", "b", "c");
270 assertThrows(JexlException.class, () -> unshielded.execute(null, null, "b", "c"));
271 }
272
273 @Test
274 void test406a() {
275
276 final JexlEngine jexl = new JexlBuilder()
277 .cache(64)
278 .strict(true)
279 .safe(false)
280 .create();
281
282
283 final JexlContext context = new XuContext();
284
285 final List<String> list = Arrays.asList(
286 "[1, 2, 3, 4, ...].join('-')",
287 "[1, 2, 3, 4,].join('-')",
288 "(1 .. 4).join('-')",
289 "join([1, 2, 3, 4, ...], '-')",
290 "join([1, 2, 3, 4], '-')",
291 "join((1 .. 4), '-')");
292
293 for (final String src : list) {
294 final JexlScript script = jexl.createScript(src);
295 final Object result = script.execute(context);
296 assertEquals("1-2-3-4", result, src);
297 }
298
299 final String src0 = "x.join('*')";
300 final JexlScript script0 = jexl.createScript(src0, "x");
301 final String src1 = "join(x, '*')";
302 final JexlScript script1 = jexl.createScript(src1, "x");
303 for (final Object x : Arrays.asList(Arrays.asList(1, 2, 3, 4), new int[]{1, 2, 3, 4})) {
304 Object result = script0.execute(context, x);
305 assertEquals("1*2*3*4", result, src0);
306 result = script1.execute(context, x);
307 assertEquals("1*2*3*4", result, src1);
308 }
309 }
310
311 @Test
312 void test407() {
313
314 final double r = 99.0d + 7.82d - 99.0d - 7.82d;
315 assertEquals(0d, r, 8.e-15);
316
317 final JexlEngine jexl = new JexlBuilder().create();
318 final JexlScript script = jexl.createScript("a + b - a - b", "a", "b");
319
320 Number result = (Number) script.execute(null, 99.0d, 7.82d);
321 assertEquals(0d, result.doubleValue(), 8.e-15);
322
323 result = (Number) script.execute(null, new BigDecimal("99.0"), new BigDecimal("7.82"));
324 assertEquals(0d, result.doubleValue(), 3.e-32);
325 }
326
327 @Test
328 void test412() {
329 final Map<Object, Object> ctl = new HashMap<>();
330 ctl.put("one", 1);
331 ctl.put("two", 2);
332 final String fnsrc0 = "function f(x) { x }\n" + "let one = 'one', two = 'two';\n";
333
334 final List<String> list = Arrays.asList(
335 "{ one : f(1), two:f(2) }",
336 "{ one: f(1), two: f(2) }",
337 "{ one: f(1), two:f(2) }",
338 "{ one :f(1), two:f(2) }");
339
340 for (final String map0 : list) {
341 final String fnsrc = fnsrc0 + map0;
342 final JexlContext jc = new MapContext();
343 final JexlEngine jexl = new JexlBuilder().create();
344 final JexlScript e = jexl.createScript(fnsrc);
345 final Object o = e.execute(jc);
346 assertInstanceOf(Map.class, o);
347 final Map<?, ?> map = (Map<?, ?>) o;
348 assertEquals(map, ctl);
349 }
350 }
351
352 @Test
353 void test413a() {
354 final JexlBuilder builder = new JexlBuilder();
355 final JexlEngine jexl = builder.create();
356 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
357 final Number result = (Number) script.execute(null, 12);
358 assertEquals(54, result);
359 }
360
361 @Test
362 void test413b() {
363 final JexlBuilder builder = new JexlBuilder();
364 final JexlOptions options = builder.options();
365 options.setConstCapture(true);
366 options.setLexical(true);
367 final JexlEngine jexl = builder.create();
368 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
369 final JexlException.Variable xvar = assertThrows(JexlException.Variable.class,
370 () -> script.execute(null, 12), "c should be const");
371 assertEquals("c", xvar.getVariable());
372 }
373
374 @Test
375 void test413c() {
376 final JexlBuilder builder = new JexlBuilder();
377 final JexlEngine jexl = builder.create();
378 final String pragma = "#pragma jexl.options '+constCapture'\n"
379 + "var c = 42; var f = y -> c += y; f(z)";
380 final JexlScript script = jexl.createScript(pragma, "z");
381 final JexlException.Variable xvar = assertThrows(
382 JexlException.Variable.class, () -> script.execute(null, 12), "c should be const");
383 assertEquals("c", xvar.getVariable());
384 }
385
386 @Test
387 void test413d() {
388 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
389 final JexlEngine jexl = builder.create();
390 final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class,
391 () -> jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z"),
392 "c should be const");
393 assertTrue(xparse.getMessage().contains("const"));
394 }
395
396 @Test
397 void test415() {
398 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
399 final JexlEngine jexl = builder.create();
400 JexlScript script;
401 Object result;
402 script = jexl.createScript("`#${c}`", "c");
403 result = script.execute(null, 42);
404 assertEquals("#42", result.toString());
405 script = jexl.createScript("`$${c}`", "c");
406 result = script.execute(null, 42);
407 assertEquals("$42", result.toString());
408 script = jexl.createScript("`$#{c}`", "c");
409 result = script.execute(null, 42);
410 assertEquals("$42", result.toString());
411 script = jexl.createScript("`##{c}`", "c");
412 result = script.execute(null, 42);
413 assertEquals("#42", result.toString());
414 script = jexl.createScript("`--##{c}`", "c");
415 result = script.execute(null, 42);
416 assertEquals("--#42", result.toString());
417 }
418
419 @Test
420 void test419() throws NoSuchMethodException {
421
422 final Method currentTimeMillis = System.class.getMethod("currentTimeMillis");
423 assertFalse(RESTRICTED.allow(currentTimeMillis));
424
425 final JexlPermissions permissions = RESTRICTED.compose("java.lang { +System { currentTimeMillis(); } }");
426
427 assertTrue(permissions.allow(currentTimeMillis));
428 assertFalse(RESTRICTED.allow(currentTimeMillis));
429
430
431 final JexlEngine jexl = new JexlBuilder()
432 .namespaces(Collections.singletonMap("sns", System.class))
433 .permissions(permissions)
434 .create();
435
436 final AtomicLong result = new AtomicLong();
437 assertEquals(0, result.get());
438 final long now = System.currentTimeMillis();
439
440 jexl.createScript("result.set(sns:currentTimeMillis())", "result").execute(null, result);
441 assertTrue(result.get() >= now);
442
443
444 final JexlScript script = jexl.createScript("sns:gc()");
445 final JexlException.Method method = assertThrows(JexlException.Method.class, () -> script.execute(null));
446 assertEquals("gc", method.getMethod());
447
448 }
449
450 @Test
451 void testDocBreakContinue() {
452 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
453 final JexlEngine jexl = builder.create();
454 JexlScript script;
455 Object result;
456
457 final String srcContinue = "let text = '';\n" +
458 "for (let i : (4..2)) { if (i == 3) continue; text += i; }\n" +
459 "text;";
460
461 script = jexl.createScript(srcContinue);
462 result = script.execute(null);
463 assertEquals("42", result);
464
465 final String srcBreak = "let i = 33;\n" +
466 "while (i < 66) { if (i == 42) { break; } i += 1; }\n" +
467 "i;";
468
469 script = jexl.createScript(srcBreak);
470 result = script.execute(null);
471 assertEquals(42, result);
472 }
473
474 @Test
475 void testNamespaceVsTernary0() {
476 final VinzContext ctxt = new VinzContext();
477 ctxt.set("Users", "USERS");
478 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
479
480 JexlScript script = jexl.createScript("() -> {\n"
481 + " var fn = (user) -> {\n"
482 + " user ? user : member(Users, 'user');\n"
483 + " }\n"
484 + "}");
485
486 Object r = script.execute(ctxt);
487 assertNotNull(r);
488 script = (JexlScript) r;
489 r = script.execute(ctxt);
490 assertEquals("USERS.user", r);
491 }
492
493 @Test
494 void testNamespaceVsTernary1() {
495 final VinzContext ctxt = new VinzContext();
496 ctxt.set("Users", "USERS");
497 ctxt.set("vinz", new VinzCaller(ctxt));
498 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
499
500 final JexlScript script = jexl.createScript(
501 "vinz.execute(() -> {\n"
502 + " var test = 42;\n"
503 + " var user = useTest ? test : member(Users, 'user');\n"
504 + "})\n" , "useTest");
505
506 Object r = script.execute(ctxt, false);
507 assertNotNull(r);
508 assertEquals("USERS.user", r);
509 r = script.execute(ctxt, true);
510 assertNotNull(r);
511 assertEquals(42, r);
512 }
513
514 public static class Ns429 {
515 public int f(final int x) {
516 return x * 10000 + 42;
517 }
518 }
519
520 @Test
521 void test429a() {
522 final MapContext ctxt = new MapContext();
523 final JexlFeatures features = JexlFeatures.createDefault();
524 final JexlEngine jexl = new JexlBuilder().features(features).safe(false).strict(true).silent(false).create();
525 final JexlScript f = jexl.createScript("x -> x");
526 ctxt.set("f", f);
527 String src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b : f(2);";
528 JexlScript script = jexl.createScript(src, "b");
529 assertEquals(1, (int) script.execute(ctxt, 1));
530
531 src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b:f(2) : 1;";
532 script = jexl.createScript(src, "b");
533 assertEquals(20042, (int) script.execute(ctxt, 1));
534 }
535
536 @Test
537 void test429b() {
538 final MapContext ctxt = new MapContext();
539 ctxt.set("b", 1);
540 final JexlFeatures features = JexlFeatures.createDefault();
541 features.namespaceIdentifier(true);
542 final JexlEngine jexl = new JexlBuilder().features(features).safe(false).strict(true).silent(false).create();
543 final JexlScript f = jexl.createScript("x -> x");
544 ctxt.set("f", f);
545 String src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b : f(2);";
546 JexlScript script = jexl.createScript(src);
547 assertEquals(1, (int) script.execute(ctxt));
548
549 src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b:f(2) : 1;";
550 script = jexl.createScript(src);
551 assertEquals(20042, (int) script.execute(ctxt));
552 }
553
554 @Test
555 void test431a() {
556 final JexlEngine jexl = new JexlBuilder().create();
557 final String src = "let x = 0; try { x += 19 } catch (let error) { return 169 } "
558 + "try { x += 23 } catch (let error) { return 169 }";
559 final JexlScript script = jexl.createScript(src);
560 assertNotNull(script);
561 final Object result = script.execute(null);
562 assertEquals(42, result);
563 }
564
565 Closeable foo() {
566 return null;
567 }
568
569 @Test
570 void test431b() {
571 final JexlEngine jexl = new JexlBuilder().create();
572 final String src = "let x = 0; try(let error) { x += 19 } catch (let error) { return 169 } "
573 + "try { x += 23 } catch (let error) { return 169 }";
574 final JexlScript script = jexl.createScript(src);
575 assertNotNull(script);
576 final Object result = script.execute(null);
577 assertEquals(42, result);
578 }
579
580 @Test
581 void test431c() {
582 final JexlEngine jexl = new JexlBuilder().create();
583 final String src = "let xx = 0; try { xx += 19 } catch (let xx) { return 169 }";
584 try {
585 final JexlScript script = jexl.createScript(src);
586 fail("xx is already defined in scope");
587 } catch (final JexlException.Parsing parsing) {
588 assertTrue(parsing.getDetail().contains("xx"));
589 }
590 }
591
592 @Test
593 void test433() {
594 final JexlEngine jexl = new JexlBuilder().create();
595 final String src = "let condition = true; if (condition) { return; }";
596 final JexlScript script = jexl.createScript(src);
597 assertNotNull(script);
598 final Object result = script.execute(null);
599 assertNull(result);
600 final Debugger debugger = new Debugger();
601 assertTrue(debugger.debug(script));
602 final String dbgStr = debugger.toString();
603 assertTrue(JexlTestCase.equalsIgnoreWhiteSpace(src, dbgStr));
604 }
605
606 @Test
607 void test434() {
608 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
609 final String src = "let foo = null; let value = foo?[bar]";
610 final JexlScript script = jexl.createScript(src);
611 assertNotNull(script);
612 final Object result = script.execute(null);
613 assertNull(result);
614 }
615
616 public static class Arithmetic435 extends JexlArithmetic {
617 public Arithmetic435(final boolean strict) {
618 super(strict);
619 }
620
621 public Object empty(final String type) {
622 if ("list".equals(type)) {
623 return Collections.emptyList();
624 }
625 return null;
626 }
627 }
628
629 @Test
630 void test435() {
631 final JexlArithmetic arithmetic = new Arithmetic435(true);
632 final JexlEngine jexl = new JexlBuilder().arithmetic(arithmetic).create();
633 final String src = "empty('list')";
634 final JexlScript script = jexl.createScript(src);
635 assertNotNull(script);
636 final Object result = script.execute(null);
637 assertInstanceOf(List.class, result);
638 }
639
640 @Test
641 void test436a() {
642 final String[] srcs = {"let i = null; ++i", "let i; ++i;", "let i; i--;", "let i; i++;"};
643 run436(null, srcs);
644 }
645
646 @Test
647 void test436b() {
648 final String[] srcs = {"var i = null; ++i", "var i; ++i;", "var i; i--;", "var i; i++;"};
649 run436(null, srcs);
650 }
651
652 @Test
653 void test436c() {
654 final JexlContext ctxt = new MapContext();
655 ctxt.set("i", null);
656 final String[] srcs = {"++i", "++i;", "i--;", "i++;"};
657 run436(null, srcs);
658 }
659
660 void run436(final JexlContext ctxt, final String[] srcs) {
661 final JexlEngine jexl = new JexlBuilder().create();
662 for (final String src : srcs) {
663 final JexlScript script = jexl.createScript(src);
664 assertThrows(JexlException.Operator.class, () -> script.execute(ctxt));
665 }
666 }
667
668 @Test
669 void test437a() {
670 final JexlEngine jexl = new JexlBuilder().create();
671 final String src = "let values = [...]\n"
672 + "function append(const value) {\n"
673 + " values.add(value)\n"
674 + "}\n"
675 + "\n"
676 + "append(1)\n"
677 + "append(2)\n"
678 + "return values ";
679 final JexlScript script = jexl.createScript(src);
680 assertNotNull(script);
681 final Object result = script.execute(null);
682 assertInstanceOf(List.class, result);
683 final List<?> values = (List<?>) result;
684 assertEquals(2, values.size());
685 }
686
687 @Test
688 void test437b() {
689 final JexlFeatures features = JexlFeatures.createDefault().ambiguousStatement(true);
690 assertTrue(features.supportsAmbiguousStatement());
691 final JexlEngine jexl = new JexlBuilder().features(features).create();
692 final String src = "let values = [...]"
693 + "function append(const value) {"
694 + " values.add(value)"
695 + "}"
696 + "append(1)"
697 + "append(2)"
698 + "return values ";
699 final JexlScript script = jexl.createScript(src);
700 assertNotNull(script);
701 final Object result = script.execute(null);
702 assertInstanceOf(List.class, result);
703 final List<?> values = (List<?>) result;
704 assertEquals(2, values.size());
705 }
706
707
708
709
710 static final char[] EQ_FRIEND;
711
712 static {
713 final char[] eq = {'!', ':', '<', '>', '^', '|', '&', '+', '-', '/', '*', '~', '='};
714 Arrays.sort(eq);
715 EQ_FRIEND = eq;
716 }
717
718
719
720
721
722
723
724 private static String transcodeSQLExpr(final CharSequence expr) {
725 final StringBuilder strb = new StringBuilder(expr.length());
726 final int end = expr.length();
727 char previous = 0;
728 for (int i = 0; i < end; ++i) {
729 final char c = expr.charAt(i);
730 if (previous == '<') {
731
732 if (c == '>') {
733
734 strb.append("!=");
735 previous = c;
736 continue;
737 }
738 strb.append('<');
739 }
740 if (c != '<') {
741 if (c == '=') {
742
743 if (Arrays.binarySearch(EQ_FRIEND, previous) >= 0) {
744 strb.append(c);
745 } else {
746 strb.append("==");
747 }
748 } else {
749 strb.append(c);
750 if (c == '"' || c == '\'') {
751
752 boolean escape = false;
753 for (i += 1; i < end; ++i) {
754 final char ec = expr.charAt(i);
755 strb.append(ec);
756 if (ec == '\\') {
757 escape = !escape;
758 } else if (escape) {
759 escape = false;
760 } else if (ec == c) {
761 break;
762 }
763 }
764 }
765 }
766 }
767 previous = c;
768 }
769 return strb.toString();
770 }
771
772 public static class SQLParser implements JexlScriptParser {
773 final Parser parser;
774
775 public SQLParser() {
776 parser = new Parser(new StringProvider(";"));
777 }
778
779 @Override
780 public ASTJexlScript parse(final JexlInfo info, final JexlFeatures features, final String src, final Scope scope) {
781 return parser.parse(info, features, transcodeSQLExpr(src), scope);
782 }
783
784 @Override
785 public ASTJexlScript jxltParse(final JexlInfo info, final JexlFeatures features, final String src, final Scope scope) {
786 return new Parser(parser).parse(info, features, transcodeSQLExpr(src), scope);
787 }
788 }
789
790
791 @Test
792 void testSQLTranspose() {
793 final String[] e = {"a<>b", "a = 2", "a.b.c <> '1<>0'"};
794 final String[] j = {"a!=b", "a == 2", "a.b.c != '1<>0'"};
795 for (int i = 0; i < e.length; ++i) {
796 final String je = transcodeSQLExpr(e[i]);
797 assertEquals(j[i], je);
798 }
799 }
800
801 @Test
802 void testSQLNoChange() {
803 final String[] e = {"a <= 2", "a >= 2", "a := 2", "a + 3 << 4 > 5",};
804 for (final String element : e) {
805 final String je = transcodeSQLExpr(element);
806 assertEquals(element, je);
807 }
808 }
809
810 @Test
811 void test438() {
812 final JexlFeatures f = new JexlFeatures()
813 .localVar(false)
814 .lambda(false)
815 .loops(false)
816 .sideEffect(false)
817 .sideEffectGlobal(false);
818 final JexlBuilder builder = new JexlBuilder().parserFactory(SQLParser::new).cache(32).features(f);
819 final JexlEngine sqle = builder.create();
820 assertTrue((boolean) sqle.createScript("a <> 25", "a").execute(null, 24));
821 assertFalse((boolean) sqle.createScript("a <> 25", "a").execute(null, 25));
822 assertFalse((boolean) sqle.createScript("a = 25", "a").execute(null, 24));
823 assertTrue((boolean) sqle.createScript("a != 25", "a").execute(null, 24));
824 assertTrue((boolean) sqle.createScript("a = 25", "a").execute(null, 25));
825 assertFalse((boolean) sqle.createScript("a != 25", "a").execute(null, 25));
826 }
827
828 @Test
829 void testIssue441() {
830 final JexlEngine jexl = new JexlBuilder().create();
831 String ctl = "\nab\nc`d\n";
832 final JexlExpression e = jexl.createExpression("`\nab\nc\\`d\n`");
833 Object o = e.evaluate(null);
834 assertEquals(ctl, o);
835
836 final JexlContext context = new MapContext();
837 context.set("name", "Hello");
838 final String code = "return `${name + '\\n' + name}`;";
839 final JexlScript script = jexl.createScript(code);
840 o = script.execute(context);
841 ctl = "Hello\nHello";
842 assertEquals(ctl, o);
843 }
844
845 @Test
846 void testIssue442() {
847 final JexlEngine jexl = new JexlBuilder().create();
848 final JexlContext context = new MapContext();
849 final String code = "var x = 'hello';\n" + "function test(z) {\n" +
850
851 "`${x} ${z}`;\n" + "}\n" + "test('world');";
852 final JexlScript script = jexl.createScript(code);
853 final Object result = script.execute(context);
854 assertEquals("hello world", result);
855 }
856
857
858 @Test
859 void testIssue447() {
860 final JexlEngine jexl = new JexlBuilder().create();
861 final String src = "const c = `${a}\n?= ${b}`; "
862 + "function foo(const left, const right) { `${left}\n?== ${right}` } "
863 + "c+foo(a, b)";
864 final JexlScript script = jexl.createScript(src, "a", "b");
865 final Object result = script.execute(null, "a", "b");
866 assertEquals("a\n?= ba\n?== b", result);
867 final String[] locals = script.getLocalVariables();
868 assertArrayEquals(new String[]{"c", "foo"}, locals);
869 final String TEST447 = "src/test/scripts/test447.jexl";
870 final File src447 = new File(TEST447);
871 final JexlScript script447 = jexl.createScript(src447);
872 final Object result447 = script447.execute(null);
873 assertInstanceOf(List.class, result447);
874 @SuppressWarnings("unchecked") final List<Boolean> list = (List<Boolean>) result447;
875 for (final Boolean item : list) {
876 assertTrue(item);
877 }
878 }
879
880 public static class BrkContext extends MapContext {
881 public BrkContext() {
882 set("SYSTEM", System.class);
883 set("UNRESTRICTED", UNRESTRICTED);
884 }
885
886 public static Object brk(final Object debug) {
887 return debug;
888 }
889
890 }
891
892 @Test
893 void test450a() {
894 final JexlEngine jexl0 = new JexlBuilder().silent(false).permissions(JexlPermissions.RESTRICTED).create();
895 assertThrows(JexlException.Method.class,
896 () -> jexl0.newInstance("org.apache.commons.jexl3.internal.introspection.Uberspect", null, null),
897 "should not be able to create Uberspect with RESTRICTED");
898 final JexlPermissions perm = new JexlPermissions.ClassPermissions(
899 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
900 final JexlEngine jexl1 = new JexlBuilder().silent(false).permissions(perm).create();
901 assertNotNull(jexl1.newInstance(
902 "org.apache.commons.jexl3.internal.introspection.Uberspect", null, null),
903 "should able to create Uberspect with Uberspect permission");
904
905 }
906
907 @Test
908 void test450b() throws NoSuchMethodException {
909
910 assertThrows(JexlException.Method.class, () -> run450b(JexlPermissions.RESTRICTED),
911 "should not be able to load System with RESTRICTED");
912
913 final Method exitMethod = java.lang.System.class.getMethod("exit", int.class);
914 assertTrue(UNRESTRICTED.allow(exitMethod));
915 assertFalse(RESTRICTED.allow(exitMethod));
916 assertEquals(java.lang.System.class, run450b(UNRESTRICTED));
917
918 final Class<? extends ClassLoader> cloader = getClass().getClassLoader().getClass();
919 final JexlPermissions perm = new JexlPermissions.ClassPermissions(
920 getClass().getClassLoader().getClass(),
921 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
922 assertTrue(perm.allow(cloader), "should be able to access ClassLoader");
923 assertTrue(perm.allow(cloader, cloader.getMethod("loadClass", String.class)), "should be able to access ClassLoader::loadClass");
924 assertEquals(java.lang.System.class, run450b(perm));
925 }
926
927 private static Object run450b(final JexlPermissions perm) {
928 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).permissions(perm).create();
929 final String uscript = "new('org.apache.commons.jexl3.internal.introspection.Uberspect', "
930 + "null, null, perm).getClassLoader().loadClass('java.lang.System')";
931 final JexlScript u0 = jexl.createScript(uscript, "perm");
932 return u0.execute(null, perm);
933 }
934
935 @Test
936 void test450c() {
937
938 assertNotNull(run450c(UNRESTRICTED));
939
940
941 final JexlPermissions perm = new JexlPermissions.ClassPermissions(
942 getClass().getClassLoader().getClass(),
943 JexlPermissions.ClassPermissions.class,
944 org.apache.commons.jexl3.internal.introspection.Uberspect.class,
945 org.apache.commons.jexl3.internal.introspection.MethodExecutor.class,
946 BrkContext.class);
947 assertNotNull(run450c(perm));
948
949 assertThrows(JxltEngine.Exception.class, () -> run450c(JexlPermissions.RESTRICTED),
950 "should not be able to load System with RESTRICTED");
951 }
952
953 private static Object run450c(final JexlPermissions perm) {
954 final JexlBuilder builder = new JexlBuilder().silent(false).permissions(perm);
955 final Object result = new TemplateEngine(new Engine32(builder), false, 2, '$', '#')
956 .createExpression(
957 "${x = new ('org.apache.commons.jexl3.internal.introspection.Uberspect', "
958 + "null, null, UNRESTRICTED);"
959 + "sys = x?.getClassLoader()?.loadClass('java.lang.System') ?: SYSTEM;"
960 + "p = new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions', [sys]);"
961 + "c = new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null, p);"
962 + "z = brk(c.getMethod(sys,'currentTimeMillis')).invoke(x,null);}")
963 .evaluate(new BrkContext());
964 return result;
965 }
966
967 @Test
968 void test450() throws Exception {
969 final JexlPermissions perms = Engine33.createPermissions();
970 final Class<? extends ClassLoader> cl = Issues400Test.class.getClassLoader().getClass();
971 assertTrue(perms.allow(cl, cl.getMethod("loadClass", String.class)),
972 "should be able to access ClassLoader::loadClass with specific permissions");
973 assertNotNull(run450(JexlPermissions.UNRESTRICTED),
974 "should be able to reach and invoke System::currentTimeMillis with UNRESTRICTED");
975 assertNotNull(
976 run450(new JexlPermissions.ClassPermissions(perms,
977 org.apache.commons.jexl3.internal.TemplateEngine.class)),
978 "should be able to reach and invoke System::currentTimeMillis with TemplateEngine permission");
979 assertThrows(JexlException.Method.class, () -> run450(RESTRICTED),
980 "should not be able to reach and invoke System::currentTimeMillis with RESTRICTED");
981 }
982
983 public static class Engine33 extends Engine32 {
984 public Engine33() {
985 this(createBuilder());
986 }
987
988 public Engine33(final JexlBuilder builder) {
989 super(builder);
990 }
991
992 static JexlPermissions createPermissions() {
993
994 return new JexlPermissions.ClassPermissions(JexlTestCase.TEST_PERMS,
995 java.util.Arrays.asList(
996 Engine33.class.getClassLoader().getClass().getCanonicalName(),
997 Engine33.class.getCanonicalName(),
998 JexlPermissions.ClassPermissions.class.getCanonicalName(),
999 org.apache.commons.jexl3.internal.TemplateEngine.class.getCanonicalName(),
1000
1001
1002
1003 org.apache.commons.jexl3.internal.TemplateEngine.class.getCanonicalName() + ".TemplateExpression",
1004 org.apache.commons.jexl3.internal.TemplateEngine.class.getCanonicalName() + ".JexlBasedExpression",
1005 org.apache.commons.jexl3.internal.TemplateEngine.class.getCanonicalName() + ".DeferredExpression",
1006 org.apache.commons.jexl3.internal.introspection.Uberspect.class.getCanonicalName()));
1007 }
1008
1009 static JexlBuilder createBuilder() {
1010 final JexlPermissions perm = createPermissions();
1011 return new JexlBuilder().safe(false).silent(false).permissions(perm);
1012 }
1013 }
1014
1015 private static Object run450(final JexlPermissions perm) {
1016 final JexlEngine jexl = new JexlBuilder().silent(false).strict(true).safe(false)
1017 .permissions(perm).create();
1018 final String script = "new('org.apache.commons.jexl3.internal.TemplateEngine',"
1019 + "new('org.apache.commons.jexl3.Issues400Test$Engine33'),false,256,"
1020 + "'$'.charAt(0),'#'.charAt(0))"
1021 + ".createExpression("
1022 + "\"#{x = new ('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null);"
1023 + "sys = x?.getClassLoader().loadClass('java.lang.System') ?: SYSTEM;"
1024 + "p = new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions', [sys]);"
1025 + "c = new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null, p);"
1026 + "z = c.getMethod(sys,'currentTimeMillis').invoke(x,null);}\")"
1027 + ".evaluate(new('org.apache.commons.jexl3.Issues400Test$BrkContext'))";
1028 return jexl.createScript(script).execute(null);
1029 }
1030
1031 @Test
1032 void test451() throws NoSuchMethodException {
1033 final JexlEngine jexl = new JexlBuilder().create();
1034 assertEquals("42", jexl.createScript("o.toString()", "o").execute(null, "42"));
1035 final JexlPermissions perms = RESTRICTED.compose("java.lang { +Class { getSimpleName(); } }");
1036 assertTrue(perms.allow(String.class.getMethod("toString")));
1037 final JexlSandbox sandbox = new JexlSandbox(false, true);
1038 sandbox.permissions(Object.class.getName(), true, true, false, false);
1039 sandbox.allow(String.class.getName()).execute("toString");
1040 final JexlEngine jexl451 = new JexlBuilder().safe(false).silent(false).permissions(perms).sandbox(sandbox).create();
1041
1042 assertEquals("42", jexl451.createScript("o.toString()", "o").execute(null, "42"));
1043
1044 assertThrows(JexlException.Method.class, () -> jexl451.createScript("oo.getClass()", "oo").execute(null, "42"));
1045
1046 assertEquals(String.class, jexl451.createScript("o.class", "o").execute(null, "42"));
1047
1048 assertEquals("Object", jexl451.createScript("o.class.simpleName", "o").execute(null, new Object()));
1049
1050 assertThrows(JexlException.Property.class,
1051 () -> jexl451.createScript("o.class.classLoader", "o").execute(null, new Object()));
1052 }
1053
1054 @Test
1055 void testIssue455a() {
1056 final JexlEngine jexl = new JexlBuilder().create();
1057 final String code = "name -> `${name +\n\t\f\r name}`";
1058 final JexlScript script = jexl.createScript(code);
1059 final Object o = script.execute(null, "Hello");
1060 final String ctl = "HelloHello";
1061 assertEquals(ctl, o);
1062 }
1063
1064 @Test
1065 void testIssue455b() {
1066 final JexlEngine jexl = new JexlBuilder().create();
1067 final String code = "name -> `${name}\n${name}`;";
1068 final JexlScript script = jexl.createScript(code);
1069 final Object o = script.execute(null, "Hello");
1070 final String ctl = "Hello\nHello";
1071 assertEquals(ctl, o);
1072 }
1073
1074 @Test
1075 void testIssue455c() {
1076 final JexlEngine jexl = new JexlBuilder().create();
1077 final JexlContext context = new MapContext();
1078 context.set("name", "Hello");
1079 final JxltEngine jxlt = jexl.createJxltEngine();
1080 final JxltEngine.Template template = jxlt.createTemplate("<b>\n\t${name\n\t+\r\f name}\n</b>");
1081 final StringWriter writer = new StringWriter();
1082 template.evaluate(context, writer);
1083 assertEquals("<b>\n\tHelloHello\n</b>", writer.toString());
1084 }
1085
1086 @Test
1087 void testIssue455d() {
1088 final JexlEngine jexl = new JexlBuilder().create();
1089
1090 final String code = "`#{${\nref\t}}\n#{${\rref\f}}`;";
1091 final JexlScript script = jexl.createScript(code, "ref", "greeting");
1092 final Object o = script.execute(null, "greeting", "Hello");
1093 final String ctl = "Hello\nHello";
1094 assertEquals(ctl, o);
1095 }
1096
1097 @Test
1098 void testIssue455e() {
1099 final JexlEngine jexl = new JexlBuilder().create();
1100
1101 final String src = "(name, suffix) -> `#{name} Hello ${name} ! #{suffix}`";
1102 final JexlScript script = jexl.createScript(src);
1103 final Object result = script.execute(null, "World", "~");
1104 assertEquals("World Hello World ! ~", result);
1105 }
1106
1107 @Test
1108 void testIssue455f() {
1109 final JexlEngine jexl = new JexlBuilder().create();
1110
1111 final String src = "(name, suffix) -> `#{name + ' Hello'} ${name + ' !'} #{suffix}`";
1112 final JexlScript script = jexl.createScript(src);
1113 final Object result = script.execute(null, "World", "~");
1114 assertEquals("World Hello World ! ~", result);
1115 }
1116
1117 @Test
1118 void testIssue455g() {
1119 final JexlEngine jexl = new JexlBuilder().create();
1120 final JxltEngine jxlt = jexl.createJxltEngine();
1121 final JxltEngine.Template template = jxlt.createTemplate("${name} #{suffix}", "name", "suffix");
1122 final StringWriter writer = new StringWriter();
1123
1124 template.prepare(null, "World", null).evaluate(null, writer, null, "~");
1125 assertEquals("World ~", writer.toString());
1126 }
1127
1128 @Test
1129 void testIssue455h() {
1130 final JexlEngine jexl = new JexlBuilder().create();
1131 final JxltEngine jxlt = jexl.createJxltEngine();
1132 final JxltEngine.Template template = jxlt.createTemplate("#{name + ' Hello'} ${name + ' !'} #{suffix}", "name", "suffix");
1133 final StringWriter writer = new StringWriter();
1134
1135 template.prepare(null, "World").evaluate(null, writer, "World", "~");
1136 assertEquals("World Hello World ! ~", writer.toString());
1137 }
1138
1139 @Test
1140 void testIssue456a() {
1141 final JexlFeatures features = JexlFeatures.createDefault();
1142 assertThrows(JexlException.Parsing.class, () -> run456(
1143 f -> new JexlBuilder().features(f).strict(true).create(),
1144 features, null));
1145 }
1146
1147
1148 @Test
1149 void testIssue456b() {
1150 final JexlFeatures features = JexlFeatures.createDefault().ignoreTemplatePrefix(true);
1151 assertNotNull(run456(
1152 f -> new JexlBuilder().features(f).strict(true).create(),
1153 features, null));
1154 }
1155
1156 @Test
1157 void testIssue456c() {
1158 final JexlFeatures features = JexlFeatures.createDefault().ignoreTemplatePrefix(true);
1159 assertNotNull(run456(
1160 f -> new JexlBuilder().features(f).strict(false).create(),
1161 features, null));
1162 }
1163
1164 @Test
1165 void testIssue456d() {
1166
1167 final JexlContext ctxt = new MapContext();
1168 ctxt.set("$$", "");
1169 final JexlFeatures features = JexlFeatures.createDefault().ignoreTemplatePrefix(true);
1170 assertNotNull(run456(
1171 f -> new JexlBuilder().features(f).strict(true).create(),
1172 features, ctxt));
1173 }
1174
1175 JxltEngine run456(final Function<JexlFeatures, JexlEngine> engineFactory, final JexlFeatures features, final JexlContext ctxt) {
1176 final JexlEngine jexl = engineFactory.apply(features);
1177 final JxltEngine jxlt = jexl.createJxltEngine();
1178
1179 final JxltEngine.Template template = jxlt.createTemplate("$$ var foo = 'foo';$$ var bar = 'bar';\n${foo + bar}");
1180 final StringWriter writer = new StringWriter();
1181 template.evaluate(ctxt, writer);
1182 assertEquals("foobar", writer.toString());
1183 return jxlt;
1184 }
1185
1186 @Test
1187 void testIssue36x_456_var() {
1188 final JexlEngine jexl = new JexlBuilder().create();
1189 final JxltEngine jxlt = jexl.createJxltEngine();
1190
1191 jexl.createScript("var foo = 0;\nfoo = 42;");
1192 try {
1193 jxlt.createTemplate("$$ var foo = 'foo'; if (true) { var foo = 'bar'; var err =&; }");
1194 fail("should have thrown a parsing error in '&'");
1195 } catch (final JexlException xjexl) {
1196
1197 assertTrue(xjexl.getMessage().contains("&"));
1198 }
1199
1200
1201 jexl.createScript("var foo = 0;\nfoo = 42;");
1202
1203 jxlt.createTemplate("$$ var foo = 'foo'; foo = 'bar';");
1204 }
1205
1206 @Test
1207 void testIssue36x_456_let() {
1208 final JexlFeatures features = JexlFeatures.createDefault().ignoreTemplatePrefix(true);
1209 final JexlEngine jexl = new Engine32(new JexlBuilder().features(features).strict(true));
1210
1211 jexl.createScript("let foo = 0;\nfoo = 42;");
1212 final JxltEngine jxlt = jexl.createJxltEngine();
1213 try {
1214 jxlt.createTemplate("$$ var err =&;");
1215 fail("should have thrown a parsing error in '&'");
1216 } catch (final JexlException xjexl) {
1217
1218 assertTrue(xjexl.getMessage().contains("&"));
1219 }
1220
1221 jexl.createScript("let foo = 0;\nfoo = 42;");
1222
1223 final JxltEngine.Template template = jxlt.createTemplate("$$ var foo = 0;\n$$ $$ foo = 42;\n${foo}");
1224 final StringWriter writer = new StringWriter();
1225 template.evaluate(null, writer);
1226 assertEquals("42", writer.toString());
1227 }
1228
1229
1230 @Test
1231 void test459() {
1232 final CaptureLog capture = new CaptureLog("test459");
1233 final JexlBuilder builder = new JexlBuilder().logger(capture).safe(true).strict(false).silent(true);
1234 final JexlEngine jexl = builder.create();
1235 final Object[] expected = { true, true, 0, 0 };
1236 final String[] expressions = {
1237 "empty('aaa'.substring(400,500))",
1238 "empty('aaa'.substring(-1, 2))",
1239 "size('aaa'.substring(400,500))",
1240 "size('aaa'.substring(-1, 2))",
1241 };
1242 for (int i = 0; i < expressions.length; ++i) {
1243 final String expr = expressions[i];
1244 final Object control = expected[i];
1245 capture.clear();
1246 final JexlScript script = jexl.createScript(expr);
1247 final Object result = script.execute(null);
1248 assertEquals(control, result);
1249 final List<String> errors = capture.getCapturedMessages();
1250 assertEquals(1, capture.count("warn"));
1251 assertTrue(errors.stream().anyMatch(error -> error.contains("substring")));
1252 }
1253 }
1254
1255 public static class Namespace460 {
1256 public static int func(final int i) {
1257 return i * 42;
1258 }
1259 }
1260
1261 @Test
1262 void test460() {
1263 final JexlFeatures f = JexlFeatures.createDefault().namespaceIdentifier(true);
1264 final JexlEngine jexl = new JexlBuilder()
1265 .namespaces(Collections.singletonMap("z", Namespace460.class))
1266 .features(f)
1267 .create();
1268
1269 final JexlContext jc = new MapContext();
1270 jc.set("x", 1);
1271 jc.set("y", 2);
1272 jc.set("my_function", jexl.createScript("(a) -> { a * 1000 }"));
1273
1274 JexlScript script = jexl.createScript("x != null ? x : my_function(y)");
1275 Object result = script.execute(jc);
1276 assertEquals(1, result, "Result is not x");
1277 script = jexl.createScript("x != null ? z:func(x) : my_function(y)");
1278 result = script.execute(jc);
1279 assertEquals(42, result);
1280 script = jexl.createScript("y == 1 ? my_function(x) : z:func(x)");
1281 result = script.execute(jc);
1282 assertEquals(42, result);
1283 }
1284
1285 @Test
1286 void test462() {
1287
1288
1289 final JexlEngine jexl = new JexlBuilder().silent(false).permissions(RESTRICTED).create();
1290 for (final String src : new String[] {
1291 "new('java.io.PrintWriter', new('java.io.StringWriter'))",
1292 "import java.io.PrintWriter; new PrintWriter(new('java.io.StringWriter'))" }) {
1293 final JexlScript script = jexl.createScript(src);
1294 final JexlException.Method xctor = assertThrows(JexlException.Method.class,
1295 () -> script.execute(null), () -> "PrintWriter::new should be denied: " + src);
1296 assertTrue(xctor.getMethod().contains("PrintWriter"));
1297 }
1298
1299 final StringWriter sw = new StringWriter();
1300 final java.io.PrintWriter pw = new java.io.PrintWriter(sw);
1301 jexl.createScript("p.println('hello')", "p").execute(null, pw);
1302 pw.flush();
1303 assertTrue(sw.toString().contains("hello"));
1304 }
1305
1306 @Test
1307 void test462a() {
1308
1309
1310 final JexlEngine jexl = new JexlBuilder().silent(false).permissions(RESTRICTED).create();
1311 for (final String src : new String[] {
1312 "new('java.io.PrintWriter', '/tmp/pwn0.php')",
1313 "import java.io.PrintWriter; new PrintWriter('/tmp/pwn1.php')"}) {
1314 final JexlScript script = jexl.createScript(src);
1315 final JexlException.Method xctor = assertThrows(JexlException.Method.class,
1316 () -> script.execute(null), () -> "PrintWriter::new should be denied: " + src);
1317 assertTrue(xctor.getMethod().contains("PrintWriter"));
1318 }
1319
1320 StringWriter sw = new StringWriter();
1321 final java.io.PrintWriter pw = new java.io.PrintWriter(sw);
1322 jexl.createScript("p.println('hello')", "p").execute(null, pw);
1323 pw.flush();
1324 assertTrue(sw.toString().contains("hello"));
1325 for (final String src : new String[] {
1326 "new('java.util.Formatter', '/tmp/pwn2.php')",
1327 "import java.util.Formatter; new Formatter('/tmp/pwn3.php')" }) {
1328 final JexlScript script = jexl.createScript(src);
1329 final JexlException.Method xctor = assertThrows(JexlException.Method.class,
1330 () -> script.execute(null), () -> "Formatter::new should be denied: " + src);
1331 assertTrue(xctor.getMethod().contains("Formatter"));
1332 }
1333
1334
1335 sw = new StringWriter();
1336 final java.util.Formatter pf = new java.util.Formatter(sw);
1337 jexl.createScript("pf.format('%s', 'bonjour')", "pf").execute(null, pf);
1338 assertTrue(sw.toString().contains("bonjour"));
1339 }
1340
1341 @Test
1342 void test463() {
1343 final JexlEngine jexl = new JexlBuilder()
1344 .silent(false)
1345 .features(JexlFeatures.createDefault())
1346 .permissions(RESTRICTED)
1347 .create();
1348 String src = "addOne = (f) -> {\n return f + 1;\n}";
1349 JexlScript script = jexl.createScript(src);
1350 assertNotNull(script);
1351 JexlContext ctxt = new MapContext();
1352 Object result = script.execute(ctxt);
1353 assertNotNull(result);
1354 JexlScript rs = (JexlScript) result;
1355 result = rs.execute(ctxt, 1);
1356 assertEquals(2, result);
1357 }
1358
1359 @Test
1360 void test466() {
1361 final JexlEngine jexl = new JexlBuilder()
1362 .silent(false)
1363 .features(JexlFeatures.createDefault())
1364 .permissions(RESTRICTED)
1365 .create();
1366 JxltEngine jxlt = jexl.createJxltEngine();
1367
1368 String src = "$$ const a = 'a';\n" + "$$ const b = `${a}` \n" + "b:${b}";
1369 JxltEngine.Template template = jxlt.createTemplate(src);
1370 StringWriter writer = new StringWriter();
1371 template.evaluate(null, writer);
1372 assertEquals("b:a", writer.toString());
1373
1374 String expr = "forty-two: ${b + a}";
1375 JexlContext ctxt = new MapContext();
1376 ctxt.set("b", 20);
1377 ctxt.set("a", 22);
1378 JxltEngine.Expression expression = jxlt.createExpression(expr);
1379 Object value = expression.evaluate(ctxt);
1380 assertEquals("forty-two: 42", value.toString());
1381 }
1382 }
1383