001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.junit.script; 016 017 import static org.easymock.EasyMock.expect; 018 019 import java.util.Arrays; 020 import java.util.Collections; 021 import java.util.HashMap; 022 import java.util.Map; 023 024 import org.apache.hivemind.ClassResolver; 025 import org.apache.hivemind.Resource; 026 import org.apache.hivemind.impl.DefaultClassResolver; 027 import org.apache.hivemind.util.ClasspathResource; 028 import org.apache.tapestry.IRequestCycle; 029 import org.apache.tapestry.IScript; 030 import org.apache.tapestry.Tapestry; 031 import org.apache.tapestry.engine.RequestCycle; 032 import org.apache.tapestry.enhance.ClassFactoryImpl; 033 import org.apache.tapestry.junit.TapestryTestCase; 034 import org.apache.tapestry.script.ScriptParser; 035 import org.apache.tapestry.script.ScriptSession; 036 import org.apache.tapestry.script.ScriptSessionImpl; 037 import org.apache.tapestry.services.ExpressionEvaluator; 038 import org.apache.tapestry.services.impl.ExpressionCacheImpl; 039 import org.apache.tapestry.services.impl.ExpressionEvaluatorImpl; 040 import org.apache.tapestry.spec.IApplicationSpecification; 041 import org.apache.tapestry.util.xml.DocumentParseException; 042 import org.testng.annotations.AfterMethod; 043 import org.testng.annotations.Test; 044 045 /** 046 * A collection of tests for Tapestry scripting. 047 * 048 * @author Howard Lewis Ship 049 * @since 2.2 050 */ 051 @Test(sequential=true) 052 public class TestScript extends TapestryTestCase 053 { 054 private MockScriptProcessor _processor = new MockScriptProcessor(); 055 056 private ExpressionEvaluatorImpl _eval; 057 058 @AfterMethod 059 public void reset() 060 { 061 _processor.reset(); 062 } 063 064 protected ExpressionEvaluator createExpressionEvaluator() 065 { 066 IApplicationSpecification spec = newMock(IApplicationSpecification.class); 067 068 expect(spec.checkExtension(Tapestry.OGNL_TYPE_CONVERTER)).andReturn(false); 069 070 ExpressionCacheImpl cache = new ExpressionCacheImpl(); 071 _eval = new ExpressionEvaluatorImpl(); 072 _eval.setExpressionCache(cache); 073 _eval.setClassFactory(new ClassFactoryImpl()); 074 075 cache.setEvaluator(_eval); 076 077 _eval.setApplicationSpecification(spec); 078 _eval.setContributions(Collections.EMPTY_LIST); 079 _eval.setNullHandlerContributions(Collections.EMPTY_LIST); 080 081 return _eval; 082 } 083 084 private IScript read(String file) throws DocumentParseException 085 { 086 ClassResolver resolver = new DefaultClassResolver(); 087 ScriptParser parser = new ScriptParser(resolver, createExpressionEvaluator(), null); 088 089 String classAsPath = "/" + getClass().getName().replace('.', '/'); 090 091 Resource classLocation = new ClasspathResource(resolver, classAsPath); 092 Resource scriptLocation = classLocation.getRelativeResource(file); 093 094 return parser.parse(scriptLocation); 095 } 096 097 private IScript execute(String file, Map symbols) throws DocumentParseException 098 { 099 IScript script = read(file); 100 101 IRequestCycle cycle = newMock(IRequestCycle.class); 102 103 replay(); 104 105 _eval.initializeService(); 106 107 script.execute(cycle, _processor, symbols); 108 109 verify(); 110 111 return script; 112 } 113 114 private void assertSymbol(Map symbols, String key, Object expected) 115 { 116 Object actual = symbols.get(key); 117 118 assertEquals(expected, actual); 119 } 120 121 /** 122 * Simple test where the body and initialization are static. 123 */ 124 125 public void testSimple() throws Exception 126 { 127 execute("simple.script", null); 128 129 assertEquals("\nBODY\n", _processor.getBody()); 130 assertEquals("\nINITIALIZATION\n", _processor.getInitialization()); 131 132 assert _processor.getExternalScripts() == null 133 || _processor.getExternalScripts().length == 0; 134 } 135 136 /** 137 * Test the <unique> element, new in the 1.3 DTD 138 * 139 * @since 3.0 140 */ 141 142 public void testUnique() throws Exception 143 { 144 IScript script = read("unique.script"); 145 146 IRequestCycle cycle = new RequestCycle(); 147 148 script.execute(cycle, _processor, null); 149 script.execute(cycle, _processor, null); 150 151 assertEquals("Block1\nBlock2\nNotUnique\n\n\n\nNotUnique", _processor.getBody().trim()); 152 } 153 154 /** 155 * Test omitting body and initialization, ensure they return null. 156 */ 157 158 public void testEmpty() throws Exception 159 { 160 execute("empty.script", null); 161 162 assert _processor.getBody() == null || _processor.getBody().length() == 0; 163 assert _processor.getInitialization() == null || _processor.getInitialization().length() == 0; 164 } 165 166 /** 167 * Test the ability of the let element to create an output symbol. Also, test the insert 168 * element. 169 */ 170 171 public void testLet() throws Exception 172 { 173 String inputSymbol = Long.toHexString(System.currentTimeMillis()); 174 Map symbols = new HashMap(); 175 symbols.put("inputSymbol", inputSymbol); 176 177 execute("let.script", symbols); 178 179 // Unlike body, the let element trims whitespace. 180 181 String outputSymbol = "output: " + inputSymbol; 182 183 assertEquals(outputSymbol, symbols.get("outputSymbol")); 184 } 185 186 /** 187 * Test the unique attribute on the <let> element. New in the 1.3 DTD 188 * 189 * @since 3.0 190 */ 191 public void testUniqueLet() throws Exception 192 { 193 Map symbols = new HashMap(); 194 195 execute("unique-let.script", symbols); 196 197 assertSymbol(symbols, "alpha", "Alpha"); 198 assertSymbol(symbols, "beta", "Alpha_0"); 199 assertSymbol(symbols, "gamma", "Alpha_1"); 200 201 assertSymbol(symbols, "id1", "form1_field"); 202 assertSymbol(symbols, "id2", "form1_field_0"); 203 assertSymbol(symbols, "id3", "form1_field_last_name"); 204 } 205 206 public void testIncludeScript() throws Exception 207 { 208 IScript script = execute("include-script.script", null); 209 210 Resource scriptLocation = script.getScriptResource(); 211 212 Resource[] expected = new Resource[] 213 { scriptLocation.getRelativeResource("first"), 214 scriptLocation.getRelativeResource("second"), 215 scriptLocation.getRelativeResource("third") }; 216 217 assertEquals(Arrays.asList(expected), Arrays.asList(_processor 218 .getExternalScripts())); 219 } 220 221 public void testAntSyntax() throws Exception 222 { 223 Map form = new HashMap(); 224 225 form.put("name", "gallahad"); 226 227 Map component = new HashMap(); 228 component.put("form", form); 229 component.put("name", "lancelot"); 230 231 Map symbols = new HashMap(); 232 symbols.put("component", component); 233 234 execute("ant-syntax.script", symbols); 235 236 assertSymbol(symbols, "functionName", "gallahad_lancelot"); 237 assertSymbol(symbols, "incomplete1", "Incomplete: $"); 238 assertSymbol(symbols, "incomplete2", "Incomplete: ${"); 239 assertSymbol(symbols, "nopath", "This ${} ends up as literal."); 240 assertSymbol(symbols, "OGNL", "This is a brace: }."); 241 } 242 243 public void testSet() throws Exception 244 { 245 Map symbols = new HashMap(); 246 247 execute("set.script", symbols); 248 249 assertSymbol(symbols, "element2", new Character('p')); 250 } 251 252 public void testInvalidKeyLet() throws Exception 253 { 254 try 255 { 256 execute("invalid-key-let.script", new HashMap()); 257 258 unreachable(); 259 } 260 catch (DocumentParseException ex) 261 { 262 checkException(ex, "key"); 263 } 264 } 265 266 public void testInvalidKeySet() throws Exception 267 { 268 try 269 { 270 execute("invalid-key-set.script", new HashMap()); 271 272 unreachable(); 273 } 274 catch (DocumentParseException ex) 275 { 276 checkException(ex, "key"); 277 } 278 } 279 280 public void testInputSymbolClass() throws Exception 281 { 282 try 283 { 284 Map symbols = new HashMap(); 285 symbols.put("input", new Integer(20)); 286 287 execute("input-symbol-class.script", symbols); 288 289 unreachable(); 290 } 291 catch (Exception ex) 292 { 293 checkException(ex, "Integer"); 294 checkException(ex, "Long"); 295 } 296 } 297 298 public void testInputSymbol() throws Exception 299 { 300 Map symbols = new HashMap(); 301 symbols.put("input", new Long(20)); 302 303 execute("input-symbol.script", symbols); 304 305 assertSymbol(symbols, "success", "Success"); 306 } 307 308 public void testInputSymbolRequired() throws Exception 309 { 310 try 311 { 312 execute("input-symbol-required.script", new HashMap()); 313 314 unreachable(); 315 } 316 catch (Exception ex) 317 { 318 checkException(ex, "required"); 319 } 320 } 321 322 public void testInputSymbolInvalidKey() throws Exception 323 { 324 try 325 { 326 execute("input-symbol-invalid-key.script", new HashMap()); 327 328 unreachable(); 329 } 330 catch (DocumentParseException ex) 331 { 332 checkException(ex, "key"); 333 } 334 335 } 336 337 /** @since 3.0 */ 338 339 public void testNameAppend() throws Exception 340 { 341 Map symbols = new HashMap(); 342 343 symbols.put("name", "fred"); 344 execute("name-append.script", symbols); 345 346 assertSymbol(symbols, "output", "fred$suffix"); 347 } 348 349 /** 350 * A bunch of quickies to push up the code coverage numbers. 351 */ 352 public void testCheats() throws Exception 353 { 354 IScript script = execute("simple.script", null); 355 356 ScriptSession session = new ScriptSessionImpl(script.getScriptResource(), null, null, 357 createExpressionEvaluator(), null, null); 358 assertEquals("ScriptSession[" + script.getScriptResource() + "]", session.toString()); 359 } 360 }