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 java.util.HashMap;
20 import java.util.Map;
21
22 import org.apache.commons.jexl3.internal.Debugger;
23 import org.apache.commons.jexl3.internal.introspection.IndexedType;
24 import org.apache.commons.jexl3.internal.introspection.Uberspect;
25 import org.apache.commons.jexl3.introspection.JexlPermissions;
26 import org.apache.commons.jexl3.junit.Asserter;
27 import org.junit.Assert;
28 import org.junit.Before;
29 import org.junit.Test;
30
31
32
33
34
35
36 @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
37 public class PropertyAccessTest extends JexlTestCase {
38
39 private Asserter asserter;
40
41 public PropertyAccessTest() {
42 super("PropertyAccessTest");
43 }
44
45 @Before
46 @Override
47 public void setUp() {
48 asserter = new Asserter(JEXL);
49 }
50
51 @Test
52 public void testPropertyProperty() throws Exception {
53 final Integer i42 = Integer.valueOf(42);
54 final Integer i43 = Integer.valueOf(43);
55 final String s42 = "fourty-two";
56 final Object[] foo = new Object[3];
57 foo[0] = foo;
58 foo[1] = i42;
59 foo[2] = s42;
60 asserter.setVariable("foo", foo);
61 asserter.setVariable("zero", Integer.valueOf(0));
62 asserter.setVariable("one", Integer.valueOf(1));
63 asserter.setVariable("two", Integer.valueOf(2));
64 for (int l = 0; l < 2; ++l) {
65 asserter.assertExpression("foo.0", foo);
66 asserter.assertExpression("foo.0.'0'", foo);
67 asserter.assertExpression("foo.'1'", foo[1]);
68 asserter.assertExpression("foo.0.'1'", foo[1]);
69 asserter.assertExpression("foo.0.'1' = 43", i43);
70 asserter.assertExpression("foo.0.'1'", i43);
71 asserter.assertExpression("foo.0.'1' = 42", i42);
72
73 asserter.assertExpression("foo?.0.'1'", i42);
74 asserter.assertExpression("foo?.0", foo);
75 asserter.assertExpression("foo?.0.'0'", foo);
76 asserter.assertExpression("foo?.'1'", foo[1]);
77 asserter.assertExpression("foo.0?.'1'", foo[1]);
78 asserter.assertExpression("foo?.0.'1' = 43", i43);
79 asserter.assertExpression("foo?.0?.'1'", i43);
80 asserter.assertExpression("foo?.0.'1' = 42", i42);
81 asserter.assertExpression("foo?.0.'1'", i42);
82
83 asserter.assertExpression("foo?.0.`1`", i42);
84 asserter.assertExpression("foo?.0", foo);
85 asserter.assertExpression("foo?.0.'0'", foo);
86 asserter.assertExpression("foo?.`1`", foo[1]);
87 asserter.assertExpression("foo?.0.`1`", foo[1]);
88 asserter.assertExpression("foo?.0.`${one}` = 43", i43);
89 asserter.assertExpression("foo.0?.`${one}`", i43);
90 asserter.assertExpression("foo.0.`${one}` = 42", i42);
91 asserter.assertExpression("foo?.0?.`${one}`", i42);
92 }
93 }
94
95
96
97
98 public static class PropertyContainer {
99 String value0;
100 int value1;
101
102 public PropertyContainer(final String name, final int number) {
103 value0 = name;
104 value1 = number;
105 }
106
107 public Object getProperty(final String name) {
108 if ("name".equals(name)) {
109 return value0;
110 }
111 if ("number".equals(name)) {
112 return value1;
113 }
114 return null;
115 }
116
117 public void setProperty(final String name, final String value) {
118 if ("name".equals(name)) {
119 this.value0 = value.toUpperCase();
120 }
121 if ("number".equals(name)) {
122 this.value1 = Integer.parseInt(value) + 1000;
123 }
124 }
125 }
126
127
128
129
130
131 public static class PropertyArithmetic extends JexlArithmetic {
132 int ncalls = 0;
133
134 public PropertyArithmetic(final boolean astrict) {
135 super(astrict);
136 }
137
138 public Object propertySet(final IndexedType.IndexedContainer map, final String key, final Integer value) {
139 if (map.getContainerClass().equals(PropertyContainer.class)
140 && map.getContainerName().equals("property")) {
141 try {
142 map.set(key, value.toString());
143 ncalls += 1;
144 } catch (final Exception xany) {
145 throw new JexlException.Operator(null, key + "." + value.toString(), xany);
146 }
147 return null;
148 }
149 return JexlEngine.TRY_FAILED;
150 }
151
152 public int getCalls() {
153 return ncalls;
154 }
155 }
156
157 @Test
158 public void testInnerViaArithmetic() throws Exception {
159 final PropertyArithmetic pa = new PropertyArithmetic(true);
160 final JexlEngine jexl = new JexlBuilder().arithmetic(pa).debug(true).strict(true).cache(32).create();
161 final PropertyContainer quux = new PropertyContainer("bar", 169);
162 Object result;
163
164 final JexlScript getName = jexl.createScript("foo.property.name", "foo");
165 result = getName.execute(null, quux);
166 Assert.assertEquals("bar", result);
167 final int calls = pa.getCalls();
168 final JexlScript setName = jexl.createScript("foo.property.name = $0", "foo", "$0");
169 setName.execute(null, quux, 123);
170 result = getName.execute(null, quux);
171 Assert.assertEquals("123", result);
172 setName.execute(null, quux, 456);
173 result = getName.execute(null, quux);
174 Assert.assertEquals("456", result);
175 Assert.assertEquals(calls + 2, pa.getCalls());
176 setName.execute(null, quux, "quux");
177 result = getName.execute(null, quux);
178 Assert.assertEquals("QUUX", result);
179 Assert.assertEquals(calls + 2, pa.getCalls());
180
181 final JexlScript getNumber = jexl.createScript("foo.property.number", "foo");
182 result = getNumber.execute(null, quux);
183 Assert.assertEquals(169, result);
184 final JexlScript setNumber = jexl.createScript("foo.property.number = $0", "foo", "$0");
185 setNumber.execute(null, quux, 42);
186 result = getNumber.execute(null, quux);
187 Assert.assertEquals(1042, result);
188 setNumber.execute(null, quux, 24);
189 result = getNumber.execute(null, quux);
190 Assert.assertEquals(1024, result);
191 Assert.assertEquals(calls + 4, pa.getCalls());
192 setNumber.execute(null, quux, "42");
193 result = getNumber.execute(null, quux);
194 Assert.assertEquals(1042, result);
195 Assert.assertEquals(calls + 4, pa.getCalls());
196 }
197
198 public static class Container extends PropertyContainer {
199 public Container(final String name, final int number) {
200 super(name, number);
201 }
202
203 public Object getProperty(final int ref) {
204 switch (ref) {
205 case 0:
206 return value0;
207 case 1:
208 return value1;
209 default:
210 return null;
211 }
212 }
213
214 @Override
215 public void setProperty(final String name, final String value) {
216 if ("name".equals(name)) {
217 this.value0 = value;
218 }
219 }
220
221 public void setProperty(final String name, final int value) {
222 if ("number".equals(name)) {
223 this.value1 = value;
224 }
225 }
226
227 public void setProperty(final int ref, final String value) {
228 if (0 == ref) {
229 this.value0 = value;
230 }
231 }
232
233 public void setProperty(final int ref, final int value) {
234 if (1 == ref) {
235 this.value1 = value;
236 }
237 }
238 }
239
240 @Test
241 public void testInnerProperty() throws Exception {
242 final PropertyArithmetic pa = new PropertyArithmetic(true);
243 final JexlEngine jexl = new JexlBuilder().arithmetic(pa).debug(true).strict(true).cache(32).create();
244 final Container quux = new Container("quux", 42);
245 final JexlScript get;
246 Object result;
247
248 final int calls = pa.getCalls();
249 final JexlScript getName = JEXL.createScript("foo.property.name", "foo");
250 result = getName.execute(null, quux);
251 Assert.assertEquals("quux", result);
252
253 final JexlScript get0 = JEXL.createScript("foo.property.0", "foo");
254 result = get0.execute(null, quux);
255 Assert.assertEquals("quux", result);
256
257 final JexlScript getNumber = JEXL.createScript("foo.property.number", "foo");
258 result = getNumber.execute(null, quux);
259 Assert.assertEquals(42, result);
260
261 final JexlScript get1 = JEXL.createScript("foo.property.1", "foo");
262 result = get1.execute(null, quux);
263 Assert.assertEquals(42, result);
264
265 final JexlScript setName = JEXL.createScript("foo.property.name = $0", "foo", "$0");
266 setName.execute(null, quux, "QUUX");
267 result = getName.execute(null, quux);
268 Assert.assertEquals("QUUX", result);
269 result = get0.execute(null, quux);
270 Assert.assertEquals("QUUX", result);
271
272 final JexlScript set0 = JEXL.createScript("foo.property.0 = $0", "foo", "$0");
273 set0.execute(null, quux, "BAR");
274 result = getName.execute(null, quux);
275 Assert.assertEquals("BAR", result);
276 result = get0.execute(null, quux);
277 Assert.assertEquals("BAR", result);
278
279 final JexlScript setNumber = JEXL.createScript("foo.property.number = $0", "foo", "$0");
280 setNumber.execute(null, quux, -42);
281 result = getNumber.execute(null, quux);
282 Assert.assertEquals(-42, result);
283 result = get1.execute(null, quux);
284 Assert.assertEquals(-42, result);
285
286 final JexlScript set1 = JEXL.createScript("foo.property.1 = $0", "foo", "$0");
287 set1.execute(null, quux, 24);
288 result = getNumber.execute(null, quux);
289 Assert.assertEquals(24, result);
290 result = get1.execute(null, quux);
291 Assert.assertEquals(24, result);
292
293 Assert.assertEquals(calls, pa.getCalls());
294 }
295
296
297 @Test
298 public void testStringIdentifier() throws Exception {
299 final Map<String, String> foo = new HashMap<>();
300
301 final JexlContext jc = new MapContext();
302 jc.set("foo", foo);
303 foo.put("q u u x", "456");
304 JexlExpression e = JEXL.createExpression("foo.\"q u u x\"");
305 Object result = e.evaluate(jc);
306 Assert.assertEquals("456", result);
307 e = JEXL.createExpression("foo.'q u u x'");
308 result = e.evaluate(jc);
309 Assert.assertEquals("456", result);
310 JexlScript s = JEXL.createScript("foo.\"q u u x\"");
311 result = s.execute(jc);
312 Assert.assertEquals("456", result);
313 s = JEXL.createScript("foo.'q u u x'");
314 result = s.execute(jc);
315 Assert.assertEquals("456", result);
316
317 final Debugger dbg = new Debugger();
318 dbg.debug(e);
319 final String dbgdata = dbg.toString();
320 Assert.assertEquals("foo.'q u u x'", dbgdata);
321 }
322
323 @Test
324 public void testErroneousIdentifier() throws Exception {
325 final MapContext ctx = new MapContext();
326 final JexlEngine engine = new JexlBuilder().strict(true).silent(false).create();
327
328
329 String stmt = "(x)->{ x?.class ?? 'oops' }";
330 JexlScript script = engine.createScript(stmt);
331 Object result = script.execute(ctx, "querty");
332 Assert.assertEquals("querty".getClass(), result);
333
334
335 stmt = "(x)->{ x.class1 ?? 'oops' }";
336 script = engine.createScript(stmt);
337 result = script.execute(ctx, "querty");
338 Assert.assertEquals("oops", result);
339
340
341 ctx.set("al", "la");
342 stmt = "(x)->{ x.`c${al}ss` ?? 'oops' }";
343 script = engine.createScript(stmt);
344 result = script.execute(ctx, "querty");
345 Assert.assertEquals("querty".getClass(), result);
346
347
348 stmt = "(x)->{ x?.`c${al}ss` ?? 'oops' }";
349 script = engine.createScript(stmt);
350 result = script.execute(ctx, "querty");
351 Assert.assertEquals("querty".getClass(), result);
352
353
354 stmt = "(x)->{ x?.`c${la}ss` ?? 'oops' }";
355 script = engine.createScript(stmt);
356 result = script.execute(ctx, "querty");
357 Assert.assertEquals("oops", result);
358
359
360 stmt = "(x)->{ x.`c${la}ss` ?? 'oops' }";
361 script = engine.createScript(stmt);
362 result = script.execute(ctx, "querty");
363 Assert.assertEquals("oops", result);
364
365
366 stmt = "(x)->{ x?.`c${la--ss` ?? 'oops' }";
367 script = engine.createScript(stmt);
368 result = script.execute(ctx, "querty");
369 Assert.assertEquals("oops", result);
370
371
372 stmt = "(x)->{ x.`c${la--ss` ?? 'oops' }";
373 script = engine.createScript(stmt);
374 result = script.execute(ctx, "querty");
375 Assert.assertEquals("oops", result);
376 }
377
378 @Test
379 public void test250() throws Exception {
380 final MapContext ctx = new MapContext();
381 final HashMap<Object, Object> x = new HashMap<>();
382 x.put(2, "123456789");
383 ctx.set("x", x);
384 final JexlEngine engine = new JexlBuilder()
385 .uberspect(new Uberspect(null, null, JexlPermissions.UNRESTRICTED))
386 .strict(true).silent(false).create();
387 String stmt = "x.2.class.name";
388 JexlScript script = engine.createScript(stmt);
389 Object result = script.execute(ctx);
390 Assert.assertEquals("java.lang.String", result);
391
392 try {
393 stmt = "x.3?.class.name";
394 script = engine.createScript(stmt);
395 result = script.execute(ctx);
396 Assert.assertNull(result);
397 } catch (final JexlException xany) {
398 Assert.fail("Should have evaluated to null");
399 }
400 try {
401 stmt = "x?.3.class.name";
402 script = engine.createScript(stmt);
403 result = script.execute(ctx);
404 Assert.fail("Should have thrown, fail on 3");
405 Assert.assertNull(result);
406 } catch (final JexlException xany) {
407 Assert.assertTrue(xany.detailedMessage().contains("3"));
408 }
409 try {
410 stmt = "x?.3?.class.name";
411 script = engine.createScript(stmt);
412 result = script.execute(ctx);
413 Assert.assertNull(result);
414 } catch (final JexlException xany) {
415 Assert.fail("Should have evaluated to null");
416 }
417 try {
418 stmt = "y?.3.class.name";
419 script = engine.createScript(stmt);
420 result = script.execute(ctx);
421 Assert.assertNull(result);
422 } catch (final JexlException xany) {
423 Assert.fail("Should have evaluated to null");
424 }
425 try {
426 stmt = "x?.y?.z";
427 script = engine.createScript(stmt);
428 result = script.execute(ctx);
429 Assert.assertNull(result);
430 } catch (final JexlException xany) {
431 Assert.fail("Should have evaluated to null");
432 }
433 try {
434 stmt = "x? (x.y? (x.y.z ?: null) :null) : null";
435 script = engine.createScript(stmt);
436 result = script.execute(ctx);
437 Assert.assertNull(result);
438 } catch (final JexlException xany) {
439 Assert.fail("Should have evaluated to null");
440 }
441 }
442
443 public static class Prompt {
444 private final Map<String, PromptValue> values = new HashMap<>();
445
446 public Object get(final String name) {
447 final PromptValue v = values.get(name);
448 return v != null? v.getValue() : null;
449 }
450
451 public void set(final String name, final Object value) {
452 values.put(name, new PromptValue(value));
453 }
454 }
455
456
457
458
459 public static class PromptValue {
460
461
462 private Object value;
463
464 public PromptValue(final Object v) {
465 value = v;
466 }
467
468 public Object getValue() {
469 return value;
470 }
471
472 public void setValue(final Object value) {
473 this.value = value;
474 }
475 }
476
477 @Test
478 public void test275a() throws Exception {
479 final JexlEngine jexl = new JexlBuilder().strict(true).safe(false).create();
480 final JexlContext ctxt = new MapContext();
481 JexlScript script;
482 Object result = null;
483 final Prompt p0 = new Prompt();
484 p0.set("stuff", 42);
485 ctxt.set("$in", p0);
486
487
488 script = jexl.createScript("$in[p].intValue()", "p");
489 try {
490 result = script.execute(ctxt, "fail");
491 Assert.fail("should have thrown a " + JexlException.Property.class);
492 } catch (final JexlException xany) {
493 Assert.assertEquals(JexlException.Property.class, xany.getClass());
494 }
495 Assert.assertNull(result);
496 result = script.execute(ctxt, "stuff");
497 Assert.assertEquals(42, result);
498
499
500 script = jexl.createScript("$in[p]?.intValue()", "p");
501 result = script.execute(ctxt, "fail");
502 Assert.assertNull(result);
503 result = script.execute(ctxt, "stuff");
504 Assert.assertEquals(42, result);
505
506
507 script = jexl.createScript("$in.`${p}`.intValue()", "p");
508 try {
509 result = script.execute(ctxt, "fail");
510 Assert.fail("should have thrown a " + JexlException.Property.class);
511 } catch (final JexlException xany) {
512 Assert.assertEquals(JexlException.Property.class, xany.getClass());
513 }
514 result = script.execute(ctxt, "stuff");
515 Assert.assertEquals(42, result);
516
517
518 script = jexl.createScript("$in.`${p}`?.intValue()", "p");
519 result = script.execute(ctxt, "fail");
520 Assert.assertNull(result);
521 result = script.execute(ctxt, "stuff");
522 Assert.assertEquals(42, result);
523
524 }
525 @Test
526 public void test275b() throws Exception {
527 final JexlEngine jexl = new JexlBuilder().strict(true).safe(true).create();
528 final JexlContext ctxt = new MapContext();
529 JexlScript script;
530 final Prompt p0 = new Prompt();
531 p0.set("stuff", 42);
532 ctxt.set("$in", p0);
533
534
535 script = jexl.createScript("$in[p].intValue()", "p");
536 Object result = script.execute(ctxt, "fail");
537 Assert.assertNull(result);
538
539 result = script.execute(ctxt, "stuff");
540 Assert.assertEquals(42, result);
541
542
543
544 script = jexl.createScript("$in.`${p}`.intValue()", "p");
545 result = script.execute(ctxt, "fail");
546 Assert.assertNull(result);
547 result = script.execute(ctxt, "stuff");
548 Assert.assertEquals(42, result);
549
550
551 script = jexl.createScript("$in.`${p}`?.intValue()", "p");
552 result = script.execute(ctxt, "fail");
553 Assert.assertNull(result);
554 result = script.execute(ctxt, "stuff");
555 Assert.assertEquals(42, result);
556 }
557
558 }