| /* |
| * 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.scxml2.env.javascript; |
| |
| import java.io.StringReader; |
| import java.util.Map; |
| |
| import org.apache.commons.scxml2.Context; |
| import org.apache.commons.scxml2.Evaluator; |
| import org.apache.commons.scxml2.SCXMLExecutor; |
| import org.apache.commons.scxml2.SCXMLExpressionException; |
| import org.apache.commons.scxml2.SCXMLTestHelper; |
| import org.apache.commons.scxml2.io.SCXMLReader; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| /** JUnit 3 test case for the JSEvaluator expression evaluator |
| * class. Includes basic tests for: |
| * <ul> |
| * <li> constructor |
| * <li> simple standard Javascript expressions |
| * <li> Javascript expressions referencing SCXML <var..> variables. |
| * <li> Javascript expressions referencing SCXML data model elements. |
| * <li> Javascript expressions referencing SCXML data model locations. |
| * <li> Javascript functions referencing SCXML context variables. |
| * </ul> |
| */ |
| |
| public class JSEvaluatorTest { |
| // TEST CONSTANTS |
| |
| private static final String BAD_EXPRESSION = ">"; |
| private static final String SCRIPT = "<?xml version='1.0'?>" + |
| "<scxml xmlns = 'http://www.w3.org/2005/07/scxml'" + |
| " xmlns:scxml = 'http://commons.apache.org/scxml'" + |
| " datamodel = 'ecmascript'" + |
| " initial = 'start'" + |
| " version = '1.0'>" + |
| " <datamodel>" + |
| " <data id='forest'>" + |
| " { \"tree\" :" + |
| " { \"branch\" :" + |
| " { \"twig\" : \"leaf\" }" + |
| " }" + |
| " }" + |
| " </data>" + |
| " </datamodel>" + |
| " <state id='start'>" + |
| " <transition target='end'/>" + |
| " </state>" + |
| " <state id='end' final='true'/>" + |
| "</scxml>"; |
| |
| private static final TestItem[] SIMPLE_EXPRESSIONS = { |
| new TestItem("'FIB: ' + (1 + 1 + 2 + 3 + 5)",new String("FIB: 12")), |
| new TestItem("1 + 1 + 2 + 3 + 5", new Integer(12)), // Force comparison using intValue |
| new TestItem("1.1 + 1.1 + 2.1 + 3.1 + 5.1", new Double(12.5)), |
| new TestItem("(1 + 1 + 2 + 3 + 5) == 12", new Boolean(true)), |
| new TestItem("(1 + 1 + 2 + 3 + 5) == 13", new Boolean(false)), |
| }; |
| |
| private static final TestItem[] VAR_EXPRESSIONS = { |
| new TestItem("'FIB: ' + fibonacci",new String("FIB: 12")), |
| new TestItem("fibonacci * 2", new Double(24)), |
| }; |
| |
| private static final String FUNCTION = "function factorial(N) {\r\n" + |
| "if (N == 1)\r\n" + |
| " return N;\r\n" + |
| "\r\n" + |
| "return N * factorial(N-1);\r\n" + |
| "};\r\n" + |
| "\r\n" + |
| "function fact5() {\r\n" + |
| " return factorial(FIVE);\r\n" + |
| "};\r\n" + |
| "\r\n" + |
| "fact5()"; |
| |
| // TEST VARIABLES |
| |
| private Context context; |
| private Evaluator evaluator; |
| private SCXMLExecutor fsm; |
| |
| // TEST SETUP |
| |
| /** |
| * Creates and initialises an SCXML data model in the context. |
| * |
| */ |
| @Before |
| public void setUp() throws Exception { |
| fsm = SCXMLTestHelper.getExecutor(SCXMLReader.read(new StringReader(SCRIPT))); |
| evaluator = fsm.getEvaluator(); |
| context = fsm.getGlobalContext(); |
| context.set(Context.NAMESPACES_KEY,null); |
| } |
| |
| // CLASS METHODS |
| |
| /** |
| * Standalone test runtime. |
| * |
| */ |
| public static void main(String args[]) { |
| String[] testCaseName = {JSEvaluatorTest.class.getName()}; |
| |
| junit.textui.TestRunner.main(testCaseName); |
| } |
| |
| // INSTANCE METHOD TESTS |
| |
| /** |
| * Ensures implementation of JSEvaluator default constructor and test basic |
| * expression evaluation. |
| * |
| */ |
| @Test |
| public void testBasic() throws SCXMLExpressionException { |
| Evaluator evaluator = new JSEvaluator(); |
| |
| Assert.assertNotNull(evaluator); |
| Assert.assertTrue (((Boolean) evaluator.eval(context, "1+1 == 2")).booleanValue()); |
| } |
| |
| @Test |
| public void testScript() throws SCXMLExpressionException { |
| Evaluator evaluator = new JSEvaluator(); |
| context.set("x", 3); |
| context.set("y", 0); |
| String script = |
| "if ((x * 2.0) == 5.0) {" + |
| "y = 1.0;\n" + |
| "} else {\n" + |
| "y = 2.0;\n" + |
| "}"; |
| Assert.assertEquals(2.0, evaluator.evalScript(context, script)); |
| Assert.assertEquals(2.0, context.get("y")); |
| } |
| |
| /** |
| * Tests handling of illegal expressions. |
| * |
| */ |
| @Test |
| public void testIllegalExpresssion() { |
| Evaluator evaluator = new JSEvaluator(); |
| |
| Assert.assertNotNull(evaluator); |
| |
| try { |
| evaluator.eval(context,BAD_EXPRESSION); |
| Assert.fail ("JSEvaluator should throw SCXMLExpressionException"); |
| |
| } catch (SCXMLExpressionException x) { |
| Assert.assertTrue("JSEvaluator: Incorrect error message", |
| x.getMessage().startsWith("Error evaluating ['" + BAD_EXPRESSION + "']")); |
| } |
| } |
| |
| /** |
| * Tests evaluation with simple standard expressions. |
| * |
| */ |
| @Test |
| public void testStandardExpressions() throws Exception { |
| for (TestItem item: SIMPLE_EXPRESSIONS) { |
| Object eval = evaluator.eval(context,item.expression); |
| if (item.result instanceof Integer && eval instanceof Number) { |
| Assert.assertEquals("Invalid result: " + item.expression, |
| ((Integer) item.result).intValue(), |
| ((Number) eval).intValue()); |
| } else { |
| Assert.assertEquals("Invalid result: " + item.expression, |
| item.result, |
| eval); |
| } |
| } |
| } |
| |
| /** |
| * Tests evaluation with SCXML context variables. |
| * |
| */ |
| @Test |
| public void testVarExpressions() throws Exception { |
| context.set("fibonacci",Integer.valueOf(12)); |
| |
| for (TestItem item: VAR_EXPRESSIONS) { |
| Assert.assertNotNull(context.get("fibonacci")); |
| Assert.assertEquals (Integer.valueOf(12),context.get("fibonacci")); |
| Assert.assertEquals ("Invalid result: " + item.expression, |
| item.result, |
| evaluator.eval(context,item.expression)); |
| } |
| } |
| |
| /** |
| * Tests evaluation with invalid SCXML context variables. |
| * |
| */ |
| @Test |
| public void testInvalidVarExpressions() { |
| for (TestItem item: VAR_EXPRESSIONS) { |
| try { |
| Assert.assertNull (context.get("fibonacci")); |
| evaluator.eval(context,item.expression); |
| Assert.fail ("Evaluated invalid <var... expression: " + item.expression); |
| |
| } catch (SCXMLExpressionException x) { |
| // expected, ignore |
| } |
| } |
| } |
| |
| /** |
| * Tests evaluation with SCXML data model expressions. |
| * |
| */ |
| @Test |
| public void testDataModelExpressions() throws Exception { |
| Assert.assertEquals("Invalid result: " + "forest.tree.branch.twig", |
| "leaf", |
| evaluator.eval(context,"forest.tree.branch.twig")); |
| } |
| |
| /** |
| * Tests evaluation with invalid SCXML data model expressions. |
| * |
| */ |
| @Test |
| public void testInvalidDataModelExpressions() { |
| Assert.assertNull(context.get("forestx")); |
| |
| try { |
| evaluator.eval(context,"forestx.tree.branch.twig"); |
| Assert.fail ("Evaluated invalid DataModel expression: " + "forestx.tree.branch.twig"); |
| |
| } catch (SCXMLExpressionException x) { |
| // expected, ignore |
| } |
| } |
| |
| /** |
| * Tests evaluation of SCXML data model locations. |
| * |
| */ |
| @Test |
| public void testDataModelLocations() throws Exception { |
| Assert.assertTrue("Invalid result: forest instanceof Map", |
| evaluator.eval(context, "forest") instanceof Map); |
| |
| Assert.assertTrue("Invalid result: forest.tree.branch.twig instanceof String", |
| evaluator.eval(context, "forest.tree.branch.twig") instanceof String); |
| } |
| |
| /** |
| * Tests evaluation of invalid SCXML data model locations. |
| * |
| */ |
| @Test |
| public void testInvalidDataModelLocations() throws Exception { |
| Assert.assertNotNull(context.get("forest")); |
| Assert.assertNull("Invalid result: " + "forest.tree.branch.twigx", |
| evaluator.eval(context,"forest.tree.branch.twigx")); |
| } |
| |
| /** |
| * Tests evaluation of Javascript functions with variables from SCXML context. |
| * |
| */ |
| @Test |
| public void testScriptFunctions() throws Exception { |
| context.set("FIVE",Integer.valueOf(5)); |
| Assert.assertEquals(Integer.valueOf(5),context.get("FIVE")); |
| Assert.assertEquals("Invalid function result",Double.valueOf(120.0),evaluator.eval(context,FUNCTION)); |
| } |
| |
| |
| // INNER CLASSES |
| |
| private static class TestItem { |
| private String expression; |
| private Object result; |
| |
| private TestItem(String expression,Object result) { |
| this.expression = expression; |
| this.result = result; |
| } |
| } |
| |
| } |
| |