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    }