You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2007/04/29 22:23:10 UTC

svn commit: r533554 - in /tapestry/tapestry-test/trunk: ./ .settings/ src/java/org/apache/tapestry/ src/site/ src/site/apt/ src/site/resources/ src/site/resources/css/ src/test/ src/test/conf/ src/test/java/ src/test/java/org/ src/test/java/org/apache/...

Author: jkuhnert
Date: Sun Apr 29 13:23:08 2007
New Revision: 533554

URL: http://svn.apache.org/viewvc?view=rev&rev=533554
Log:
-) Added core source previously found in tapestry-testng so that the library is a little easier to maintain.

-) Added a pretty good chunk of documentation. Fixes TAPESTRY-765. Also deployed site and a fresh copy of the module.

Added:
    tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java   (with props)
    tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java   (with props)
    tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java   (with props)
    tapestry/tapestry-test/trunk/src/site/
    tapestry/tapestry-test/trunk/src/site/apt/
    tapestry/tapestry-test/trunk/src/site/apt/components.apt
    tapestry/tapestry-test/trunk/src/site/apt/easymock.apt
    tapestry/tapestry-test/trunk/src/site/apt/gettingstarted.apt
    tapestry/tapestry-test/trunk/src/site/apt/index.apt
    tapestry/tapestry-test/trunk/src/site/apt/installation.apt
    tapestry/tapestry-test/trunk/src/site/resources/
    tapestry/tapestry-test/trunk/src/site/resources/css/
    tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css   (with props)
    tapestry/tapestry-test/trunk/src/site/resources/css/site.css   (with props)
    tapestry/tapestry-test/trunk/src/site/site.xml   (with props)
    tapestry/tapestry-test/trunk/src/test/
    tapestry/tapestry-test/trunk/src/test/conf/
    tapestry/tapestry-test/trunk/src/test/conf/testng.xml   (with props)
    tapestry/tapestry-test/trunk/src/test/java/
    tapestry/tapestry-test/trunk/src/test/java/org/
    tapestry/tapestry-test/trunk/src/test/java/org/apache/
    tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/
    tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java   (with props)
    tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java   (with props)
    tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java   (with props)
    tapestry/tapestry-test/trunk/src/test/webapp/
    tapestry/tapestry-test/trunk/src/test/webapp/index.html   (with props)
Removed:
    tapestry/tapestry-test/trunk/.classpath
    tapestry/tapestry-test/trunk/.project
    tapestry/tapestry-test/trunk/.settings/
Modified:
    tapestry/tapestry-test/trunk/   (props changed)
    tapestry/tapestry-test/trunk/pom.xml
    tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/BaseComponentTestCase.java

Propchange: tapestry/tapestry-test/trunk/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Apr 29 13:23:08 2007
@@ -1,3 +1,6 @@
-
 bin
 target
+cobertura.ser
+*.iml
+*.ipr
+*.iws

Modified: tapestry/tapestry-test/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/pom.xml?view=diff&rev=533554&r1=533553&r2=533554
==============================================================================
--- tapestry/tapestry-test/trunk/pom.xml (original)
+++ tapestry/tapestry-test/trunk/pom.xml Sun Apr 29 13:23:08 2007
@@ -1,10 +1,11 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.tapestry</groupId>
     <artifactId>tapestry-test</artifactId>
     <packaging>jar</packaging>
-    <version>4.1.1-SNAPSHOT</version>
+    <version>4.1.2-SNAPSHOT</version>
     <description>Tapestry Test Utilities</description>
     <name>Tapestry Test</name>
     <inceptionYear>2006</inceptionYear>
@@ -84,12 +85,12 @@
         <dependency>
             <groupId>org.apache.tapestry</groupId>
             <artifactId>tapestry-framework</artifactId>
-            <version>4.1.1-SNAPSHOT</version>
+            <version>4.1.2-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>jboss</groupId>
             <artifactId>javassist</artifactId>
-            <version>3.0</version>
+            <version>3.4.ga</version>
             <scope>runtime</scope>
         </dependency>
         <dependency>
@@ -113,9 +114,7 @@
         <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
-            <version>1.0.4</version>
-            <!-- This is almost always provided by the container. If not, then WARs will have to
-                create an explicit dependency. -->
+            <version>1.1</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -126,12 +125,12 @@
         <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymockclassextension</artifactId>
-            <version>2.2</version>
+            <version>2.2.2</version>
         </dependency>
         <dependency>
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
-            <version>5.1</version>
+            <version>5.5</version>
             <classifier>jdk15</classifier>
             <scope>provided</scope>
             <exclusions>
@@ -149,7 +148,7 @@
         <dependency>
             <groupId>ognl</groupId>
             <artifactId>ognl</artifactId>
-            <version>2.6.9</version>
+            <version>2.7-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
@@ -159,7 +158,7 @@
         <dependency>
             <groupId>commons-fileupload</groupId>
             <artifactId>commons-fileupload</artifactId>
-            <version>1.1.1</version>
+            <version>1.2</version>
         </dependency>
         <dependency>
             <groupId>commons-beanutils</groupId>
@@ -169,22 +168,25 @@
         <dependency>
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
-            <version>2.2</version>
+            <version>2.3</version>
         </dependency>
         <dependency>
-            <groupId>com.javaforge.tapestry</groupId>
-            <artifactId>tapestry-testng</artifactId>
-            <version>1.0.0-SNAPSHOT</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>tapestry</groupId>
-                    <artifactId>tapestry</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.testng</groupId>
-                    <artifactId>testng</artifactId>
-                </exclusion>
-            </exclusions>
+            <groupId>org.openqa.selenium.client-drivers</groupId>
+            <artifactId>selenium-java-client-driver</artifactId>
+            <version>0.9.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openqa.selenium.server</groupId>
+            <artifactId>selenium-server</artifactId>
+            <version>0.9.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty</artifactId>
+            <version>6.1.1</version>
+            <scope>provided</scope>
         </dependency>
     </dependencies>
 
@@ -206,12 +208,23 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <version>2.8-SNAPSHOT</version>
+                <version>2.4-SNAPSHOT</version>
+                <configuration>
+                    <suiteXmlFiles>
+                        <suiteXmlFile>src/test/conf/testng.xml</suiteXmlFile>
+                    </suiteXmlFiles>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>2.1-SNAPSHOT</version>
+                <configuration>
+                    <archive>
+                        <compress>true</compress>
+                        <index>true</index>
+                    </archive>
+                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -244,18 +257,86 @@
         </plugins>
     </build>
 
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-report-plugin</artifactId>
+                <version>2.4-SNAPSHOT</version>
+                <inherited>true</inherited>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.0</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <version>2.1-SNAPSHOT</version>
+                <inherited>true</inherited>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>project-team</report>
+                            <report>mailing-list</report>
+                            <report>issue-tracking</report>
+                            <report>license</report>
+                            <report>scm</report>
+                            <report>index</report>
+                            <report>dependencies</report>
+                            <report>dependency-convergence</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+                <configuration>
+                    <dependencyLocationsEnabled>true</dependencyLocationsEnabled>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.2-SNAPSHOT</version>
+                <configuration>
+                    <linksource>true</linksource>
+                    <tags>
+                        <tag>
+                            <name>todo</name>
+                            <placement>a</placement>
+                            <head>To do something:</head>
+                        </tag>
+                    </tags>
+                    <links>
+                        <link>http://hivemind.apache.org/hivemind1/hivemind/apidocs/</link>
+                        <link>http://java.sun.com/j2se/1.4.2/docs/api/</link>
+                        <link>http://java.sun.com/products/servlet/2.3/javadoc/</link>
+                        <link>http://jakarta.apache.org/commons/codec/api-release/</link>
+                        <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+                        <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+                        <link>http://www.ognl.org/2.6.9/Documentation/javadoc/</link>
+                    </links>
+                    <stylesheetfile>${basedir}/src/site/resources/css/jdstyle.css</stylesheetfile>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-site-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </reporting>
+
     <distributionManagement>
         <site>
             <id>tapestry</id>
-            <url>scp://apache.org/www/tapestry.apache.org/tapestry-test/</url>
+            <url>scpexe://people.apache.org/www/tapestry.apache.org/tapestry4.1/tapestry-test/</url>
         </site>
         <repository>
-            <id>tapestry-repo</id>
-            <url>scp://apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+            <id>tapestry</id>
+            <url>scpexe://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
         </repository>
         <snapshotRepository>
-            <id>tapestry-snapshot-repo</id>
-            <url>scp://apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
+            <id>tapestry</id>
+            <url>scpexe://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
         </snapshotRepository>
     </distributionManagement>
 
@@ -265,8 +346,9 @@
             <url>http://people.apache.org/repo/m2-snapshot-repository</url>
         </repository>
         <repository>
-            <id>tapestry.javaforge</id>
-            <url>http://howardlewisship.com/repository</url>
+            <id>openqa</id>
+            <name>OpenQA Maven Repository</name>
+            <url>http://maven.openqa.org/</url>
         </repository>
     </repositories>
 
@@ -274,13 +356,18 @@
         <pluginRepository>
             <id>apache.snapshots</id>
             <url>http://people.apache.org/repo/m2-snapshot-repository</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
         </pluginRepository>
         <pluginRepository>
             <id>tapestry.javaforge</id>
             <url>http://howardlewisship.com/repository</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>codehaus.org</id>
+            <url>http://snapshots.repository.codehaus.org</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>codehaus.org</id>
+            <url>http://repository.codehaus.org</url>
         </pluginRepository>
     </pluginRepositories>
 

Modified: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/BaseComponentTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/BaseComponentTestCase.java?view=diff&rev=533554&r1=533553&r2=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/BaseComponentTestCase.java (original)
+++ tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/BaseComponentTestCase.java Sun Apr 29 13:23:08 2007
@@ -1,17 +1,7 @@
 package org.apache.tapestry;
 
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.checkOrder;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-
 import org.apache.commons.logging.Log;
-import org.apache.hivemind.ClassResolver;
-import org.apache.hivemind.Locatable;
-import org.apache.hivemind.Location;
-import org.apache.hivemind.ModuleDescriptorProvider;
-import org.apache.hivemind.Registry;
-import org.apache.hivemind.Resource;
+import org.apache.hivemind.*;
 import org.apache.hivemind.impl.DefaultClassResolver;
 import org.apache.hivemind.impl.RegistryBuilder;
 import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
@@ -31,6 +21,7 @@
 import org.apache.tapestry.spec.IParameterSpecification;
 import org.apache.tapestry.test.Creator;
 import org.apache.tapestry.web.WebRequest;
+import static org.easymock.EasyMock.*;
 
 import java.io.CharArrayWriter;
 import java.io.PrintWriter;
@@ -40,16 +31,10 @@
 import java.util.List;
 import java.util.Locale;
 
-import com.javaforge.tapestry.testng.TestBase;
-
 /**
  * Base class for testing components, or testing classes that operate on components. Simplifies
  * creating much of the infrastructure around the components.
- * <p>
- * This class may eventually be part of the Tapestry distribution.
- * 
- * @author Howard M. Lewis Ship
- * @since 4.0
+ *  
  */
 public class BaseComponentTestCase extends TestBase
 {
@@ -322,10 +307,8 @@
     }
 
     protected IEngine newEngine(ClassResolver resolver)
-    {
-        IEngine engine = newMock(IEngine.class);
-        
-        return engine;
+    {   
+        return newMock(IEngine.class);
     }
 
     protected void trainGetEngine(IPage page, IEngine engine)
@@ -524,31 +507,43 @@
     /**
      * Convienience method for invoking {@link #buildFrameworkRegistry(String[])} with only a single
      * file.
+     *
+     * @param file
+     *          The path to the hivemind xml configuration file.
+     * @return The constructed registry.
+     * 
+     * @throws Exception When file can't be found or parsed.
      */
-    protected Registry buildFrameworkRegistry(String file) throws Exception
+    protected Registry buildFrameworkRegistry(String file)
+            throws Exception
     {
-        return buildFrameworkRegistry(new String[]
-        { file });
+        return buildFrameworkRegistry(new String[] { file });
     }
     
     /**
      * Builds a minimal registry, containing only the specified files, plus the master module
      * descriptor (i.e., those visible on the classpath).
+     *
+     * @param files
+     *          The path to the hivemind xml configuration files to parse.
+     * @return The constructed registry.
+     *
+     * @throws Exception When file can't be found or parsed.
      */
-    protected Registry buildFrameworkRegistry(String[] files) throws Exception
+    protected Registry buildFrameworkRegistry(String[] files)
+            throws Exception
     {
         ClassResolver resolver = getClassResolver();
 
-        List descriptorResources = new ArrayList();
-        for (int i = 0; i < files.length; i++)
+        List<Resource> descriptorResources = new ArrayList<Resource>();
+        for (String file : files)
         {
-            Resource resource = getResource(files[i]);
+            Resource resource = getResource(file);
 
             descriptorResources.add(resource);
         }
-
-        ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver,
-                descriptorResources);
+        
+        ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver, descriptorResources);
 
         return buildFrameworkRegistry(provider);
     }
@@ -557,6 +552,11 @@
      * Builds a registry, containing only the modules delivered by the specified
      * {@link org.apache.hivemind.ModuleDescriptorProvider}, plus the master module descriptor
      * (i.e., those visible on the classpath).
+     *
+     * @param customProvider
+     *          The custom module provider that should be added to the configuration.
+     *
+     * @return A constructed {@link Registry}.
      */
     protected Registry buildFrameworkRegistry(ModuleDescriptorProvider customProvider)
     {
@@ -573,8 +573,15 @@
     /**
      * Builds a registry from exactly the provided resource; this registry will not include the
      * <code>hivemind</code> module.
+     *
+     * @param l
+     *         The resource to build the registry from.
+     * @return A constructed {@link Registry} instance.
+     * 
+     * @throws Exception If error building registry.
      */
-    protected Registry buildMinimalRegistry(Resource l) throws Exception
+    protected Registry buildMinimalRegistry(Resource l)
+            throws Exception
     {
         RegistryBuilder builder = new RegistryBuilder();
 
@@ -584,6 +591,10 @@
     /**
      * Returns the given file as a {@link Resource} from the classpath. Typically, this is to find
      * files in the same folder as the invoking class.
+     *
+     * @param file
+     *          Gets a resource object for the file representing the path specified.
+     * @return A {@link Resource} object.
      */
     protected Resource getResource(String file)
     {

Added: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java (added)
+++ tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,83 @@
+package org.apache.tapestry;
+
+import static org.easymock.EasyMock.reportMatcher;
+import org.easymock.IArgumentMatcher;
+
+/**
+ * An EasyMock 2.0 argument matcher that captures a method argument value. This allows an object
+ * created inside a test method to be interrogated after the method completes, even when the object
+ * is not a return value, but is merely passed as a parameter to a mock object.
+ *
+ * @author Howard M. Lewis Ship
+ * @param <T>
+ *            the type of object to capture
+ */
+public final class Capturer<T> implements IArgumentMatcher
+{
+    private final Class<T> _matchType;
+
+    private T _captured;
+
+    /**
+     * Creates a new Capturer for the given type. Because of Generics syntax, it is easier to use
+     * the static method.
+     */
+    public Capturer(Class<T> matchType)
+    {
+        _matchType = matchType;
+    }
+
+    /**
+     * Factory method that invokes the normal constructor in a way that keeps Java Generics happy.
+     */
+    public static <T> Capturer<T> newCapturer(Class<T> matchType)
+    {
+        return new Capturer<T>(matchType);
+    }
+
+    public void appendTo(StringBuffer buffer)
+    {
+        buffer.append(String.format("capture(%s)", _matchType.getName()));
+    }
+
+    public boolean matches(Object parameter)
+    {
+        boolean result = _matchType.isInstance(parameter);
+
+        if (result)
+            _captured = _matchType.cast(parameter);
+
+        return result;
+    }
+
+    /** Returns the method argument value previously captured. */
+    public T getCaptured()
+    {
+        return _captured;
+    }
+
+    /**
+     * Useage (with static imports):
+     * <p>
+     * Capturer&lt;Type&gt; c = newCapturer(Type.class);
+     * <p>
+     * mock.someMethod(capture(c));
+     * <p> . . .
+     * <p>
+     * c.getCaptured().getXXX()
+     * <p>
+     * The interrogation of the captured argument should occur after the test subject has invoked
+     * the method on the mock; the best time for this is typically after invoking
+     * {@link TestBase#verify()}.
+     * <p>
+     * Remember that when you use an argument matcher for one argument of a method invocation, you
+     * must use argument matchers for <em>all</em> arguments of the method invocation.
+     */
+    public static <T> T capture(Capturer<T> capturer)
+    {
+        reportMatcher(capturer);
+
+        return null;
+    }
+
+}

Propchange: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/Capturer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java (added)
+++ tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,110 @@
+package org.apache.tapestry;
+
+import org.mortbay.jetty.Connector;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.nio.BlockingChannelConnector;
+import org.mortbay.jetty.webapp.WebAppContext;
+
+import static java.lang.String.format;
+
+/**
+ * A utitilty class for running an instance of the <a
+ * href="http://jetty.mortbay.com/jetty/index.html">Jetty servlet container</a> from within a unit
+ * test. This code is based on the Jetty 6 code base (which is in beta at the time of writing). When
+ * combined with <a href="http://jwebunit.sourceforge.net/">jWebUnit</a>, this allows for basic
+ * <em>integration</em> testing of an application from within a unit test case.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class JettyRunner
+{
+    public static final String DEFAULT_CONTEXT_PATH = "/";
+
+    public static final int DEFAULT_PORT = 80;
+
+    public static final String DEFAULT_WAR_PATH = "src/main/webapp";
+
+    private final String _contextPath;
+
+    private final int _port;
+
+    private final String _warPath;
+
+    private final Server _jetty;
+
+    /**
+     * Creates and starts a new instance of Jetty, using default configuration values. The
+     * contextPath will be /, the port will be 80, the warPath will be src/main/webapp.
+     */
+    public JettyRunner()
+    {
+        this(DEFAULT_CONTEXT_PATH, DEFAULT_PORT, DEFAULT_WAR_PATH);
+    }
+
+    /**
+     * Creates and starts a new instance of Jetty. This should be done from a test case setup
+     * method.
+     *
+     * @param contextPath
+     *            the context path for the deployed application
+     * @param port
+     *            the port number used to access the application
+     * @param warPath
+     *            the path to the exploded web application (typically, "src/main/webapp")
+     */
+    public JettyRunner(String contextPath, int port, String warPath)
+    {
+        _contextPath = contextPath;
+        _port = port;
+        _warPath = warPath;
+
+        _jetty = new Server();
+
+        startJetty();
+    }
+
+    /** Stops the Jetty instance. This should be called from a test case tear down method. */
+    public void stop()
+    {
+        try
+        {
+            _jetty.stop();
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException("Error stopping Jetty instance: " + ex.toString(), ex);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return format("<JettyRunner %s:%d (%s)>", _contextPath, _port, _warPath);
+    }
+
+    private void startJetty()
+    {
+        try
+        {
+            BlockingChannelConnector connector = new BlockingChannelConnector();
+            connector.setPort(_port);
+
+            _jetty.setConnectors(new Connector[]
+            { connector });
+
+            WebAppContext context = new WebAppContext();
+
+            context.setContextPath(_contextPath);
+            context.setWar(_warPath);
+
+            _jetty.addHandler(context);
+
+            _jetty.start();
+        }
+        catch (Exception ex)
+        {
+            throw new RuntimeException("Failure starting Jetty instance: " + ex.toString(), ex);
+        }
+    }
+
+}

Propchange: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/JettyRunner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java (added)
+++ tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,181 @@
+package org.apache.tapestry;
+
+import org.apache.tapestry.test.Creator;
+import static org.easymock.EasyMock.createStrictControl;
+import org.easymock.IMocksControl;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+
+/**
+ * A base class for creating TestNG unit tests for Tapestry 4 applications. With slightly more
+ * effort, this may be used as a utility class with other frameworks, such as JUnit.
+ * <p>
+ * A single <em>strict</em> mock control is used for <strong>all</strong> mocks, which means that
+ * order of operations is checked not just for any single mock but across mocks.
+ * <p>
+ * Provides common mock factory and mock trainer methods.
+ * <p>
+ * Provides easy access to instantiated component instances.
+ * <p>
+ * Extends from {@link org.testng.Assert} to bring in all the public static assert methods without
+ * requiring extra imports.
+ * <p>
+ * TestNG supports running tests in parallel, as does this class. The EasyMock control is stored in
+ * a <em>thread local</em>. This is necessary as TestNG instantiates a single instance of the
+ * test case class, and invokes methods on it from multiple threads.
+ *
+ * @author Howard M. Lewis Ship
+ */
+public class TestBase extends Assert
+{
+    private static class ControlSource extends ThreadLocal<IMocksControl>
+    {
+        /** Creates a strick control for <em>this</em> thread. */
+        @Override
+        protected IMocksControl initialValue()
+        {
+            return createStrictControl();
+        }
+    }
+
+    private final ControlSource _source = new ControlSource();
+
+    // Access to this is synchronized.
+
+    private Creator _creator;
+
+    /**
+     * Creates a new instance of the provided class using the
+     * {@link org.apache.tapestry.test.Creator} utility.
+     *
+     * @param componentClass
+     *            the component type to build
+     * @param properties
+     *            alternating property names and property values to be injected into the instance
+     * @return the instantiated and configured component instance
+     */
+    public synchronized final <T> T newInstance(Class<T> componentClass, Object... properties)
+    {
+        if (_creator == null)
+            _creator = new Creator();
+
+        Object instance = _creator.newInstance(componentClass, properties);
+
+        return componentClass.cast(instance);
+    }
+
+    /**
+     * Discards any mock objects created during the test. When using TestBase as a utility class,
+     * not a base class, you must be careful to either invoke this method, or discard the TestBase
+     * instance at the end of each test.
+     */
+    @AfterMethod(alwaysRun = true)
+    public final void cleanupControlSource()
+    {
+        // TestNG reuses the same class instance across all tests within that
+        // class, so if we don't
+        // clear out the mocks, they will tend to accumulate. That can get
+        // expensive, and can
+        // cause unexpected cascade errors when an earlier test fails.
+
+        // After each method runs, we clear this thread's mocks control.
+        _source.remove();
+    }
+
+    /**
+     * Creates a new mock object of the indicated type. The created object is retained for the
+     * duration of the test (specifically to support {@link #replay()} and {@link #verify()}).
+     *
+     * @param <T>
+     *            the type of the mock object
+     * @param mockClass
+     *            the class to mock
+     * @return the mock object, ready for training
+     */
+    public final <T> T newMock(Class<T> mockClass)
+    {
+        return getMocksControl().createMock(mockClass);
+    }
+
+    /**
+     * Replay's the mocks control, preparing all mocks for testing.
+     */
+    public final void replay()
+    {
+        getMocksControl().replay();
+    }
+
+    /**
+     * Verifies the mocks control, ensuring that all mocks completed all trained method invocations,
+     * then resets the control to allow more training of the mocks.
+     */
+    public final void verify()
+    {
+        IMocksControl control = getMocksControl();
+
+        control.verify();
+        control.reset();
+    }
+
+    /**
+     * Returns the control object used for all mocks created by this test case.
+     *
+     * @return The {@link IMocksControl} used to manage mocks.  
+     */
+    public final IMocksControl getMocksControl()
+    {
+        return _source.get();
+    }
+
+    /**
+     * Sets the return value for the most recent method call upon the mock.
+     *
+     * @param returnValue
+     *            value to be returned from the method call
+     */
+    @SuppressWarnings("unchecked")
+    public final <T> void setReturnValue(T returnValue)
+    {
+        getMocksControl().andReturn(returnValue);
+    }
+
+    /**
+     * Trains a mock object to throw an exception.
+     *
+     * @param throwable
+     *            the exception to be thrown by the most recent method call on the mock
+     */
+    public final void setThrowable(Throwable throwable)
+    {
+        getMocksControl().andThrow(throwable);
+    }
+
+    /**
+     * Invoked to indicate code should not reach a point. This is typically used after code that
+     * should throw an exception.
+     */
+    public final void unreachable()
+    {
+        fail("This code should not be reachable.");
+    }
+
+    /**
+     * Simply returns a new mock around {@link IRequestCycle}.
+     *
+     * @return The mocked request.
+     */
+    public final IRequestCycle newRequestCycle()
+    {
+        return newMock(IRequestCycle.class);
+    }
+
+    /**
+     * Creates a mock for {@link IMarkupWriter}.
+     *
+     * @return The mock.
+     */
+    public final IMarkupWriter newMarkupWriter()
+    {
+        return newMock(IMarkupWriter.class);
+    }
+}

Propchange: tapestry/tapestry-test/trunk/src/java/org/apache/tapestry/TestBase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/site/apt/components.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/apt/components.apt?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/apt/components.apt (added)
+++ tapestry/tapestry-test/trunk/src/site/apt/components.apt Sun Apr 29 13:23:08 2007
@@ -0,0 +1,104 @@
+ ------
+Testing Pages/Component classes
+ ------
+Jesse Kuhnert
+ ------
+29 April 2007
+ ------
+
+Component Tests
+
+  The most important kind of tests for any {{{http://tapestry.apache.org}Tapestry}} application will probably be those
+  covering Page / Component classes. This library also provides some conveniences for those kinds of tests.
+
+  In this example we'll take a look at how one of the core {{{http://tapestry.apache.org}Tapestry}} components is tested
+  using a couple of tricks provided by this library - {{{http://tapestry.apache.org/tapestry4.1/components/form/button.html}Button}}. This
+  is a simple {{{http://tapestry.apache.org/tapestry4.1/components/form/form.html}Form}} component that renders an html button block
+  like:
+
++----------------------------------------------------------
+<button type="button" name="updateForm">Submit</button>
++----------------------------------------------------------
+
+  To get us started we'll jump right in to a real world example of testing the rendering logic of the {{{http://tapestry.apache.org/tapestry4.1/components/form/button.html}Button}}
+  component. The full source for this test can be found
+  {{{http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/TestButton.java?view=markup}here}}. The source of the actual
+  button component itself can also be found {{{http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/Button.java?view=markup}here}}.
+
++-------------------------------------------------------------------------------------------------------------------------
+...
+import org.apache.tapestry.BaseComponentTestCase;
+import org.testng.annotations.Test;
+
+@Test
+public class TestButton extends BaseComponentTestCase
+{
+    public void testRender()
+    {
+        Button b = newInstance(Button.class, "name", "assignedName");
+
+        IMarkupWriter writer = newBufferWriter();
+        IRequestCycle cycle = newCycle();
+
+        replay();
+
+        b.renderFormComponent(writer, cycle);
+
+        verify();
+
+        assertBuffer("<button type=\"button\" name=\"assignedName\"></button>");
+    }
+}
++-------------------------------------------------------------------------------------------------------------------------
+
+  The following sections will expand further on each part of the test used.
+
+* {{{/apidocs/org/apache/tapestry/BaseComponentTestCase.html}BaseComponentTestCase}}
+
+  In almost all of the core Taptestry test cases {{{/apidocs/org/apache/tapestry/BaseComponentTestCase.html}BaseComponentTestCase}} is the actual test class extended. It provides
+  a number of additional conveniences not found in the basic {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} class - such as being able to create a buffered
+  {{{http://tapestry.apache.org/tapestry4.1/apidocs/org/apache/tapestry/IMarkupWriter.html}IMarkupWriter}} instance that allows you to check the string produced from a component
+  render instead of having to do mock calls for all of the method invocations on a mock {{{http://tapestry.apache.org/tapestry4.1/apidocs/org/apache/tapestry/IMarkupWriter.html}IMarkupWriter}}
+  object.
+
+  The example above makes use of this method with the following lines:
+
++-----------------------------------------------------------------------------
+    ...
+    IMarkupWriter writer = newBufferWriter();
+
+    ..
+
+    assertBuffer("<button type=\"button\" name=\"assignedName\"></button>");
++-----------------------------------------------------------------------------
+
+  You will find many other small convenience methods, such as various <<<trainDoFoo()>>> methods which do some of the grunt work of training a mock object for common
+  things like getting a {{{http://tapestry.apache.org/tapestry4.1/apidocs/org/apache/tapestry/engine/ILink.html}ILink}} object from an engine service.
+
+* newInstance(Class class, Object...arguments)
+
+  This is really probably the most important method for everyones tests. What it does is allows you to create a real object instance of any component / page class
+  along with a pre-configured set of properties for your abstract getter/setter methods.
+
+  The example above did this with the {{{http://tapestry.apache.org/tapestry4.1/components/form/button.html}Button}} component by giving it a default value for
+  the <<<name>>> property. The {{{http://tapestry.apache.org/tapestry4.1/components/form/button.html}Button}} component inherits the <<<getName()/setName(String name)>>> methods
+  from the {{{http://tapestry.apache.org/tapestry4.1/apidocs/org/apache/tapestry/form/AbstractFormComponent.html}AbstractFormComponent}} class - like all Tapestry form based components
+  do.
+
+  The key to understanding how to use <<<newInstance()>>> is that you must pass in a <<name>> <and> <<value>> for each property you want to set on your page / component. The method
+  has a varargs definition so you can pass in as many properties as you like. For instance - if you had another hypothetical form component with a simple Date value getter/setter you could
+  create it like this:
+
++-------------------------------------------------------------------------------------------------------------------------
+...
+    public void test_TestField_Render()
+    {
+        TextField field = newInstance(TextField.class,
+                                        "name", "simple",
+                                        "value", new java.util.Date(),
+                                        "clientId", "simple");
+
+        assert field.getValue() != null;
+        assert java.util.Date.class.isInstance(field.getValue());
+    }
++-------------------------------------------------------------------------------------------------------------------------

Added: tapestry/tapestry-test/trunk/src/site/apt/easymock.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/apt/easymock.apt?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/apt/easymock.apt (added)
+++ tapestry/tapestry-test/trunk/src/site/apt/easymock.apt Sun Apr 29 13:23:08 2007
@@ -0,0 +1,96 @@
+ ------
+EasyMock
+ ------
+Jesse Kuhnert
+ ------
+29 April 2007
+ ------
+
+Mock Objects
+
+  Mock object testing is indispensible in situations where creating real objects would be redundant or require too much
+  code to make testing feasible. The tapestry-test library provides a few conveniences to make managing mock objects a
+  little easier in your own unit tests.
+
+  For example, if you were using {{{http://easymock.org}EasyMock}} without extending {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} you
+  might have to write a test looking something like this:
+
++-------------------------------------------------------------------------------------------------------------------------
+import org.apache.tapestry.IMarkupWriter;
+import org.testng.annotations.Test;
+import static org.easymock.EasyMock.*;
+
+@Test
+public class MarkupWriterTest {
+
+    public void test_Attribute_Write()
+    {
+        IMarkupWriter mw = createMock(IMarkupWriter.class);
+        IRequestCycle cycle  = createMock(IRequestCycle.class);
+
+        expect(cycle.isRewinding()).andReturn(false);
+        mw.attribute("style", "display:block;background-color:red");
+
+        replay(mw, cycle);
+
+        MyWriterClass writer = new MyWriterClass();
+        writer.renderAttributes(mw, cycle);
+
+        verify(mw, cycle);
+    }
+
+    class MyWriterClass {
+
+      public void renderAttributes(IMarkupWriter writer, IRequestCycle cycle)
+      {
+        if (cycle.isRewinding())
+            return;
+
+        writer.attribute("style", "display:block;background-color:red");
+      }
+    }
+}
++-------------------------------------------------------------------------------------------------------------------------
+
+  In particular you want to note that we had to pass in each mock we created in the <<<replay(mw, cycle)>>> method of {{{http://easymock.org}EasyMock}}. This
+  can get a little unweildy / painfaul at times so {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} has made this part easier by keeping track of your
+  mock objects for you.
+
+  The same class above re-written to use the {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} features would look more like:
+
++-------------------------------------------------------------------------------------------------------------------------
+import org.apache.tapestry.IMarkupWriter;
+import org.testng.annotations.Test;
+import static org.easymock.EasyMock.*;
+
+@Test
+public class MarkupWriterTest extends TestBase {
+
+    public void test_Attribute_Write()
+    {
+        IMarkupWriter mw = newMock(IMarkupWriter.class); // notice call changed to newMock() instead of createMock()
+        IRequestCycle cycle  = newMock(IRequestCycle.class);
+
+        expect(cycle.isRewinding()).andReturn(false);
+        mw.attribute("style", "display:block;background-color:red");
+
+        replay(); // notice no arguments
+
+        MyWriterClass writer = new MyWriterClass();
+        writer.renderAttributes(mw, cycle);
+
+        verify();
+    }
+
+    class MyWriterClass {
+
+      public void renderAttributes(IMarkupWriter writer, IRequestCycle cycle)
+      {
+        if (cycle.isRewinding())
+            return;
+
+        writer.attribute("style", "display:block;background-color:red");
+      }
+    }
+}
++-------------------------------------------------------------------------------------------------------------------------

Added: tapestry/tapestry-test/trunk/src/site/apt/gettingstarted.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/apt/gettingstarted.apt?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/apt/gettingstarted.apt (added)
+++ tapestry/tapestry-test/trunk/src/site/apt/gettingstarted.apt Sun Apr 29 13:23:08 2007
@@ -0,0 +1,62 @@
+ ------
+Getting Started
+ ------
+Jesse Kuhnert
+ ------
+29 April 2007
+ ------
+
+Simple Test
+
+  There's no better way to get going than by looking at real code. This example uses the {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} class as
+  the main class to extend from.
+
+  This isn't a requirement with {{{http://testng.org}TestNG}} - but it does make some things a lot easier. <(such as managing
+  the mock objects created with {{{http://easymock.org}EasyMock}}.)>
+
++-------------------------------------------------------------------------------------------------------------------------
+import org.testng.annotations.Test;
+
+@Test
+public class StringTest extends TestBase {
+
+    public void test_String_Length()
+    {
+        String str = "simple";
+        
+        assertEquals(str.length(), 6);
+    }
+
+    public void test_String_Equals()
+    {
+        assert "simple".equals("simple");
+    }
+}
++-------------------------------------------------------------------------------------------------------------------------
+
+  You'll notice that we used the <<<...@Test>>> annotation at the class level instead of each individual method. {{{http://testng.org}TestNG}} is very flexible
+  in how you can tell it to run your tests, in our example we didn't need to configure each method differently so using the single <<<...@Test>>> annotation at the
+  top of the class is more than enough to tell {{{http://testng.org}TestNG}} that this is a test class.
+
+* Assertions
+
+  The previous example used a {{{http://testng.org}}} <<<assertEquals(actual, expected)>>> utiltity method to do equality checking. It is provided in the
+  {{{/apidocs/org/apache/tapestry/TestBase.html}TestBase}} class as a convenience, but you could do the same thing in your own tests with a static import of
+  the {{{http://testng.org/javadocs/org/testng/Assert.html}Assert}} class like this:
+
++-------------------------------------------------------------------------------------------------------------------------
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class StringTest {
+
+    public void test_String_Length()
+    {
+        String str = "simple";
+
+        assertEquals(str.length(), 6);
+    }
+}
++-------------------------------------------------------------------------------------------------------------------------
+

Added: tapestry/tapestry-test/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/apt/index.apt?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/apt/index.apt (added)
+++ tapestry/tapestry-test/trunk/src/site/apt/index.apt Sun Apr 29 13:23:08 2007
@@ -0,0 +1,29 @@
+ ------
+Tapestry Testing
+ ------
+Jesse Kuhnert
+ ------
+29 April 2007
+ ------
+
+Tapestry Testing
+
+  This library provides a small set of base classes and utilities to make testing {{{http://tapestry.apache.org}Tapestry}} related
+  pages / components easier. {{{http://testng.org} TestNG}} is used as thefoundation for all test code. This library is based off of
+  the original code provided by the {{{http://howardlewisship.com/tapestry-javaforge/tapestry-testng/} tapestry-testng}} project.
+
+  All of the unit tests for the Tapestry framework use this library, so there should be an endless supply of examples simply by
+  looking at the source of some of those {{{http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/}here}}.
+
+Resources
+
+  The following is a quick list of links / explanations for some of the libraries used.
+
+  * {{{http://testng.org/doc/documentation-main.html}TestNG Documentation}} - Comprehensive documentation covering uses of TestNG.
+
+  * {{{http://easymock.org/EasyMock2_2_Documentation.html}EasyMock Documentation}} - Mock object library that provides ability to test
+    against interfaces / classes without actually having to instantiate real instances of them.
+    
+  * {{{http://openqa.org/selenium-rc/tutorial.html}Selenium}} - Very good integration testing framework used to test your applications
+    by launching instances of web browsers and running the suite in real environments. For ajax testing this is really the only way.
+    
\ No newline at end of file

Added: tapestry/tapestry-test/trunk/src/site/apt/installation.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/apt/installation.apt?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/apt/installation.apt (added)
+++ tapestry/tapestry-test/trunk/src/site/apt/installation.apt Sun Apr 29 13:23:08 2007
@@ -0,0 +1,195 @@
+ ------
+Installation
+ ------
+Jesse Kuhnert
+ ------
+29 April 2007
+ ------
+
+Maven2 Configuration
+
+  This library is currently available only via the {{{http://people.apache.org/repo/m2-snapshot-repository/}maven2 snapshot repositories}}. You'll need
+  to include that repository as a maven plugin repository as well as the necessary project dependencies. A sample project using this library might look
+  like:
+
++-----------------------------------------------------------
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+   ... project meta
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-framework</artifactId>
+            <version>4.1.2-SNAPSHOT</version>
+        </dependency>
+        <dependency> // <----------------------------- The tapestry-test definition
+            <groupId>org.apache.tapestry</groupId>
+            <artifactId>tapestry-test</artifactId>
+            <version>4.1.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>jboss</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.4.ga</version>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>hivemind</groupId>
+            <artifactId>hivemind</artifactId>
+            <version>1.1.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>hivemind</groupId>
+            <artifactId>hivemind-lib</artifactId>
+            <version>1.1.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- Really, a transitive dependency of hivemind. -->
+        <dependency>
+            <groupId>oro</groupId>
+            <artifactId>oro</artifactId>
+            <version>2.0.8</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+            <version>1.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <version>2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymockclassextension</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <version>5.5</version>
+            <classifier>jdk15</classifier>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>junit</groupId>
+                    <artifactId>junit</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>ognl</groupId>
+            <artifactId>ognl</artifactId>
+            <version>2.7-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.4</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.7.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.openqa.selenium.client-drivers</groupId>
+            <artifactId>selenium-java-client-driver</artifactId>
+            <version>0.9.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openqa.selenium.server</groupId>
+            <artifactId>selenium-server</artifactId>
+            <version>0.9.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty</artifactId>
+            <version>6.1.1</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <sourceDirectory>src/java</sourceDirectory>
+        <resources>
+            <resource>
+                <directory>src/java</directory>
+                <includes>
+                    <include>**/*</include>
+                </includes>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>2.4-SNAPSHOT</version>
+                <configuration>
+                    <suiteXmlFiles>
+                        <suiteXmlFile>src/test/conf/testng.xml</suiteXmlFile>
+                    </suiteXmlFiles>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>apache.snapshots</id>
+            <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+        </repository>
+        <repository>
+            <id>openqa</id>
+            <name>OpenQA Maven Repository</name>
+            <url>http://maven.openqa.org/</url>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>apache.snapshots</id>
+            <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>tapestry.javaforge</id>
+            <url>http://howardlewisship.com/repository</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>codehaus.org</id>
+            <url>http://snapshots.repository.codehaus.org</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>codehaus.org</id>
+            <url>http://repository.codehaus.org</url>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>
++-----------------------------------------------------------
\ No newline at end of file

Added: tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css (added)
+++ tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css Sun Apr 29 13:23:08 2007
@@ -0,0 +1,117 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults  */
+
+/* Page background color */
+body { 	font-family: Arial;
+	background-color: white;
+	font-size: 10pt;
+ }
+td { 	font-family: Arial;
+	font-size: 10pt;
+ }
+/* Table colors */
+.TableHeadingColor     { background: #F4F4F4 }
+.TableSubHeadingColor  { background: #F4F4F4 }
+.TableRowColor         { background: #FFFFFF }
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont   { font-size: normal; font-family: Arial }
+.FrameHeadingFont { font-size: normal; font-family: Arial }
+.FrameItemFont    { font-size: normal; font-family: Arial }
+
+/* Example of smaller, sans-serif font in frames */
+/* .FrameItemFont  { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */
+
+/* Navigation bar fonts and colors */
+.NavBarCell1    { background-color:#F4F4F4;}
+.NavBarCell1Rev { background-color:silver;}
+
+.NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+
+A {
+    color: #003399;
+}
+
+A:active {
+    color: #003399;
+}
+
+A:visited {
+    color: #888888;
+}
+
+P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE {
+    color: #000000;
+}
+
+TD, TH, SPAN {
+    color: #000000;
+}
+
+BLOCKQUOTE {
+    margin-right: 0px;
+}
+
+
+/*H1, H2, H3, H4, H5, H6    {
+    color: #000000;
+    font-weight:500;
+    margin-top:10px;
+    padding-top:15px;
+}
+
+H1 { font-size: 150%; }
+H2 { font-size: 140%; }
+H3 { font-size: 110%; font-weight: bold; }
+H4 { font-size: 110%; font-weight: bold;}
+H5 { font-size: 100%; font-style: italic; }
+H6 { font-size: 100%; font-style: italic; }*/
+
+TT {
+font-size: 90%;
+    font-family: "Courier New", Courier, monospace;
+    color: #000000;
+}
+
+PRE {
+font-size: 90%;
+    padding: 5px;
+    border-style: solid;
+    border-width: 1px;
+    border-color: #CCCCCC;
+    background-color: #F4F4F4;
+}
+
+UL, OL, LI {
+    list-style: disc;
+}
+
+HR  {
+    width: 100%;
+    height: 1px;
+    background-color: #CCCCCC;
+    border-width: 0px;
+    padding: 0px;
+    color: #CCCCCC;
+}
+
+.variablelist { 
+    padding-top: 10; 
+    padding-bottom:10; 
+    margin:0;
+}
+
+.itemizedlist, UL { 
+    padding-top: 0; 
+    padding-bottom:0; 
+    margin:0; 
+}
+
+.term { 
+    font-weight:bold;
+}

Propchange: tapestry/tapestry-test/trunk/src/site/resources/css/jdstyle.css
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/site/resources/css/site.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/resources/css/site.css?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/resources/css/site.css (added)
+++ tapestry/tapestry-test/trunk/src/site/resources/css/site.css Sun Apr 29 13:23:08 2007
@@ -0,0 +1,5 @@
+
+a.externalLink, a.externalLink:link, a.externalLink:visited, a.externalLink:active, a.externalLink:hover {
+  background: none;
+  padding: 0;
+}

Propchange: tapestry/tapestry-test/trunk/src/site/resources/css/site.css
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/site/site.xml?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/site/site.xml (added)
+++ tapestry/tapestry-test/trunk/src/site/site.xml Sun Apr 29 13:23:08 2007
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<project name="Tapestry">
+    <bannerLeft>
+        <name>Tapestry Web Application Framework</name>
+        <href>http://tapestry.apache.org/</href>
+        <src>images/tapestry_banner.gif</src>
+    </bannerLeft>
+    <bannerRight>
+        <name>Apache Software Foundation</name>
+        <href>http://www.apache.org</href>
+        <src>images/asf_logo_wide.gif</src>
+    </bannerRight>
+
+    <skin>
+        <groupId>org.apache.tapestry</groupId>
+        <artifactId>maven-skin</artifactId>
+        <version>1.1</version>
+    </skin>
+
+    <publishDate format="dd MMM yyyy" />
+
+    <body>
+        <links>
+            <item name="Tapestry" href="http://tapestry.apache.org/" />
+            <item name="Hivemind" href="http://hivemind.apache.org/" />
+            <item name="Apache" href="http://www.apache.org/" />
+        </links>
+
+        <head>
+            <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
+            <script type="text/javascript">_uacct = "UA-400821-1"; urchinTracker();</script>
+            <link rel="shortcut icon" href="http://tapestry.apache.org/tapestry4.1/favicon.ico" />
+        </head>
+
+        
+        <menu name="Documentation" >
+
+            <item name="Introduction" href="/index.html" />
+            <item name="Installation" href="/installation.html" />
+            <item name="Getting Started" href="/gettingstarted.html" />
+            <item name="EasyMock" href="/easymock.html" />
+            <item name="Testing Components" href="/components.html" />
+
+        </menu>
+
+        ${reports}
+    </body>
+
+</project>

Propchange: tapestry/tapestry-test/trunk/src/site/site.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/test/conf/testng.xml?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/test/conf/testng.xml (added)
+++ tapestry/tapestry-test/trunk/src/test/conf/testng.xml Sun Apr 29 13:23:08 2007
@@ -0,0 +1,25 @@
+<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
+<!--
+    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.
+-->
+
+<suite name="tapestry-testng" parallel="methods" thread-count="5">
+    <test verbose="2" name="Base" annotations="1.5">
+        <classes>
+            <class name="org.apache.tapestry.CapturerTest" />
+            <class name="org.apache.tapestry.TestBaseTest" />
+        </classes>
+    </test>
+</suite>

Propchange: tapestry/tapestry-test/trunk/src/test/conf/testng.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java (added)
+++ tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,99 @@
+package org.apache.tapestry;
+
+import static org.apache.tapestry.Capturer.capture;
+import static org.apache.tapestry.Capturer.newCapturer;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+/** @author Howard M. Lewis Ship */
+@Test(groups =
+{ "default" })
+public class CapturerTest extends TestBase
+{
+    /** Normal behavior. */
+    @Test
+    public void standard()
+    {
+        List<String> l = newList();
+        String value = "SOME VALUE";
+
+        Capturer<String> c = newCapturer(String.class);
+
+        l.add(capture(c));
+        setReturnValue(false);
+
+        replay();
+
+        l.add(value);
+
+        verify();
+
+        assertSame(c.getCaptured(), value);
+    }
+
+    /**
+     * Tests behavior when an object of the wrong type is passed to the Capturer. This includes the
+     * logic that generates a text description of the Capturer for the message in the thrown
+     * exception.
+     */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void captured_parameter_type_does_not_match_expectation()
+    {
+        List l = newList();
+        Integer value = 999;
+
+        Capturer<String> c = newCapturer(String.class);
+
+        l.add(capture(c));
+        setReturnValue(false);
+
+        replay();
+
+        try
+        {
+            l.add(value);
+            unreachable();
+        }
+        catch (AssertionError err)
+        {
+            assertTrue(err.getMessage().contains("capture(java.lang.String)"));
+        }
+
+        assertNull(c.getCaptured());
+    }
+
+    /** Check that a Capturer rejects null values, just like values that aren't the correct type. */
+    @Test
+    public void captured_parameter_value_is_null()
+    {
+        List<String> l = newList();
+
+        Capturer<String> c = newCapturer(String.class);
+
+        l.add(capture(c));
+        setReturnValue(false);
+
+        replay();
+
+        try
+        {
+            l.add(null);
+            unreachable();
+        }
+        catch (AssertionError err)
+        {
+            assertTrue(err.getMessage().contains("capture(java.lang.String)"));
+        }
+
+        assertNull(c.getCaptured());
+    }
+
+    @SuppressWarnings("unchecked")
+    protected final List<String> newList()
+    {
+        return newMock(List.class);
+    }
+}
+

Propchange: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/CapturerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java (added)
+++ tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,26 @@
+package org.apache.tapestry;
+
+
+import org.testng.annotations.Test;
+
+/** @author Howard M. Lewis Ship */
+@Test(groups =
+{ "default" })
+public class JettyRunnerTest
+{
+    @Test
+    public void run()
+    {
+        JettyRunner runner = new JettyRunner("/ctx", 8080, "src/test/webapp");
+
+        try
+        {
+            
+        }
+        finally
+        {
+            runner.stop();
+        }
+
+    }
+}

Propchange: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/JettyRunnerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java (added)
+++ tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java Sun Apr 29 13:23:08 2007
@@ -0,0 +1,149 @@
+package org.apache.tapestry;
+
+import org.apache.tapestry.components.Insert;
+import org.apache.tapestry.html.BasePage;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+/**
+ * Who tests the testers? We do!
+ *
+ * @author Howard M. Lewis Ship
+ */
+@Test(groups =
+{ "default" })
+public class TestBaseTest extends TestBase
+{
+    /** Test that you can create new component instances (with Creator under the covers). */
+    @Test
+    public void creator()
+    {
+        IPage page = newInstance(BasePage.class, "pageName", "Fred");
+        Insert insert = newInstance(
+                Insert.class,
+                "id",
+                "flintstone",
+                "container",
+                page,
+                "page",
+                page);
+
+        assertEquals(insert.getExtendedId(), "Fred/flintstone");
+    }
+
+    @Test
+    public void exersize_mock_factories()
+    {
+        assertNotNull(newRequestCycle());
+    }
+
+    /** Test basic creation, training, and verification. */
+    @SuppressWarnings("unchecked")
+    @Test
+    public void create_and_train_mock()
+    {
+        Object o = new Object();
+
+        List l = newMock(List.class);
+
+        l.add(o);
+        setReturnValue(false);
+
+        replay();
+
+        assertEquals(false, l.add(o));
+
+        verify();
+    }
+
+    @Test(invocationCount = 20, threadPoolSize = 5)
+    public void ensure_that_mocks_control_access_is_threadsafe()
+    {
+        IMarkupWriter writer = newMarkupWriter();
+
+        writer.print("");
+
+        replay();
+
+        writer.print("");
+
+        verify();
+    }
+
+    @Test(expectedExceptions = AssertionError.class)
+    public void test_unreachable()
+    {
+        // This is expected to fail.
+        unreachable();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void set_throwable() throws Exception
+    {
+        Object o = new Object();
+        List l = newMock(List.class);
+        RuntimeException re = new RuntimeException();
+
+        l.add(o);
+        setThrowable(re);
+
+        replay();
+
+        try
+        {
+            l.add(o);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertSame(ex, re);
+        }
+
+        verify();
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verify_that_method_invocation_order_counts()
+    {
+        Object o = new Object();
+        List l1 = newMock(List.class);
+        List l2 = newMock(List.class);
+
+        l1.add(o);
+        setReturnValue(false);
+
+        l2.add(o);
+        setReturnValue(true);
+
+        replay();
+
+        assertEquals(false, l1.add(o));
+        assertEquals(true, l2.add(o));
+
+        verify();
+
+        // OK, more training
+
+        l1.add(o);
+        setReturnValue(false);
+
+        l2.add(o);
+        setReturnValue(true);
+
+        replay();
+
+        try
+        {
+            // Violated the script, did not invoke method on l1 first.
+            l2.add(o);
+            unreachable();
+        }
+        catch (AssertionError ex)
+        {
+            assertTrue(ex.getMessage().contains("Unexpected method call"));
+        }
+    }
+}

Propchange: tapestry/tapestry-test/trunk/src/test/java/org/apache/tapestry/TestBaseTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry-test/trunk/src/test/webapp/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry-test/trunk/src/test/webapp/index.html?view=auto&rev=533554
==============================================================================
--- tapestry/tapestry-test/trunk/src/test/webapp/index.html (added)
+++ tapestry/tapestry-test/trunk/src/test/webapp/index.html Sun Apr 29 13:23:08 2007
@@ -0,0 +1,8 @@
+<html>
+    <head>
+        <title>Jetty is Running</title>
+    </head>
+    <body>
+        <h1>Jetty is running care/of JettyRunner</h1>
+    </body>
+</html>

Propchange: tapestry/tapestry-test/trunk/src/test/webapp/index.html
------------------------------------------------------------------------------
    svn:eol-style = native