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.JexlFeatures.NAMESPACE_INSTANTIATE;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.junit.jupiter.api.Assertions.fail;
26
27 import java.util.Arrays;
28 import java.util.Collection;
29
30 import org.junit.jupiter.api.Test;
31
32
33
34
35 @SuppressWarnings({"AssertEqualsBetweenInconvertibleTypes"})
36 class FeaturesTest extends JexlTestCase {
37 private final JexlEngine jexl = new JexlBuilder().create();
38
39
40
41
42 public FeaturesTest() {
43 super("FeaturesTest");
44 }
45
46 private void assertOk(final String[] scripts) {
47 for(final String str : scripts) {
48 try {
49 final JexlScript e = jexl.createScript(str);
50 } catch (final JexlException.Feature xfeature) {
51 fail(str + " :: should not fail parse: " + xfeature.getMessage());
52 }
53 }
54 }
55
56
57
58
59
60
61
62
63 private void checkFeature(final JexlFeatures features, final String[] scripts) {
64 for (final String script : scripts) {
65 final JexlScript ctl = JEXL.createScript(script);
66 assertNotNull(ctl);
67 final JexlException.Parsing xfeature = assertThrows(JexlException.Parsing.class, () -> jexl.createScript(features, null, script));
68 assertNotNull(xfeature.getMessage());
69 }
70 }
71
72 @Test
73 void test410a() {
74 final long x = JexlFeatures.createAll().getFlags();
75 assertEquals(NAMESPACE_INSTANTIATE + 1, Long.bitCount(x));
76 assertTrue((x & 1L << NAMESPACE_INSTANTIATE) != 0);
77
78 final JexlFeatures all = JexlFeatures.createAll();
79 final JexlEngine jexl = new JexlBuilder().features(all).create();
80 final JexlScript script = jexl.createScript("#0 * #1", "#0", "#1");
81 final Object r = script.execute(null, 6, 7);
82 assertEquals(42, r);
83 }
84
85 @Test
86 void test410b() {
87 final JexlFeatures features = JexlFeatures.createScript();
88 assertTrue(features.isLexical());
89 assertTrue(features.isLexicalShade());
90 assertTrue(features.supportsConstCapture());
91
92 assertFalse(features.supportsPragmaAnywhere());
93
94 assertFalse(features.supportsComparatorNames());
95
96 final JexlEngine jexl = new JexlBuilder().features(features).create();
97 final Collection<String> reserved = features.getReservedNames();
98 for(final String varName : reserved) {
99 final String src = "var " + varName;
100
101 assertThrows(JexlException.Feature.class, () -> jexl.createScript(src), src);
102 }
103 final String[] cmpNameScripts = {
104 "1 eq 1",
105 "2 ne 3",
106 "1 lt 2",
107 "3 le 3",
108 "4 gt 2",
109 "3 ge 2"
110 };
111 for(final String src : cmpNameScripts) {
112 assertThrows(JexlException.Ambiguous.class, () -> jexl.createScript(src), src);
113 }
114 }
115
116 @Test
117 void testAnnotations() {
118 final JexlFeatures f = new JexlFeatures().annotation(false);
119 final String[] scripts = {
120 "@synchronized(2) { return 42; }",
121 "@two var x = 3;"
122 };
123 checkFeature(f, scripts);
124 }
125
126 @Test
127 void testArrayRefs() {
128 final JexlFeatures f = new JexlFeatures().arrayReferenceExpr(false);
129
130 final String[] scripts = {
131 "x[y]",
132 "x['a'][b]",
133 "x()['a'][b]",
134 "x.y['a'][b]"
135 };
136 checkFeature(f, scripts);
137 assertOk(scripts);
138
139 final String[] scriptsOk = {
140 "x['y']",
141 "x['a'][1]",
142 "x()['a']['b']",
143 "x.y['a']['b']"
144 };
145 assertOk(scriptsOk);
146 }
147
148 @Test
149 void testConstCapture() {
150 final JexlFeatures f = new JexlFeatures().constCapture(true);
151 final String[] scripts = {
152 "let x = 0; const f = y -> x += y; f(42)",
153 "let x = 0; function f(y) { z -> x *= y }; f(42)"
154 };
155 checkFeature(f, scripts);
156 final JexlFeatures nof = new JexlFeatures().constCapture(true);
157 assertOk(scripts);
158 }
159
160 @Test
161 void testCreate() {
162 final JexlFeatures f = JexlFeatures.createNone();
163 assertTrue(f.supportsExpression());
164
165 assertFalse(f.supportsAnnotation());
166 assertFalse(f.supportsArrayReferenceExpr());
167 assertFalse(f.supportsComparatorNames());
168 assertFalse(f.supportsFatArrow());
169 assertFalse(f.supportsImportPragma());
170 assertFalse(f.supportsLambda());
171 assertFalse(f.supportsLocalVar());
172 assertFalse(f.supportsLoops());
173 assertFalse(f.supportsMethodCall());
174 assertFalse(f.supportsNamespacePragma());
175 assertFalse(f.supportsNewInstance());
176 assertFalse(f.supportsPragma());
177 assertFalse(f.supportsPragmaAnywhere());
178 assertFalse(f.supportsScript());
179 assertFalse(f.supportsStructuredLiteral());
180
181 assertFalse(f.isLexical());
182 assertFalse(f.isLexicalShade());
183 assertFalse(f.supportsConstCapture());
184
185 final JexlEngine jnof = new JexlBuilder().features(f).create();
186 assertThrows(JexlException.Feature.class, ()->jnof.createScript("{ 3 + 4 }"));
187 assertNotNull(jnof.createExpression("3 + 4"));
188 }
189
190 @Test
191 void testIssue409() {
192 final JexlFeatures baseFeatures = JexlFeatures.createDefault();
193 assertFalse(baseFeatures.isLexical());
194 assertFalse(baseFeatures.isLexicalShade());
195 assertFalse(baseFeatures.supportsConstCapture());
196
197 final JexlFeatures scriptFeatures = JexlFeatures.createScript();
198 assertTrue(scriptFeatures.isLexical());
199 assertTrue(scriptFeatures.isLexicalShade());
200 scriptFeatures.lexical(false);
201 assertFalse(scriptFeatures.isLexical());
202 assertFalse(scriptFeatures.isLexicalShade());
203 }
204
205 @Test
206 void testMethodCalls() {
207 final JexlFeatures f = new JexlFeatures().methodCall(false);
208 final String[] scripts = {
209 "x.y(z)",
210 "x['a'].m(b)",
211 "x()['a'](b)",
212 "x.y['a'](b)"
213 };
214 checkFeature(f, scripts);
215
216 final String[] scriptsOk = {
217 "x('y')",
218 "x('a')[1]",
219 "x()['a']['b']",
220 };
221 assertOk(scriptsOk);
222 }
223
224 @Test
225 void testMixedFeatures() {
226
227 final JexlFeatures f = new JexlFeatures()
228 .newInstance(false)
229 .localVar(false)
230 .lambda(false)
231 .loops(false)
232 .sideEffectGlobal(false);
233 final String[] scripts = {
234 "return new(clazz);",
235 "()->{ return 0 };",
236 "var x = 0;",
237 "(x, y)->{ return 0 };",
238 "for(var i : {0 .. 10}) { bar(i); }",
239 "x += 1",
240 "x.y += 1"
241 };
242 checkFeature(f, scripts);
243 }
244 @Test
245 void testNoComparatorNames() {
246 final JexlFeatures f = new JexlFeatures().comparatorNames(false);
247 final String[] scripts = {
248 "1 eq 1",
249 "2 ne 3",
250 "1 lt 2",
251 "3 le 3",
252 "4 gt 2",
253 "3 ge 2"
254 };
255 checkFeature(f, scripts);
256 }
257
258 @Test
259 void testNoLambda() {
260 final JexlFeatures f = new JexlFeatures().lambda(false);
261 final String[] scripts = {
262 "var x = ()->{ return 0 };",
263 "()->{ return 0 };",
264 "(x, y)->{ return 0 };",
265 "function() { return 0 };",
266 "function(x, y) { return 0 };",
267 "if (false) { (function(x, y) { return x + y })(3, 4) }"
268 };
269 checkFeature(f, scripts);
270 }
271
272 @Test
273 void testNoLocals() {
274 final JexlFeatures f = new JexlFeatures().localVar(false);
275 final String[] scripts = {
276 "var x = 0;",
277 "(x)->{ x }"
278 };
279 checkFeature(f, scripts);
280 }
281
282 @Test
283 void testNoLoop() {
284 final JexlFeatures f = new JexlFeatures().loops(false);
285 final String[] scripts = {
286 "while(true);",
287 "for(var i : {0 .. 10}) { bar(i); }"
288 };
289 checkFeature(f, scripts);
290 }
291 @Test
292 void testNoNew() {
293 final JexlFeatures f = new JexlFeatures().newInstance(false);
294 final String[] scripts = {
295 "return new(clazz);",
296 "new('java.math.BigDecimal', 12) + 1"
297 };
298 checkFeature(f, scripts);
299 }
300
301 @Test
302 void testNoScript() {
303 final JexlFeatures f = new JexlFeatures().script(false);
304 assertTrue(f.supportsExpression());
305 final String[] scripts = {
306 "if (false) { block(); }",
307 "{ noway(); }",
308 "while(true);",
309 "for(var i : {0 .. 10}) { bar(i); }"
310 };
311 checkFeature(f, scripts);
312 }
313
314 @Test
315 void testNoSideEffects() {
316 final JexlFeatures f = new JexlFeatures().sideEffect(false);
317 final String[] scripts = {
318 "x = 1",
319 "x.y = 1",
320 "x().y = 1",
321 "x += 1",
322 "x.y += 1",
323 "x().y += 1",
324 "x -= 1",
325 "x *= 1",
326 "x /= 1",
327 "x %= 1",
328 "x ^= 1",
329 "x &= 1",
330 "x |= 1",
331 "x >>= 1",
332 "x <<= 1",
333 "x >>>= 1",
334 };
335 checkFeature(f, scripts);
336 }
337
338 @Test
339 void testNoSideEffectsGlobal() {
340 final JexlFeatures f = new JexlFeatures().sideEffectGlobal(false);
341 final String[] scripts = {
342 "x = 1",
343 "x.y = 1",
344 "x().y = 1",
345 "x += 1",
346 "x.y += 1",
347 "x().y += 1",
348 "x -= 1",
349 "x *= 1",
350 "x /= 1",
351 "x ^= 1",
352 "x &= 1",
353 "x |= 1",
354 "4 + (x.y = 1)",
355 "if (true) x.y.z = 4"
356 };
357
358 checkFeature(f, scripts);
359
360 for(final String str : scripts) {
361 try {
362 final JexlScript e = jexl.createScript("var x = foo(); " + str);
363 } catch (final JexlException.Feature xfeature) {
364 fail(str + " :: should not fail parse: " + xfeature.getMessage());
365 }
366 }
367 }
368
369 @Test
370 void testPragma() {
371 final JexlFeatures f = new JexlFeatures().pragma(false);
372 final String[] scripts = {
373 "#pragma foo 42",
374 "#pragma foo 'bar'\n@two var x = 3;"
375 };
376 checkFeature(f, scripts);
377 }
378
379 @Test
380 void testPragmaAnywhere() {
381 final JexlFeatures f = new JexlFeatures().pragmaAnywhere(false);
382 final String[] scripts = {
383 "var x = 3;\n#pragma foo 42",
384 };
385 checkFeature(f, scripts);
386 }
387
388 @Test
389 void testReservedVars() {
390 final JexlFeatures f = new JexlFeatures().reservedNames(Arrays.asList("foo", "bar"));
391 final String[] scripts = {
392 "var foo = 0;",
393 "(bar)->{ bar }",
394 "var f = function(bar) { bar; }"
395 };
396 checkFeature(f, scripts);
397 final String[] scriptsOk = {
398 "var foo0 = 0;",
399 "(bar1)->{ bar }",
400 "var f = function(bar2) { bar2; }"
401 };
402 assertOk(scriptsOk);
403 }
404
405 @Test
406 void testStructuredLiterals() {
407 final JexlFeatures f = new JexlFeatures().structuredLiteral(false);
408 final String[] scripts = {
409 "{1, 2, 3}",
410 "[1, 2, 3]",
411 "{ 1 :'one', 2 : 'two', 3 : 'three' }",
412 "(1 .. 5)"
413 };
414 checkFeature(f, scripts);
415 assertOk(scripts);
416 }
417 }