View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jexl3;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
21  import static org.junit.jupiter.api.Assertions.assertNotEquals;
22  import static org.junit.jupiter.api.Assertions.assertSame;
23  
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.concurrent.atomic.AtomicInteger;
32  
33  import org.apache.commons.jexl3.jexl342.OptionalArithmetic;
34  import org.apache.commons.jexl3.junit.Asserter;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.junit.jupiter.api.BeforeEach;
38  import org.junit.jupiter.api.Test;
39  
40  /**
41   * Tests for array access operator []
42   */
43  @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
44  class SideEffectTest extends JexlTestCase {
45  
46      /**
47       * An arithmetic that implements 2 selfAdd methods.
48       */
49      public static class Arithmetic246 extends JexlArithmetic {
50          public Arithmetic246(final boolean astrict) {
51              super(astrict);
52          }
53  
54          @Override
55          public Object add(final Object right, final Object left) {
56              return super.add(left, right);
57          }
58  
59          public Object selfAdd(final Appendable c, final String item) throws IOException {
60              c.append(item);
61              return c;
62          }
63  
64          public Object selfAdd(final Collection<String> c, final String item) {
65              c.add(item);
66              return c;
67          }
68      }
69  
70      public static class Arithmetic246b extends Arithmetic246 {
71              public Arithmetic246b(final boolean astrict) {
72                  super(astrict);
73              }
74  
75              public Object selfAdd(final Object c, final String item) throws IOException {
76                  if (c == null) {
77                      return new ArrayList<>(Collections.singletonList(item));
78                  }
79                  if (c instanceof Appendable) {
80                      ((Appendable) c).append(item);
81                      return c;
82                  }
83                  return JexlEngine.TRY_FAILED;
84              }
85          }
86  
87      // an arithmetic that performs side effects
88      public static class Arithmetic248 extends JexlArithmetic {
89          public Arithmetic248(final boolean strict) {
90              super(strict);
91          }
92  
93          public Object arrayGet(final List<?> list, final Collection<Integer> range) {
94              final List<Object> rl = new ArrayList<>(range.size());
95              for(final int i : range) {
96                  rl.add(list.get(i));
97              }
98              return rl;
99          }
100 
101         public Object arraySet(final List<Object> list, final Collection<Integer> range, final Object value) {
102             for(final int i : range) {
103                 list.set(i, value);
104             }
105             return list;
106         }
107     }
108 
109     public static class Foo {
110         int value;
111         Foo(final int v) {
112             value = v;
113         }
114 
115         public int getBar(final int x) {
116             return value + x;
117         }
118 
119         public int getValue() {
120             return value;
121         }
122         public void setBar(final int x, final long v) {
123             value = (int) v + x;
124         }
125 
126         public void setValue(final long v) {
127             value = (int) v;
128         }
129 
130         @Override
131         public String toString() {
132             return Integer.toString(value);
133         }
134     }
135 
136     // an arithmetic that performs side effects
137     public static class SelfArithmetic extends OptionalArithmetic {
138         public SelfArithmetic(final boolean strict) {
139             super(strict);
140         }
141 
142         public Var and(final Var lhs, final Var rhs) {
143             return new Var(lhs.value & rhs.value);
144         }
145 
146         public Object arrayGet(final Var variable, final String property) {
147             return "VALUE".equals(property)? variable.value : JexlEngine.TRY_FAILED;
148         }
149 
150         public Object arraySet(final Var variable, final String property, final int v) {
151             return "VALUE".equals(property)? variable.value = v : JexlEngine.TRY_FAILED;
152         }
153 
154         public int decrement(final Var lhs) {
155             return lhs.value - 1;
156         }
157 
158         public int getAndIncrement(final AtomicInteger i) {
159             return i.getAndIncrement();
160         }
161 
162         public int increment(final Var lhs) {
163             return lhs.value + 1;
164         }
165 
166         public int incrementAndGet(final AtomicInteger i) {
167             return i.incrementAndGet();
168         }
169 
170         public Var or(final Var lhs, final Var rhs) {
171             return new Var(lhs.value | rhs.value);
172         }
173 
174         public int positivize(final Number n) {
175             return n.intValue();
176         }
177 
178         public int positivize(final Var n) {
179             return n.value;
180         }
181 
182         public Object propertyGet(final Var variable, final String property) {
183             return "value".equals(property)? variable.value : JexlEngine.TRY_FAILED;
184         }
185 
186         public Object propertySet(final Var variable, final String property, final int v) {
187             return "value".equals(property)? variable.value = v : JexlEngine.TRY_FAILED;
188         }
189 
190         public Var selfAdd(final Var lhs, final Var rhs) {
191             lhs.value += rhs.value;
192             return lhs;
193         }
194 
195         public Var selfAnd(final Var lhs, final Var rhs) {
196             lhs.value &= rhs.value;
197             return lhs;
198         }
199 
200         public Var selfDivide(final Var lhs, final Var rhs) {
201             lhs.value /= rhs.value;
202             return lhs;
203         }
204 
205         public Var selfMod(final Var lhs, final Var rhs) {
206             lhs.value %= rhs.value;
207             return lhs;
208         }
209 
210         public Var selfMultiply(final Var lhs, final Var rhs) {
211             lhs.value *= rhs.value;
212             return lhs;
213         }
214 
215         public Var selfOr(final Var lhs, final Var rhs) {
216             lhs.value |= rhs.value;
217             return lhs;
218         }
219 
220         public Var selfShiftLeft(final Var lhs, final int rhs) {
221             lhs.value <<= rhs;
222             return lhs;
223         }
224 
225         public Var selfShiftRight(final Var lhs, final int rhs) {
226             lhs.value >>= rhs;
227             return lhs;
228         }
229 
230         public Var selfShiftRightUnsigned(final Var lhs, final int rhs) {
231             lhs.value >>>= rhs;
232             return lhs;
233         }
234 
235         // for kicks, this one does not side effect but overloads nevertheless
236         public Var selfSubtract(final Var lhs, final Var rhs) {
237             return new Var(lhs.value - rhs.value);
238         }
239 
240         public Var selfXor(final Var lhs, final Var rhs) {
241             lhs.value ^= rhs.value;
242             return lhs;
243         }
244 
245         public Var shiftLeft(final Var lhs, final int rhs) {
246             return new Var(lhs.value << rhs);
247         }
248 
249         public Var shiftRight(final Var lhs, final int rhs) {
250             return new Var(lhs.value >> rhs);
251         }
252 
253         public Var shiftRightUnsigned(final Var lhs, final int rhs) {
254             return new Var(lhs.value >>> rhs);
255         }
256 
257         public Var xor(final Var lhs, final Var rhs) {
258             return new Var(lhs.value ^ rhs.value);
259         }
260     }
261 
262     public static class Var {
263         int value;
264 
265         Var(final int v) {
266             value = v;
267         }
268 
269         @Override public String toString() {
270             return Integer.toString(value);
271         }
272     }
273 
274     private Asserter asserter;
275 
276     public SideEffectTest() {
277         super("SideEffectTest");
278     }
279 
280     private void run246(final JexlArithmetic j246) {
281         final Log log246 = LogFactory.getLog(SideEffectTest.class);
282         // quiesce the logger
283         final java.util.logging.Logger ll246 = java.util.logging.LogManager.getLogManager().getLogger(SideEffectTest.class.getName());
284        // ll246.setLevel(Level.WARNING);
285         final JexlEngine jexl = new JexlBuilder().arithmetic(j246).cache(32).logger(log246).create();
286         final JexlScript script = jexl.createScript("z += x", "x");
287         final MapContext ctx = new MapContext();
288         List<String> z = new ArrayList<>(1);
289 
290         // no ambiguous, std case
291         ctx.set("z", z);
292         Object zz = script.execute(ctx, "42");
293         assertSame(zz, z);
294         assertEquals(1, z.size());
295         z.clear();
296 
297         boolean t246 = false;
298         // call with null
299         try {
300             script.execute(ctx, "42");
301             zz = ctx.get("z");
302             assertInstanceOf(List.class, zz);
303             z = (List<String>) zz;
304             assertEquals(1, z.size());
305         } catch (JexlException | ArithmeticException xjexl) {
306             t246 = true;
307             assertEquals(j246.getClass(), Arithmetic246.class);
308         }
309         ctx.clear();
310 
311         // a non ambiguous call still succeeds
312         ctx.set("z", z);
313         zz = script.execute(ctx, "-42");
314         assertSame(zz, z);
315         assertEquals(t246? 1 : 2, z.size());
316     }
317 
318     protected void runSelfIncrement(final JexlEngine jexl, final JexlContext jc) {
319         JexlScript script = jexl.createScript("x -> [+x, +(x++), +x]");
320         final Var v11 = new Var(3115);
321         final AtomicInteger i11 = new AtomicInteger(3115);
322         for(final Object v : Arrays.asList(v11, i11)) {
323             final Object result = script.execute(jc, v);
324             assertInstanceOf(int[].class, result);
325             final int[] r = (int[]) result;
326             assertEquals(3115, r[0]);
327             assertEquals(3115, r[1]);
328             assertEquals(3116, r[2]);
329         }
330 
331         script = jexl.createScript("x -> [+x, +(++x), +x]");
332         final Var v12 = new Var(3189);
333         final AtomicInteger i12 = new AtomicInteger(3189);
334         for(final Object v : Arrays.asList(v12, i12)) {
335             final Object result = script.execute(jc, v);
336             assertInstanceOf(int[].class, result);
337             final int[] r = (int[]) result;
338             assertEquals(3189, r[0]);
339             assertEquals(3190, r[1]);
340             assertEquals(3190, r[2]);
341         }
342 
343         script = jexl.createScript("x -> [+x, +(x--), +x]");
344         final Var v13 = new Var(3115);
345         for(final Object v : Arrays.asList(v13)) {
346             final Object result = script.execute(jc, v13);
347             assertInstanceOf(int[].class, result);
348             final int[] r = (int[]) result;
349             assertEquals(3115, r[0]);
350             assertEquals(3115, r[1]);
351             assertEquals(3114, r[2]);
352         }
353 
354         script = jexl.createScript("x -> [+x, +(--x), +x]");
355         final Var v14 = new Var(3189);
356         for(final Object v : Arrays.asList(v14)) {
357             final Object result = script.execute(jc, v);
358             assertInstanceOf(int[].class, result);
359             final int[] r = (int[]) result;
360             assertEquals(3189, r[0]);
361             assertEquals(3188, r[1]);
362             assertEquals(3188, r[2]);
363         }
364     }
365 
366     protected void runSelfOverload(final JexlEngine jexl, final JexlContext jc) {
367         JexlScript script;
368         Object result;
369         script = jexl.createScript("(x, y)->{ x += y }");
370         result = script.execute(jc, 3115, 15);
371         assertEquals(3115 + 15, result);
372         final Var v0 = new Var(3115);
373         result = script.execute(jc, v0, new Var(15));
374         assertEquals(result, v0);
375         assertEquals(3115 + 15, v0.value);
376 
377         script = jexl.createScript("(x, y)->{ x -= y}");
378         result = script.execute(jc, 3115, 15);
379         assertEquals(3115 - 15, result);
380         final Var v1 = new Var(3115);
381         result = script.execute(jc, v1, new Var(15));
382         assertNotEquals(result, v1); // not a real side effect
383         assertEquals(3115 - 15, ((Var) result).value);
384 
385         script = jexl.createScript("(x, y)->{ x *= y }");
386         result = script.execute(jc, 3115, 15);
387         assertEquals(3115 * 15, result);
388         final Var v2 = new Var(3115);
389         result = script.execute(jc, v2, new Var(15));
390         assertEquals(result, v2);
391         assertEquals(3115 * 15, v2.value);
392 
393         script = jexl.createScript("(x, y)->{ x /= y }");
394         result = script.execute(jc, 3115, 15);
395         assertEquals(3115 / 15, result);
396         final Var v3 = new Var(3115);
397         result = script.execute(jc, v3, new Var(15));
398         assertEquals(result, v3);
399         assertEquals(3115 / 15, v3.value);
400 
401         script = jexl.createScript("(x, y)->{ x %= y }");
402         result = script.execute(jc, 3115, 15);
403         assertEquals(3115 % 15, result);
404         final Var v4 = new Var(3115);
405         result = script.execute(jc, v4, new Var(15));
406         assertEquals(result, v4);
407         assertEquals(3115 % 15, v4.value);
408 
409         script = jexl.createScript("(x, y)->{ x &= y }");
410         result = script.execute(jc, 3115, 15);
411         assertEquals(3115L & 15, result);
412         final Var v5 = new Var(3115);
413         result = script.execute(jc, v5, new Var(15));
414         assertEquals(result, v5);
415         assertEquals(3115 & 15, v5.value);
416 
417         script = jexl.createScript("(x, y)->{ x |= y }");
418         result = script.execute(jc, 3115, 15);
419         assertEquals(3115L | 15, result);
420         final Var v6 = new Var(3115);
421         result = script.execute(jc, v6, new Var(15));
422         assertEquals(result, v6);
423         assertEquals(3115L | 15, v6.value);
424 
425         script = jexl.createScript("(x, y)->{ x ^= y }");
426         result = script.execute(jc, 3115, 15);
427         assertEquals(3115L ^ 15, result);
428         final Var v7 = new Var(3115);
429         result = script.execute(jc, v7, new Var(15));
430         assertEquals(result, v7);
431         assertEquals(3115L ^ 15, v7.value);
432 
433         script = jexl.createScript("(x, y)->{ x >>>= y }");
434         result = script.execute(jc, 234453115, 5);
435         assertEquals(234453115L >>> 5, result);
436         final Var v8 = new Var(234453115);
437         result = script.execute(jc, v8, 5);
438         assertEquals(result, v8);
439         assertEquals(234453115L >>> 5, v8.value);
440 
441         script = jexl.createScript("(x, y)->{ x >>= y }");
442         result = script.execute(jc, 435566788L, 7);
443         assertEquals(435566788L >> 7, result);
444         final Var v9 = new Var(435566788);
445         result = script.execute(jc, v9, 7);
446         assertEquals(result, v9);
447         assertEquals(435566788L >> 7, v9.value);
448 
449         script = jexl.createScript("(x, y)->{ x <<= y }");
450         result = script.execute(jc, 3115, 2);
451         assertEquals(3115L << 2, result);
452         final Var v10 = new Var(3115);
453         result = script.execute(jc, v10, 2);
454         assertEquals(result, v10);
455         assertEquals(3115L << 2, v10.value);
456     }
457 
458     @Override
459     @BeforeEach
460     public void setUp() {
461         asserter = new Asserter(JEXL);
462     }
463 
464     @Test
465     void test246() {
466         run246(new Arithmetic246(true));
467     }
468 
469     @Test
470     void test246b() {
471         run246(new Arithmetic246b(true));
472     }
473 
474     @Test
475     void test248() {
476         final MapContext ctx = new MapContext();
477         final List<Object> foo = new ArrayList<>(Arrays.asList(10, 20, 30, 40));
478         ctx.set("foo", foo);
479 
480         final JexlEngine engine = new JexlBuilder().arithmetic(new Arithmetic248(true)).create();
481         final JexlScript foo12 = engine.createScript("foo[1..2]");
482         Object r = foo12.execute(ctx);
483         assertEquals(Arrays.asList(20, 30), r);
484 
485         final JexlScript foo12assign = engine.createScript("foo[1..2] = x", "x");
486         r = foo12assign.execute(ctx, 25);
487         assertEquals(25, r);
488         assertEquals(Arrays.asList(10, 25, 25, 40), foo);
489     }
490 
491     @Test
492     void testArithmeticSelf() {
493         final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new SelfArithmetic(false)).create();
494         final JexlContext jc = null;
495         runSelfOverload(jexl, jc);
496         runSelfOverload(jexl, jc);
497     }
498 
499     @Test
500     void testArithmeticSelfNoCache() {
501         final JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new SelfArithmetic(false)).create();
502         final JexlContext jc = null;
503         runSelfOverload(jexl, jc);
504     }
505 
506     @Test
507     void testIncrementSelf() {
508         final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new SelfArithmetic(false)).create();
509         final JexlContext jc = null;
510         runSelfIncrement(jexl, jc);
511         runSelfIncrement(jexl, jc);
512     }
513 
514     @Test
515     void testIncrementSelfNoCache() {
516         final JexlEngine jexl = new JexlBuilder().cache(0).arithmetic(new SelfArithmetic(false)).create();
517         final JexlContext jc = null;
518         runSelfIncrement(jexl, jc);
519     }
520 
521     @Test
522     void testOverrideGetSet() {
523         final JexlEngine jexl = new JexlBuilder().cache(64).arithmetic(new SelfArithmetic(false)).create();
524         final JexlContext jc = null;
525 
526         JexlScript script;
527         Object result;
528         final Var v0 = new Var(3115);
529         script = jexl.createScript("(x)->{ x.value}");
530         result = script.execute(jc, v0);
531         assertEquals(3115, result);
532         script = jexl.createScript("(x)->{ x['VALUE']}");
533         result = script.execute(jc, v0);
534         assertEquals(3115, result);
535         script = jexl.createScript("(x,y)->{ x.value = y}");
536         result = script.execute(jc, v0, 42);
537         assertEquals(42, result);
538         script = jexl.createScript("(x,y)->{ x['VALUE'] = y}");
539         result = script.execute(jc, v0, 169);
540         assertEquals(169, result);
541     }
542 
543     @Test
544     void testSideEffectAntishArray() throws Exception {
545         final Integer i41 = Integer.valueOf(4141);
546         final Integer i42 = Integer.valueOf(42);
547         final Integer i43 = Integer.valueOf(43);
548         final Object[] foo = new Object[3];
549         foo[1] = i42;
550         foo[2] = i43;
551         asserter.setVariable("foo.bar", foo);
552         foo[0] = i41;
553         asserter.assertExpression("foo.bar[0] += 2", i41 + 2);
554         assertEquals(foo[0], i41 + 2);
555         foo[0] = i41;
556         asserter.assertExpression("foo.bar[0] -= 2", i41 - 2);
557         assertEquals(foo[0], i41 - 2);
558         foo[0] = i41;
559         asserter.assertExpression("foo.bar[0] *= 2", i41 * 2);
560         assertEquals(foo[0], i41 * 2);
561         foo[0] = i41;
562         asserter.assertExpression("foo.bar[0] /= 2", i41 / 2);
563         assertEquals(foo[0], i41 / 2);
564         foo[0] = i41;
565         asserter.assertExpression("foo.bar[0] %= 2", i41 % 2);
566         assertEquals(foo[0], i41 % 2);
567         foo[0] = i41;
568         asserter.assertExpression("foo.bar[0] &= 3", (long) (i41 & 3));
569         assertEquals(foo[0], (long)(i41 & 3));
570         foo[0] = i41;
571         asserter.assertExpression("foo.bar[0] |= 2", (long)(i41 | 2));
572         assertEquals(foo[0], (long)(i41 | 2));
573         foo[0] = i41;
574         asserter.assertExpression("foo.bar[0] ^= 2", (long)(i41 ^ 2));
575         assertEquals(foo[0], (long)(i41 ^ 2));
576     }
577 
578     @Test
579     void testSideEffectArray() throws Exception {
580         final Integer i41 = Integer.valueOf(4141);
581         final Integer i42 = Integer.valueOf(42);
582         final Integer i43 = Integer.valueOf(43);
583         final String s42 = "fourty-two";
584         final String s43 = "fourty-three";
585         final Object[] foo = new Object[3];
586         foo[1] = i42;
587         foo[2] = i43;
588         asserter.setVariable("foo", foo);
589         foo[0] = i41;
590         asserter.assertExpression("foo[0] += 2", i41 + 2);
591         assertEquals(foo[0], i41 + 2);
592         foo[0] = i41;
593         asserter.assertExpression("foo[0] -= 2", i41 - 2);
594         assertEquals(foo[0], i41 - 2);
595         foo[0] = i41;
596         asserter.assertExpression("foo[0] *= 2", i41 * 2);
597         assertEquals(foo[0], i41 * 2);
598         foo[0] = i41;
599         asserter.assertExpression("foo[0] /= 2", i41 / 2);
600         assertEquals(foo[0], i41 / 2);
601         foo[0] = i41;
602         asserter.assertExpression("foo[0] %= 2", i41 % 2);
603         assertEquals(foo[0], i41 % 2);
604         foo[0] = i41;
605         asserter.assertExpression("foo[0] &= 3", (long) (i41 & 3));
606         assertEquals(foo[0], (long) (i41 & 3));
607         foo[0] = i41;
608         asserter.assertExpression("foo[0] |= 2", (long) (i41 | 2));
609         assertEquals(foo[0], (long) (i41 | 2));
610         foo[0] = i41;
611         asserter.assertExpression("foo[0] ^= 2", (long) (i41 ^ 2));
612         assertEquals(foo[0], (long) (i41 ^ 2));
613     }
614 
615     @Test
616     void testSideEffectBean() throws Exception {
617         final Integer i41 = Integer.valueOf(4141);
618         final Foo foo = new Foo(0);
619         asserter.setVariable("foo", foo);
620         foo.value = i41;
621         asserter.assertExpression("foo.value += 2", i41 + 2);
622         assertEquals(foo.value, i41 + 2);
623         foo.value = i41;
624         asserter.assertExpression("foo.value -= 2", i41 - 2);
625         assertEquals(foo.value, i41 - 2);
626         foo.value = i41;
627         asserter.assertExpression("foo.value *= 2", i41 * 2);
628         assertEquals(foo.value, i41 * 2);
629         foo.value = i41;
630         asserter.assertExpression("foo.value /= 2", i41 / 2);
631         assertEquals(foo.value, i41 / 2);
632         foo.value = i41;
633         asserter.assertExpression("foo.value %= 2", i41 % 2);
634         assertEquals(foo.value, i41 % 2);
635         foo.value = i41;
636         asserter.assertExpression("foo.value &= 3", (long) (i41 & 3));
637         assertEquals(foo.value, i41 & 3);
638         foo.value = i41;
639         asserter.assertExpression("foo.value |= 2", (long)(i41 | 2));
640         assertEquals(foo.value, i41 | 2);
641         foo.value = i41;
642         asserter.assertExpression("foo.value ^= 2", (long)(i41 ^ 2));
643         assertEquals(foo.value, i41 ^ 2);
644     }
645 
646     @Test
647     void testSideEffectBeanContainer() throws Exception {
648         final Integer i41 = Integer.valueOf(4141);
649         final Foo foo = new Foo(0);
650         asserter.setVariable("foo", foo);
651         foo.value = i41;
652         asserter.assertExpression("foo.bar[0] += 2", i41 + 2);
653         assertEquals(foo.value, i41 + 2);
654         foo.value = i41;
655         asserter.assertExpression("foo.bar[1] += 2", i41 + 3);
656         assertEquals(foo.value, i41 + 4);
657         foo.value = i41;
658         asserter.assertExpression("foo.bar[0] -= 2", i41 - 2);
659         assertEquals(foo.value, i41 - 2);
660         foo.value = i41;
661         asserter.assertExpression("foo.bar[0] *= 2", i41 * 2);
662         assertEquals(foo.value, i41 * 2);
663         foo.value = i41;
664         asserter.assertExpression("foo.bar[0] /= 2", i41 / 2);
665         assertEquals(foo.value, i41 / 2);
666         foo.value = i41;
667         asserter.assertExpression("foo.bar[0] %= 2", i41 % 2);
668         assertEquals(foo.value, i41 % 2);
669         foo.value = i41;
670         asserter.assertExpression("foo.bar[0] &= 3", (long) (i41 & 3));
671         assertEquals(foo.value, i41 & 3);
672         foo.value = i41;
673         asserter.assertExpression("foo.bar[0] |= 2", (long)(i41 | 2));
674         assertEquals(foo.value, i41 | 2);
675         foo.value = i41;
676         asserter.assertExpression("foo.bar[0] ^= 2", (long)(i41 ^ 2));
677         assertEquals(foo.value, i41 ^ 2);
678     }
679 
680     @Test
681     void testSideEffectDotArray() throws Exception {
682         final Integer i41 = Integer.valueOf(4141);
683         final Integer i42 = Integer.valueOf(42);
684         final Integer i43 = Integer.valueOf(43);
685         final String s42 = "fourty-two";
686         final String s43 = "fourty-three";
687         final Object[] foo = new Object[3];
688         foo[1] = i42;
689         foo[2] = i43;
690         asserter.setVariable("foo", foo);
691         foo[0] = i41;
692         asserter.assertExpression("foo.0 += 2", i41 + 2);
693         assertEquals(foo[0], i41 + 2);
694         foo[0] = i41;
695         asserter.assertExpression("foo.0 -= 2", i41 - 2);
696         assertEquals(foo[0], i41 - 2);
697         foo[0] = i41;
698         asserter.assertExpression("foo.0 *= 2", i41 * 2);
699         assertEquals(foo[0], i41 * 2);
700         foo[0] = i41;
701         asserter.assertExpression("foo.0 /= 2", i41 / 2);
702         assertEquals(foo[0], i41 / 2);
703         foo[0] = i41;
704         asserter.assertExpression("foo.0 %= 2", i41 % 2);
705         assertEquals(foo[0], i41 % 2);
706         foo[0] = i41;
707         asserter.assertExpression("foo.0 &= 3", (long) (i41 & 3));
708         assertEquals(foo[0], (long)(i41 & 3));
709         foo[0] = i41;
710         asserter.assertExpression("foo.0 |= 2", (long)(i41 | 2));
711         assertEquals(foo[0], (long)(i41 | 2));
712         foo[0] = i41;
713         asserter.assertExpression("foo.0 ^= 2", (long)(i41 ^ 2));
714         assertEquals(foo[0], (long)(i41 ^ 2));
715     }
716 
717     @Test
718     void testSideEffectVar() throws Exception {
719         final Map<String,Object> context = asserter.getVariables();
720         final Integer i41 = Integer.valueOf(4141);
721         final Object foo = i41;
722 
723         context.put("foo", foo);
724         asserter.assertExpression("foo += 2", i41 + 2);
725         assertEquals(context.get("foo"), i41 + 2);
726 
727         context.put("foo", foo);
728         asserter.assertExpression("foo -= 2", i41 - 2);
729         assertEquals(context.get("foo"), i41 - 2);
730 
731         context.put("foo", foo);
732         asserter.assertExpression("foo *= 2", i41 * 2);
733         assertEquals(context.get("foo"), i41 * 2);
734 
735         context.put("foo", foo);
736         asserter.assertExpression("foo /= 2", i41 / 2);
737         assertEquals(context.get("foo"), i41 / 2);
738 
739         context.put("foo", foo);
740         asserter.assertExpression("foo %= 2", i41 % 2);
741         assertEquals(context.get("foo"), i41 % 2);
742 
743         context.put("foo", foo);
744         asserter.assertExpression("foo &= 3", (long) (i41 & 3));
745         assertEquals(context.get("foo"), (long)(i41 & 3));
746 
747         context.put("foo", foo);
748         asserter.assertExpression("foo |= 2", (long)(i41 | 2));
749         assertEquals(context.get("foo"), (long)(i41 | 2));
750 
751         context.put("foo", foo);
752         asserter.assertExpression("foo ^= 2", (long)(i41 ^ 2));
753         assertEquals(context.get("foo"), (long)(i41 ^ 2));
754 
755         context.put("foo", foo);
756         asserter.assertExpression("foo <<= 2", (long)(i41 << 2));
757         assertEquals(context.get("foo"), (long)(i41 << 2));
758 
759         context.put("foo", foo);
760         asserter.assertExpression("foo >>= 2", (long)(i41 >> 2));
761         assertEquals(context.get("foo"), (long)(i41 >> 2));
762 
763         context.put("foo", foo);
764         asserter.assertExpression("foo >>>= 2", (long)(i41 >>> 2));
765         assertEquals(context.get("foo"), (long)(i41 >>> 2));
766     }
767 
768     @Test
769     void testSideEffectVarDots() throws Exception {
770         final Map<String,Object> context = asserter.getVariables();
771         final Integer i41 = Integer.valueOf(4141);
772         final Object foo = i41;
773 
774         context.put("foo.bar.quux", foo);
775         asserter.assertExpression("foo.bar.quux += 2", i41 + 2);
776         assertEquals(context.get("foo.bar.quux"), i41 + 2);
777 
778         context.put("foo.bar.quux", foo);
779         asserter.assertExpression("foo.bar.quux -= 2", i41 - 2);
780         assertEquals(context.get("foo.bar.quux"), i41 - 2);
781 
782         context.put("foo.bar.quux", foo);
783         asserter.assertExpression("foo.bar.quux *= 2", i41 * 2);
784         assertEquals(context.get("foo.bar.quux"), i41 * 2);
785 
786         context.put("foo.bar.quux", foo);
787         asserter.assertExpression("foo.bar.quux /= 2", i41 / 2);
788         assertEquals(context.get("foo.bar.quux"), i41 / 2);
789 
790         context.put("foo.bar.quux", foo);
791         asserter.assertExpression("foo.bar.quux %= 2", i41 % 2);
792         assertEquals(context.get("foo.bar.quux"), i41 % 2);
793 
794         context.put("foo.bar.quux", foo);
795         asserter.assertExpression("foo.bar.quux &= 3", (long) (i41 & 3));
796         assertEquals(context.get("foo.bar.quux"), (long)(i41 & 3));
797 
798         context.put("foo.bar.quux", foo);
799         asserter.assertExpression("foo.bar.quux |= 2", (long)(i41 | 2));
800         assertEquals(context.get("foo.bar.quux"), (long)(i41 | 2));
801 
802         context.put("foo.bar.quux", foo);
803         asserter.assertExpression("foo.bar.quux ^= 2", (long)(i41 ^ 2));
804         assertEquals(context.get("foo.bar.quux"), (long)(i41 ^ 2));
805     }
806 
807 }