/**
* Copyright 2016 Nabarun Mondal
* Licensed 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 com.noga.njexl.lang;
import com.noga.njexl.lang.internal.logging.Log;
import com.noga.njexl.lang.internal.logging.LogFactory;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Test cases for the UnifiedEL.
*/
public class UnifiedJEXLTest extends JexlTestCase {
private static final JexlEngine ENGINE = createEngine(false);
static {
ENGINE.setSilent(false);
ENGINE.setCache(128);
}
private static final UnifiedJEXL EL = new UnifiedJEXL(ENGINE);
private static final Log LOG = LogFactory.getLog(UnifiedJEXL.class);
private JexlContext context = null;
private Map<String, Object> vars = null;
@Override
public void setUp() throws Exception {
// ensure jul logging is only error
java.util.logging.Logger.getLogger(JexlEngine.class.getName()).setLevel(java.util.logging.Level.SEVERE);
vars = new HashMap<String, Object>();
context = new MapContext(vars);
}
@Override
protected void tearDown() throws Exception {
debuggerCheck(ENGINE);
super.tearDown();
}
/** Extract the source from a toString-ed expression. */
private String getSource(String tostring) {
int len = tostring.length();
int sc = tostring.lastIndexOf(" /*= ");
if (sc >= 0) {
sc += " /*= ".length();
}
int ec = tostring.lastIndexOf(" */");
if (sc >= 0 && ec >= 0 && ec > sc && ec < len) {
return tostring.substring(sc, ec);
} else {
return tostring;
}
}
public static class Froboz {
int value;
public Froboz(int v) {
value = v;
}
public void setValue(int v) {
value = v;
}
public int getValue() {
return value;
}
public int plus10() {
int i = value;
value += 10;
return i;
}
}
public UnifiedJEXLTest(String testName) {
super(testName);
}
public void testStatement() throws Exception {
vars.put("froboz", new Froboz(123));
UnifiedJEXL.Expression check = EL.parse("${froboz.value = 32; froboz.plus10(); froboz.value}");
Object o = check.evaluate(context);
assertEquals("Result is not 42", new Integer(42), o);
Set<List<String>> evars = check.getVariables();
assertEquals(2, evars.size());
}
public void testAssign() throws Exception {
UnifiedJEXL.Expression assign = EL.parse("${froboz.value = 10}");
UnifiedJEXL.Expression check = EL.parse("${froboz.value}");
Object o = assign.evaluate(context);
assertEquals("Result is not 10", new Integer(10), o);
o = check.evaluate(context);
assertEquals("Result is not 10", new Integer(10), o);
}
public void testComposite() throws Exception {
String source = "Dear ${p} ${name};";
UnifiedJEXL.Expression expr = EL.parse(source);
vars.put("p", "Mr");
vars.put("name", "Doe");
assertTrue("expression should be immediate", expr.isImmediate());
Object o = expr.evaluate(context);
assertEquals("Dear Mr Doe;", o);
vars.put("p", "Ms");
vars.put("name", "Jones");
o = expr.evaluate(context);
assertEquals("Dear Ms Jones;", o);
assertEquals(source, getSource(expr.toString()));
}
public void testPrepareEvaluate() throws Exception {
final String source = "Dear #{p} ${name};";
UnifiedJEXL.Expression expr = EL.parse("Dear #{p} ${name};");
assertTrue("expression should be deferred", expr.isDeferred());
Set<List<String>> evars = expr.getVariables();
assertEquals(1, evars.size());
assertTrue(evars.contains(Arrays.asList("name")));
vars.put("name", "Doe");
UnifiedJEXL.Expression phase1 = expr.prepare(context);
String as = phase1.asString();
assertEquals("Dear ${p} Doe;", as);
Set<List<String>> evars1 = phase1.getVariables();
assertEquals(1, evars1.size());
assertTrue(evars1.contains(Arrays.asList("p")));
vars.put("p", "Mr");
vars.put("name", "Should not be used in 2nd phase");
Object o = phase1.evaluate(context);
assertEquals("Dear Mr Doe;", o);
String p1 = getSource(phase1.toString());
assertEquals(source, getSource(phase1.toString()));
assertEquals(source, getSource(expr.toString()));
}
public void testNested() throws Exception {
final String source = "#{${hi}+'.world'}";
UnifiedJEXL.Expression expr = EL.parse(source);
Set<List<String>> evars = expr.getVariables();
assertEquals(1, evars.size());
assertTrue(evars.contains(Arrays.asList("hi")));
vars.put("hi", "greeting");
vars.put("greeting.world", "Hello World!");
assertTrue("expression should be deferred", expr.isDeferred());
Object o = expr.evaluate(context);
assertEquals("Hello World!", o);
assertEquals(source, getSource(expr.toString()));
}
public void testImmediate() throws Exception {
JexlContext none = null;
final String source = "${'Hello ' + 'World!'}";
UnifiedJEXL.Expression expr = EL.parse(source);
UnifiedJEXL.Expression prepared = expr.prepare(none);
assertEquals("prepare should return same expression", "Hello World!", prepared.asString());
Object o = expr.evaluate(none);
assertTrue("expression should be immediate", expr.isImmediate());
assertEquals("Hello World!", o);
assertEquals(source, getSource(expr.toString()));
}
public void testConstant() throws Exception {
JexlContext none = null;
final String source = "Hello World!";
UnifiedJEXL.Expression expr = EL.parse(source);
assertTrue("prepare should return same expression", expr.prepare(none) == expr);
Object o = expr.evaluate(none);
assertTrue("expression should be immediate", expr.isImmediate());
assertEquals("Hello World!", o);
assertEquals(source, getSource(expr.toString()));
}
public void testDeferred() throws Exception {
JexlContext none = null;
final String source = "#{'world'}";
UnifiedJEXL.Expression expr = EL.parse(source);
assertTrue("expression should be deferred", expr.isDeferred());
String as = expr.prepare(none).asString();
assertEquals("prepare should return immediate version", "${'world'}", as);
Object o = expr.evaluate(none);
assertEquals("world", o);
assertEquals(source, getSource(expr.toString()));
}
public void testEscape() throws Exception {
JexlContext none = null;
UnifiedJEXL.Expression expr;
Object o;
// $ and # are escapable in UnifiedJEXL
expr = EL.parse("\\#{'world'}");
o = expr.evaluate(none);
assertEquals("#{'world'}", o);
expr = EL.parse("\\${'world'}");
o = expr.evaluate(none);
assertEquals("${'world'}", o);
}
public void testEscapeString() throws Exception {
UnifiedJEXL.Expression expr = EL.parse("\\\"${'world\\'s finest'}\\\"");
JexlContext none = null;
Object o = expr.evaluate(none);
assertEquals("\"world's finest\"", o);
}
public void testNonEscapeString() throws Exception {
UnifiedJEXL.Expression expr = EL.parse("c:\\some\\windows\\path");
JexlContext none = null;
Object o = expr.evaluate(none);
assertEquals("c:\\some\\windows\\path", o);
}
public void testMalformed() throws Exception {
try {
UnifiedJEXL.Expression expr = EL.parse("${'world'");
JexlContext none = null;
expr.evaluate(none);
fail("should be malformed");
} catch (UnifiedJEXL.Exception xjexl) {
// expected
String xmsg = xjexl.getMessage();
LOG.warn(xmsg);
}
}
public void testMalformedNested() throws Exception {
try {
UnifiedJEXL.Expression expr = EL.parse("#{${hi} world}");
JexlContext none = null;
expr.evaluate(none);
fail("should be malformed");
} catch (UnifiedJEXL.Exception xjexl) {
// expected
String xmsg = xjexl.getMessage();
LOG.warn(xmsg);
}
}
public void testBadContextNested() throws Exception {
try {
UnifiedJEXL.Expression expr = EL.parse("#{${hi}+'.world'}");
JexlContext none = null;
expr.evaluate(none);
fail("should be malformed");
} catch (UnifiedJEXL.Exception xjexl) {
// expected
String xmsg = xjexl.getMessage();
LOG.warn(xmsg);
}
}
public void testCharAtBug() throws Exception {
vars.put("foo", "abcdef");
UnifiedJEXL.Expression expr = EL.parse("${foo.substring(2,4)/*comment*/}");
Object o = expr.evaluate(context);
assertEquals("cd", o);
vars.put("bar", "foo");
try {
ENGINE.setSilent(true);
expr = EL.parse("#{${bar}+'.charAt(-2)'}");
expr = expr.prepare(context);
o = expr.evaluate(context);
assertEquals(null, o);
} finally {
ENGINE.setSilent(false);
}
}
public void testTemplate0() throws Exception {
String source = " $$ if(x) {\nx is ${x}\n $$ } else {\n${'no x'}\n$$ }\n";
StringWriter strw;
String output;
UnifiedJEXL.Template t = EL.createTemplate(source);
vars.put("x", 42);
strw = new StringWriter();
t.evaluate(context, strw);
output = strw.toString();
assertEquals("x is 42\n", output);
strw = new StringWriter();
vars.put("x", "");
t.evaluate(context, strw);
output = strw.toString();
assertEquals("no x\n", output);
String dstr = t.toString();
assertNotNull(dstr);
}
public void testTemplate1() throws Exception {
String source = "$$ if(x) {\nx is ${x}\n$$ } else {\n${'no x'}\n$$ }\n";
StringWriter strw;
String output;
UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader(source), "x");
String dstr = t.asString();
assertNotNull(dstr);
strw = new StringWriter();
t.evaluate(context, strw, 42);
output = strw.toString();
assertEquals("x is 42\n", output);
strw = new StringWriter();
t.evaluate(context, strw, "");
output = strw.toString();
assertEquals("no x\n", output);
}
public void testPrepareTemplate() throws Exception {
String source =
"$$ for(var x : list) {\n"
+ "${l10n}=#{x}\n"
+ "$$ }\n";
int[] args = { 42 };
UnifiedJEXL.Template tl10n = EL.createTemplate(source, "list");
String dstr = tl10n.asString();
assertNotNull(dstr);
context.set("l10n", "valeur");
UnifiedJEXL.Template tpFR = tl10n.prepare(context);
context.set("l10n", "value");
UnifiedJEXL.Template tpEN = tl10n.prepare(context);
context.set("l10n", null);
StringWriter strw;
strw = new StringWriter();
tpFR.evaluate(context, strw, args);
String outFR = strw.toString();
assertEquals("valeur=42\n", outFR);
context.set("l10n", null);
strw = new StringWriter();
tpEN.evaluate(context, strw, args);
String outEN = strw.toString();
assertEquals("value=42\n", outEN);
}
public void test42() throws Exception {
String test42 =
"$$ for(var x : list) {\n"
+ "$$ if (x == 42) {\n"
+ "Life, the universe, and everything\n"
+ "$$ } else if (x > 42) {\n"
+ "The value ${x} is over fourty-two\n"
+ "$$ } else {\n"
+ "The value ${x} is under fourty-two\n"
+ "$$ }\n"
+ "$$ }\n";
UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader(test42), "list");
StringWriter strw = new StringWriter();
int[] list = {1, 3, 5, 42, 169};
t.evaluate(context, strw, list);
String output = strw.toString();
String out42 =
"The value 1 is under fourty-two\n"
+ "The value 3 is under fourty-two\n"
+ "The value 5 is under fourty-two\n"
+ "Life, the universe, and everything\n"
+ "The value 169 is over fourty-two\n";
assertEquals(out42, output);
String dstr = t.asString();
assertNotNull(dstr);
}
public static class FrobozWriter extends PrintWriter {
public FrobozWriter(Writer w) {
super(w);
}
public void print(Froboz froboz) {
super.print("froboz{");
super.print(froboz.value);
super.print("}");
}
@Override
public String toString() {
return out.toString();
}
}
public void testWriter() throws Exception {
Froboz froboz = new Froboz(42);
Writer writer = new FrobozWriter(new StringWriter());
UnifiedJEXL.Template t = EL.createTemplate("$$", new StringReader("$$$jexl.print(froboz)"), "froboz");
t.evaluate(context, writer, froboz);
assertEquals("froboz{42}", writer.toString());
}
}