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.enhance; 016 017 import org.apache.hivemind.ApplicationRuntimeException; 018 import org.apache.hivemind.ErrorLog; 019 import org.apache.hivemind.Location; 020 import org.apache.hivemind.service.BodyBuilder; 021 import org.apache.hivemind.service.MethodSignature; 022 import org.apache.tapestry.BaseComponent; 023 import org.apache.tapestry.BaseComponentTestCase; 024 import org.apache.tapestry.IBinding; 025 import org.apache.tapestry.IComponent; 026 import org.apache.tapestry.spec.IComponentSpecification; 027 import org.apache.tapestry.spec.IParameterSpecification; 028 import org.apache.tapestry.spec.ParameterSpecification; 029 import static org.easymock.EasyMock.expect; 030 import org.testng.annotations.Test; 031 032 import java.lang.reflect.Modifier; 033 import java.util.Collections; 034 035 /** 036 * Tests for {@link org.apache.tapestry.enhance.ParameterPropertyWorker}. 037 * 038 * @author Howard M. Lewis Ship 039 */ 040 @Test 041 public class TestParameterPropertyWorker extends BaseComponentTestCase 042 { 043 044 private ParameterSpecification buildParameterSpec(String parameterName, String type, 045 Location location) 046 { 047 return buildParameterSpec(parameterName, parameterName, type, location); 048 } 049 050 private ParameterSpecification buildParameterSpec(String parameterName, String propertyName, 051 String type, Location location) 052 { 053 ParameterSpecification ps = new ParameterSpecification(); 054 055 ps.setParameterName(parameterName); 056 ps.setPropertyName(propertyName); 057 ps.setType(type); 058 ps.setLocation(location); 059 060 return ps; 061 } 062 063 private IComponentSpecification buildComponentSpecification(String parameterName, 064 IParameterSpecification ps) 065 { 066 IComponentSpecification result = newSpec(); 067 068 expect(result.getParameterNames()).andReturn(Collections.singletonList(parameterName)); 069 070 expect(result.getParameter(parameterName)).andReturn(ps); 071 072 return result; 073 } 074 075 public void test_Failure() throws Exception 076 { 077 Location l = newLocation(); 078 079 IComponentSpecification spec = buildComponentSpecification("wilma", buildParameterSpec( 080 "wilma", 081 "String", 082 l)); 083 084 EnhancementOperation op = newMock(EnhancementOperation.class); 085 086 Throwable ex = new ApplicationRuntimeException("Simulated error."); 087 expect(op.convertTypeName("String")).andThrow(ex); 088 089 expect(op.getBaseClass()).andReturn(BaseComponent.class); 090 091 ErrorLog log = newMock(ErrorLog.class); 092 093 log 094 .error( 095 "Error adding property wilma to class org.apache.tapestry.BaseComponent: Simulated error.", 096 l, 097 ex); 098 099 replay(); 100 101 ParameterPropertyWorker w = new ParameterPropertyWorker(); 102 w.setErrorLog(log); 103 104 w.performEnhancement(op, spec); 105 106 verify(); 107 } 108 109 public void test_Skip_Parameter_Alias() 110 { 111 IComponentSpecification spec = buildComponentSpecification("barney", buildParameterSpec( 112 "fred", 113 null, 114 null)); 115 116 EnhancementOperation op = newMock(EnhancementOperation.class); 117 118 replay(); 119 120 ParameterPropertyWorker w = new ParameterPropertyWorker(); 121 122 w.performEnhancement(op, spec); 123 124 verify(); 125 } 126 127 /** 128 * Tests for ordinary, object type of binding (as opposed to primitive types, which have a 129 * slightly different control flow. 130 */ 131 132 public void test_Standard() 133 { 134 IComponentSpecification spec = 135 buildComponentSpecification("fred", buildParameterSpec("fred", null, null)); 136 137 EnhancementOperation op = newMock(EnhancementOperation.class); 138 139 expect(op.getPropertyType("fred")).andReturn(String.class); 140 op.claimProperty("fred"); 141 142 String bindingFieldName = "_$fred$Binding"; 143 String bindingChecked = bindingFieldName + "Checked"; 144 145 op.addField("_$fred", String.class); 146 op.addField("_$fred$Default", String.class); 147 op.addField("_$fred$Cached", boolean.class); 148 op.addField(bindingFieldName, IBinding.class); 149 op.addField(bindingChecked, Boolean.TYPE); 150 151 BodyBuilder builder = new BodyBuilder(); 152 builder.begin(); 153 builder.addln("if (!{0})", bindingChecked); 154 builder.begin(); 155 builder.addln("{0} = getBinding(\"{1}\");", bindingFieldName, "fred"); 156 builder.addln("{0} = true;", bindingChecked); 157 builder.end(); 158 builder.addln("return {0};", bindingFieldName); 159 builder.end(); 160 161 String methodName = EnhanceUtils.createAccessorMethodName(bindingFieldName); 162 op.addMethod(Modifier.PUBLIC, 163 new MethodSignature(IBinding.class, methodName, new Class[0], null), 164 builder.toString(), null); 165 166 expect(op.getClassReference(String.class)).andReturn("_class$String"); 167 168 builder.clear(); 169 builder.begin(); 170 builder.addln("if (_$fred$Cached) return _$fred;"); 171 builder.addln("if (get_$fred$Binding() == null) return _$fred$Default;"); 172 builder.add("java.lang.String result = "); 173 builder.addln("(java.lang.String) get_$fred$Binding().getObject(_class$String);"); 174 builder.addln("if (isRendering() || get_$fred$Binding().isInvariant())"); 175 builder.begin(); 176 builder.addln("_$fred = result;"); 177 builder.addln("_$fred$Cached = true;"); 178 builder.end(); 179 builder.addln("return result;"); 180 builder.end(); 181 182 expect(op.getAccessorMethodName("fred")).andReturn("getFred"); 183 184 op.addMethod(Modifier.PUBLIC, new MethodSignature(String.class, "getFred", null, null), 185 builder.toString(), 186 null); 187 188 builder.clear(); 189 190 builder.begin(); 191 builder.addln("if (! isInActiveState())"); 192 builder.begin(); 193 builder.addln("_$fred$Default = $1;"); 194 builder.addln("return;"); 195 builder.end(); 196 197 builder.addln("if (get_$fred$Binding() == null)"); 198 builder.addln(" throw new org.apache.hivemind.ApplicationRuntimeException(\"Parameter 'fred' is not bound and can not be updated.\");"); 199 200 builder.addln("get_$fred$Binding().setObject(($w) $1);"); 201 202 builder.addln("if (isRendering())"); 203 builder.begin(); 204 builder.addln("_$fred = $1;"); 205 builder.addln("_$fred$Cached = true;"); 206 builder.end(); 207 builder.end(); 208 209 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[] 210 { String.class }, null), builder.toString(), null); 211 212 BodyBuilder expectedCleanup = new BodyBuilder(); 213 214 expectedCleanup.addln("if (_$fred$Cached && ! get_$fred$Binding().isInvariant())"); 215 expectedCleanup.begin(); 216 expectedCleanup.addln("_$fred$Cached = false;"); 217 expectedCleanup.addln("_$fred = _$fred$Default;"); 218 expectedCleanup.end(); 219 220 op.extendMethodImplementation( 221 IComponent.class, 222 EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE, 223 expectedCleanup.toString()); 224 225 replay(); 226 227 ParameterPropertyWorker w = new ParameterPropertyWorker(); 228 229 w.performEnhancement(op, spec); 230 231 verify(); 232 } 233 234 /** 235 * Test where the parameter name does not equal the property name. The parameter is "barney", 236 * but the binding is "fred". 237 */ 238 239 public void test_Different_Property_Name() 240 { 241 Location l = newLocation(); 242 IComponentSpecification spec = buildComponentSpecification("myparam", buildParameterSpec("myparam", "fred", null, l)); 243 244 EnhancementOperation op = newMock(EnhancementOperation.class); 245 246 expect(op.getPropertyType("fred")).andReturn(String.class); 247 248 op.claimProperty("fred"); 249 250 String bindingFieldName = "_$fred$Binding"; 251 String bindingChecked = bindingFieldName + "Checked"; 252 253 op.addField("_$fred", String.class); 254 op.addField("_$fred$Default", String.class); 255 op.addField("_$fred$Cached", boolean.class); 256 op.addField(bindingFieldName, IBinding.class); 257 op.addField(bindingChecked, Boolean.TYPE); 258 259 BodyBuilder builder = new BodyBuilder(); 260 builder.begin(); 261 builder.addln("if (!{0})", bindingChecked); 262 builder.begin(); 263 builder.addln("{0} = getBinding(\"{1}\");", bindingFieldName, "myparam"); 264 builder.addln("{0} = true;", bindingChecked); 265 builder.end(); 266 builder.addln("return {0};", bindingFieldName); 267 builder.end(); 268 269 String methodName = EnhanceUtils.createAccessorMethodName(bindingFieldName); 270 op.addMethod(Modifier.PUBLIC, 271 new MethodSignature(IBinding.class, methodName, new Class[0], null), 272 builder.toString(), l); 273 274 expect(op.getClassReference(String.class)).andReturn("_class$String"); 275 276 builder.clear(); 277 builder.begin(); 278 builder.addln("if (_$fred$Cached) return _$fred;"); 279 builder.addln("if (get_$fred$Binding() == null) return _$fred$Default;"); 280 builder.add("java.lang.String result = "); 281 builder.addln("(java.lang.String) get_$fred$Binding().getObject(_class$String);"); 282 builder.addln("if (isRendering() || get_$fred$Binding().isInvariant())"); 283 builder.begin(); 284 builder.addln("_$fred = result;"); 285 builder.addln("_$fred$Cached = true;"); 286 builder.end(); 287 builder.addln("return result;"); 288 builder.end(); 289 290 expect(op.getAccessorMethodName("fred")).andReturn("getFred"); 291 292 op.addMethod( 293 Modifier.PUBLIC, 294 new MethodSignature(String.class, "getFred", null, null), 295 builder.toString(), 296 l); 297 298 builder.clear(); 299 300 builder.begin(); 301 builder.addln("if (! isInActiveState())"); 302 builder.begin(); 303 builder.addln("_$fred$Default = $1;"); 304 builder.addln("return;"); 305 builder.end(); 306 307 builder.addln("if (get_$fred$Binding() == null)"); 308 builder 309 .addln(" throw new org.apache.hivemind.ApplicationRuntimeException(\"Parameter 'myparam' is not bound and can not be updated.\");"); 310 311 builder.addln("get_$fred$Binding().setObject(($w) $1);"); 312 313 builder.addln("if (isRendering())"); 314 builder.begin(); 315 builder.addln("_$fred = $1;"); 316 builder.addln("_$fred$Cached = true;"); 317 builder.end(); 318 builder.end(); 319 320 op.addMethod(Modifier.PUBLIC, new MethodSignature(void.class, "setFred", new Class[] 321 { String.class }, null), builder.toString(), l); 322 323 BodyBuilder expectedCleanup = new BodyBuilder(); 324 325 expectedCleanup.addln("if (_$fred$Cached && ! get_$fred$Binding().isInvariant())"); 326 expectedCleanup.begin(); 327 expectedCleanup.addln("_$fred$Cached = false;"); 328 expectedCleanup.addln("_$fred = _$fred$Default;"); 329 expectedCleanup.end(); 330 331 op.extendMethodImplementation( 332 IComponent.class, 333 EnhanceUtils.CLEANUP_AFTER_RENDER_SIGNATURE, 334 expectedCleanup.toString()); 335 336 replay(); 337 338 ParameterPropertyWorker w = new ParameterPropertyWorker(); 339 340 w.performEnhancement(op, spec); 341 342 verify(); 343 } 344 345 public void test_Primitive_Type() 346 { 347 Location l = newLocation(); 348 349 EnhancementOperation op = newMock(EnhancementOperation.class); 350 351 BodyBuilder builder = new BodyBuilder(); 352 builder.begin(); 353 builder.addln("if (_$fred$Cached) return _$fred;"); 354 builder.addln("if (get_$fred$Binding() == null) return _$fred$Default;"); 355 builder.add("boolean result = "); 356 builder.addln(EnhanceUtils.class.getName() + ".toBoolean(get_$fred$Binding());"); 357 builder.addln("if (isRendering() || get_$fred$Binding().isInvariant())"); 358 builder.begin(); 359 builder.addln("_$fred = result;"); 360 builder.addln("_$fred$Cached = true;"); 361 builder.end(); 362 builder.addln("return result;"); 363 builder.end(); 364 365 expect(op.getAccessorMethodName("fred")).andReturn("isFred"); 366 367 op.addMethod( 368 Modifier.PUBLIC, 369 new MethodSignature(boolean.class, "isFred", null, null), 370 builder.toString(), 371 l); 372 373 replay(); 374 375 new ParameterPropertyWorker().buildAccessor( 376 op, 377 "fred", 378 boolean.class, 379 "_$fred", 380 "_$fred$Default", 381 "_$fred$Cached", 382 "get_$fred$Binding()", 383 true, 384 l); 385 386 verify(); 387 } 388 389 public void test_Parameter_Cache_Disabled() 390 { 391 Location l = newLocation(); 392 393 EnhancementOperation op = newMock(EnhancementOperation.class); 394 395 BodyBuilder builder = new BodyBuilder(); 396 builder.begin(); 397 builder.addln("if (_$fred$Cached) return _$fred;"); 398 builder.addln("if (get_$fred$Binding() == null) return _$fred$Default;"); 399 builder.add("boolean result = "); 400 builder.addln(EnhanceUtils.class.getName() + ".toBoolean(get_$fred$Binding());"); 401 builder.addln("if (get_$fred$Binding().isInvariant())"); 402 builder.begin(); 403 builder.addln("_$fred = result;"); 404 builder.addln("_$fred$Cached = true;"); 405 builder.end(); 406 builder.addln("return result;"); 407 builder.end(); 408 409 expect(op.getAccessorMethodName("fred")).andReturn("isFred"); 410 411 op.addMethod( 412 Modifier.PUBLIC, 413 new MethodSignature(boolean.class, "isFred", null, null), 414 builder.toString(), 415 l); 416 417 replay(); 418 419 new ParameterPropertyWorker().buildAccessor( 420 op, 421 "fred", 422 boolean.class, 423 "_$fred", 424 "_$fred$Default", 425 "_$fred$Cached", 426 "get_$fred$Binding()", 427 false, 428 l); 429 430 verify(); 431 } 432 }