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.assertInstanceOf;
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.math.BigDecimal;
27 import java.math.BigInteger;
28 import java.time.Duration;
29 import java.util.Collections;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.TreeMap;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.concurrent.ConcurrentMap;
35 import java.util.concurrent.atomic.AtomicInteger;
36
37 import org.apache.commons.lang3.ThreadUtils;
38 import org.junit.jupiter.api.Test;
39
40
41
42
43 class PragmaTest extends JexlTestCase {
44 public static class CachingModuleContext extends ModuleContext implements JexlContext.ModuleProcessor {
45 private final ConcurrentMap<String, Object> modules = new ConcurrentHashMap<>();
46 private final AtomicInteger count = new AtomicInteger();
47
48 CachingModuleContext() {
49 }
50
51 public int getCountCompute() {
52 return count.get();
53 }
54
55 @Override
56 public Object processModule(final JexlEngine engine, final JexlInfo info, final String name, final String body) {
57 if (body.isEmpty()) {
58 modules.remove(name);
59 return null;
60 }
61 return modules.computeIfAbsent(name, n -> {
62 Object module = engine.createExpression(info, body).evaluate(this);
63 if (module instanceof JexlScript) {
64 module = ((JexlScript) module).execute(this);
65 }
66 count.incrementAndGet();
67 return module;
68 });
69 }
70 }
71
72 public static class ModuleContext extends MapContext {
73 protected final Map<String, JexlScript> sources = new TreeMap<>();
74
75 ModuleContext() { }
76 public Object script(final String name) {
77 return sources.get(name);
78 }
79
80 void script(final String name, final JexlScript script) { sources.put(name, script); }
81 }
82
83 public static class SafeContext extends JexlEvalContext {
84
85 public void processPragmas(final Map<String, Object> pragmas) {
86 if (pragmas != null && !pragmas.isEmpty()) {
87 final JexlOptions options = getEngineOptions();
88 for (final Map.Entry<String, Object> pragma : pragmas.entrySet()) {
89 final String key = pragma.getKey();
90 final Object value = pragma.getValue();
91 if ("jexl.safe".equals(key) && value instanceof Boolean) {
92 options.setSafe((Boolean) value);
93 } else if ("jexl.strict".equals(key) && value instanceof Boolean) {
94 options.setStrict((Boolean) value);
95 } else if ("jexl.silent".equals(key) && value instanceof Boolean) {
96 options.setSilent((Boolean) value);
97 }
98 }
99 }
100 }
101
102
103
104
105
106 public void sleep(final long ms) {
107 ThreadUtils.sleepQuietly(Duration.ofMillis(ms));
108 }
109 }
110
111 public static class Sleeper {
112 public void sleep(final long ms) {
113 ThreadUtils.sleepQuietly(Duration.ofMillis(ms));
114 }
115 }
116
117 public static class StaticSleeper {
118 public static void sleep(final long ms) {
119 ThreadUtils.sleepQuietly(Duration.ofMillis(ms));
120 }
121
122
123 private StaticSleeper() {}
124 }
125
126
127
128
129 public PragmaTest() {
130 super("PragmaTest");
131 }
132
133 void runPragmaModule(final ModuleContext ctxt, final CachingModuleContext cmCtxt) {
134 ctxt.script("module0", JEXL.createScript("function f42(x) { 42 + x; } function f43(x) { 43 + x; }; { 'f42' : f42, 'f43' : f43 }"));
135 final ConcurrentMap<String, Object> modules = new ConcurrentHashMap<>();
136 JexlScript script;
137 Object result;
138 script = JEXL.createScript("#pragma jexl.module.m0 \"script('module0')\"\n m0:f42(10);");
139 result = script.execute(ctxt);
140 assertEquals(52, result);
141 if (cmCtxt != null) {
142 assertEquals(1, cmCtxt.getCountCompute());
143 }
144 result = script.execute(ctxt);
145 assertEquals(52, result);
146 if (cmCtxt != null) {
147 assertEquals(1, cmCtxt.getCountCompute());
148 }
149 script = JEXL.createScript("#pragma jexl.module.m0 \"script('module0')\"\n m0:f43(10);");
150 result = script.execute(ctxt);
151 assertEquals(53, result);
152 if (cmCtxt != null) {
153 assertEquals(1, cmCtxt.getCountCompute());
154 }
155 final JexlScript script1 = JEXL.createScript("#pragma jexl.module.m0 ''\n#pragma jexl.module.m0 \"fubar('module0')\"\n m0:f43(10);");
156 final JexlException.Method xmethod = assertThrows(JexlException.Method.class, () -> script1.execute(ctxt));
157 assertEquals("fubar", xmethod.getMethod());
158 }
159
160 @Test void test354() {
161 final Map<String, Number> values = new TreeMap<>();
162 values.put("1", 1);
163 values.put("+1", 1);
164 values.put("-1", -1);
165 values.put("1l", 1L);
166 values.put("+1l", 1L);
167 values.put("-1l", -1L);
168 values.put("10h", BigInteger.valueOf(10));
169 values.put("-11h", BigInteger.valueOf(-11));
170 values.put("+12h", BigInteger.valueOf(12));
171 values.put("0xa", 0xa);
172 values.put("+0xa", 0xa);
173 values.put("-0xa", -0xa);
174 values.put("0xacl", 0xacL);
175 values.put("+0xadl", 0xadL);
176 values.put("-0xafl", -0xafL);
177 values.put("1d", 1d);
178 values.put("-1d", -1d);
179 values.put("+1d", 1d);
180 values.put("1f", 1f);
181 values.put("-1f", -1f);
182 values.put("+1f", 1f);
183 values.put("1B", new BigDecimal(1));
184 values.put("-1B", new BigDecimal(-1));
185 values.put("+1B", new BigDecimal(1));
186 values.put("-42424242424242424242424242424242", new BigInteger("-42424242424242424242424242424242"));
187 values.put("+42424242424242424242424242424242", new BigInteger("+42424242424242424242424242424242"));
188 values.put("42424242424242424242424242424242", new BigInteger("42424242424242424242424242424242"));
189 final JexlEngine jexl = new JexlBuilder().safe(true).create();
190 for(final Map.Entry<String, Number> e : values.entrySet()) {
191 final String text = "#pragma number " + e.getKey();
192 final JexlScript script = jexl.createScript(text);
193 assertNotNull(script);
194 final Map<String, Object> pragmas = script.getPragmas();
195 assertNotNull(pragmas);
196 assertEquals(e.getValue(), pragmas.get("number"), e::getKey);
197 }
198 }
199 @Test
200 void testImportPragmaDisabled() {
201 final String src =
202 "#pragma jexl.import java.util\n"+
203 "#pragma jexl.import java.io\n"+
204 "#pragma jexl.import java.net\n"+
205 "42";
206 final JexlFeatures features = new JexlFeatures();
207 features.importPragma(false);
208 final JexlEngine jexl = new JexlBuilder().features(features).create();
209 final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript(src));
210 assertTrue(xparse.getMessage().contains("import pragma"));
211 }
212
213 @Test
214 void testImportPragmaValueSet() {
215 final String src =
216 "#pragma jexl.import java.util\n"+
217 "#pragma jexl.import java.io\n"+
218 "#pragma jexl.import java.net\n"+
219 "42";
220 final JexlScript script = JEXL.createScript(src);
221 final Map<String, Object> pragmas = script.getPragmas();
222 final Object importz = pragmas.get("jexl.import");
223 assertInstanceOf(Set.class, importz);
224 final Set<String> importzz = (Set<String>) importz;
225 assertTrue(importzz.contains("java.util"));
226 assertTrue(importzz.contains("java.io"));
227 assertTrue(importzz.contains("java.net"));
228 assertEquals(3, importzz.size());
229 final String parsed = script.getParsedText();
230 assertEquals(src, parsed);
231 }
232
233 @Test
234 void testIssue416() {
235 final JexlEngine jexl = new JexlBuilder().create();
236 final JexlScript script = jexl.createScript("#pragma myNull null\n");
237 final Map<String, Object> pragmas = script.getPragmas();
238 assertTrue(pragmas.containsKey("myNull"), "pragma key present?");
239 assertNull(pragmas.get("myNull"), "expected null value");
240 }
241
242 @Test
243 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
244 void testJxltPragmas() {
245 final JxltEngine engine = new JexlBuilder().create().createJxltEngine();
246 final JxltEngine.Template tscript = engine.createTemplate("$$ #pragma one 1\n$$ #pragma the.very.hard 'truth'\n2;");
247 assertNotNull(tscript);
248 final Map<String, Object> pragmas = tscript.getPragmas();
249 assertEquals(2, pragmas.size());
250 assertEquals(1, pragmas.get("one"));
251 assertEquals("truth", pragmas.get("the.very.hard"));
252 }
253
254 @Test
255 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
256 void testNamespacePragma() {
257 final JexlContext jc = new SafeContext();
258 final String src =
259 "#pragma jexl.namespace.sleeper " + Sleeper.class.getName() + "\n"
260 + "sleeper:sleep(100);\n"
261 + "42;\n";
262 final JexlScript script = JEXL.createScript(src);
263 final Object result = script.execute(jc);
264 assertEquals(42, result);
265 final String parsed = script.getParsedText();
266 assertEquals(src, parsed);
267 }
268 @Test
269 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
270 void testNamespacePragmaCtl() {
271 final Map<String, Object> ns = Collections.singletonMap("sleeper", Sleeper.class.getName());
272 final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
273 final JexlContext jc = new SafeContext();
274 final JexlScript script = jexl.createScript(
275 "sleeper:sleep(100);"
276 + "42");
277 final Object result = script.execute(jc);
278 assertEquals(42, result);
279 }
280 @Test
281 void testNamespacePragmaDisabled() {
282 final JexlFeatures features = new JexlFeatures();
283 features.namespacePragma(false);
284 final JexlEngine jexl = new JexlBuilder().features(features).create();
285
286 final JexlException.Parsing xparse = assertThrows(JexlException.Parsing.class, () -> jexl.createScript(
287 "#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
288 + "sleeper:sleep(100);"
289 + "42"));
290
291 assertTrue(xparse.getMessage().contains("namespace pragma"));
292 }
293
294 @Test void testPragmaModuleCache() {
295 final CachingModuleContext ctxt = new CachingModuleContext();
296 runPragmaModule(ctxt, ctxt);
297 }
298
299 @Test void testPragmaModuleNoCache() {
300 final ModuleContext ctxt = new ModuleContext();
301 runPragmaModule(ctxt, null);
302 }
303
304 @Test
305 void testPragmaOptions1() {
306 final String str = "i; #pragma jexl.options '-strict'\n";
307
308 final JexlEngine jexl = new JexlBuilder()
309 .features(new JexlFeatures().pragmaAnywhere(false))
310 .strict(true).create();
311
312 assertThrows(JexlException.class, () -> jexl.createScript(str), "i should not be resolved");
313 }
314
315
316
317
318 @Test
319 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
320 void testPragmas() {
321 final JexlScript script = JEXL.createScript("#pragma one 1\n#pragma the.very.hard 'truth'\n2;");
322 assertNotNull(script);
323 final Map<String, Object> pragmas = script.getPragmas();
324 assertEquals(2, pragmas.size());
325 assertEquals(1, pragmas.get("one"));
326 assertEquals("truth", pragmas.get("the.very.hard"));
327 }
328
329 @Test
330 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
331 void testSafePragma() {
332 final SafeContext jc = new SafeContext();
333 jc.set("foo", null);
334 final JexlScript script = JEXL.createScript("#pragma jexl.safe true\nfoo.bar;");
335 assertNotNull(script);
336 jc.processPragmas(script.getPragmas());
337 final Object result = script.execute(jc);
338 assertNull(result);
339 final SafeContext jc1 = new SafeContext();
340 jc1.set("foo", null);
341 assertThrows(JexlException.class, () -> script.execute(jc1));
342 }
343
344 @Test
345 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
346 void testStaticNamespacePragma() {
347 final JexlContext jc = new SafeContext();
348 final JexlScript script = JEXL.createScript(
349 "#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
350 + "sleeper:sleep(100);"
351 + "42");
352 final Object result = script.execute(jc);
353 assertEquals(42, result);
354 }
355
356 @Test
357 @SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
358 void testStatictNamespacePragmaCtl() {
359 final Map<String, Object> ns = Collections.singletonMap("sleeper", StaticSleeper.class.getName());
360 final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
361 final JexlContext jc = new SafeContext();
362 final JexlScript script = jexl.createScript(
363 "sleeper:sleep(100);"
364 + "42");
365 final Object result = script.execute(jc);
366 assertEquals(42, result);
367 }
368 }