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
45 import org.apache.commons.jexl3.internal.Debugger;
46 import org.apache.commons.jexl3.internal.Engine32;
47 import org.apache.commons.jexl3.internal.Scope;
48 import org.apache.commons.jexl3.internal.TemplateEngine;
49 import org.apache.commons.jexl3.introspection.JexlPermissions;
50 import org.apache.commons.jexl3.introspection.JexlSandbox;
51 import org.apache.commons.jexl3.parser.ASTJexlScript;
52 import org.apache.commons.jexl3.parser.JexlScriptParser;
53 import org.apache.commons.jexl3.parser.Parser;
54 import org.apache.commons.jexl3.parser.StringProvider;
55 import org.junit.jupiter.api.Assertions;
56 import org.junit.jupiter.api.Test;
57
58
59
60
61 public class Issues400Test {
62
63 public static class VinzCaller {
64 private final JexlContext context;
65
66 VinzCaller(final JexlContext context) {
67 this.context = context;
68 }
69
70 public Object execute(final JexlScript script) {
71 return script.execute(context);
72 }
73 }
74
75 public static class VinzContext extends MapContext {
76 public String member(final String m, final String u) {
77 return m + '.' + u;
78 }
79 }
80
81
82
83
84 public static class XuContext extends MapContext {
85
86 public String join(final int[] list, final String str) {
87 return join(Arrays.stream(list).iterator(), str);
88 }
89
90 public String join(final Iterable<?> list, final String str) {
91 return join(list.iterator(), str);
92 }
93
94 public String join(final Iterator<?> iterator, final String str) {
95 if (!iterator.hasNext()) {
96 return "";
97 }
98 final StringBuilder strb = new StringBuilder(256);
99 strb.append(iterator.next().toString());
100 while (iterator.hasNext()) {
101 strb.append(str);
102 strb.append(Objects.toString(iterator.next(), "?"));
103 }
104 return strb.toString();
105 }
106 }
107
108 private static void run404(final JexlEngine jexl, final String src, final Object... a) {
109 final JexlScript script = jexl.createScript(src, "a", "b");
110 if (!src.endsWith(";")) {
111 assertEquals(script.getSourceText(), script.getParsedText());
112 }
113 final Object result = script.execute(null, a);
114 assertEquals(42, result);
115 }
116
117 @Test
118 void test402() {
119 final JexlContext jc = new MapContext();
120
121 final String[] sources = {
122 "if (true) { return }",
123 "if (true) { 3; return }",
124 "(x->{ 3; return })()"
125 };
126
127 final JexlEngine jexl = new JexlBuilder().create();
128 for (final String source : sources) {
129 final JexlScript e = jexl.createScript(source);
130 final Object o = e.execute(jc);
131 assertNull(o);
132 }
133 }
134
135 @Test
136 void test403() {
137
138 final String[] strings = {
139 " map1.`${item.a}` = 1;\n",
140 " map1[`${item.a}`] = 1;\n",
141 " map1[item.a] = 1;\n"
142 };
143
144 for (final String setmap : strings) {
145
146 final String src = "var a = {'a': 1};\n" +
147 "var list = [a, a];\n" +
148 "let map1 = {:};\n" +
149 "for (let item : list) {\n" +
150 setmap +
151 "}\n " +
152 "map1";
153
154 final JexlEngine jexl = new JexlBuilder().cache(64).create();
155 final JexlScript script = jexl.createScript(src);
156 for (int i = 0; i < 2; ++i) {
157 final Object result = script.execute(null);
158 assertInstanceOf(Map.class, result);
159 final Map<?, ?> map = (Map<?, ?>) result;
160 assertEquals(1, map.size());
161 final Object val = jexl.createScript("m -> m[1]").execute(null, map);
162 assertEquals(1, val);
163 }
164 }
165 }
166
167 @Test
168 void test404a() {
169 final JexlEngine jexl = new JexlBuilder().cache(64).strict(true).safe(false).create();
170 Map<String, Object> a = Collections.singletonMap("b", 42);
171
172 for (final String src : new String[]{"a.b", "a?.b", "a['b']", "a?['b']", "a?.`b`"}) {
173 run404(jexl, src, a);
174 run404(jexl, src + ";", a);
175 }
176
177 for (final String src : new String[]{"a[b]", "a?[b]", "a?.`${b}`"}) {
178 run404(jexl, src, a, "b");
179 run404(jexl, src + ";", a, "b");
180 }
181
182 final Map<String, Object> b = Collections.singletonMap("c", 42);
183 a = Collections.singletonMap("b", b);
184 for (final String src : new String[]{"a[b].c", "a?[b]?['c']", "a?.`${b}`.c"}) {
185 run404(jexl, src, a, "b");
186 }
187 }
188
189 @Test
190 void test404b() {
191
192 final JexlEngine jexl = new JexlBuilder()
193 .cache(64)
194 .strict(true)
195 .safe(false)
196 .create();
197
198 final Map<String, Object> b = Collections.singletonMap("c", 42);
199 final Map<String, Object> a = Collections.singletonMap("b", b);
200 JexlScript script;
201 Object result;
202 script = jexl.createScript("a?['B']?['C']", "a");
203 result = script.execute(null, a);
204 assertEquals(script.getSourceText(), script.getParsedText());
205 assertNull(result);
206 script = jexl.createScript("a?['b']?['C']", "a");
207 assertEquals(script.getSourceText(), script.getParsedText());
208 result = script.execute(null, a);
209 assertNull(result);
210 script = jexl.createScript("a?['b']?['c']", "a");
211 assertEquals(script.getSourceText(), script.getParsedText());
212 result = script.execute(null, a);
213 assertEquals(42, result);
214 script = jexl.createScript("a?['B']?['C']?: 1042", "a");
215 assertEquals(script.getSourceText(), script.getParsedText());
216 result = script.execute(null, a);
217 assertEquals(1042, result);
218
219 script = jexl.createScript("a? ['B']:['C']", "a");
220 result = script.execute(null, a);
221 assertArrayEquals(new String[]{"B"}, (String[]) result);
222 script = jexl.createScript("a?['b'] ?: ['C']", "a");
223 result = script.execute(null, a);
224 assertEquals(b, result);
225 script = jexl.createScript("a?['B'] ?: ['C']", "a");
226 result = script.execute(null, a);
227 assertArrayEquals(new String[]{"C"}, (String[]) result);
228 }
229
230 @Test
231 void test406a() {
232
233 final JexlEngine jexl = new JexlBuilder()
234 .cache(64)
235 .strict(true)
236 .safe(false)
237 .create();
238
239
240 final JexlContext context = new XuContext();
241
242 final List<String> list = Arrays.asList(
243 "[1, 2, 3, 4, ...].join('-')",
244 "[1, 2, 3, 4,].join('-')",
245 "(1 .. 4).join('-')",
246 "join([1, 2, 3, 4, ...], '-')",
247 "join([1, 2, 3, 4], '-')",
248 "join((1 .. 4), '-')");
249
250 for (final String src : list) {
251 final JexlScript script = jexl.createScript(src);
252 final Object result = script.execute(context);
253 assertEquals("1-2-3-4", result, src);
254 }
255
256 final String src0 = "x.join('*')";
257 final JexlScript script0 = jexl.createScript(src0, "x");
258 final String src1 = "join(x, '*')";
259 final JexlScript script1 = jexl.createScript(src1, "x");
260 for (final Object x : Arrays.asList(Arrays.asList(1, 2, 3, 4), new int[]{1, 2, 3, 4})) {
261 Object result = script0.execute(context, x);
262 assertEquals("1*2*3*4", result, src0);
263 result = script1.execute(context, x);
264 assertEquals("1*2*3*4", result, src1);
265 }
266 }
267
268 @Test
269 void test407() {
270
271 final double r = 99.0d + 7.82d - 99.0d - 7.82d;
272 assertEquals(0d, r, 8.e-15);
273
274 final JexlEngine jexl = new JexlBuilder().create();
275 final JexlScript script = jexl.createScript("a + b - a - b", "a", "b");
276
277 Number result = (Number) script.execute(null, 99.0d, 7.82d);
278 assertEquals(0d, result.doubleValue(), 8.e-15);
279
280 result = (Number) script.execute(null, new BigDecimal("99.0"), new BigDecimal("7.82"));
281 assertEquals(0d, result.doubleValue(), 3.e-32);
282 }
283
284 @Test
285 void test412() {
286 final Map<Object, Object> ctl = new HashMap<>();
287 ctl.put("one", 1);
288 ctl.put("two", 2);
289 final String fnsrc0 = "function f(x) { x }\n" + "let one = 'one', two = 'two';\n";
290
291 final List<String> list = Arrays.asList(
292 "{ one : f(1), two:f(2) }",
293 "{ one: f(1), two: f(2) }",
294 "{ one: f(1), two:f(2) }",
295 "{ one :f(1), two:f(2) }");
296
297 for (final String map0 : list) {
298 final String fnsrc = fnsrc0 + map0;
299 final JexlContext jc = new MapContext();
300 final JexlEngine jexl = new JexlBuilder().create();
301 final JexlScript e = jexl.createScript(fnsrc);
302 final Object o = e.execute(jc);
303 assertInstanceOf(Map.class, o);
304 final Map<?, ?> map = (Map<?, ?>) o;
305 assertEquals(map, ctl);
306 }
307 }
308
309 @Test
310 void test413a() {
311 final JexlBuilder builder = new JexlBuilder();
312 final JexlEngine jexl = builder.create();
313 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
314 final Number result = (Number) script.execute(null, 12);
315 assertEquals(54, result);
316 }
317
318 @Test
319 void test413b() {
320 final JexlBuilder builder = new JexlBuilder();
321 final JexlOptions options = builder.options();
322 options.setConstCapture(true);
323 options.setLexical(true);
324 final JexlEngine jexl = builder.create();
325 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
326 final JexlException.Variable xvar = assertThrows(JexlException.Variable.class,
327 () -> script.execute(null, 12), "c should be const");
328 assertEquals("c", xvar.getVariable());
329 }
330
331 @Test
332 void test413c() {
333 final JexlBuilder builder = new JexlBuilder();
334 final JexlEngine jexl = builder.create();
335 final String pragma = "#pragma jexl.options '+constCapture'\n"
336 + "var c = 42; var f = y -> c += y; f(z)";
337 final JexlScript script = jexl.createScript(pragma, "z");
338 final JexlException.Variable xvar = assertThrows(
339 JexlException.Variable.class, () -> script.execute(null, 12), "c should be const");
340 assertEquals("c", xvar.getVariable());
341 }
342
343 @Test
344 void test413d() {
345 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
346 final JexlEngine jexl = builder.create();
347 final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class,
348 () -> jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z"),
349 "c should be const");
350 assertTrue(xparse.getMessage().contains("const"));
351 }
352
353 @Test
354 void test415() {
355 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
356 final JexlEngine jexl = builder.create();
357 JexlScript script;
358 Object result;
359 script = jexl.createScript("`#${c}`", "c");
360 result = script.execute(null, 42);
361 assertEquals("#42", result.toString());
362 script = jexl.createScript("`$${c}`", "c");
363 result = script.execute(null, 42);
364 assertEquals("$42", result.toString());
365 script = jexl.createScript("`$#{c}`", "c");
366 result = script.execute(null, 42);
367 assertEquals("$42", result.toString());
368 script = jexl.createScript("`##{c}`", "c");
369 result = script.execute(null, 42);
370 assertEquals("#42", result.toString());
371 script = jexl.createScript("`--##{c}`", "c");
372 result = script.execute(null, 42);
373 assertEquals("--#42", result.toString());
374 }
375
376 @Test
377 void test419() throws NoSuchMethodException {
378
379 final Method currentTimeMillis = System.class.getMethod("currentTimeMillis");
380 assertFalse(RESTRICTED.allow(currentTimeMillis));
381
382 final JexlPermissions permissions = RESTRICTED.compose("java.lang { +System { currentTimeMillis(); } }");
383
384 assertTrue(permissions.allow(currentTimeMillis));
385 assertFalse(RESTRICTED.allow(currentTimeMillis));
386
387
388 final JexlEngine jexl = new JexlBuilder()
389 .namespaces(Collections.singletonMap("sns", System.class))
390 .permissions(permissions)
391 .create();
392
393 final AtomicLong result = new AtomicLong();
394 assertEquals(0, result.get());
395 final long now = System.currentTimeMillis();
396
397 jexl.createScript("result.set(sns:currentTimeMillis())", "result").execute(null, result);
398 assertTrue(result.get() >= now);
399
400
401 final JexlScript script = jexl.createScript("sns:gc()");
402 final JexlException.Method method = assertThrows(JexlException.Method.class, () -> script.execute(null));
403 assertEquals("gc", method.getMethod());
404
405 }
406
407 @Test
408 void testDocBreakContinue() {
409 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
410 final JexlEngine jexl = builder.create();
411 JexlScript script;
412 Object result;
413
414 final String srcContinue = "let text = '';\n" +
415 "for (let i : (4..2)) { if (i == 3) continue; text += i; }\n" +
416 "text;";
417
418 script = jexl.createScript(srcContinue);
419 result = script.execute(null);
420 assertEquals("42", result);
421
422 final String srcBreak = "let i = 33;\n" +
423 "while (i < 66) { if (i == 42) { break; } i += 1; }\n" +
424 "i;";
425
426 script = jexl.createScript(srcBreak);
427 result = script.execute(null);
428 assertEquals(42, result);
429 }
430
431 @Test
432 void testNamespaceVsTernary0() {
433 final VinzContext ctxt = new VinzContext();
434 ctxt.set("Users", "USERS");
435 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
436
437 JexlScript script = jexl.createScript("() -> {\n"
438 + " var fn = (user) -> {\n"
439 + " user ? user : member(Users, 'user');\n"
440 + " }\n"
441 + "}");
442
443 Object r = script.execute(ctxt);
444 assertNotNull(r);
445 script = (JexlScript) r;
446 r = script.execute(ctxt);
447 assertEquals("USERS.user", r);
448 }
449
450 @Test
451 void testNamespaceVsTernary1() {
452 final VinzContext ctxt = new VinzContext();
453 ctxt.set("Users", "USERS");
454 ctxt.set("vinz", new VinzCaller(ctxt));
455 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
456
457 final JexlScript script = jexl.createScript(
458 "vinz.execute(() -> {\n"
459 + " var test = 42;\n"
460 + " var user = useTest ? test : member(Users, 'user');\n"
461 + "})\n" , "useTest");
462
463 Object r = script.execute(ctxt, false);
464 assertNotNull(r);
465 assertEquals("USERS.user", r);
466 r = script.execute(ctxt, true);
467 assertNotNull(r);
468 assertEquals(42, r);
469 }
470
471 public static class Ns429 {
472 public int f(final int x) {
473 return x * 10000 + 42;
474 }
475 }
476
477 @Test
478 void test429a() {
479 final MapContext ctxt = new MapContext();
480 final JexlFeatures features = JexlFeatures.createDefault();
481 final JexlEngine jexl = new JexlBuilder().features(features).safe(false).strict(true).silent(false).create();
482 final JexlScript f = jexl.createScript("x -> x");
483 ctxt.set("f", f);
484 String src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b : f(2);";
485 JexlScript script = jexl.createScript(src, "b");
486 assertEquals(1, (int) script.execute(ctxt, 1));
487
488 src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b:f(2) : 1;";
489 script = jexl.createScript(src, "b");
490 assertEquals(20042, (int) script.execute(ctxt, 1));
491 }
492
493 @Test
494 void test429b() {
495 final MapContext ctxt = new MapContext();
496 ctxt.set("b", 1);
497 final JexlFeatures features = JexlFeatures.createDefault();
498 features.namespaceIdentifier(true);
499 final JexlEngine jexl = new JexlBuilder().features(features).safe(false).strict(true).silent(false).create();
500 final JexlScript f = jexl.createScript("x -> x");
501 ctxt.set("f", f);
502 String src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b : f(2);";
503 JexlScript script = jexl.createScript(src);
504 assertEquals(1, (int) script.execute(ctxt));
505
506 src = "#pragma jexl.namespace.b " + Ns429.class.getName() + "\n" + "b ? b:f(2) : 1;";
507 script = jexl.createScript(src);
508 assertEquals(20042, (int) script.execute(ctxt));
509 }
510
511 @Test
512 void test431a() {
513 final JexlEngine jexl = new JexlBuilder().create();
514 final String src = "let x = 0; try { x += 19 } catch (let error) { return 169 } "
515 + "try { x += 23 } catch (let error) { return 169 }";
516 final JexlScript script = jexl.createScript(src);
517 assertNotNull(script);
518 final Object result = script.execute(null);
519 assertEquals(42, result);
520 }
521
522 Closeable foo() {
523 return null;
524 }
525
526 @Test
527 void test431b() {
528 final JexlEngine jexl = new JexlBuilder().create();
529 final String src = "let x = 0; try(let error) { x += 19 } catch (let error) { return 169 } "
530 + "try { x += 23 } catch (let error) { return 169 }";
531 final JexlScript script = jexl.createScript(src);
532 assertNotNull(script);
533 final Object result = script.execute(null);
534 assertEquals(42, result);
535 }
536
537 @Test
538 void test431c() {
539 final JexlEngine jexl = new JexlBuilder().create();
540 final String src = "let xx = 0; try { xx += 19 } catch (let xx) { return 169 }";
541 try {
542 final JexlScript script = jexl.createScript(src);
543 fail("xx is already defined in scope");
544 } catch (final JexlException.Parsing parsing) {
545 assertTrue(parsing.getDetail().contains("xx"));
546 }
547 }
548
549 @Test
550 void test433() {
551 final JexlEngine jexl = new JexlBuilder().create();
552 final String src = "let condition = true; if (condition) { return; }";
553 final JexlScript script = jexl.createScript(src);
554 assertNotNull(script);
555 final Object result = script.execute(null);
556 assertNull(result);
557 final Debugger debugger = new Debugger();
558 assertTrue(debugger.debug(script));
559 final String dbgStr = debugger.toString();
560 assertTrue(JexlTestCase.equalsIgnoreWhiteSpace(src, dbgStr));
561 }
562
563 @Test
564 void test434() {
565 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
566 final String src = "let foo = null; let value = foo?[bar]";
567 final JexlScript script = jexl.createScript(src);
568 assertNotNull(script);
569 final Object result = script.execute(null);
570 assertNull(result);
571 }
572
573 public static class Arithmetic435 extends JexlArithmetic {
574 public Arithmetic435(final boolean strict) {
575 super(strict);
576 }
577
578 public Object empty(final String type) {
579 if ("list".equals(type)) {
580 return Collections.emptyList();
581 }
582 return null;
583 }
584 }
585
586 @Test
587 void test435() {
588 final JexlArithmetic arithmetic = new Arithmetic435(true);
589 final JexlEngine jexl = new JexlBuilder().arithmetic(arithmetic).create();
590 final String src = "empty('list')";
591 final JexlScript script = jexl.createScript(src);
592 assertNotNull(script);
593 final Object result = script.execute(null);
594 assertInstanceOf(List.class, result);
595 }
596
597 @Test
598 void test436a() {
599 final String[] srcs = {"let i = null; ++i", "let i; ++i;", "let i; i--;", "let i; i++;"};
600 run436(null, srcs);
601 }
602
603 @Test
604 void test436b() {
605 final String[] srcs = {"var i = null; ++i", "var i; ++i;", "var i; i--;", "var i; i++;"};
606 run436(null, srcs);
607 }
608
609 @Test
610 void test436c() {
611 final JexlContext ctxt = new MapContext();
612 ctxt.set("i", null);
613 final String[] srcs = {"++i", "++i;", "i--;", "i++;"};
614 run436(null, srcs);
615 }
616
617 void run436(final JexlContext ctxt, final String[] srcs) {
618 final JexlEngine jexl = new JexlBuilder().create();
619 for (final String src : srcs) {
620 final JexlScript script = jexl.createScript(src);
621 assertThrows(JexlException.Operator.class, () -> script.execute(ctxt));
622 }
623 }
624
625 @Test
626 void test437a() {
627 final JexlEngine jexl = new JexlBuilder().create();
628 final String src = "let values = [...]\n"
629 + "function append(const value) {\n"
630 + " values.add(value)\n"
631 + "}\n"
632 + "\n"
633 + "append(1)\n"
634 + "append(2)\n"
635 + "return values ";
636 final JexlScript script = jexl.createScript(src);
637 assertNotNull(script);
638 final Object result = script.execute(null);
639 assertInstanceOf(List.class, result);
640 final List<?> values = (List<?>) result;
641 assertEquals(2, values.size());
642 }
643
644 @Test
645 void test437b() {
646 final JexlFeatures features = JexlFeatures.createDefault().ambiguousStatement(true);
647 assertTrue(features.supportsAmbiguousStatement());
648 final JexlEngine jexl = new JexlBuilder().features(features).create();
649 final String src = "let values = [...]"
650 + "function append(const value) {"
651 + " values.add(value)"
652 + "}"
653 + "append(1)"
654 + "append(2)"
655 + "return values ";
656 final JexlScript script = jexl.createScript(src);
657 assertNotNull(script);
658 final Object result = script.execute(null);
659 assertInstanceOf(List.class, result);
660 final List<?> values = (List<?>) result;
661 assertEquals(2, values.size());
662 }
663
664
665
666
667 static final char[] EQ_FRIEND;
668
669 static {
670 final char[] eq = {'!', ':', '<', '>', '^', '|', '&', '+', '-', '/', '*', '~', '='};
671 Arrays.sort(eq);
672 EQ_FRIEND = eq;
673 }
674
675
676
677
678
679
680
681 private static String transcodeSQLExpr(final CharSequence expr) {
682 final StringBuilder strb = new StringBuilder(expr.length());
683 final int end = expr.length();
684 char previous = 0;
685 for (int i = 0; i < end; ++i) {
686 final char c = expr.charAt(i);
687 if (previous == '<') {
688
689 if (c == '>') {
690
691 strb.append("!=");
692 previous = c;
693 continue;
694 }
695 strb.append('<');
696 }
697 if (c != '<') {
698 if (c == '=') {
699
700 if (Arrays.binarySearch(EQ_FRIEND, previous) >= 0) {
701 strb.append(c);
702 } else {
703 strb.append("==");
704 }
705 } else {
706 strb.append(c);
707 if (c == '"' || c == '\'') {
708
709 boolean escape = false;
710 for (i += 1; i < end; ++i) {
711 final char ec = expr.charAt(i);
712 strb.append(ec);
713 if (ec == '\\') {
714 escape = !escape;
715 } else if (escape) {
716 escape = false;
717 } else if (ec == c) {
718 break;
719 }
720 }
721 }
722 }
723 }
724 previous = c;
725 }
726 return strb.toString();
727 }
728
729 public static class SQLParser implements JexlScriptParser {
730 final Parser parser;
731
732 public SQLParser() {
733 parser = new Parser(new StringProvider(";"));
734 }
735
736 @Override
737 public ASTJexlScript parse(final JexlInfo info, final JexlFeatures features, final String src, final Scope scope) {
738 return parser.parse(info, features, transcodeSQLExpr(src), scope);
739 }
740
741 @Override
742 public ASTJexlScript jxltParse(final JexlInfo info, final JexlFeatures features, final String src, final Scope scope) {
743 return new Parser(parser).parse(info, features, transcodeSQLExpr(src), scope);
744 }
745 }
746
747
748 @Test
749 void testSQLTranspose() {
750 final String[] e = {"a<>b", "a = 2", "a.b.c <> '1<>0'"};
751 final String[] j = {"a!=b", "a == 2", "a.b.c != '1<>0'"};
752 for (int i = 0; i < e.length; ++i) {
753 final String je = transcodeSQLExpr(e[i]);
754 Assertions.assertEquals(j[i], je);
755 }
756 }
757
758 @Test
759 void testSQLNoChange() {
760 final String[] e = {"a <= 2", "a >= 2", "a := 2", "a + 3 << 4 > 5",};
761 for (final String element : e) {
762 final String je = transcodeSQLExpr(element);
763 Assertions.assertEquals(element, je);
764 }
765 }
766
767 @Test
768 void test438() {
769 final JexlFeatures f = new JexlFeatures()
770 .localVar(false)
771 .lambda(false)
772 .loops(false)
773 .sideEffect(false)
774 .sideEffectGlobal(false);
775 final JexlBuilder builder = new JexlBuilder().parserFactory(SQLParser::new).cache(32).features(f);
776 final JexlEngine sqle = builder.create();
777 Assertions.assertTrue((boolean) sqle.createScript("a <> 25", "a").execute(null, 24));
778 Assertions.assertFalse((boolean) sqle.createScript("a <> 25", "a").execute(null, 25));
779 Assertions.assertFalse((boolean) sqle.createScript("a = 25", "a").execute(null, 24));
780 Assertions.assertTrue((boolean) sqle.createScript("a != 25", "a").execute(null, 24));
781 Assertions.assertTrue((boolean) sqle.createScript("a = 25", "a").execute(null, 25));
782 Assertions.assertFalse((boolean) sqle.createScript("a != 25", "a").execute(null, 25));
783 }
784
785 @Test
786 void testIssue441() {
787 final JexlEngine jexl = new JexlBuilder().create();
788 String ctl = "\nab\nc`d\n";
789 final JexlExpression e = jexl.createExpression("`\nab\nc\\`d\n`");
790 Object o = e.evaluate(null);
791 Assertions.assertEquals(ctl, o);
792
793 final JexlContext context = new MapContext();
794 context.set("name", "Hello");
795 final String code = "return `${name + '\\n' + name}`;";
796 final JexlScript script = jexl.createScript(code);
797 o = script.execute(context);
798 ctl = "Hello\nHello";
799 Assertions.assertEquals(ctl, o);
800 }
801
802 @Test
803 void testIssue442() {
804 final JexlEngine jexl = new JexlBuilder().create();
805 final JexlContext context = new MapContext();
806 final String code = "var x = 'hello';\n" + "function test(z) {\n" +
807
808 "`${x} ${z}`;\n" + "}\n" + "test('world');";
809 final JexlScript script = jexl.createScript(code);
810 final Object result = script.execute(context);
811 Assertions.assertEquals("hello world", result);
812 }
813
814
815 @Test
816 void testIssue447() {
817 final JexlEngine jexl = new JexlBuilder().create();
818 final String src = "const c = `${a}\n?= ${b}`; "
819 + "function foo(const left, const right) { `${left}\n?== ${right}` } "
820 + "c+foo(a, b)";
821 final JexlScript script = jexl.createScript(src, "a", "b");
822 final Object result = script.execute(null, "a", "b");
823 Assertions.assertEquals("a\n?= ba\n?== b", result);
824 String[] locals = script.getLocalVariables();
825 Assertions.assertArrayEquals(new String[]{"c", "foo"}, locals);
826 final String TEST447 = "src/test/scripts/test447.jexl";
827 final File src447 = new File(TEST447);
828 final JexlScript script447 = jexl.createScript(src447);
829 final Object result447 = script447.execute(null);
830 Assertions.assertInstanceOf(List.class, result447);
831 @SuppressWarnings("unchecked") final List<Boolean> list = (List<Boolean>) result447;
832 for (final Boolean item : list) {
833 Assertions.assertTrue(item);
834 }
835 }
836
837 public static class BrkContext extends MapContext {
838 public BrkContext() {
839 super();
840 set("SYSTEM", System.class);
841 set("UNRESTRICTED", UNRESTRICTED);
842 }
843
844 public static Object brk(Object debug) {
845 return debug;
846 }
847
848 }
849
850 @Test
851 void test450a() {
852 JexlEngine jexl0 = new JexlBuilder().silent(false).permissions(JexlPermissions.RESTRICTED).create();
853 assertThrows(JexlException.Method.class,
854 () -> jexl0.newInstance("org.apache.commons.jexl3.internal.introspection.Uberspect", null, null),
855 "should not be able to create Uberspect with RESTRICTED");
856 JexlPermissions perm = new JexlPermissions.ClassPermissions(
857 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
858 JexlEngine jexl1 = new JexlBuilder().silent(false).permissions(perm).create();
859 assertNotNull(jexl1.newInstance(
860 "org.apache.commons.jexl3.internal.introspection.Uberspect", null, null),
861 "should able to create Uberspect with Uberspect permission");
862
863 }
864
865 @Test
866 void test450b() {
867
868 assertThrows(JexlException.Method.class, () -> run450b(JexlPermissions.RESTRICTED),
869 "should not be able to load System with RESTRICTED");
870
871 assertEquals(java.lang.System.class, run450b(UNRESTRICTED));
872
873 JexlPermissions perm = new JexlPermissions.ClassPermissions(
874 getClass().getClassLoader().getClass(),
875 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
876 assertEquals(java.lang.System.class, run450b(perm));
877 }
878
879 private static Object run450b(JexlPermissions perm) {
880 JexlEngine jexl = new JexlBuilder().silent(false).permissions(perm).create();
881 String uscript = "new('org.apache.commons.jexl3.internal.introspection.Uberspect', "
882 + "null, null, perm).getClassLoader().loadClass('java.lang.System')";
883 JexlScript u0 = jexl.createScript(uscript, "perm");
884 return u0.execute(null, perm);
885 }
886
887 @Test
888 void test450c() {
889
890 assertNotNull(run450c(UNRESTRICTED));
891
892
893 JexlPermissions perm = new JexlPermissions.ClassPermissions(
894 JexlPermissions.ClassPermissions.class,
895 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
896 assertNotNull(run450c(perm));
897
898 assertThrows(JxltEngine.Exception.class, () -> run450c(JexlPermissions.RESTRICTED),
899 "should not be able to load System with RESTRICTED");
900 }
901
902 private static Object run450c(JexlPermissions perm) {
903 JexlBuilder builder = new JexlBuilder().silent(false).permissions(perm);
904 Object result = new TemplateEngine(new Engine32(builder), false, 2, '$', '#')
905 .createExpression(
906 "${x = new ('org.apache.commons.jexl3.internal.introspection.Uberspect', "
907 + "null, null, UNRESTRICTED);"
908 + "sys = x?.getClassLoader()?.loadClass('java.lang.System') ?: SYSTEM;"
909 + "p = new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions', [sys]);"
910 + "c = new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null, p);"
911 + "z = c.getMethod(sys,'currentTimeMillis').invoke(x,null);}")
912 .evaluate(new BrkContext());
913 return result;
914 }
915
916 @Test
917 void test450() {
918 assertNotNull(run450(JexlPermissions.UNRESTRICTED),
919 "should be able to reach and invoke System::currentTimeMillis with UNRESTRICTED");
920 assertNotNull(
921 run450(new JexlPermissions.ClassPermissions(
922 org.apache.commons.jexl3.internal.TemplateEngine.class)),
923 "should be able to reach and invoke System::currentTimeMillis with TemplateEngine permission");
924 assertThrows(JexlException.Method.class, () -> run450(RESTRICTED),
925 "should not be able to reach and invoke System::currentTimeMillis with RESTRICTED");
926 }
927
928 public static class Engine33 extends Engine32 {
929 public Engine33() {
930 this(createBuilder());
931 }
932
933 public Engine33(JexlBuilder builder) {
934 super(builder);
935 }
936
937 static JexlBuilder createBuilder() {
938 JexlPermissions perm = new JexlPermissions.ClassPermissions(
939 Issues400Test.class.getClassLoader().getClass(),
940 JexlPermissions.ClassPermissions.class,
941 org.apache.commons.jexl3.internal.TemplateEngine.class,
942 org.apache.commons.jexl3.internal.introspection.Uberspect.class);
943 return new JexlBuilder().safe(false).silent(false).permissions(perm);
944 }
945 }
946
947 private static Object run450(JexlPermissions perm) {
948 JexlEngine jexl = new JexlBuilder().silent(false).strict(true).safe(false)
949 .permissions(perm).create();
950 String script = "new('org.apache.commons.jexl3.internal.TemplateEngine',"
951 + "new('org.apache.commons.jexl3.Issues400Test$Engine33'),false,256,"
952 + "'$'.charAt(0),'#'.charAt(0))"
953 + ".createExpression("
954 + "\"#{x = new ('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null);"
955 + "sys = x?.getClassLoader().loadClass('java.lang.System') ?: SYSTEM;"
956 + "p = new('org.apache.commons.jexl3.introspection.JexlPermissions$ClassPermissions', [sys]);"
957 + "c = new('org.apache.commons.jexl3.internal.introspection.Uberspect', null, null, p);"
958 + "z = c.getMethod(sys,'currentTimeMillis').invoke(x,null);}\")"
959 + ".evaluate(new('org.apache.commons.jexl3.Issues400Test$BrkContext'))";
960 return jexl.createScript(script).execute(null);
961 }
962
963 @Test
964 void test451() {
965 JexlEngine jexl = new JexlBuilder().create();
966 assertEquals("42", jexl.createScript("o.toString()", "o").execute(null, "42"));
967 JexlPermissions perms = RESTRICTED.compose("java.lang { +Class { getSimpleName(); } }");
968 JexlSandbox sandbox = new JexlSandbox(false, true);
969 sandbox.permissions(Object.class.getName(), true, true, false, false);
970 sandbox.allow(String.class.getName()).execute("toString");
971 final JexlEngine jexl451 = new JexlBuilder().safe(false).silent(false).permissions(perms).sandbox(sandbox).create();
972
973 assertEquals("42", jexl451.createScript("o.toString()", "o").execute(null, "42"));
974
975 assertThrows(JexlException.Method.class, () -> jexl451.createScript("oo.getClass()", "oo").execute(null, "42"));
976
977 assertEquals(String.class, jexl451.createScript("o.class", "o").execute(null, "42"));
978
979 assertEquals("Object", jexl451.createScript("o.class.simpleName", "o").execute(null, new Object()));
980
981 assertThrows(JexlException.Property.class,
982 () -> jexl451.createScript("o.class.classLoader", "o").execute(null, new Object()));
983 }
984
985 @Test
986 void testIssue455a() {
987 final JexlEngine jexl = new JexlBuilder().create();
988 String code = "name -> `${name +\n\t\f\r name}`";
989 JexlScript script = jexl.createScript(code);
990 Object o = script.execute(null, "Hello");
991 String ctl = "HelloHello";
992 Assertions.assertEquals(ctl, o);
993 }
994
995 @Test
996 void testIssue455b() {
997 final JexlEngine jexl = new JexlBuilder().create();
998 String code = "name -> `${name}\n${name}`;";
999 JexlScript script = jexl.createScript(code);
1000 Object o = script.execute(null, "Hello");
1001 String ctl = "Hello\nHello";
1002 Assertions.assertEquals(ctl, o);
1003 }
1004
1005 @Test
1006 void testIssue455c() {
1007 final JexlEngine jexl = new JexlBuilder().create();
1008 final JexlContext context = new MapContext();
1009 context.set("name", "Hello");
1010 final JxltEngine jxlt = jexl.createJxltEngine();
1011 final JxltEngine.Template template = jxlt.createTemplate("<b>\n\t${name\n\t+\r\f name}\n</b>");
1012 final StringWriter writer = new StringWriter();
1013 template.evaluate(context, writer);
1014 assertEquals("<b>\n\tHelloHello\n</b>", writer.toString());
1015 }
1016
1017 @Test
1018 void testIssue455d() {
1019 final JexlEngine jexl = new JexlBuilder().create();
1020
1021 String code = "`#{${\nref\t}}\n#{${\rref\f}}`;";
1022 JexlScript script = jexl.createScript(code, "ref", "greeting");
1023 Object o = script.execute(null, "greeting", "Hello");
1024 String ctl = "Hello\nHello";
1025 Assertions.assertEquals(ctl, o);
1026 }
1027
1028 @Test
1029 void testIssue455e() {
1030 final JexlEngine jexl = new JexlBuilder().create();
1031
1032 final String src = "(name, suffix) -> `#{name} Hello ${name} ! #{suffix}`";
1033 final JexlScript script = jexl.createScript(src);
1034 final Object result = script.execute(null, "World", "~");
1035 Assertions.assertEquals("World Hello World ! ~", result);
1036 }
1037
1038 @Test
1039 void testIssue455f() {
1040 final JexlEngine jexl = new JexlBuilder().create();
1041
1042 final String src = "(name, suffix) -> `#{name + ' Hello'} ${name + ' !'} #{suffix}`";
1043 final JexlScript script = jexl.createScript(src);
1044 final Object result = script.execute(null, "World", "~");
1045 Assertions.assertEquals("World Hello World ! ~", result);
1046 }
1047
1048 @Test
1049 void testIssue455g() {
1050 final JexlEngine jexl = new JexlBuilder().create();
1051 final JxltEngine jxlt = jexl.createJxltEngine();
1052 final JxltEngine.Template template = jxlt.createTemplate("${name} #{suffix}", "name", "suffix");
1053 final StringWriter writer = new StringWriter();
1054
1055 template.prepare(null, "World", null).evaluate(null, writer, null, "~");
1056 Assertions.assertEquals("World ~", writer.toString());
1057 }
1058
1059 @Test
1060 void testIssue455h() {
1061 final JexlEngine jexl = new JexlBuilder().create();
1062 final JxltEngine jxlt = jexl.createJxltEngine();
1063 final JxltEngine.Template template = jxlt.createTemplate("#{name + ' Hello'} ${name + ' !'} #{suffix}", "name", "suffix");
1064 final StringWriter writer = new StringWriter();
1065
1066 template.prepare(null, "World").evaluate(null, writer, "World", "~");
1067 Assertions.assertEquals("World Hello World ! ~", writer.toString());
1068 }
1069
1070 }
1071