blob: 95ba9068e97e63cd902c0be636822b6a58773a46 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jexl3;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests for pragmas
*/
public class PragmaTest extends JexlTestCase {
public static class CachingModuleContext extends ModuleContext implements JexlContext.ModuleProcessor {
private final ConcurrentMap<String, Object> modules = new ConcurrentHashMap<>();
private final AtomicInteger count = new AtomicInteger(0);
CachingModuleContext() {
}
public int getCountCompute() {
return count.get();
}
@Override
public Object processModule(final JexlEngine engine, final JexlInfo info, final String name, final String body) {
if (body.isEmpty()) {
modules.remove(name);
return null;
}
return modules.computeIfAbsent(name, n -> {
Object module = engine.createExpression(info, body).evaluate(this);
if (module instanceof JexlScript) {
module = ((JexlScript) module).execute(this);
}
count.incrementAndGet();
return module;
});
}
}
public static class ModuleContext extends MapContext {
protected final Map<String, JexlScript> sources = new TreeMap<>();
ModuleContext() { }
public Object script(final String name) {
return sources.get(name);
}
void script(final String name, final JexlScript script) { sources.put(name, script); }
}
public static class SafeContext extends JexlEvalContext {
// @Override
public void processPragmas(final Map<String, Object> pragmas) {
if (pragmas != null && !pragmas.isEmpty()) {
final JexlOptions options = getEngineOptions();
for (final Map.Entry<String, Object> pragma : pragmas.entrySet()) {
final String key = pragma.getKey();
final Object value = pragma.getValue();
if ("jexl.safe".equals(key) && value instanceof Boolean) {
options.setSafe((Boolean) value);
} else if ("jexl.strict".equals(key) && value instanceof Boolean) {
options.setStrict((Boolean) value);
} else if ("jexl.silent".equals(key) && value instanceof Boolean) {
options.setSilent((Boolean) value);
}
}
}
}
/**
* Sleeps, called through scripts.
* @param ms time to sleep in ms
*/
public void sleep(final long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException e) {
// ignore
}
}
}
public static class Sleeper {
public void sleep(final long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException e) {
// ignore
}
}
}
public static class StaticSleeper {
public static void sleep(final long ms) {
try {
Thread.sleep(ms);
} catch (final InterruptedException e) {
// ignore
}
}
// precludes instantiation
private StaticSleeper() {}
}
/**
* Create a new test case.
*/
public PragmaTest() {
super("PragmaTest");
}
void runPragmaModule(final ModuleContext ctxt, final CachingModuleContext cmCtxt) {
ctxt.script("module0", JEXL.createScript("function f42(x) { 42 + x; } function f43(x) { 43 + x; }; { 'f42' : f42, 'f43' : f43 }"));
final ConcurrentMap<String, Object> modules = new ConcurrentHashMap<>();
JexlScript script ;
Object result ;
script = JEXL.createScript("#pragma jexl.module.m0 \"script('module0')\"\n m0:f42(10);");
result = script.execute(ctxt);
Assert.assertEquals(52, result);
if (cmCtxt != null) {
Assert.assertEquals(1, cmCtxt.getCountCompute());
}
result = script.execute(ctxt);
Assert.assertEquals(52, result);
if (cmCtxt != null) {
Assert.assertEquals(1, cmCtxt.getCountCompute());
}
script = JEXL.createScript("#pragma jexl.module.m0 \"script('module0')\"\n m0:f43(10);");
result = script.execute(ctxt);
Assert.assertEquals(53, result);
if (cmCtxt != null) {
Assert.assertEquals(1, cmCtxt.getCountCompute());
}
try {
script = JEXL.createScript("#pragma jexl.module.m0 ''\n#pragma jexl.module.m0 \"fubar('module0')\"\n m0:f43(10);");
result = script.execute(ctxt);
Assert.fail("fubar sshoud fail");
} catch (final JexlException.Method xmethod) {
Assert.assertEquals("fubar", xmethod.getMethod());
}
}
@Test public void test354() {
final Map<String, Number> values = new TreeMap<>();
values.put("1", 1);
values.put("+1", 1);
values.put("-1", -1);
values.put("1l", 1L);
values.put("+1l", 1L);
values.put("-1l", -1L);
values.put("10h", BigInteger.valueOf(10));
values.put("-11h", BigInteger.valueOf(-11));
values.put("+12h", BigInteger.valueOf(12));
values.put("0xa", 0xa);
values.put("+0xa", 0xa);
values.put("-0xa", -0xa);
values.put("0xacl", 0xacL);
values.put("+0xadl", 0xadL);
values.put("-0xafl", -0xafL);
values.put("1d", 1d);
values.put("-1d", -1d);
values.put("+1d", 1d);
values.put("1f", 1f);
values.put("-1f", -1f);
values.put("+1f", 1f);
values.put("1B", new BigDecimal(1));
values.put("-1B", new BigDecimal(-1));
values.put("+1B", new BigDecimal(1));
values.put("-42424242424242424242424242424242", new BigInteger("-42424242424242424242424242424242"));
values.put("+42424242424242424242424242424242", new BigInteger("+42424242424242424242424242424242"));
values.put("42424242424242424242424242424242", new BigInteger("42424242424242424242424242424242"));
final JexlEngine jexl = new JexlBuilder().safe(true).create();
for(final Map.Entry<String, Number> e : values.entrySet()) {
final String text = "#pragma number " + e.getKey();
final JexlScript script = jexl.createScript(text);
Assert.assertNotNull(script);
final Map<String, Object> pragmas = script.getPragmas();
Assert.assertNotNull(pragmas);
Assert.assertEquals(e.getKey(), e.getValue(), pragmas.get("number"));
}
}
@Test
public void testImportPragmaDisabled() {
final String src =
"#pragma jexl.import java.util\n"+
"#pragma jexl.import java.io\n"+
"#pragma jexl.import java.net\n"+
"42";
final JexlFeatures features = new JexlFeatures();
features.importPragma(false);
final JexlEngine jexl = new JexlBuilder().features(features).create();
try {
final JexlScript script = jexl.createScript(src);
} catch (JexlException.Parsing xparse) {
Assert.assertTrue(xparse.getMessage().contains("import pragma"));
}
}
@Test
public void testImportPragmaValueSet() {
final String src =
"#pragma jexl.import java.util\n"+
"#pragma jexl.import java.io\n"+
"#pragma jexl.import java.net\n"+
"42";
final JexlScript script = JEXL.createScript(src);
final Map<String, Object> pragmas = script.getPragmas();
final Object importz = pragmas.get("jexl.import");
Assert.assertTrue(importz instanceof Set<?>);
final Set<String> importzz = (Set<String>) importz;
Assert.assertTrue(importzz.contains("java.util"));
Assert.assertTrue(importzz.contains("java.io"));
Assert.assertTrue(importzz.contains("java.net"));
Assert.assertEquals(3, importzz.size());
final String parsed = script.getParsedText();
Assert.assertEquals(src, parsed);
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testJxltPragmas() {
final JxltEngine engine = new JexlBuilder().create().createJxltEngine();
final JxltEngine.Template tscript = engine.createTemplate("$$ #pragma one 1\n$$ #pragma the.very.hard 'truth'\n2;");
Assert.assertNotNull(tscript);
final Map<String, Object> pragmas = tscript.getPragmas();
Assert.assertEquals(2, pragmas.size());
Assert.assertEquals(1, pragmas.get("one"));
Assert.assertEquals("truth", pragmas.get("the.very.hard"));
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testNamespacePragma() {
final JexlContext jc = new SafeContext();
final String src =
"#pragma jexl.namespace.sleeper " + Sleeper.class.getName() + "\n"
+ "sleeper:sleep(100);\n"
+ "42;\n";
final JexlScript script = JEXL.createScript(src);
final Object result = script.execute(jc);
Assert.assertEquals(42, result);
final String parsed = script.getParsedText();
Assert.assertEquals(src, parsed);
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testNamespacePragmaCtl() {
final Map<String, Object> ns = Collections.singletonMap("sleeper", Sleeper.class.getName());
final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
final JexlContext jc = new SafeContext();
final JexlScript script = jexl.createScript(
"sleeper:sleep(100);"
+ "42");
final Object result = script.execute(jc);
Assert.assertEquals(42, result);
}
@Test
public void testNamespacePragmaDisabled() {
final JexlFeatures features = new JexlFeatures();
features.namespacePragma(false);
final JexlEngine jexl = new JexlBuilder().features(features).create();
try {
final JexlScript src = jexl.createScript(
"#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
+ "sleeper:sleep(100);"
+ "42");
Assert.fail("should have thrown syntax exception");
} catch (JexlException.Parsing xparse) {
Assert.assertTrue(xparse.getMessage().contains("namespace pragma"));
}
}
@Test public void testPragmaModuleCache() {
final CachingModuleContext ctxt = new CachingModuleContext();
runPragmaModule(ctxt, ctxt);
}
@Test public void testPragmaModuleNoCache() {
final ModuleContext ctxt = new ModuleContext();
runPragmaModule(ctxt, null);
}
@Test
public void testPragmaOptions1() {
final String str = "i; #pragma jexl.options '-strict'\n";
final JexlEngine jexl = new JexlBuilder()
.features(new JexlFeatures().pragmaAnywhere(false))
.strict(true).create();
final JexlContext ctxt = new MapContext();
try {
final JexlScript e = jexl.createScript(str);
Assert.fail("i should not be resolved");
} catch (final JexlException xany) {
Assert.assertNotNull(xany);
}
}
/**
* Test creating a script from a string.
*/
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testPragmas() {
final JexlScript script = JEXL.createScript("#pragma one 1\n#pragma the.very.hard 'truth'\n2;");
Assert.assertNotNull(script);
final Map<String, Object> pragmas = script.getPragmas();
Assert.assertEquals(2, pragmas.size());
Assert.assertEquals(1, pragmas.get("one"));
Assert.assertEquals("truth", pragmas.get("the.very.hard"));
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testSafePragma() {
SafeContext jc = new SafeContext();
jc.set("foo", null);
final JexlScript script = JEXL.createScript("#pragma jexl.safe true\nfoo.bar;");
Assert.assertNotNull(script);
jc.processPragmas(script.getPragmas());
final Object result = script.execute(jc);
Assert.assertNull(result);
jc = new SafeContext();
jc.set("foo", null);
try {
script.execute(jc);
Assert.fail("should have thrown");
} catch (final JexlException xvar) {
// ok, expected
}
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testStaticNamespacePragma() {
final JexlContext jc = new SafeContext();
final JexlScript script = JEXL.createScript(
"#pragma jexl.namespace.sleeper " + StaticSleeper.class.getName() + "\n"
+ "sleeper:sleep(100);"
+ "42");
final Object result = script.execute(jc);
Assert.assertEquals(42, result);
}
@Test
@SuppressWarnings("AssertEqualsBetweenInconvertibleTypes")
public void testStatictNamespacePragmaCtl() {
final Map<String, Object> ns = Collections.singletonMap("sleeper", StaticSleeper.class.getName());
final JexlEngine jexl = new JexlBuilder().namespaces(ns).create();
final JexlContext jc = new SafeContext();
final JexlScript script = jexl.createScript(
"sleeper:sleep(100);"
+ "42");
final Object result = script.execute(jc);
Assert.assertEquals(42, result);
}
@Test
public void testIssue416() {
final JexlEngine jexl = new JexlBuilder().create();
JexlScript script = jexl.createScript("#pragma myNull null\n");
Map<String, Object> pragmas = script.getPragmas();
Assert.assertTrue("pragma key present?", pragmas.containsKey("myNull"));
Assert.assertNull("expected null value", pragmas.get("myNull"));
}
}