1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jexl3.scripting;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26
27 import java.io.BufferedReader;
28 import java.io.BufferedWriter;
29 import java.io.ByteArrayOutputStream;
30 import java.io.FileWriter;
31 import java.io.PrintStream;
32 import java.io.PrintWriter;
33 import java.io.Reader;
34 import java.io.StringReader;
35 import java.io.StringWriter;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.util.Arrays;
39 import java.util.List;
40 import java.util.Map;
41
42 import javax.script.CompiledScript;
43 import javax.script.ScriptContext;
44 import javax.script.ScriptEngine;
45 import javax.script.ScriptEngineManager;
46 import javax.script.ScriptException;
47
48 import org.apache.commons.jexl3.JexlException;
49 import org.apache.commons.jexl3.introspection.JexlPermissions;
50 import org.junit.jupiter.api.AfterEach;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53
54 class JexlScriptEngineTest {
55 public static class Errors {
56 public int illegal() {
57 throw new IllegalArgumentException("jexl");
58 }
59 public int npe() {
60 throw new NullPointerException("jexl");
61 }
62 }
63 private static final List<String> NAMES = Arrays.asList("JEXL", "Jexl", "jexl",
64 "JEXL2", "Jexl2", "jexl2",
65 "JEXL3", "Jexl3", "jexl3");
66 private static final List<String> EXTENSIONS = Arrays.asList("jexl", "jexl2", "jexl3");
67
68 private static final List<String> MIMES = Arrays.asList("application/x-jexl",
69 "application/x-jexl2",
70 "application/x-jexl3");
71
72 private static final String LF = System.lineSeparator();
73
74
75 private static final String PERMS_LOGGER = "jexl.test.permissions";
76
77 @BeforeEach
78 void setUp() {
79
80 java.util.logging.Logger.getLogger(PERMS_LOGGER).setLevel(java.util.logging.Level.SEVERE);
81 }
82
83 @AfterEach
84 void tearDown() {
85 JexlScriptEngine.setInstance(null);
86 JexlScriptEngineFactory.setDefaultPermissions(null);
87 }
88
89 @Test
90 void testCompile() throws Exception {
91 final ScriptEngineManager manager = new ScriptEngineManager();
92 final JexlScriptEngine engine = (JexlScriptEngine) manager.getEngineByName("JEXL");
93 final ScriptContext ctxt = engine.getContext();
94 final String str = null;
95 final Reader reader = null;
96 assertThrows(NullPointerException.class, () -> engine.compile(str));
97 assertThrows(NullPointerException.class, () -> engine.compile(reader));
98 final CompiledScript script0 = engine.compile(new StringReader("3 + 4"));
99 assertEquals(engine, script0.getEngine());
100 Object result = script0.eval();
101 assertEquals(7, result);
102 result = script0.eval();
103 assertEquals(7, result);
104 result = engine.eval(new StringReader("38 + 4"));
105 assertEquals(42, result);
106 result = engine.eval("38 + 4");
107 assertEquals(42, result);
108
109 final CompiledScript script1 = engine.compile("3 + 4");
110 assertEquals(engine, script1.getEngine());
111 Object result1 = script1.eval();
112 assertEquals(7, result1);
113 result1 = script1.eval();
114 assertEquals(7, result1);
115
116 ctxt.setAttribute("x", 20, ScriptContext.ENGINE_SCOPE);
117 ctxt.setAttribute("y", 22, ScriptContext.ENGINE_SCOPE);
118 final CompiledScript script2 = engine.compile("x + y");
119 Object result2 = script2.eval();
120 assertEquals(42, result2);
121 ctxt.setAttribute("x", -20, ScriptContext.ENGINE_SCOPE);
122 ctxt.setAttribute("y", -22, ScriptContext.ENGINE_SCOPE);
123 result2 = script2.eval();
124 assertEquals(-42, result2);
125 }
126
127 @Test
128 void testDirectNew() throws Exception {
129 final ScriptEngine engine = new JexlScriptEngine();
130 final Integer initialValue = 123;
131 assertEquals(initialValue,engine.eval("123"));
132 }
133
134 @Test
135 void testDottedNames() throws Exception {
136 final ScriptEngineManager manager = new ScriptEngineManager();
137 assertNotNull(manager, "Manager should not be null");
138 final ScriptEngine engine = manager.getEngineByName("JEXL");
139 assertNotNull(engine, "Engine should not be null (JEXL)");
140 engine.eval("this.is.a.test=null");
141 assertNull(engine.get("this.is.a.test"));
142 assertEquals(Boolean.TRUE, engine.eval("empty(this.is.a.test)"));
143 final Object mymap = engine.eval("testmap={ 'key1' : 'value1', 'key2' : 'value2' }");
144 assertInstanceOf(Map.class, mymap);
145 assertEquals(2,((Map<?, ?>)mymap).size());
146 }
147
148 @Test
149 void testErrors() throws Exception {
150 final JexlPermissions permissions = new JexlPermissions.ClassPermissions(Errors.class);
151 JexlScriptEngineFactory.setDefaultPermissions(permissions);
152 final ScriptEngineManager manager = new ScriptEngineManager();
153 final JexlScriptEngine engine = (JexlScriptEngine) manager.getEngineByName("JEXL");
154 engine.put("errors", new Errors());
155 assertInstanceOf(NullPointerException.class, assertThrows(ScriptException.class, () -> engine.eval("errors.npe()")).getCause());
156 assertInstanceOf(IllegalArgumentException.class, assertThrows(ScriptException.class, () -> engine.eval("errors.illegal()")).getCause());
157 final CompiledScript script0 = engine.compile("errors.npe()");
158 assertInstanceOf(NullPointerException.class, assertThrows(ScriptException.class, script0::eval).getCause());
159 final CompiledScript script1 = engine.compile("errors.illegal()");
160 assertInstanceOf(IllegalArgumentException.class, assertThrows(ScriptException.class, script1::eval).getCause());
161 }
162
163 @Test
164 void testNulls() {
165 final ScriptEngineManager manager = new ScriptEngineManager();
166 assertNotNull(manager, "Manager should not be null");
167 final ScriptEngine engine = manager.getEngineByName("jexl3");
168 assertNotNull(engine, "Engine should not be null (name)");
169 assertNotNull(engine.getFactory());
170 assertThrows(NullPointerException.class, () -> engine.eval((String) null));
171 assertThrows(NullPointerException.class, () -> engine.eval((Reader) null));
172 final ScriptContext ctxt = null;
173 assertThrows(NullPointerException.class, () -> engine.eval((String) null, ctxt));
174 assertThrows(NullPointerException.class, () -> engine.eval((Reader) null, ctxt));
175 }
176
177 @Test
178 void testScopes() throws Exception {
179 final ScriptEngineManager manager = new ScriptEngineManager();
180 assertNotNull(manager, "Manager should not be null");
181 final ScriptEngine engine = manager.getEngineByName("jexl3");
182 assertNotNull(engine, "Engine should not be null (name)");
183 manager.put("global", 1);
184 engine.put("local", 10);
185 manager.put("both", 7);
186 engine.put("both", 7);
187 engine.eval("local=local+1");
188 engine.eval("global=global+1");
189 engine.eval("both=both+1");
190 engine.eval("newvar=42;");
191 assertEquals(2,manager.get("global"));
192 assertEquals(11,engine.get("local"));
193 assertEquals(7,manager.get("both"));
194 assertEquals(8,engine.get("both"));
195 assertEquals(42,engine.get("newvar"));
196 assertNull(manager.get("newvar"));
197 }
198
199 @Test
200 void testScriptEngineFactory() {
201 final JexlScriptEngineFactory factory = new JexlScriptEngineFactory();
202 assertEquals("JEXL Engine", factory.getParameter(ScriptEngine.ENGINE));
203 assertEquals("3.7", factory.getParameter(ScriptEngine.ENGINE_VERSION));
204 assertEquals("JEXL", factory.getParameter(ScriptEngine.LANGUAGE));
205 assertEquals("3.7", factory.getParameter(ScriptEngine.LANGUAGE_VERSION));
206 assertNull(factory.getParameter("THREADING"));
207 assertEquals(NAMES, factory.getParameter(ScriptEngine.NAME));
208 assertEquals(EXTENSIONS, factory.getExtensions());
209 assertEquals(MIMES, factory.getMimeTypes());
210
211 assertEquals("42;", factory.getProgram("42"));
212 assertEquals("str.substring(3,4)", factory.getMethodCallSyntax("str", "substring", "3", "4"));
213 }
214
215 @Test
216 void testScripting() throws Exception {
217 final ScriptEngineManager manager = new ScriptEngineManager();
218 assertNotNull(manager, "Manager should not be null");
219 final ScriptEngine engine = manager.getEngineByName("jexl3");
220 final Integer initialValue = 123;
221 assertEquals(initialValue, engine.eval("123"));
222 assertEquals(initialValue, engine.eval("0;123"));
223 final ScriptException xscript = assertThrows(ScriptException.class,
224 () -> engine.eval("sys=context.class.forName(\"java.lang.System\");now=sys.currentTimeMillis();"));
225 final JexlException.Property xjexl = (JexlException.Property) xscript.getCause();
226 assertEquals("class", xjexl.getProperty());
227 engine.put("value", initialValue);
228 assertEquals(initialValue, engine.get("value"));
229 final Integer newValue = 124;
230 assertEquals(newValue, engine.eval("old=value;value=value+1"));
231 assertEquals(initialValue, engine.get("old"));
232 assertEquals(newValue, engine.get("value"));
233 assertEquals(engine.getContext(), engine.get(JexlScriptEngine.CONTEXT_KEY));
234
235 assertEquals(engine.getContext().getReader(), engine.eval("JEXL.in"));
236 assertEquals(engine.getContext().getWriter(), engine.eval("JEXL.out"));
237 assertEquals(engine.getContext().getErrorWriter(), engine.eval("JEXL.err"));
238 assertEquals(System.class, engine.eval("JEXL.System"));
239 }
240
241 @Test
242 void testScriptingGetBy() {
243 final ScriptEngineManager manager = new ScriptEngineManager();
244 assertNotNull(manager, "Manager should not be null");
245 for (final String name : NAMES) {
246 final ScriptEngine engine = manager.getEngineByName(name);
247 assertNotNull(engine, "Engine should not be null (name)");
248 }
249 for (final String extension : EXTENSIONS) {
250 final ScriptEngine engine = manager.getEngineByExtension(extension);
251 assertNotNull(engine, "Engine should not be null (extension)");
252 }
253 for (final String mime : MIMES) {
254 final ScriptEngine engine = manager.getEngineByMimeType(mime);
255 assertNotNull(engine, "Engine should not be null (mime)");
256 }
257 }
258 @Test
259 void testScriptingInstance0() throws Exception {
260 JexlScriptEngineFactory.setDefaultPermissions(JexlPermissions.UNRESTRICTED);
261 final ScriptEngineManager manager = new ScriptEngineManager();
262 final ScriptEngine engine = manager.getEngineByName("jexl3");
263 final Long time2 = (Long) engine.eval(
264 "sys=context.class.forName(\"java.lang.System\");"
265 + "now=sys.currentTimeMillis();");
266 assertTrue(time2 <= System.currentTimeMillis());
267 }
268
269 @Test
270 void testScriptingPermissions1() throws Exception {
271
272 JexlScriptEngineFactory.setDefaultPermissions(
273 JexlPermissions.RESTRICTED.compose(
274 "javax.script { +SimpleScriptContext { getClass(); } }"
275 + "java.lang { "
276 + "+System { currentTimeMillis(); }"
277 + "+Class { forName(); } "
278 + "}").logging(PERMS_LOGGER));
279 final ScriptEngineManager manager = new ScriptEngineManager();
280 final ScriptEngine engine = manager.getEngineByName("jexl3");
281 final Long time2 = (Long) engine.eval(
282 "sys=context.class.forName(\"java.lang.System\");"
283 + "now=sys.currentTimeMillis();");
284 assertTrue(time2 <= System.currentTimeMillis());
285 }
286
287 @Test
288 void testMain0() throws Exception {
289 final StringWriter strw = new StringWriter();
290 final StringReader strr = new StringReader("a=20\nb=22\na+b\n//q!\n");
291 Main.run(new BufferedReader(strr), new PrintWriter(strw), null);
292 final String ctl = "> >> 20" + LF +
293 "> >> 22" + LF +
294 "> >> 42" + LF +
295 "> ";
296 assertEquals(ctl, strw.toString());
297 }
298
299 @Test
300 void testMain1() throws Exception {
301 final StringWriter strw = new StringWriter();
302 final StringReader strr = new StringReader("args[0]+args[1]");
303 Main.run(new BufferedReader(strr), new PrintWriter(strw), new Object[]{20, 22});
304 final String ctl = ">>: 42" + LF;
305 assertEquals(ctl, strw.toString());
306 }
307
308 @Test
309 void testMain2() throws Exception {
310 final PrintStream originalOut = System.out;
311 Path file = null;
312 try {
313 file = Files.createTempFile("test-jsr233", ".jexl");
314 try (BufferedWriter writer = new BufferedWriter(new FileWriter(file.toFile()));
315 ByteArrayOutputStream outContent = new ByteArrayOutputStream();
316 PrintStream printStream = new PrintStream(outContent)) {
317 writer.write("a=20;\nb=22;\na+b\n");
318 writer.flush();
319 System.setOut(printStream);
320 final String ctl = ">>: 42" + LF;
321 Main.main(new String[]{file.toString()});
322 assertEquals(ctl, outContent.toString());
323 } finally {
324 System.setOut(originalOut);
325 }
326 } finally {
327 if (file != null) {
328 Files.delete(file);
329 }
330 }
331 }
332 }