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.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertTrue;
22 import static org.junit.jupiter.api.Assertions.fail;
23
24 import java.util.Arrays;
25 import java.util.List;
26
27 import org.apache.commons.jexl3.internal.Debugger;
28 import org.junit.jupiter.api.Test;
29
30
31
32
33 @SuppressWarnings({"AssertEqualsBetweenInconvertibleTypes"})
34 public class SwitchTest extends JexlTestCase {
35
36 public SwitchTest() {
37 super("SwitchTest");
38 }
39
40
41
42
43
44
45 @Test
46 void testContinueInSwitchStatement() {
47 final JexlEngine jexl = new JexlBuilder().create();
48
49 final String continueSrc =
50 "var r = '';\n" +
51 "for (var i : [1, 2, 3]) {\n" +
52 " switch (i) {\n" +
53 " case 2 : continue;\n" +
54 " default : {}\n" +
55 " }\n" +
56 " r += i;\n" +
57 "}\n" +
58 "r";
59 assertEquals("13", jexl.createScript(continueSrc).execute(null));
60
61 final String breakSrc =
62 "var r = '';\n" +
63 "for (var i : [1, 2, 3]) {\n" +
64 " switch (i) {\n" +
65 " case 2 : break;\n" +
66 " default : {}\n" +
67 " }\n" +
68 " r += i;\n" +
69 "}\n" +
70 "r";
71 assertEquals("123", jexl.createScript(breakSrc).execute(null));
72 }
73
74 @Test
75 void testSwitchExpression() {
76 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
77 final JexlScript e = jexl.createScript("var j = switch(i) { case 1 -> 2; case 2 -> 3; default -> 4; }; j", "i");
78 final JexlContext jc = new MapContext();
79 final Object o = e.execute(jc, 1);
80 assertEquals(2, o);
81 }
82
83 @Test
84 void testBrokenSwitchExpression0() {
85 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
86 try {
87 jexl.createScript("var j = switch(i) { case 1 -> return 2; }; j", "i");
88 fail("should not be able to create script with return in switch expression");
89 } catch (final JexlException.Parsing xparse) {
90 assertTrue(xparse.getMessage().contains("return"));
91 }
92 try {
93 jexl.createScript("var j = switch(i) { case 1 -> break; }; j", "i");
94 fail("should not be able to create script with break in switch expression");
95 } catch (final JexlException.Parsing xparse) {
96 assertTrue(xparse.getMessage().contains("break"));
97 }
98 }
99
100 @Test
101 void testSwitchStatement() {
102 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
103 final JexlScript e = jexl.createScript("switch(i) { case 1: i += 2; case 2: i += 3; default: i += 4; }; i + 33", "i");
104 final JexlContext jc = new MapContext();
105 final Object o = e.execute(jc, 2);
106 assertEquals(42, o);
107 }
108
109 @Test
110 void test440a() {
111 final JexlFeatures f = JexlFeatures.createDefault().ambiguousStatement(true);
112 final JexlEngine jexl = new JexlBuilder().features(f).safe(false).strict(true).create();
113 String src =
114 "let y = switch (x) { case 10,11 -> 3 case 20, 21 -> 4\n" + "default -> { let z = 4; z + x } } y";
115 JexlScript script = jexl.createScript(src, "x");
116 assertNotNull(script);
117 final String dbgStr = script.getParsedText();
118 assertNotNull(dbgStr);
119
120 Object result = script.execute(null, 10);
121 assertEquals(3, result);
122 result = script.execute(null, 11);
123 assertEquals(3, result);
124 result = script.execute(null, 20);
125 assertEquals(4, result);
126 result = script.execute(null, 21);
127 assertEquals(4, result);
128 result = script.execute(null, 38);
129 assertEquals(42, result);
130 src = "let y = switch (x) { case 10,11 -> break; case 20, 21 -> 4; } y";
131 try {
132 script = jexl.createScript(src, "x");
133 fail("should not be able to create script with break in switch");
134 } catch (final JexlException.Parsing xparse) {
135 assertTrue(xparse.getMessage().contains("break"));
136 }
137 assertNotNull(script);
138 }
139
140 @Test
141 void test440b() {
142 final JexlEngine jexl = new JexlBuilder().safe(false).strict(true).create();
143 final String src =
144 "switch (x) {\n" +
145 " case 10 : return 3\n;" +
146 " case 20 : case 21 : return 4;\n" +
147 " case 32: break; \n" +
148 " default : return x + 4;\n" +
149 " }\n" +
150 " 169";
151 final JexlScript script = jexl.createScript(src, "x");
152 assertNotNull(script);
153 final String dbgStr = script.getParsedText();
154 assertNotNull(dbgStr);
155
156 Object result = script.execute(null, 10);
157 assertEquals(3, result);
158 result = script.execute(null, 20);
159 assertEquals(4, result);
160 result = script.execute(null, 21);
161 assertEquals(4, result);
162 result = script.execute(null, 32);
163 assertEquals(169, result);
164 result = script.execute(null, 38);
165 assertEquals(42, result);
166 }
167
168 public enum Scope440 {
169 UNDEFINED, UNDECLARED, GLOBAL, LOCAL, THIS, SUPER;
170 }
171
172
173 @Test
174 void test440p() {
175 assertTrue(TEST_PERMS.allow(this.getClass()));
176 }
177
178 @Test
179 void test440c() {
180 final JexlEngine jexl = new JexlBuilder().loader(getClass().getClassLoader()).imports(this.getClass().getName()).create();
181 final String src =
182 "let s = switch (x) { case Scope440.UNDEFINED -> 'undefined'; case Scope440.THIS -> 'this'; default -> 'OTHER'; } s";
183 final JexlScript script = jexl.createScript(src, "x");
184 assertNotNull(script);
185 final String dbgStr = script.getParsedText();
186 assertNotNull(dbgStr);
187
188 Object result = script.execute(null, Scope440.UNDEFINED);
189 assertEquals("undefined", result);
190 result = script.execute(null, Scope440.THIS);
191 assertEquals("this", result);
192 result = script.execute(null, 21);
193 assertEquals("OTHER", result);
194 }
195
196 @Test
197 void test440d() {
198 final JexlEngine jexl = new JexlBuilder().loader(getClass().getClassLoader()).imports(this.getClass().getName()).create();
199 final String src = "let s = switch (x) { case Scope440.UNDEFINED -> 'undefined'; } s";
200 final JexlScript script = jexl.createScript(src, "x");
201 try {
202 script.execute(null, Scope440.THIS);
203 fail("should not be able to execute script with switch expression with no default");
204 } catch (final JexlException xjexl) {
205 assertTrue(xjexl.getMessage().contains("switch"));
206 }
207 }
208
209 @Test
210 void test440e() {
211 final JexlEngine jexl = new JexlBuilder().loader(getClass().getClassLoader()).imports(this.getClass().getName()).create();
212 final String src = "function f(x) { switch (x) { case Scope440.UNDEFINED : return 'undefined'; } } f(x)";
213 final JexlScript script = jexl.createScript(src, "x");
214 final Object result = script.execute(null, Scope440.UNDEFINED);
215 assertEquals("undefined", result);
216 try {
217 script.execute(null, Scope440.THIS);
218 fail("should not be able to execute script with switch expression with no default");
219 } catch (final JexlException xjexl) {
220 assertTrue(xjexl.getMessage().contains("switch"));
221 }
222 }
223
224 @Test
225 void testSwitchStatement1() {
226
227 final String src = "switch (x) {\n"
228 + " case 1: return 'one';\n"
229 + " case 2: return 'two';\n"
230 + " case 3: return 'three';\n"
231 + " default: return 'many';\n"
232 + "}";
233 runSwitch(src);
234 final String src2 = "if (true) { " + src + " }";
235 runSwitch(src2);
236 }
237
238 @Test
239 void testSwitchExpression1() {
240
241 final String src = "switch (x) {\n"
242 + " case 1 -> 'one';\n"
243 + " case 2 -> 'two';\n"
244 + " case 3 -> 'three';\n"
245 + " default -> 'many';\n"
246 + "}";
247 runSwitch(src);
248 final String src2 = "if (true) { " + src + " }";
249 runSwitch(src2);
250 }
251
252 void runSwitch(final String src) {
253 final JexlEngine jexl = new JexlBuilder().create();
254 final JexlScript script = jexl.createScript(src, "x");
255 Object result;
256 result = script.execute(null, 1);
257 assertEquals("one", result);
258 result = script.execute(null, 2);
259 assertEquals("two", result);
260 result = script.execute(null, 3);
261 assertEquals("three", result);
262 result = script.execute(null, 4);
263 assertEquals("many", result);
264 result = script.execute(null, 42);
265 assertEquals("many", result);
266 final Debugger debugger = new Debugger();
267 assertTrue(debugger.debug(script));
268 final String dbgStr = debugger.toString();
269 assertTrue(JexlTestCase.equalsIgnoreWhiteSpace(src, dbgStr));
270 }
271
272 @Test
273 void testSwitchExpressionFail() {
274 final List<String> err = Arrays.asList("break", "continue");
275 for (final String keyword : err) {
276 switchExpressionFailKeyword(keyword);
277 }
278 }
279
280 private void switchExpressionFailKeyword(final String keyword) {
281
282 final String src = "switch (x) {\n"
283 + " case 1 -> 'one';\n"
284 + " case 2 -> " + keyword + ";\n"
285 + " default -> 'many';\n"
286 + "}";
287 final JexlEngine jexl = new JexlBuilder().create();
288 try {
289 jexl.createScript(src, "x");
290 fail("should not be able to create script with " + keyword + " in switch expression");
291 } catch (final JexlException.Parsing xparse) {
292 assertTrue(xparse.getMessage().contains(keyword));
293 }
294 }
295
296 @Test
297 void testTryCatchFinally() {
298 final JexlEngine jexl = new JexlBuilder().create();
299 final String src = "try { return 42 } catch(const xerror){} finally { return 169 }";
300 final JexlScript script = jexl.createScript(src);
301 assertNotNull(script);
302 final Object result = script.execute(null);
303 assertEquals(169, result);
304 }
305
306 @Test
307 void testSwitchNaN0() {
308
309 final String src = "switch (x) {\n"
310 + " case NaN: return 'NotANumber';\n"
311 + " case 1: return 'one';\n"
312 + " case 2: return 'two';\n"
313 + " case 3: return 'three';\n"
314 + " default: return 'many';\n"
315 + "}";
316 runSwitchNaN(src);
317 }
318
319 @Test
320 void testSwitchNaN1() {
321
322 final String src = "switch (x) {\n"
323 + " case NaN -> 'NotANumber';\n"
324 + " case 1 -> 'one';\n"
325 + " case 2 -> 'two';\n"
326 + " case 3 -> 'three';\n"
327 + " default -> 'many';\n"
328 + "}";
329 runSwitchNaN(src);
330 }
331
332 static void runSwitchNaN(final String src) {
333 final JexlEngine jexl = new JexlBuilder().create();
334 final JexlScript script = jexl.createScript(src, "x");
335 Object result = script.execute(null, Double.NaN);
336 assertEquals("NotANumber", result);
337 result = script.execute(null, 1);
338 assertEquals("one", result);
339 result = script.execute(null, 42);
340 assertEquals("many", result);
341 }
342
343 }