/** * 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()); } }