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.assertThrows;
21
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.concurrent.atomic.AtomicInteger;
26
27 import org.junit.jupiter.api.Test;
28
29
30
31
32 @SuppressWarnings({"AssertEqualsBetweenInconvertibleTypes"})
33 class ContextNamespaceTest extends JexlTestCase {
34
35 public static class Context346 extends MapContext {
36 public int func(final int y) { return 42 * y;}
37 }
38
39 public static class ContextNs348 extends MapContext implements JexlContext.NamespaceResolver {
40 ContextNs348() { }
41
42 @Override
43 public Object resolveNamespace(final String name) {
44 return "ns".equals(name)? new Ns348() : null;
45 }
46 }
47
48 public static class Ns348 {
49 public static int func(final int y) { return 42 * y;}
50 }
51
52 public static class NsNs {
53 private final int constVar;
54 public NsNs(final JexlContext ctxt) {
55 nsnsCtor.incrementAndGet();
56 final Object n = ctxt.get("NUMBER");
57 constVar = n instanceof Number ? ((Number) n).intValue() : -1;
58 }
59
60 public int callIt(final int n) {
61 return n + constVar;
62 }
63 }
64
65 public static class StaticNs {
66 public static int callIt(final int n) {
67 return n + 19;
68 }
69 private StaticNs() { }
70 }
71
72
73
74
75 public static class Taxes {
76 private final double vat;
77
78 public Taxes(final double d) {
79 vat = d;
80 }
81
82 public Taxes(final TaxesContext ctxt) {
83 vat = ctxt.getVAT();
84 }
85
86 public double vat(final double n) {
87 return n * vat / 100.;
88 }
89 }
90
91
92
93
94 public static class TaxesContext extends MapContext implements JexlContext.ThreadLocal, JexlContext.NamespaceResolver {
95 private Taxes taxes;
96 private final double vat;
97
98 TaxesContext(final double vat) {
99 this.vat = vat;
100 }
101
102 public double getVAT() {
103 return vat;
104 }
105
106 @Override
107 public Object resolveNamespace(final String name) {
108 if ("taxes".equals(name)) {
109 if (taxes == null) {
110 taxes = new Taxes(vat);
111 }
112 return taxes;
113 }
114 return null;
115 }
116 }
117
118 public static class Vat {
119 private double vat;
120
121 Vat(final double vat) {
122 this.vat = vat;
123 }
124
125 public double getvat() {
126 throw new UnsupportedOperationException("no way");
127 }
128
129 public double getVAT() {
130 return vat;
131 }
132
133 public void setvat(final double vat) {
134 throw new UnsupportedOperationException("no way");
135 }
136
137 public void setVAT(final double vat) {
138 this.vat = vat;
139 }
140 }
141
142 static AtomicInteger nsnsCtor = new AtomicInteger();
143
144 public ContextNamespaceTest() {
145 super("ContextNamespaceTest");
146 }
147
148 private void run348a(final JexlEngine jexl, final JexlContext ctxt) {
149 run348a(jexl, ctxt, "ns : ");
150 }
151
152 private void run348a(final JexlEngine jexl, final JexlContext ctxt, final String ns) {
153 final String src = "empty(x) ? "+ns+"func(y) : z";
154
155 final JexlScript script = jexl.createScript(src, "x", "y", "z");
156 Object result = script.execute(ctxt, null, 1, 169);
157 assertEquals(42, result);
158 result = script.execute(ctxt, "42", 1, 169);
159 assertEquals(169, result);
160 }
161
162 private void run348b(final JexlEngine jexl, final JexlContext ctxt) {
163 run348b(jexl, ctxt, "ns : ");
164 }
165
166 private void run348b(final JexlEngine jexl, final JexlContext ctxt, final String ns) {
167 final String src = "empty(x) ? "+ns+"func(y) : z";
168
169 final JexlScript script = jexl.createScript(src);
170 ctxt.set("x", null);
171 ctxt.set("y", 1);
172 ctxt.set("z", 169);
173 Object result = script.execute(ctxt);
174 assertEquals(42, result);
175 ctxt.set("x", "42");
176 result = script.execute(ctxt);
177 assertEquals(169, result);
178
179 result = script.execute(ctxt);
180 assertEquals(169, result);
181 }
182
183 private void run348c(final JexlEngine jexl, final JexlContext ctxt) {
184 run348c(jexl, ctxt, "ns : ");
185 }
186 private void run348c(final JexlEngine jexl, final JexlContext ctxt, final String ns) {
187 final String src = "empty(x) ? z : "+ns+"func(y)";
188
189 final JexlScript script = jexl.createScript(src, "x", "z", "y");
190 Object result = script.execute(ctxt, null, 169, 1);
191 assertEquals(169, result, src);
192 result = script.execute(ctxt, "42", 169, 1);
193 assertEquals(42, result, src);
194 }
195
196 private void run348d(final JexlEngine jexl, final JexlContext ctxt) {
197 run348d(jexl, ctxt, "ns : ");
198 }
199 private void run348d(final JexlEngine jexl, final JexlContext ctxt, final String ns) {
200 final String src = "empty(x) ? z : "+ns+"func(y)";
201
202 final JexlScript script = jexl.createScript(src);
203
204 ctxt.set("x", null);
205 ctxt.set("z", 169);
206 ctxt.set("y", 1);
207 Object result = script.execute(ctxt);
208 assertEquals(169, result, src);
209 ctxt.set("x", "42");
210 result = script.execute(ctxt);
211 assertEquals(42, result, src);
212 }
213
214 private void runNsNsContext(final Map<String,Object> nsMap) {
215 final JexlContext ctxt = new MapContext();
216 ctxt.set("NUMBER", 19);
217 final JexlEngine jexl = new JexlBuilder().strict(true).silent(false).cache(32)
218 .namespaces(nsMap).create();
219 final JexlScript script = jexl.createScript("x ->{ nsns:callIt(x); nsns:callIt(x); }");
220 Number result = (Number) script.execute(ctxt, 23);
221 assertEquals(42, result);
222 assertEquals(1, nsnsCtor.get());
223 result = (Number) script.execute(ctxt, 623);
224 assertEquals(642, result);
225 assertEquals(2, nsnsCtor.get());
226 }
227 private void runStaticNsContext(final Map<String,Object> nsMap) {
228 final JexlContext ctxt = new MapContext();
229 final JexlEngine jexl = new JexlBuilder().strict(true).silent(false).cache(32)
230 .namespaces(nsMap).create();
231 final JexlScript script = jexl.createScript("x ->{ sns:callIt(x); sns:callIt(x); }");
232 Number result = (Number) script.execute(ctxt, 23);
233 assertEquals(42, result);
234 result = (Number) script.execute(ctxt, 623);
235 assertEquals(642, result);
236 }
237
238 @Test
239 void testNamespace346a() {
240 final JexlContext ctxt = new Context346();
241 final JexlEngine jexl = new JexlBuilder().safe(false).create();
242 final String src = "x != null ? x : func(y)";
243 final JexlScript script = jexl.createScript(src,"x","y");
244 Object result = script.execute(ctxt, null, 1);
245 assertEquals(42, result);
246 result = script.execute(ctxt, 169, -169);
247 assertEquals(169, result);
248 }
249 @Test
250 void testNamespace346b() {
251 final JexlContext ctxt = new MapContext();
252 final Map<String, Object> ns = new HashMap<>();
253 ns.put("x", Math.class);
254 ns.put(null, Math.class);
255 final JexlEngine jexl = new JexlBuilder().safe(false).namespaces(ns).create();
256 final String src = "x != null ? x : abs(y)";
257 final JexlScript script = jexl.createScript(src,"x","y");
258 Object result = script.execute(ctxt, null, 42);
259 assertEquals(42, result);
260 result = script.execute(ctxt, 169, -169);
261 assertEquals(169, result);
262 }
263
264 @Test
265 void testNamespace348a() {
266 final JexlContext ctxt = new MapContext();
267 final Map<String, Object> ns = new HashMap<>();
268 ns.put("ns", Ns348.class);
269 final JexlEngine jexl = new JexlBuilder().safe(false).namespaces(ns).create();
270 run348a(jexl, ctxt);
271 run348b(jexl, ctxt);
272 run348c(jexl, ctxt);
273 run348d(jexl, ctxt);
274 }
275
276 @Test
277 void testNamespace348b() {
278 final JexlContext ctxt = new ContextNs348();
279 final JexlEngine jexl = new JexlBuilder().safe(false).create();
280
281 run348a(jexl, ctxt, "ns:");
282 run348b(jexl, ctxt, "ns:");
283 run348c(jexl, ctxt, "ns:");
284 run348d(jexl, ctxt, "ns:");
285 }
286
287 @Test
288 void testNamespace348c() {
289 final JexlContext ctxt = new ContextNs348();
290 final Map<String, Object> ns = new HashMap<>();
291 ns.put("ns", Ns348.class);
292 final JexlFeatures f = new JexlFeatures();
293 f.namespaceTest(n -> true);
294 final JexlEngine jexl = new JexlBuilder().namespaces(ns).features(f).safe(false).create();
295 run348a(jexl, ctxt);
296 run348b(jexl, ctxt);
297 run348c(jexl, ctxt);
298 run348d(jexl, ctxt);
299 }
300
301 @Test
302 void testNamespace348d() {
303 final JexlContext ctxt = new ContextNs348();
304 final JexlFeatures f = new JexlFeatures();
305 f.namespaceTest(n -> true);
306 final JexlEngine jexl = new JexlBuilder().features(f).safe(false).create();
307 run348a(jexl, ctxt);
308 run348b(jexl, ctxt);
309 run348c(jexl, ctxt);
310 run348d(jexl, ctxt);
311 }
312
313 @Test
314 void testNamespacePragma() {
315 final JexlEngine jexl = new JexlBuilder().create();
316 final JexlContext context = new TaxesContext(18.6);
317
318 final String strs =
319 "#pragma jexl.namespace.tax org.apache.commons.jexl3.ContextNamespaceTest$Taxes\n"
320 + "tax:vat(2000)";
321 final JexlScript staxes = jexl.createScript(strs);
322 final Object result = staxes.execute(context);
323 assertEquals(372., result);
324 }
325
326 @Test
327 void testNamespacePragmaString() {
328 final JexlEngine jexl = new JexlBuilder().create();
329 final JexlContext context = new MapContext();
330
331 final String strs =
332 "#pragma jexl.namespace.str java.lang.String\n"
333 + "str:format('%04d', 42)";
334 final JexlScript staxes = jexl.createScript(strs);
335 final Object result = staxes.execute(context);
336 assertEquals("0042", result);
337 }
338
339 @Test
340 void testNsNsContext0() {
341 nsnsCtor.set(0);
342 final String clsName = NsNs.class.getName();
343 runNsNsContext(Collections.singletonMap("nsns", clsName));
344 }
345
346 @Test
347 void testNsNsContext1() {
348 nsnsCtor.set(0);
349 runNsNsContext(Collections.singletonMap("nsns", NsNs.class));
350 }
351
352 @Test
353 void testObjectContext() {
354 final JexlEngine jexl = new JexlBuilder().strict(true).silent(false).create();
355 final Vat vat = new Vat(18.6);
356 final ObjectContext<Vat> ctxt = new ObjectContext<>(jexl, vat);
357 assertEquals(18.6d, (Double) ctxt.get("VAT"), 0.0001d);
358 ctxt.set("VAT", 20.0d);
359 assertEquals(20.0d, (Double) ctxt.get("VAT"), 0.0001d);
360 assertThrows(JexlException.Property.class, () -> ctxt.get("vat"));
361 assertThrows(JexlException.Property.class, () -> ctxt.set("vat", 33.0d));
362 }
363
364 @Test
365 void testStaticNs0() {
366 runStaticNsContext(Collections.singletonMap("sns", StaticNs.class));
367 }
368
369 @Test
370 void testStaticNs1() {
371 runStaticNsContext(Collections.singletonMap("sns", StaticNs.class.getName()));
372 }
373
374 @Test
375 void testThreadedContext() {
376 final JexlEngine jexl = new JexlBuilder().create();
377 final JexlContext context = new TaxesContext(18.6);
378 final String strs = "taxes:vat(1000)";
379 final JexlScript staxes = jexl.createScript(strs);
380 final Object result = staxes.execute(context);
381 assertEquals(186., result);
382 }
383 }