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.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertNull;
25 import static org.junit.jupiter.api.Assertions.assertThrows;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27
28 import java.lang.reflect.Method;
29 import java.math.BigDecimal;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Objects;
37 import java.util.concurrent.atomic.AtomicLong;
38
39 import org.apache.commons.jexl3.introspection.JexlPermissions;
40 import org.junit.jupiter.api.Test;
41
42
43
44
45 public class Issues400Test {
46
47 public static class VinzCaller {
48 private final JexlContext context;
49
50 VinzCaller(final JexlContext context) {
51 this.context = context;
52 }
53
54 public Object execute(final JexlScript script) {
55 return script.execute(context);
56 }
57 }
58
59 public static class VinzContext extends MapContext {
60 public String member(final String m, final String u) {
61 return m + '.' + u;
62 }
63 }
64
65
66
67
68 public static class XuContext extends MapContext {
69
70 public String join(final int[] list, final String str) {
71 return join(Arrays.stream(list).iterator(), str);
72 }
73
74 public String join(final Iterable<?> list, final String str) {
75 return join(list.iterator(), str);
76 }
77
78 public String join(final Iterator<?> iterator, final String str) {
79 if (!iterator.hasNext()) {
80 return "";
81 }
82 final StringBuilder strb = new StringBuilder(256);
83 strb.append(iterator.next().toString());
84 while (iterator.hasNext()) {
85 strb.append(str);
86 strb.append(Objects.toString(iterator.next(), "?"));
87 }
88 return strb.toString();
89 }
90 }
91
92 private static void run404(final JexlEngine jexl, final String src, final Object... a) {
93 final JexlScript script = jexl.createScript(src, "a", "b");
94 if (!src.endsWith(";")) {
95 assertEquals(script.getSourceText(), script.getParsedText());
96 }
97 final Object result = script.execute(null, a);
98 assertEquals(42, result);
99 }
100
101 @Test
102 public void test402() {
103 final JexlContext jc = new MapContext();
104
105 final String[] sources = {
106 "if (true) { return }",
107 "if (true) { 3; return }",
108 "(x->{ 3; return })()"
109 };
110
111 final JexlEngine jexl = new JexlBuilder().create();
112 for (final String source : sources) {
113 final JexlScript e = jexl.createScript(source);
114 final Object o = e.execute(jc);
115 assertNull(o);
116 }
117 }
118
119 @Test
120 public void test403() {
121
122 final String[] strings = {
123 " map1.`${item.a}` = 1;\n",
124 " map1[`${item.a}`] = 1;\n",
125 " map1[item.a] = 1;\n"
126 };
127
128 for (final String setmap : strings) {
129
130 final String src = "var a = {'a': 1};\n" +
131 "var list = [a, a];\n" +
132 "let map1 = {:};\n" +
133 "for (var item : list) {\n" +
134 setmap +
135 "}\n " +
136 "map1";
137
138 final JexlEngine jexl = new JexlBuilder().cache(64).create();
139 final JexlScript script = jexl.createScript(src);
140 for (int i = 0; i < 2; ++i) {
141 final Object result = script.execute(null);
142 assertTrue(result instanceof Map);
143 final Map<?, ?> map = (Map<?, ?>) result;
144 assertEquals(1, map.size());
145 assertTrue(map.containsKey(1));
146 assertTrue(map.containsValue(1));
147 }
148 }
149 }
150
151 @Test
152 public void test404a() {
153 final JexlEngine jexl = new JexlBuilder().cache(64).strict(true).safe(false).create();
154 Map<String, Object> a = Collections.singletonMap("b", 42);
155
156 for (final String src : new String[] { "a.b", "a?.b", "a['b']", "a?['b']", "a?.`b`" }) {
157 run404(jexl, src, a);
158 run404(jexl, src + ";", a);
159 }
160
161 for (final String src : new String[] { "a[b]", "a?[b]", "a?.`${b}`" }) {
162 run404(jexl, src, a, "b");
163 run404(jexl, src + ";", a, "b");
164 }
165
166 final Map<String, Object> b = Collections.singletonMap("c", 42);
167 a = Collections.singletonMap("b", b);
168 for (final String src : new String[] { "a[b].c", "a?[b]?['c']", "a?.`${b}`.c" }) {
169 run404(jexl, src, a, "b");
170 }
171 }
172
173 @Test
174 public void test404b() {
175
176 final JexlEngine jexl = new JexlBuilder()
177 .cache(64)
178 .strict(true)
179 .safe(false)
180 .create();
181
182 final Map<String, Object> b = Collections.singletonMap("c", 42);
183 final Map<String, Object> a = Collections.singletonMap("b", b);
184 JexlScript script;
185 Object result = -42;
186 script = jexl.createScript("a?['B']?['C']", "a");
187 result = script.execute(null, a);
188 assertEquals(script.getSourceText(), script.getParsedText());
189 assertNull(result);
190 script = jexl.createScript("a?['b']?['C']", "a");
191 assertEquals(script.getSourceText(), script.getParsedText());
192 result = script.execute(null, a);
193 assertNull(result);
194 script = jexl.createScript("a?['b']?['c']", "a");
195 assertEquals(script.getSourceText(), script.getParsedText());
196 result = script.execute(null, a);
197 assertEquals(42, result);
198 script = jexl.createScript("a?['B']?['C']?: 1042", "a");
199 assertEquals(script.getSourceText(), script.getParsedText());
200 result = script.execute(null, a);
201 assertEquals(1042, result);
202
203 script = jexl.createScript("a? ['B']:['C']", "a");
204 result = script.execute(null, a);
205 assertArrayEquals(new String[] { "B" }, (String[]) result);
206 script = jexl.createScript("a?['b'] ?: ['C']", "a");
207 result = script.execute(null, a);
208 assertEquals(b, result);
209 script = jexl.createScript("a?['B'] ?: ['C']", "a");
210 result = script.execute(null, a);
211 assertArrayEquals(new String[] { "C" }, (String[]) result);
212 }
213
214 @Test
215 public void test406a() {
216
217 final JexlEngine jexl = new JexlBuilder()
218 .cache(64)
219 .strict(true)
220 .safe(false)
221 .create();
222
223
224 final JexlContext context = new XuContext();
225
226 final List<String> list = Arrays.asList(
227 "[1, 2, 3, 4, ...].join('-')",
228 "[1, 2, 3, 4,].join('-')",
229 "(1 .. 4).join('-')",
230 "join([1, 2, 3, 4, ...], '-')",
231 "join([1, 2, 3, 4], '-')",
232 "join((1 .. 4), '-')");
233
234 for (final String src : list) {
235 final JexlScript script = jexl.createScript(src);
236 final Object result = script.execute(context);
237 assertEquals("1-2-3-4", result, src);
238 }
239
240 final String src0 = "x.join('*')";
241 final JexlScript script0 = jexl.createScript(src0, "x");
242 final String src1 = "join(x, '*')";
243 final JexlScript script1 = jexl.createScript(src1, "x");
244 for (final Object x : Arrays.asList(Arrays.asList(1, 2, 3, 4), new int[] { 1, 2, 3, 4 })) {
245 Object result = script0.execute(context, x);
246 assertEquals("1*2*3*4", result, src0);
247 result = script1.execute(context, x);
248 assertEquals("1*2*3*4", result, src1);
249 }
250 }
251
252 @Test
253 public void test407() {
254
255 final double r = 99.0d + 7.82d - 99.0d - 7.82d;
256 assertEquals(0d, r, 8.e-15);
257
258 final JexlEngine jexl = new JexlBuilder().create();
259 final JexlScript script = jexl.createScript("a + b - a - b", "a", "b");
260
261 Number result = (Number) script.execute(null, 99.0d, 7.82d);
262 assertEquals(0d, result.doubleValue(), 8.e-15);
263
264 result = (Number) script.execute(null, new BigDecimal(99.0d), new BigDecimal(7.82d));
265 assertEquals(0d, result.doubleValue(), 3.e-32);
266 }
267
268 @Test
269 public void test412() {
270 final Map<Object, Object> ctl = new HashMap<>();
271 ctl.put("one", 1);
272 ctl.put("two", 2);
273 final String fnsrc0 = "function f(x) { x }\n" + "let one = 'one', two = 'two';\n";
274
275 final List<String> list = Arrays.asList(
276 "{ one : f(1), two:f(2) }",
277 "{ one: f(1), two: f(2) }",
278 "{ one: f(1), two:f(2) }",
279 "{ one :f(1), two:f(2) }");
280
281 for (final String map0 : list) {
282 final String fnsrc = fnsrc0 + map0;
283 final JexlContext jc = new MapContext();
284 final JexlEngine jexl = new JexlBuilder().create();
285 final JexlScript e = jexl.createScript(fnsrc);
286 final Object o = e.execute(jc);
287 assertTrue(o instanceof Map);
288 final Map<?, ?> map = (Map<?, ?>) o;
289 assertEquals(map, ctl);
290 }
291 }
292
293 @Test
294 public void test413a() {
295 final JexlBuilder builder = new JexlBuilder();
296 final JexlEngine jexl = builder.create();
297 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
298 final Number result = (Number) script.execute(null, 12);
299 assertEquals(54, result);
300 }
301
302 @Test
303 public void test413b() {
304 final JexlBuilder builder = new JexlBuilder();
305 final JexlOptions options = builder.options();
306 options.setConstCapture(true);
307 options.setLexical(true);
308 final JexlEngine jexl = builder.create();
309 final JexlScript script = jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z");
310 final JexlException.Variable xvar = assertThrows(JexlException.Variable.class, () -> script.execute(null, 12), "c should be const");
311 assertEquals("c", xvar.getVariable());
312 }
313
314 @Test
315 public void test413c() {
316 final JexlBuilder builder = new JexlBuilder();
317 final JexlEngine jexl = builder.create();
318 final JexlScript script = jexl.createScript("#pragma jexl.options '+constCapture'\nvar c = 42; var f = y -> c += y; f(z)", "z");
319 final JexlException.Variable xvar = assertThrows(JexlException.Variable.class, () -> script.execute(null, 12), "c should be const");
320 assertEquals("c", xvar.getVariable());
321 }
322
323 @Test
324 public void test413d() {
325 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
326 final JexlEngine jexl = builder.create();
327 final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript("var c = 42; var f = y -> c += y; f(z)", "z"),
328 "c should be const");
329 assertTrue(xparse.getMessage().contains("const"));
330 }
331
332 @Test
333 public void test415() {
334 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
335 final JexlEngine jexl = builder.create();
336 JexlScript script;
337 Object result;
338 script = jexl.createScript("`#${c}`", "c");
339 result = script.execute(null, 42);
340 assertEquals("#42", result.toString());
341 script = jexl.createScript("`$${c}`", "c");
342 result = script.execute(null, 42);
343 assertEquals("$42", result.toString());
344 script = jexl.createScript("`$#{c}`", "c");
345 result = script.execute(null, 42);
346 assertEquals("$42", result.toString());
347 script = jexl.createScript("`##{c}`", "c");
348 result = script.execute(null, 42);
349 assertEquals("#42", result.toString());
350 script = jexl.createScript("`--##{c}`", "c");
351 result = script.execute(null, 42);
352 assertEquals("--#42", result.toString());
353 }
354
355 @Test
356 public void test419() throws NoSuchMethodException {
357
358 final Method currentTimeMillis = System.class.getMethod("currentTimeMillis");
359 assertFalse(RESTRICTED.allow(currentTimeMillis));
360
361 final JexlPermissions permissions = RESTRICTED.compose("java.lang { +System { currentTimeMillis(); } }");
362
363 assertTrue(permissions.allow(currentTimeMillis));
364 assertFalse(RESTRICTED.allow(currentTimeMillis));
365
366
367 final JexlEngine jexl = new JexlBuilder().namespaces(Collections.singletonMap("sns", System.class)).permissions(permissions).create();
368
369 final AtomicLong result = new AtomicLong();
370 assertEquals(0, result.get());
371 final long now = System.currentTimeMillis();
372
373 jexl.createScript("result.set(sns:currentTimeMillis())", "result").execute(null, result);
374 assertTrue(result.get() >= now);
375
376
377 final JexlScript script = jexl.createScript("sns:gc()");
378 final JexlException.Method method = assertThrows(JexlException.Method.class, () -> script.execute(null));
379 assertEquals("gc", method.getMethod());
380
381 }
382
383 @Test
384 public void testDocBreakContinue() {
385 final JexlBuilder builder = new JexlBuilder().features(new JexlFeatures().constCapture(true));
386 final JexlEngine jexl = builder.create();
387 JexlScript script;
388 Object result;
389
390 final String srcContinue = "let text = '';\n" +
391 "for (let i : (4..2)) { if (i == 3) continue; text += i; }\n" +
392 "text;";
393
394 script = jexl.createScript(srcContinue);
395 result = script.execute(null);
396 assertEquals("42", result);
397
398 final String srcBreak = "let i = 33;\n" +
399 "while (i < 66) { if (i == 42) { break; } i += 1; }\n" +
400 "i;";
401
402 script = jexl.createScript(srcBreak);
403 result = script.execute(null);
404 assertEquals(42, result);
405 }
406
407 @Test
408 public void testNamespaceVsTernary0() {
409 final VinzContext ctxt = new VinzContext();
410 ctxt.set("Users", "USERS");
411 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
412
413 JexlScript script = jexl.createScript("() -> {\n"
414 + " var fn = (user) -> {\n"
415 + " user ? user : member(Users, 'user');\n"
416 + " }\n"
417 + "}");
418
419 Object r = script.execute(ctxt);
420 assertNotNull(r);
421 script = (JexlScript) r;
422 r = script.execute(ctxt);
423 assertEquals("USERS.user", r);
424 }
425
426 @Test
427 public void testNamespaceVsTernary1() {
428 final VinzContext ctxt = new VinzContext();
429 ctxt.set("Users", "USERS");
430 ctxt.set("vinz", new VinzCaller(ctxt));
431 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).silent(false).create();
432
433 final JexlScript script = jexl.createScript(
434 "vinz.execute(() -> {\n"
435 + " var test = 42;\n"
436 + " var user = useTest ? test : member(Users, 'user');\n"
437 + "})\n" , "useTest");
438
439 Object r = script.execute(ctxt, false);
440 assertNotNull(r);
441 assertEquals("USERS.user", r);
442 r = script.execute(ctxt, true);
443 assertNotNull(r);
444 assertEquals(42, r);
445 }
446 }