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.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import org.apache.commons.jexl3.internal.Engine;
30 import org.apache.commons.jexl3.internal.introspection.Uberspect;
31 import org.junit.jupiter.api.BeforeEach;
32 import org.junit.jupiter.api.Test;
33
34
35
36
37 @SuppressWarnings({"boxing", "UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
38 class IssuesTest extends JexlTestCase {
39
40 public static class Another {
41 public String name = "whatever";
42 private final Boolean foo = Boolean.TRUE;
43
44 public Boolean foo() {
45 return foo;
46 }
47
48 public int goo() {
49 return 100;
50 }
51 }
52
53
54
55 public abstract static class Base {
56 public abstract boolean foo();
57 }
58
59 static class Derived extends Base {
60 @Override
61 public boolean foo() {
62 return true;
63 }
64 }
65
66 public static class fn98 {
67 public String replace(final String str, final String target, final String replacement) {
68 return str.replace(target, replacement);
69 }
70 }
71
72 public static class Foo {
73 private final Another inner;
74
75 Foo() {
76 inner = new Another();
77 }
78
79 public Another getInner() {
80 return inner;
81 }
82 }
83
84 public IssuesTest() {
85 super("IssuesTest", null);
86 }
87
88 @BeforeEach
89 @Override
90 public void setUp() throws Exception {
91
92 java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
93 }
94
95
96 @Test
97 void test11() throws Exception {
98 final JexlEngine jexl = createEngine(false);
99 final JexlEvalContext ctxt = new JexlEvalContext();
100 final JexlOptions options = ctxt.getEngineOptions();
101
102 options.setSilent(false);
103 options.setStrict(true);
104
105 ctxt.set("a", null);
106
107 final String[] exprs = {
108
109
110
111 "a % b"
112
113 };
114 for (final String s : exprs) {
115 final JexlExpression expr = jexl.createExpression(s);
116 assertThrows(JexlException.class, () -> expr.evaluate(ctxt), () -> s + " : should have failed due to null argument");
117 }
118 }
119
120 @Test
121 void test40() throws Exception {
122 final JexlEngine jexl = new Engine();
123 final JexlEvalContext ctxt = new JexlEvalContext();
124 final JexlOptions options = ctxt.getEngineOptions();
125 options.set(jexl);
126
127 options.setSilent(false);
128
129 ctxt.set("derived", new Derived());
130
131 final JexlExpression expr = jexl.createExpression("derived.foo()");
132 final Object value = expr.evaluate(ctxt);
133 assertTrue((Boolean) value);
134 }
135
136
137
138 @Test
139 void test42() throws Exception {
140 final JexlEngine jexl = new JexlBuilder().create();
141 final JxltEngine uel = jexl.createJxltEngine();
142
143
144 final JexlEvalContext ctxt = new JexlEvalContext();
145 final JexlOptions options = ctxt.getEngineOptions();
146 options.set(jexl);
147 options.setStrict(false);
148 options.setStrictArithmetic(false);
149 ctxt.set("ax", "ok");
150
151 final JxltEngine.Expression expr = uel.createExpression("${ax+(bx)}");
152 final Object value = expr.evaluate(ctxt);
153 assertEquals("ok", value);
154 }
155
156
157 @Test
158 void test44() throws Exception {
159 final JexlEngine jexl = createEngine(false);
160 final JexlEvalContext ctxt = new JexlEvalContext();
161 final JexlOptions options = ctxt.getEngineOptions();
162
163 options.setSilent(false);
164 JexlScript script;
165 script = jexl.createScript("'hello world!'//commented");
166 assertEquals("hello world!", script.execute(ctxt));
167 script = jexl.createScript("'hello world!'; //commented\n'bye...'");
168 assertEquals("bye...", script.execute(ctxt));
169 script = jexl.createScript("'hello world!'## commented");
170 assertEquals("hello world!", script.execute(ctxt));
171 script = jexl.createScript("'hello world!';## commented\n'bye...'");
172 assertEquals("bye...", script.execute(ctxt));
173 }
174
175
176
177 @Test
178 void test47() throws Exception {
179 final JexlEngine jexl = new Engine();
180 final JexlEvalContext ctxt = new JexlEvalContext();
181 final JexlOptions options = ctxt.getEngineOptions();
182
183 options.setSilent(false);
184
185 JexlExpression expr = jexl.createExpression("true//false\n");
186 Object value = expr.evaluate(ctxt);
187 assertTrue((Boolean) value);
188
189 expr = jexl.createExpression("/*true*/false");
190 value = expr.evaluate(ctxt);
191 assertFalse((Boolean) value);
192
193 expr = jexl.createExpression("/*\"true\"*/false");
194 value = expr.evaluate(ctxt);
195 assertFalse((Boolean) value);
196 }
197
198 @Test
199 void test48() throws Exception {
200 final JexlEngine jexl = new Engine();
201 final JexlEvalContext jc = new JexlEvalContext();
202 final JexlOptions options = jc.getEngineOptions();
203
204 options.setStrict(true);
205 options.setSilent(false);
206 final String jexlExp = "(foo.getInner().foo() eq true) and (foo.getInner().goo() = (foo.getInner().goo()+1-1))";
207 jc.set("foo", new Foo());
208 assertNotNull(assertThrows(JexlException.Assignment.class, () -> jexl.createExpression(jexlExp)).toString());
209 }
210
211
212 @Test
213 void test49() throws Exception {
214 final JexlEngine jexl = new Engine();
215 final Map<String, Object> vars = new HashMap<>();
216 final JexlContext ctxt = new MapContext(vars);
217 final String stmt = "a = 'b'; c = 'd';";
218 final JexlScript expr = jexl.createScript(stmt);
219 expr.execute(ctxt);
220 assertTrue(vars.get("a").equals("b") && vars.get("c").equals("d"), "JEXL-49 is not fixed");
221 }
222
223
224 @Test
225 void test52base() throws Exception {
226 final Engine jexl = (Engine) createEngine(false);
227 final Uberspect uber = (Uberspect) jexl.getUberspect();
228
229 String[] names = uber.getMethodNames(Another.class);
230 assertTrue(names.length > 0, "should find methods");
231 int found = 0;
232 for (final String name : names) {
233 if ("foo".equals(name) || "goo".equals(name)) {
234 found += 1;
235 }
236 }
237 assertEquals(2, found, "should have foo & goo");
238
239 names = uber.getFieldNames(Another.class);
240 assertTrue(names.length > 0, "should find fields");
241 found = 0;
242 for (final String name : names) {
243 if ("name".equals(name)) {
244 found += 1;
245 }
246 }
247 assertEquals(1, found, "should have name");
248 }
249
250
251 @Test
252 void test62() throws Exception {
253 final JexlEngine jexl = createEngine(false);
254 final MapContext vars = new MapContext();
255 final JexlEvalContext ctxt = new JexlEvalContext(vars);
256 final JexlOptions options = ctxt.getEngineOptions();
257 options.setStrict(true);
258 options.setSilent(true);
259
260 JexlScript jscript;
261
262 jscript = jexl.createScript("dummy.hashCode()");
263 assertNull(jscript.execute(ctxt), jscript::getSourceText);
264
265 ctxt.set("dummy", "abcd");
266 assertEquals(Integer.valueOf("abcd".hashCode()), jscript.execute(ctxt), jscript::getSourceText);
267
268 jscript = jexl.createScript("dummy.hashCode");
269 assertNull(jscript.execute(ctxt), jscript::getSourceText);
270
271 JexlExpression jexpr;
272 vars.clear();
273 jexpr = jexl.createExpression("dummy.hashCode()");
274 assertNull(jexpr.evaluate(ctxt), jexpr::toString);
275
276 ctxt.set("dummy", "abcd");
277 assertEquals(Integer.valueOf("abcd".hashCode()), jexpr.evaluate(ctxt), jexpr::toString);
278
279 jexpr = jexl.createExpression("dummy.hashCode");
280 assertNull(jexpr.evaluate(ctxt), jexpr::toString);
281 }
282
283
284 @Test
285 void test87() throws Exception {
286 final JexlEngine jexl = createEngine(false);
287 final JexlEvalContext ctxt = new JexlEvalContext();
288 final JexlOptions options = ctxt.getEngineOptions();
289
290 options.setSilent(false);
291 final JexlExpression divide = jexl.createExpression("l / r");
292 final JexlExpression modulo = jexl.createExpression("l % r");
293
294 ctxt.set("l", java.math.BigInteger.valueOf(7));
295 ctxt.set("r", java.math.BigInteger.valueOf(2));
296 assertEquals(java.math.BigInteger.valueOf(3), divide.evaluate(ctxt));
297 assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt)));
298
299 ctxt.set("l", java.math.BigDecimal.valueOf(7));
300 ctxt.set("r", java.math.BigDecimal.valueOf(2));
301 assertEquals(java.math.BigDecimal.valueOf(3.5), divide.evaluate(ctxt));
302 assertTrue(jexl.getArithmetic().equals(1, modulo.evaluate(ctxt)));
303 }
304
305
306 @Test
307 void test90() throws Exception {
308 final JexlEngine jexl = createEngine(false);
309 final JexlEvalContext ctxt = new JexlEvalContext();
310 final JexlOptions options = ctxt.getEngineOptions();
311
312 options.setSilent(false);
313
314
315 final String[] fexprs = {
316 "a=3 b=4",
317 "while(a) while(a)",
318 "1 2",
319 "if (true) 2; 3 {}",
320 "while (x) 1 if (y) 2 3"
321 };
322
323 for (final String fexpr : fexprs) {
324 assertThrows(JexlException.class, () -> jexl.createScript(fexpr));
325 }
326
327
328 final String[] exprs = {
329 "if (x) {1} if (y) {2}",
330 "if (x) 1 if (y) 2",
331 "while (x) 1 if (y) 2 else 3",
332 "for(z : [3, 4, 5]) { z } y ? 2 : 1",
333 "for(z : [3, 4, 5]) { z } if (y) 2 else 1"
334 };
335
336 ctxt.set("x", Boolean.FALSE);
337 ctxt.set("y", Boolean.TRUE);
338 for (final String expr : exprs) {
339 final JexlScript s = jexl.createScript(expr);
340 assertEquals(Integer.valueOf(2), s.execute(ctxt));
341 }
342 debuggerCheck(jexl);
343 }
344
345 @Test
346 void test97() throws Exception {
347 final JexlEngine jexl = createEngine(false);
348 final JexlEvalContext ctxt = new JexlEvalContext();
349 final JexlOptions options = ctxt.getEngineOptions();
350
351 options.setSilent(false);
352 for (char v = 'a'; v <= 'z'; ++v) {
353 ctxt.set(Character.toString(v), 10);
354 }
355 final String input
356 = "(((((((((((((((((((((((((z+y)/x)*w)-v)*u)/t)-s)*r)/q)+p)-o)*n)-m)+l)*k)+j)/i)+h)*g)+f)/e)+d)-c)/b)+a)";
357
358 JexlExpression script;
359
360 final long start = System.nanoTime();
361 script = jexl.createExpression(input);
362 final Object value = script.evaluate(ctxt);
363 assertEquals(Integer.valueOf(11), value);
364 final long end = System.nanoTime();
365 final double millisec = (end - start) / 1e6;
366 final double limit = 200.0;
367 assertTrue(millisec < limit, () -> "Expected parse to take less than " + limit + "ms, actual " + millisec);
368 }
369
370 @Test
371 void test98() throws Exception {
372 final String[] exprs = {
373 "fn:replace('DOMAIN\\somename', '\\\\', '\\\\\\\\')",
374 "fn:replace(\"DOMAIN\\somename\", \"\\\\\", \"\\\\\\\\\")",
375 "fn:replace('DOMAIN\\somename', '\\u005c', '\\u005c\\u005c')"
376 };
377 final Map<String, Object> funcs = new HashMap<>();
378 funcs.put("fn", new fn98());
379 final JexlEngine jexl = new JexlBuilder().namespaces(funcs).create();
380 for (final String expr : exprs) {
381 final Object value = jexl.createExpression(expr).evaluate(null);
382 assertEquals("DOMAIN\\\\somename", value, expr);
383 }
384 }
385
386 }