You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2006/09/02 02:43:50 UTC

svn commit: r439507 [2/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/aspect/org/apache/tapestry/internal/aspects/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/ioc/...

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/model/MutableComponentModelImplTest.java Fri Sep  1 17:43:45 2006
@@ -1,3 +1,17 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed 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.tapestry.internal.model;
 
 import org.apache.commons.logging.Log;
@@ -34,6 +48,31 @@
 
         assertEquals(pm.getName(), parameterName);
         assertEquals(true, pm.isRequired());
+
+        verify();
+    }
+
+    @Test
+    public void add_duplicate_parameter()
+    {
+        Resource r = newResource();
+        Log log = newLog();
+
+        replay();
+
+        MutableComponentModel model = new MutableComponentModelImpl(CLASS_NAME, log, r);
+
+        model.addParameter("fred", true);
+
+        try
+        {
+            model.addParameter("fred", true);
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(ex.getMessage(), "Parameter 'fred' of component org.example.components.Foo is already defined.");
+        }
 
         verify();
     }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/BindingSourceImplTest.java Fri Sep  1 17:43:45 2006
@@ -43,7 +43,7 @@
         String description = "descrip";
         String expression = "full expression";
 
-        trainNewBinding(factory, description, component, expression, l, b);
+        train_newBinding(factory, description, component, expression, l, b);
 
         replay();
 
@@ -72,7 +72,7 @@
         String description = "descrip";
         String expression = "javascript:not-a-known-prefix";
 
-        trainNewBinding(factory, description, component, expression, l, b);
+        train_newBinding(factory, description, component, expression, l, b);
 
         replay();
 
@@ -101,7 +101,7 @@
         String description = "descrip";
 
         // The "prop:" prefix is stripped off ...
-        trainNewBinding(factory, description, component, "myproperty", l, b);
+        train_newBinding(factory, description, component, "myproperty", l, b);
 
         replay();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java Fri Sep  1 17:43:45 2006
@@ -42,7 +42,7 @@
 
         List<MethodSignature> sigs = newList();
 
-        trainFindMethodsWithAnnotation(tf, sigs);
+        train_findMethodsWithAnnotation(tf, sigs);
 
         replay();
 
@@ -64,11 +64,12 @@
 
         sigs.add(new MethodSignature("aMethod"));
 
-        trainFindMethodsWithAnnotation(tf, sigs);
+        train_findMethodsWithAnnotation(tf, sigs);
 
-        String expectedBody = join("{", "  if ($2.isAborted()) return;", "  aMethod();", "}");
-
-        tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody);
+        train_extendMethod(
+                tf,
+                TransformConstants.BEFORE_RENDER_SIGNATURE,
+                "{if ($2.isAborted()) return;  aMethod(); }");
 
         replay();
 
@@ -91,11 +92,12 @@
         sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "aMethod", new String[]
         { MarkupWriter.class.getName() }, null));
 
-        trainFindMethodsWithAnnotation(tf, sigs);
-
-        String expectedBody = join("{", "  if ($2.isAborted()) return;", "  aMethod($1);", "}");
+        train_findMethodsWithAnnotation(tf, sigs);
 
-        tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody);
+        train_extendMethod(
+                tf,
+                TransformConstants.BEFORE_RENDER_SIGNATURE,
+                "{ if ($2.isAborted()) return;  aMethod($1); }");
 
         replay();
 
@@ -118,16 +120,14 @@
 
         sigs.add(new MethodSignature(Modifier.PROTECTED, "boolean", "aMethod", null, null));
 
-        trainFindMethodsWithAnnotation(tf, sigs);
+        train_findMethodsWithAnnotation(tf, sigs);
 
-        String expectedBody = join(
-                "{",
-                "  if ($2.isAborted()) return;",
-                "  $2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");",
-                "  if ($2.isAborted()) return;",
-                "}");
-
-        tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody);
+        train_extendMethod(
+                tf,
+                TransformConstants.BEFORE_RENDER_SIGNATURE,
+                "{ if ($2.isAborted()) return; ",
+                "$2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");",
+                "if ($2.isAborted()) return; }");
 
         replay();
 
@@ -151,17 +151,15 @@
         sigs.add(new MethodSignature(Modifier.PUBLIC, "void", "bMethod", new String[]
         { MarkupWriter.class.getName() }, null));
 
-        trainFindMethodsWithAnnotation(tf, sigs);
-
-        String expectedBody = join(
-                "{",
-                "  if ($2.isAborted()) return;",
-                "  $2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");",
-                "  if ($2.isAborted()) return;",
-                "  bMethod($1);",
-                "}");
+        train_findMethodsWithAnnotation(tf, sigs);
 
-        tf.extendMethod(TransformConstants.BEFORE_RENDER_SIGNATURE, expectedBody);
+        train_extendMethod(
+                tf,
+                TransformConstants.BEFORE_RENDER_SIGNATURE,
+                "{ if ($2.isAborted()) return;",
+                "$2.storeResult(($w) aMethod(), \"protected boolean aMethod()\");",
+                "if ($2.isAborted()) return;",
+                "bMethod($1); }");
 
         replay();
 
@@ -171,14 +169,6 @@
         worker.transform(tf, model);
 
         verify();
-
-    }
-
-    protected final void trainFindMethodsWithAnnotation(ClassTransformation tf,
-            List<MethodSignature> sigs)
-    {
-        tf.findMethodsWithAnnotation(BeforeRender.class);
-        setReturnValue(sigs);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentTemplateSourceImplTest.java Fri Sep  1 17:43:45 2006
@@ -50,7 +50,7 @@
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
 
-        trainParseTemplate(parser, r, template);
+        train_parseTemplate(parser, r, template);
 
         replay();
 
@@ -67,13 +67,6 @@
         verify();
     }
 
-    protected final void trainParseTemplate(TemplateParser parser, Resource resource,
-            ComponentTemplate template)
-    {
-        parser.parseTemplate(resource);
-        setReturnValue(template);
-    }
-
     /** Tests resource invalidation. */
     @Test
     public void invalidation() throws Exception
@@ -94,7 +87,7 @@
         ComponentTemplate template = newComponentTemplate();
         InvalidationListener listener = newMock(InvalidationListener.class);
 
-        trainParseTemplate(parser, localized, template);
+        train_parseTemplate(parser, localized, template);
 
         replay();
 
@@ -130,7 +123,7 @@
 
         // Check that the cache really is cleared.
 
-        trainParseTemplate(parser, localized, template);
+        train_parseTemplate(parser, localized, template);
 
         replay();
 
@@ -139,11 +132,6 @@
         verify();
     }
 
-    protected final TemplateParser newTemplateParser()
-    {
-        return newMock(TemplateParser.class);
-    }
-
     /** Checks that localization to the same resource works (w/ caching). */
     @Test
     public void localization_to_same()
@@ -153,7 +141,7 @@
         TemplateParser parser = newTemplateParser();
         ComponentTemplate template = newComponentTemplate();
 
-        trainParseTemplate(parser, r, template);
+        train_parseTemplate(parser, r, template);
 
         replay();
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java?rev=439507&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/FieldAccessBean.java Fri Sep  1 17:43:45 2006
@@ -0,0 +1,49 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed 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.tapestry.internal.services;
+
+import org.apache.tapestry.internal.annotations.SuppressNullCheck;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+@SuppressNullCheck
+public class FieldAccessBean
+{
+    private String _foo;
+
+    private String _bar;
+
+    public String getBar()
+    {
+        return _bar;
+    }
+
+    public void setBar(String bar)
+    {
+        _bar = bar;
+    }
+
+    public String getFoo()
+    {
+        return _foo;
+    }
+
+    public void setFoo(String foo)
+    {
+        _foo = foo;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InfrastructureImplTest.java Fri Sep  1 17:43:45 2006
@@ -73,7 +73,7 @@
         Map<String, Object> configuration = newMap();
         configuration.put("myrunnable", r);
 
-        trainGetContributionsForMode(manager, "papyrus", configuration);
+        train_getContributionsForMode(manager, "papyrus", configuration);
 
         replay();
 
@@ -104,7 +104,7 @@
         Map<String, Object> configuration = newMap();
         configuration.put("myrunnable", r);
 
-        trainGetContributionsForMode(manager, "clay", configuration);
+        train_getContributionsForMode(manager, "clay", configuration);
 
         replay();
 
@@ -138,7 +138,7 @@
         configuration.put("barney", this);
         configuration.put("wilma", this);
 
-        trainGetContributionsForMode(manager, "clay", configuration);
+        train_getContributionsForMode(manager, "clay", configuration);
 
         replay();
 
@@ -174,7 +174,7 @@
         Map<String, Object> configuration = newMap();
         configuration.put("myrunnable", r);
 
-        trainGetContributionsForMode(manager, "papyrus", configuration);
+        train_getContributionsForMode(manager, "papyrus", configuration);
 
         replay();
 
@@ -204,7 +204,7 @@
 
     }
 
-    protected final void trainGetContributionsForMode(InfrastructureManager manager, String mode,
+    protected final void train_getContributionsForMode(InfrastructureManager manager, String mode,
             Map<String, Object> configuration)
     {
         manager.getContributionsForMode(mode);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/InternalClassTransformationImplTest.java Fri Sep  1 17:43:45 2006
@@ -31,6 +31,7 @@
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.annotations.Retain;
 import org.apache.tapestry.internal.InternalComponentResources;
+import org.apache.tapestry.internal.ioc.services.PropertyAccessImpl;
 import org.apache.tapestry.internal.test.InternalBaseTestCase;
 import org.apache.tapestry.internal.transform.pages.AbstractFoo;
 import org.apache.tapestry.internal.transform.pages.BarImpl;
@@ -39,6 +40,7 @@
 import org.apache.tapestry.internal.transform.pages.ClaimedFields;
 import org.apache.tapestry.internal.transform.pages.ParentClass;
 import org.apache.tapestry.internal.transform.pages.TargetObject;
+import org.apache.tapestry.ioc.services.PropertyAccess;
 import org.apache.tapestry.runtime.ComponentLifecycle;
 import org.apache.tapestry.runtime.ResourceAware;
 import org.apache.tapestry.services.ClassTransformation;
@@ -58,6 +60,8 @@
 @Test(sequential = true)
 public class InternalClassTransformationImplTest extends InternalBaseTestCase
 {
+    private static final String STRING_CLASS_NAME = "java.lang.String";
+
     private ClassPool _classPool;
 
     private final ClassLoader _contextClassLoader = currentThread().getContextClassLoader();
@@ -411,6 +415,97 @@
         assertNull(getters.getString());
         assertNull(getters.getObjectArray());
         assertNull(getters.getIntArray());
+    }
+
+    /**
+     * Tests the basic functionality of overriding read and write; also tests the case for multiple
+     * field read/field write substitions.
+     */
+    @Test
+    public void override_field_read_and_write() throws Exception
+    {
+        InternalComponentResources resources = newInternalComponentResources();
+
+        replay();
+
+        ClassLoader childLoader = newLoader();
+
+        CtClass targetObjectCtClass = findCtClass(FieldAccessBean.class);
+
+        InternalClassTransformation ct = new InternalClassTransformationImpl(targetObjectCtClass);
+
+        replaceAccessToField(ct, "foo");
+        replaceAccessToField(ct, "bar");
+
+        // Stuff ...
+
+        ct.finish();
+
+        Class transformed = _classPool.toClass(targetObjectCtClass, childLoader);
+
+        Object target = ct.createInstantiator(transformed).newInstance(resources);
+
+        // target is no longer assignable to FieldAccessBean; its a new class from a new class
+        // loader. So we use reflective access, which doesn't care about such things.
+
+        PropertyAccess access = new PropertyAccessImpl();
+
+        checkReplacedFieldAccess(access, target, "foo");
+        checkReplacedFieldAccess(access, target, "bar");
+
+        verify();
+    }
+
+    private void checkReplacedFieldAccess(PropertyAccess access, Object target, String propertyName)
+    {
+
+        try
+        {
+            access.get(target, propertyName);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            // PropertyAccess adds a wrapper exception
+            assertEquals(ex.getCause().getMessage(), "read " + propertyName);
+        }
+
+        try
+        {
+            access.set(target, propertyName, "new value");
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            // PropertyAccess adds a wrapper exception
+            assertEquals(ex.getCause().getMessage(), "write " + propertyName);
+        }
+    }
+
+    private void replaceAccessToField(InternalClassTransformation ct, String baseName)
+    {
+        String fieldName = "_" + baseName;
+        String readMethodName = "_read_" + baseName;
+
+        MethodSignature readMethodSignature = new MethodSignature(Modifier.PRIVATE,
+                STRING_CLASS_NAME, readMethodName, null, null);
+
+        ct.addMethod(readMethodSignature, String.format(
+                "throw new RuntimeException(\"read %s\");",
+                baseName));
+
+        ct.replaceReadAccess(fieldName, readMethodName);
+
+        String writeMethodName = "_write_" + baseName;
+
+        MethodSignature writeMethodSignature = new MethodSignature(Modifier.PRIVATE, "void",
+                writeMethodName, new String[]
+                { STRING_CLASS_NAME }, null);
+        ct.addMethod(writeMethodSignature, String.format(
+                "throw new RuntimeException(\"write %s\");",
+                baseName));
+
+        ct.replaceWriteAccess(fieldName, writeMethodName);
     }
 
     @Test

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/PagePoolImplTest.java Fri Sep  1 17:43:45 2006
@@ -37,7 +37,7 @@
         PageLoader loader = newPageLoader();
         Page page = newPage();
 
-        trainLoadPage(loader, PAGE_NAME, _locale, page);
+        train_loadPage(loader, PAGE_NAME, _locale, page);
 
         replay();
 
@@ -56,9 +56,9 @@
         Page page2 = newPage();
 
         page1.detached();
-        trainGetName(page1, PAGE_NAME);
+        train_getName(page1, PAGE_NAME);
 
-        trainLoadPage(loader, PAGE_NAME, _locale, page2);
+        train_loadPage(loader, PAGE_NAME, _locale, page2);
 
         replay();
 
@@ -84,11 +84,11 @@
 
         page1.detached();
 
-        trainGetName(page1, PAGE_NAME);
+        train_getName(page1, PAGE_NAME);
 
         page2.detached();
 
-        trainGetName(page2, PAGE_NAME);
+        train_getName(page2, PAGE_NAME);
 
         replay();
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java?rev=439507&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParameterWorkerTest.java Fri Sep  1 17:43:45 2006
@@ -0,0 +1,236 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed 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.tapestry.internal.services;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.MethodSignature;
+import org.apache.tapestry.services.TransformConstants;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class ParameterWorkerTest extends InternalBaseTestCase
+{
+    private static String f(String format, Object... args)
+    {
+        return String.format(format, args);
+    }
+
+    @Test
+    public void standard_cacheable_parameter()
+    {
+        runWorkerCached("_foo", "foo", "", "java.lang.String", "java.lang.String");
+    }
+
+    @Test
+    public void annotation_name_overrides_default_from_field_name()
+    {
+        runWorkerCached("_foo", "zippy", "zippy", "java.util.Map", "java.util.Map");
+    }
+
+    @Test(dataProvider = "primitiveTypes")
+    public void primitive_types(String fieldType, String expectedWrapperType)
+    {
+        runWorkerCached("_primitive", "primitive", "", fieldType, expectedWrapperType);
+    }
+
+    @DataProvider(name = "primitiveTypes")
+    public Object[][] primitiveTypes()
+    {
+        return new Object[][]
+        {
+        { "boolean", "java.lang.Boolean" },
+        { "short", "java.lang.Short" },
+        { "int", "java.lang.Integer" },
+        { "byte", "java.lang.Byte" },
+        { "char", "java.lang.Character" },
+        { "long", "java.lang.Long" },
+        { "float", "java.lang.Float" },
+        { "double", "java.lang.Double" } };
+    }
+
+    private void runWorkerCached(String fieldName, String parameterName, String annotatedName,
+            String fieldType, String wrapperType)
+    {
+        ClassTransformation transformation = newClassTransformation();
+        MutableComponentModel model = newMutableComponentModel();
+        Parameter parameter = newMock(Parameter.class);
+
+        train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName);
+        train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter);
+        train_name(parameter, annotatedName);
+        train_required(parameter, true);
+
+        model.addParameter(parameterName, true);
+
+        train_getFieldType(transformation, fieldName, fieldType);
+        train_cache(parameter, true);
+        train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache");
+        train_getResourcesFieldName(transformation, "$res");
+
+        train_addField(
+                transformation,
+                Modifier.PRIVATE,
+                "boolean",
+                fieldName + "_invariant",
+                "$invariant");
+
+        // codeEq() lets us care less about whitespace
+
+        train_extendMethod(
+                transformation,
+                TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+                String.format("$invariant = $res.isInvariant(\"%s\");", parameterName));
+
+        train_extendMethod(
+                transformation,
+                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
+                String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName));
+
+        train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read");
+
+        train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, fieldType, "$read",
+                null, null), f("{ if ($cache) return %s;", fieldName), f(
+                "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));",
+                fieldType,
+                wrapperType,
+                parameterName), f(
+                "if ($invariant || $res.isRendering()) { %s = result; $cache = true; }",
+                fieldName), "return result; }");
+
+        transformation.replaceReadAccess(fieldName, "$read");
+
+        train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write");
+
+        train_addMethod(
+                transformation,
+                new MethodSignature(Modifier.PRIVATE, "void", "$write", new String[]
+                { fieldType, }, null),
+                f("{ $res.writeParameter(\"%s\", ($w)$1);", parameterName),
+                f("if ($res.isRendering()) { %s = $1; $cache = true; } }", fieldName));
+
+        transformation.replaceWriteAccess(fieldName, "$write");
+
+        transformation.claimField(fieldName, parameter);
+
+        replay();
+
+        new ParameterWorker().transform(transformation, model);
+
+        verify();
+    }
+
+    @Test
+    public void non_cached_parameter()
+    {
+        runWorkerNonCached("_foo", "foo", "", "java.lang.String", "java.lang.String");
+    }
+
+    private void runWorkerNonCached(String fieldName, String parameterName, String annotatedName,
+            String fieldType, String wrapperType)
+    {
+        ClassTransformation transformation = newClassTransformation();
+        MutableComponentModel model = newMutableComponentModel();
+        Parameter parameter = newMock(Parameter.class);
+
+        train_findFieldsWithAnnotation(transformation, Parameter.class, fieldName);
+        train_getFieldAnnotation(transformation, fieldName, Parameter.class, parameter);
+        train_name(parameter, annotatedName);
+        train_required(parameter, true);
+
+        model.addParameter(parameterName, true);
+
+        train_getFieldType(transformation, fieldName, fieldType);
+
+        train_cache(parameter, false); // First difference
+
+        train_addField(transformation, Modifier.PRIVATE, "boolean", fieldName + "_cached", "$cache");
+        train_getResourcesFieldName(transformation, "$res");
+
+        train_addField(
+                transformation,
+                Modifier.PRIVATE,
+                "boolean",
+                fieldName + "_invariant",
+                "$invariant");
+
+        // codeEq() lets us care less about whitespace
+
+        train_extendMethod(
+                transformation,
+                TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
+                String.format("$invariant = $res.isInvariant(\"%s\");", parameterName));
+
+        train_extendMethod(
+                transformation,
+                TransformConstants.CONTAINING_PAGE_DID_DETACH_SIGNATURE,
+                String.format("if (! $invariant) { %s = null; $cache = false; }", fieldName));
+
+        train_newMemberName(transformation, "_read_parameter_" + parameterName, "$read");
+
+        // Second difference:
+
+        train_addMethod(
+                transformation,
+                new MethodSignature(Modifier.PRIVATE, fieldType, "$read", null, null),
+                f("{ if ($cache) return %s;", fieldName),
+                f(
+                        "%s result = ($r) ((%s) $res.readParameter(\"%s\", $type));",
+                        fieldType,
+                        wrapperType,
+                        parameterName),
+                f("if ($invariant) { %s = result; $cache = true; }", fieldName),
+                "return result; }");
+
+        transformation.replaceReadAccess(fieldName, "$read");
+
+        train_newMemberName(transformation, "_update_parameter_" + parameterName, "$write");
+
+        // Last difference:
+
+        train_addMethod(transformation, new MethodSignature(Modifier.PRIVATE, "void", "$write",
+                new String[]
+                { fieldType, }, null), f("{ $res.writeParameter(\"%s\", ($w)$1); }", parameterName));
+
+        transformation.replaceWriteAccess(fieldName, "$write");
+
+        transformation.claimField(fieldName, parameter);
+
+        replay();
+
+        new ParameterWorker().transform(transformation, model);
+
+        verify();
+    }
+
+    private final void train_required(Parameter parameter, boolean required)
+    {
+        parameter.required();
+        setReturnValue(required);
+    }
+
+    private void train_cache(Parameter parameter, boolean cache)
+    {
+        parameter.cache();
+        setReturnValue(cache);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/RetainWorkerTest.java Fri Sep  1 17:43:45 2006
@@ -32,7 +32,7 @@
         ClassTransformation ct = newClassTransformation();
         MutableComponentModel model = newMutableComponentModel();
 
-        trainFindFieldsWithAnnotation(ct, Retain.class);
+        train_findFieldsWithAnnotation(ct, Retain.class);
 
         replay();
 
@@ -50,9 +50,9 @@
         MutableComponentModel model = newMutableComponentModel();
         Retain annotation = newMock(Retain.class);
 
-        trainFindFieldsWithAnnotation(ct, Retain.class, "fred");
+        train_findFieldsWithAnnotation(ct, Retain.class, "fred");
 
-        trainGetFieldAnnotation(ct, "fred", Retain.class, annotation);
+        train_getFieldAnnotation(ct, "fred", Retain.class, annotation);
 
         ct.claimField("fred", annotation);
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/UnclaimedFieldWorkerTest.java Fri Sep  1 17:43:45 2006
@@ -36,7 +36,7 @@
         ClassTransformation ct = newClassTransformation();
         MutableComponentModel model = newMutableComponentModel();
 
-        trainFindUnclaimedFields(ct);
+        train_findUnclaimedFields(ct);
 
         replay();
 
@@ -51,7 +51,7 @@
         ClassTransformation ct = newClassTransformation();
         MutableComponentModel model = newMutableComponentModel();
 
-        trainFindUnclaimedFields(ct, "_fred");
+        train_findUnclaimedFields(ct, "_fred");
 
         ct.getFieldType("_fred");
         setReturnValue("foo.Bar");

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java Fri Sep  1 17:43:45 2006
@@ -1,3 +1,17 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed 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.tapestry.internal.structure;
 
 import org.apache.tapestry.Binding;
@@ -89,9 +103,27 @@
         verify();
     }
 
-    protected final ComponentModel newComponentModel()
+    @Test
+    public void write_binding()
     {
-        return newMock(ComponentModel.class);
+        Page page = newPage();
+        ComponentLifecycle component = newComponentLifecycle();
+        Instantiator ins = newInstantiator(component);
+        ComponentModel model = newComponentModel();
+
+        Binding binding = newBinding();
+
+        binding.set(23);
+
+        replay();
+
+        ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, model);
+
+        cpe.addParameter("barney", binding);
+
+        cpe.writeParameter("barney", 23);
+
+        verify();
     }
 
     private Instantiator newInstantiator(ComponentLifecycle component)

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java?rev=439507&view=auto
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/test/CodeEqTest.java Fri Sep  1 17:43:45 2006
@@ -0,0 +1,72 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed 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.tapestry.internal.test;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author Howard M. Lewis Ship
+ */
+public class CodeEqTest extends Assert
+{
+    @Test(dataProvider = "stripValues")
+    public void strip(String input, String expected)
+    {
+        assertEquals(CodeEq.strip(input), expected);
+    }
+
+    @DataProvider(name = "stripValues")
+    public Object[][] stripValues()
+    {
+        return new Object[][]
+        {
+                { "foo", "foo" },
+                { " foo\n", "foo" },
+                { "  foo \nbar\n\n  \tbaz", "foo bar baz" },
+                { "{\n  bar();\n  baz();\n  if (gnip())\n  {\n    gnop();\n  }\n}\n",
+                        "{bar(); baz(); if (gnip()){gnop();}}" } };
+    }
+
+    @Test
+    public void to_string()
+    {
+        CodeEq eq = new CodeEq("{ foo(); bar(); baz(); }");
+
+        StringBuffer buffer = new StringBuffer();
+
+        eq.appendTo(buffer);
+
+        assertEquals(buffer.toString(), "codeEq({foo(); bar(); baz();})");
+    }
+
+    @Test(dataProvider = "matchValues")
+    public void matches(String pattern, String parameter, boolean matches)
+    {
+        CodeEq ceq = new CodeEq(pattern);
+
+        assertEquals(ceq.matches(parameter), matches);
+    }
+
+    @DataProvider(name = "matchValues")
+    public Object[][] matchValues()
+    {
+        return new Object[][]
+        {
+        { "{ foo(); }", "{\n  foo();\n}", true },
+        { " foo();", "foo ();", false }, };
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html?rev=439507&r1=439506&r2=439507&view=diff
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/Start.html Fri Sep  1 17:43:45 2006
@@ -5,4 +5,8 @@
             <t:comp id="hello" type="HelloWorld"/>
         </t:comp>
     </p>
+    <p>
+        Here's some output from the Output component:
+        <t:comp id="output" type="Output" value="Yep, we have basic parameters working."/>
+    </p>
 </t:comp>