001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2.io; 018 019import java.io.StringReader; 020 021import org.apache.commons.scxml2.SCXMLExecutor; 022import org.apache.commons.scxml2.SCXMLTestHelper; 023import org.apache.commons.scxml2.model.ModelException; 024import org.apache.commons.scxml2.model.SCXML; 025import org.junit.Test; 026 027import static org.junit.Assert.assertEquals; 028import static org.junit.Assert.assertTrue; 029import static org.junit.Assert.fail; 030 031/** 032 * Test enforcement of required SCXML element attributes, spec http://www.w3.org/TR/2013/WD-scxml-20130801 033 * <p> 034 * TODO required attributes for elements: 035 * <ul> 036 * <li><raise> required attribute: 'id'</li> 037 * </ul> 038 * </p> 039 */ 040public class SCXMLRequiredAttributesTest { 041 042 private static final String VALID_SCXML = 043 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" datamodel=\"jexl\" version=\"1.0\">\n" + 044 " <state id=\"s1\">\n" + 045 " <transition target=\"fine\">\n" + 046 " <if cond=\"true\"><log expr=\"'hello'\"/></if>\n" + 047 " </transition>\n" + 048 " </state>\n" + 049 " <final id=\"fine\"/>\n" + 050 "</scxml>"; 051 052 private static final String SCXML_WITH_MISSING_VERSION = 053 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\">\n" + 054 " <final id=\"fine\"/>\n" + 055 "</scxml>"; 056 057 private static final String SCXML_WITH_INVALID_VERSION = 058 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"2.0\">\n" + 059 " <final id=\"fine\"/>\n" + 060 "</scxml>"; 061 062 private static final String SCXML_WITH_MISSING_IF_COND = 063 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 064 " <state id=\"s1\">\n" + 065 " <transition target=\"fine\">\n" + 066 " <if><log expr=\"'hello'\"/></if>\n" + 067 " </transition>\n" + 068 " </state>\n" + 069 " <final id=\"fine\"/>\n" + 070 "</scxml>"; 071 072 private static final String SCXML_WITH_MISSING_ELSEIF_COND = 073 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 074 " <state id=\"s1\">\n" + 075 " <transition target=\"fine\">\n" + 076 " <if cond=\"false\"><elseif/><log expr=\"'hello'\"/></if>\n" + 077 " </transition>\n" + 078 " </state>\n" + 079 " <final id=\"fine\"/>\n" + 080 "</scxml>"; 081 082 private static final String SCXML_WITH_MISSING_DATA_ID = 083 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 084 " <datamodel><data></data></datamodel>\n" + 085 " <final id=\"fine\"/>\n" + 086 "</scxml>"; 087 088 private static final String SCXML_WITH_MISSING_ASSIGN_LOCATION = 089 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 090 " <state id=\"s1\">\n" + 091 " <transition target=\"fine\">\n" + 092 " <assign expr=\"1\"/>\n" + 093 " </transition>\n" + 094 " </state>\n" + 095 " <final id=\"fine\"/>\n" + 096 "</scxml>"; 097 098 private static final String SCXML_WITH_MISSING_PARAM_NAME = 099 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 100 " <state id=\"s1\">\n" + 101 " <invoke type=\"scxml\" src=\"foo\">\n" + // Note: invalid src, but not executed during test 102 " <param expr=\"1\"/>\n" + 103 " </invoke>\n" + 104 " </state>\n" + 105 " <final id=\"fine\"/>\n" + 106 "</scxml>"; 107 108 private static final String SCXML_WITH_PARAM_AND_NAME = 109 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 110 " <state id=\"s1\">\n" + 111 " <invoke type=\"scxml\" src=\"foo\">\n" + // Note: invalid src, but not executed during test 112 " <param name=\"bar\" expr=\"1\"/>\n" + 113 " </invoke>\n" + 114 " </state>\n" + 115 " <final id=\"fine\"/>\n" + 116 "</scxml>"; 117 118 private static final String SCXML_WITH_MISSING_FOREACH_ARRAY = 119 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 120 " <state id=\"s1\">\n" + 121 " <transition target=\"fine\">\n" + 122 " <foreach item=\"y\"></foreach>\n" + 123 " </transition>\n" + 124 " </state>\n" + 125 " <final id=\"fine\"/>\n" + 126 "</scxml>"; 127 128 private static final String SCXML_WITH_MISSING_FOREACH_ITEM = 129 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" version=\"1.0\">\n" + 130 " <state id=\"s1\">\n" + 131 " <transition target=\"fine\">\n" + 132 " <foreach array=\"[1,2]\"></foreach>\n" + 133 " </transition>\n" + 134 " </state>\n" + 135 " <final id=\"fine\"/>\n" + 136 "</scxml>"; 137 138 private static final String SCXML_WITH_FOREACH = 139 "<scxml xmlns=\"http://www.w3.org/2005/07/scxml\" datamodel=\"jexl\" version=\"1.0\">\n" + 140 " <state id=\"s1\">\n" + 141 " <transition target=\"fine\">\n" + 142 " <foreach array=\"[1,2]\" item=\"x\"></foreach>\n" + 143 " </transition>\n" + 144 " </state>\n" + 145 " <final id=\"fine\"/>\n" + 146 "</scxml>"; 147 148 @Test 149 public void testValidSCXML() throws Exception { 150 SCXML scxml = SCXMLTestHelper.parse(new StringReader(VALID_SCXML), null); 151 SCXMLExecutor exec = SCXMLTestHelper.getExecutor(scxml); 152 exec.go(); 153 assertTrue(exec.getStatus().isFinal()); 154 } 155 156 @Test 157 public void testSCXMLMissingVersion() throws Exception { 158 try { 159 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_VERSION), null); 160 fail("SCXML reading should have failed due to missing version in SCXML"); 161 } 162 catch (ModelException e) { 163 assertTrue(e.getMessage().startsWith("<scxml> is missing required attribute \"version\" value")); 164 } 165 } 166 167 @Test 168 public void testSCXMLInvalidVersion() throws Exception { 169 try { 170 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_INVALID_VERSION), null); 171 fail("SCXML reading should have failed due to missing version in SCXML"); 172 } 173 catch (ModelException e) { 174 assertEquals("The <scxml> element defines an unsupported version \"2.0\", only version \"1.0\" is supported.", e.getMessage()); 175 } 176 } 177 178 @Test 179 public void testSCXMLMissingIfCond() throws Exception { 180 try { 181 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_IF_COND), null); 182 fail("SCXML reading should have failed due to missing if condition in SCXML"); 183 } 184 catch (ModelException e) { 185 assertTrue(e.getMessage().startsWith("<if> is missing required attribute \"cond\" value")); 186 } 187 } 188 189 @Test 190 public void testSCXMLMissingElseIfCond() throws Exception { 191 try { 192 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_ELSEIF_COND), null); 193 fail("SCXML reading should have failed due to missing elseif condition in SCXML"); 194 } 195 catch (ModelException e) { 196 assertTrue(e.getMessage().startsWith("<elseif> is missing required attribute \"cond\" value")); 197 } 198 } 199 200 @Test 201 public void testSCXMLMissingDataId() throws Exception { 202 try { 203 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_DATA_ID), null); 204 fail("SCXML reading should have failed due to missing data id in SCXML"); 205 } 206 catch (ModelException e) { 207 assertTrue(e.getMessage().startsWith("<data> is missing required attribute \"id\" value")); 208 } 209 } 210 211 @Test 212 public void testSCXMLMissingAssignLocation() throws Exception { 213 try { 214 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_ASSIGN_LOCATION), null); 215 fail("SCXML reading should have failed due to missing assign location in SCXML"); 216 } 217 catch (ModelException e) { 218 assertTrue(e.getMessage().startsWith("<assign> is missing required attribute \"location\" value")); 219 } 220 } 221 222 @Test 223 public void testSCXMLMissingParamName() throws Exception { 224 try { 225 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_PARAM_NAME), null); 226 fail("SCXML reading should have failed due to missing param name in SCXML"); 227 } 228 catch (ModelException e) { 229 assertTrue(e.getMessage().startsWith("<param> is missing required attribute \"name\" value")); 230 } 231 } 232 233 @Test 234 public void testSCXMLParamWithName() throws Exception { 235 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_PARAM_AND_NAME), null); 236 // Note: cannot execute this instance without providing proper <invoke> src attribute 237 } 238 239 @Test 240 public void testSCXMLMissingForeachArray() throws Exception { 241 try { 242 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_FOREACH_ARRAY), null); 243 fail("SCXML reading should have failed due to missing foreach array in SCXML"); 244 } 245 catch (ModelException e) { 246 assertTrue(e.getMessage().startsWith("<foreach> is missing required attribute \"array\" value")); 247 } 248 } 249 250 @Test 251 public void testSCXMLMissingForeachItem() throws Exception { 252 try { 253 SCXMLTestHelper.parse(new StringReader(SCXML_WITH_MISSING_FOREACH_ITEM), null); 254 fail("SCXML reading should have failed due to missing foreach item in SCXML"); 255 } 256 catch (ModelException e) { 257 assertTrue(e.getMessage().startsWith("<foreach> is missing required attribute \"item\" value")); 258 } 259 } 260 261 @Test 262 public void testSCXMLWithForEach() throws Exception { 263 SCXML scxml = SCXMLTestHelper.parse(new StringReader(SCXML_WITH_FOREACH), null); 264 SCXMLExecutor exec = SCXMLTestHelper.getExecutor(scxml); 265 exec.go(); 266 assertTrue(exec.getStatus().isFinal()); 267 } 268}