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