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.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24 import static org.junit.jupiter.api.Assertions.fail;
25
26 import java.util.function.Supplier;
27
28 import org.junit.jupiter.api.Test;
29
30
31
32
33 @SuppressWarnings({"UnnecessaryBoxing", "AssertEqualsBetweenInconvertibleTypes"})
34 class ExceptionTest extends JexlTestCase {
35 public static class ThrowNPE {
36 boolean doThrow;
37 public boolean getFail() {
38 if (doThrow) {
39 throw new NullPointerException("ThrowNPE/get");
40 }
41 return doThrow;
42 }
43
44 public String npe() {
45 throw new NullPointerException("ThrowNPE");
46 }
47
48 public void setFail(final boolean f) {
49 doThrow = f;
50 if (f) {
51 throw new NullPointerException("ThrowNPE/set");
52 }
53 }
54 }
55
56 public static class ConstructNPE {
57 public ConstructNPE() {
58 throw new NullPointerException("ConstructNPE");
59 }
60 }
61
62
63 public ExceptionTest() {
64 super("ExceptionTest");
65 }
66
67 private void doTest206(final String src, final boolean strict, final boolean silent) {
68 final CaptureLog l = new CaptureLog();
69 final JexlContext jc = new MapContext();
70 final JexlEngine jexl = new JexlBuilder().logger(l).strict(strict).silent(silent).create();
71 JexlScript e;
72 Object r = -1;
73 e = jexl.createScript(src);
74 try {
75 r = e.execute(jc);
76 if (strict && !silent) {
77 fail("should have thrown an exception");
78 }
79 } catch (final JexlException xjexl) {
80 if (!strict || silent) {
81 fail(src + ": should not have thrown an exception");
82 }
83 }
84 if (strict) {
85 if (silent && l.count("warn") == 0) {
86 fail(src + ": should have generated a warning");
87 }
88 } else {
89 if (l.count("debug") == 0) {
90 fail(src + ": should have generated a debug");
91 }
92 assertEquals(42, r);
93 }
94 }
95
96 @Test
97 void test206() throws Exception {
98 String src = "null.1 = 2; return 42";
99 doTest206(src, false, false);
100 doTest206(src, false, true);
101 doTest206(src, true, false);
102 doTest206(src, true, true);
103 src = "x = null.1; return 42";
104 doTest206(src, false, false);
105 doTest206(src, false, true);
106 doTest206(src, true, false);
107 doTest206(src, true, true);
108 src = "x = y.1; return 42";
109 doTest206(src, false, false);
110 doTest206(src, false, true);
111 doTest206(src, true, false);
112 doTest206(src, true, true);
113 }
114
115
116
117 @Test
118 void testEx() {
119 final JexlEngine jexl = createEngine(false);
120 final JexlExpression e = jexl.createExpression("c.e * 6");
121 final JexlEvalContext ctxt = new JexlEvalContext();
122 final JexlOptions options = ctxt.getEngineOptions();
123
124 options.setSilent(false);
125
126 options.setStrict(true);
127
128 JexlException.Variable xjexl = assertThrows(JexlException.Variable.class, () -> e.evaluate(ctxt), "c not defined as variable should throw");
129 String msg = xjexl.getMessage();
130 assertTrue(msg.indexOf("variable 'c.e'") > 0);
131
132
133 options.setStrictArithmetic(true);
134 ctxt.set("c.e", null);
135 xjexl = assertThrows(JexlException.Variable.class, () -> e.evaluate(ctxt), "c.e as null operand should throw");
136 msg = xjexl.getMessage();
137 assertTrue(msg.indexOf("variable 'c.e'") > 0);
138
139
140 options.setStrictArithmetic(false);
141 e.evaluate(ctxt);
142
143
144 ctxt.set("c", "{ 'a' : 3, 'b' : 5}");
145 ctxt.set("e", Integer.valueOf(2));
146 final JexlException.Property ep = assertThrows(JexlException.Property.class, () -> e.evaluate(ctxt));
147 msg = ep.getMessage();
148 assertTrue(msg.indexOf("property 'e") > 0);
149 }
150
151
152 @Test
153 void testExMethod() {
154 final JexlEngine jexl = createEngine(false);
155 final JexlExpression e = jexl.createExpression("c.e.foo()");
156 final JexlEvalContext ctxt = new JexlEvalContext();
157 final JexlOptions options = ctxt.getEngineOptions();
158
159 options.setSilent(false);
160
161 options.setStrict(true);
162
163 JexlException xjexl = assertThrows(JexlException.class, () -> e.evaluate(ctxt), "c not declared as variable should throw");
164 String msg = xjexl.getMessage();
165 assertTrue(msg.indexOf("variable 'c.e'") > 0);
166
167
168 options.setStrictArithmetic(true);
169 ctxt.set("c.e", null);
170 xjexl = assertThrows(JexlException.class, () -> e.evaluate(ctxt));
171 msg = xjexl.getMessage();
172 assertTrue(msg.indexOf("variable 'c.e'") > 0);
173 }
174
175
176 @Test
177 void testExVar() {
178 final JexlEngine jexl = createEngine(false);
179 final JexlScript e = jexl.createScript("(x)->{ x * 6 }");
180 final JexlEvalContext ctxt = new JexlEvalContext();
181 final JexlOptions options = ctxt.getEngineOptions();
182
183 options.setSilent(false);
184
185 options.setStrict(true);
186 options.setStrictArithmetic(true);
187
188 final JexlException xjexl = assertThrows(JexlException.class, () -> e.execute(ctxt));
189 final String msg = xjexl.getMessage();
190 assertTrue(msg.indexOf("null") > 0);
191
192
193 options.setStrictArithmetic(false);
194 assertEquals(0, e.execute(ctxt, (Object) null));
195 }
196
197 @Test
198 void testWrappedEx() {
199 runWrappedEx(true, true);
200 runWrappedEx(false, true);
201 runWrappedEx(true, false);
202 runWrappedEx(false, false);
203 }
204
205
206
207
208
209
210 private static void runWrappedEx(boolean debug, boolean silent) {
211 final CaptureLog log = new CaptureLog();
212 final JexlBuilder builder = new JexlBuilder().safe(false).strict(true)
213 .logger(log).debug(debug).silent(silent);
214 final JexlEngine jexl = builder.create();
215 final JexlContext jc = new ObjectContext<>(jexl, new ThrowNPE());
216 callWrappedEx(debug, silent, log, () -> jexl.createExpression("npe()").evaluate(jc));
217 callWrappedEx(debug, silent, log, () -> jexl.newInstance(ConstructNPE.class));
218 ThrowNPE npe = new ThrowNPE();
219 callWrappedEx(debug, silent, log, () -> jexl.invokeMethod(npe, "npe"));
220
221 callWrappedEx(debug, silent, log, () -> {
222 jexl.setProperty(npe, "fail", true);
223 return null;
224 });
225 callWrappedEx(debug, silent, log, () -> jexl.getProperty(npe, "fail"));
226 }
227
228
229
230
231
232
233
234 private static void callWrappedEx(boolean debug, boolean silent, CaptureLog log, Supplier<Object> npeCall) {
235 try {
236 npeCall.get();
237 if (!silent) {
238 fail("should have thrown");
239 } else {
240
241 assertEquals(1, log.count("warn"), "should have 1 warn log");
242 String msg = log.getCapturedMessages().get(0);
243 assertEquals(debug, msg.contains("runWrappedEx"), "class/method/line?");
244 log.clear();
245 }
246 } catch (final JexlException exception) {
247 if (silent) {
248 fail("should not have throw, should be silent");
249 }
250 assertEquals(debug, exception.getMessage().contains("runWrappedEx"), "class/method/line?");
251 final Throwable xth = exception.getCause();
252 assertEquals(NullPointerException.class, xth.getClass(), "Should have thrown NPE");
253 }
254 }
255
256 @Test
257 void testWrappedExmore() {
258 final JexlEngine jexl = new JexlBuilder().debug(true).safe(false).create();
259 final ThrowNPE npe = new ThrowNPE();
260 assertNull(assertThrows(JexlException.Property.class, () -> jexl.getProperty(npe, "foo")).getCause());
261 assertNull(assertThrows(JexlException.Property.class, () -> jexl.setProperty(npe, "foo", 42)).getCause());
262
263 final boolean b = (Boolean) jexl.getProperty(npe, "fail");
264 assertFalse(b);
265 jexl.setProperty(npe, "fail", false);
266 assertEquals(NullPointerException.class, assertThrows(JexlException.Property.class, () -> jexl.setProperty(npe, "fail", true)).getCause().getClass());
267 assertEquals(NullPointerException.class, assertThrows(JexlException.Property.class, () -> jexl.getProperty(npe, "fail")).getCause().getClass());
268 assertNull(assertThrows(JexlException.Method.class, () -> jexl.invokeMethod(npe, "foo", 42)).getCause());
269 assertEquals(NullPointerException.class, assertThrows(JexlException.Method.class, () -> jexl.invokeMethod(npe, "npe")).getCause().getClass());
270 }
271 }