You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by fr...@apache.org on 2006/12/17 09:34:35 UTC

svn commit: r487949 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/dom/ main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapest...

Author: freemant
Date: Sun Dec 17 00:34:33 2006
New Revision: 487949

URL: http://svn.apache.org/viewvc?view=rev&rev=487949
Log:
Supports unit testing of pages/components/ See IfTest.java for an example which 
tests the If component. Currently the test harness only supports simple rendering
of simple pages (no context, no session).

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/FooModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/Main.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForIf.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryAppInitializerTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IdentifyTransformer.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/Transformer.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/UppercaseTransformer.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForIf.html
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Document.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParserExperiment.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/basic.html

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/TapestryFilter.java Sun Dec 17 00:34:33 2006
@@ -30,13 +30,11 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.tapestry.internal.InternalConstants;
+import org.apache.tapestry.internal.TapestryAppInitializer;
 import org.apache.tapestry.ioc.IOCUtilities;
 import org.apache.tapestry.ioc.Registry;
 import org.apache.tapestry.ioc.RegistryBuilder;
-import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.services.ComponentClassResolver;
 import org.apache.tapestry.services.HttpServletRequestHandler;
-import org.apache.tapestry.services.Infrastructure;
 import org.apache.tapestry.services.ServletApplicationInitializer;
 import org.apache.tapestry.services.TapestryModule;
 
@@ -56,69 +54,27 @@
     private HttpServletRequestHandler _handler;
 
     /**
-     * Initializes the filter by building the {@link Registry}. The registry contains
-     * {@link org.apache.tapestry.ioc.services.TapestryIOCModule} and {@link TapestryModule}, any
-     * modules identified by {@link #addModules(RegistryBuilder)}, plus the application module.
-     * <p>
-     * The application module is optional.
-     * <p>
-     * The application module is identified as <em>package</em>.services.<em>Name</em>Module,
-     * where <em>package</em> is defined by the <code>tapestry.app-package</code> context init
-     * parameter and <em>Name</em> is the capitalization of the filter name (as specified in
-     * web.xml).
+     * Initializes the filter using the {@link TapestryAppInitializer}. The application package is
+     * defined by the <code>tapestry.app-package</code> context init parameter and the application
+     * name is the capitalization of the filter name (as specified in web.xml).
      */
     public final void init(FilterConfig filterConfig) throws ServletException
     {
         _config = filterConfig;
 
-        long start = System.currentTimeMillis();
-
-        RegistryBuilder builder = new RegistryBuilder();
-
-        builder.add(TapestryModule.class);
-
         // Note: configured as a <context-param>, not a filter <init-param>
         String appPackage = _config.getServletContext().getInitParameter(
                 InternalConstants.TAPESTRY_APP_PACKAGE_PARAM);
         String filterName = _config.getFilterName();
 
-        String className = appPackage + ".services." + InternalUtils.capitalize(filterName)
-                + "Module";
+        TapestryAppInitializer appInitializer = new TapestryAppInitializer(appPackage, filterName,
+                "servlet");
+
+        _registry = appInitializer.getRegistry();
 
-        try
-        {
-            // TapestryFilter is possibly loaded by a parent class loader of the application class
-            // loader. The context class loader should have the approprite view to the module class,
-            // if any.
-
-            Class moduleClass = Thread.currentThread().getContextClassLoader().loadClass(className);
-            builder.add(moduleClass);
-        }
-        catch (ClassNotFoundException ex)
-        {
-            // That's OK, not all applications will have a module class, even though any
-            // non-trivial application will.
-        }
-
-        addModules(builder);
-
-        _registry = builder.build();
-
-        long toRegistry = System.currentTimeMillis();
-
-        Infrastructure infra = _registry
-                .getService("tapestry.Infrastructure", Infrastructure.class);
-        infra.setMode("servlet");
-
-        // It would be nice to move this logic inside ApplicationInitializer,
-        // may have to pass in the FilterConfig, or maybe a wrapper around
-        // it.
-
-        ComponentClassResolver resolver = _registry.getService(
-                "tapestry.ComponentClassResolver",
-                ComponentClassResolver.class);
+        long start = appInitializer.getStartTime();
 
-        resolver.setApplicationPackage(appPackage);
+        long toRegistry = appInitializer.getRegistryCreatedTime();
 
         ServletApplicationInitializer ai = _registry.getService(
                 "tapestry.ServletApplicationInitializer",

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Document.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Document.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Document.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Document.java Sun Dec 17 00:34:33 2006
@@ -12,65 +12,82 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.dom;
-
-import java.io.PrintWriter;
-
-/**
- * The root node of a DOM.
- */
-public final class Document extends Node
-{
-    private Element _rootElement;
-
-    private final MarkupModel _model;
-
-    public Document(MarkupModel model)
-    {
-        super(null);
-        _model = model;
-    }
-
-    Document getDocument()
-    {
-        return this;
-    }
-
-    /** Builds with an instance of {@link DefaultMarkupModel}. */
-    public Document()
-    {
-        this(new DefaultMarkupModel());
-    }
-
-    public MarkupModel getMarkupModel()
-    {
-        return _model;
-    }
-
-    /** Creates the root element for this document, replacing any previous root element. */
-    public Element newRootElement(String name)
-    {
-        _rootElement = new Element(this, name);
-
-        return _rootElement;
-    }
-
-    @Override
-    public void toMarkup(PrintWriter writer)
-    {
-        if (_rootElement == null)
-            throw new IllegalStateException("No root element has been defined.");
-
-        // TODO: XML declaration, plus lead-in comments, directives, DOCTYPE.
-        _rootElement.toMarkup(writer);
-    }
-
-    @Override
-    public String toString()
-    {
-        if (_rootElement == null)
-            return "[empty Document]";
-
-        return super.toString();
-    }
-}
+package org.apache.tapestry.dom;
+
+import java.io.PrintWriter;
+
+/**
+ * The root node of a DOM.
+ */
+public final class Document extends Node
+{
+    private Element _rootElement;
+
+    private final MarkupModel _model;
+
+    public Document(MarkupModel model)
+    {
+        super(null);
+        _model = model;
+    }
+
+    Document getDocument()
+    {
+        return this;
+    }
+
+    /** Builds with an instance of {@link DefaultMarkupModel}. */
+    public Document()
+    {
+        this(new DefaultMarkupModel());
+    }
+
+    public MarkupModel getMarkupModel()
+    {
+        return _model;
+    }
+
+    /** Creates the root element for this document, replacing any previous root element. */
+    public Element newRootElement(String name)
+    {
+        _rootElement = new Element(this, name);
+
+        return _rootElement;
+    }
+
+    @Override
+    public void toMarkup(PrintWriter writer)
+    {
+        if (_rootElement == null)
+            throw new IllegalStateException("No root element has been defined.");
+
+        // TODO: XML declaration, plus lead-in comments, directives, DOCTYPE.
+        _rootElement.toMarkup(writer);
+    }
+
+    @Override
+    public String toString()
+    {
+        if (_rootElement == null)
+            return "[empty Document]";
+
+        return super.toString();
+    }
+
+    public Element getRootElement()
+    {
+        return _rootElement;
+    }
+
+    /**
+     * Tries to find an element in this document whose id is specified.
+     * 
+     * @param id
+     *            the value of the id attribute of the element being looked for
+     * @return the element if found. null if not found.
+     */
+    public Element getElementById(String id)
+    {
+        return _rootElement.getElementById(id);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java Sun Dec 17 00:34:33 2006
@@ -12,179 +12,220 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.dom;
-
+package org.apache.tapestry.dom;
+
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
-
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An element that will render with a begin tag and attributes, a body, and an end tag. Also acts as
- * a factory for enclosed Element, Text and Comment nodes. TODO: Support for CDATA nodes. Do we need
- * Entity nodes?
- */
-public final class Element extends Node
-{
-    private final String _name;
-
-    private Map<String, String> _attributes;
-
-    private Element _parent;
-
-    private final Document _document;
-
-    Element(Document container, String name)
-    {
-        super(container);
-
-        _document = container;
-        _name = name;
-    }
-
-    Element(Element parent, String name)
-    {
-        super(parent);
-
-        _parent = parent;
-        _name = name;
-
-        _document = parent.getDocument();
-    }
-
-    public Document getDocument()
-    {
-        return _document;
-    }
-
-    /**
-     * Returns the containing element for this element. This will be null for the root element of a
-     * document.
-     */
-    public Element getParent()
-    {
-        return _parent;
-    }
-
-    /**
-     * Adds an attribute to the element, but only if the attribute name does not already exist.
-     * 
-     * @param name
-     *            the name of the attribute to add
-     * @param value
-     *            the value for the attribute. A value of null is allowed, and no attribute will be
-     *            added to the element.
-     */
-    public void attribute(String name, String value)
-    {
-        notBlank(name, "name");
-
-        if (value == null)
-            return;
-
-        if (_attributes == null)
-            _attributes = newMap();
-
-        if (!_attributes.containsKey(name))
-            _attributes.put(name, value);
-    }
-
-    /**
-     * Convienience for invoking {@link #attribute(String, String)} multiple times.
-     * 
-     * @param namesAndValues
-     *            alternating attribute names and attribute values
-     */
-    public void attributes(String... namesAndValues)
-    {
-        int i = 0;
-        while (i < namesAndValues.length)
-        {
-            String name = namesAndValues[i++];
-            String value = namesAndValues[i++];
-
-            attribute(name, value);
-        }
-    }
-
-    /**
-     * Creates and returns a new Element node as a child of this node.
-     * 
-     * @param name
-     *            the name of the element to create
-     * @param namesAndValues
-     *            alternating attribute names and attribute values
-     */
-    public Element element(String name, String... namesAndValues)
-    {
-        notBlank(name, "name");
-
-        Element child = newChild(new Element(this, name));
-
-        child.attributes(namesAndValues);
-
-        return child;
-    }
-
-    public Comment comment(String text)
-    {
-        return newChild(new Comment(this, text));
-    }
-
-    public Text text(String text)
-    {
-        return newChild(new Text(this, _document, text));
-    }
-
-    private <T extends Node> T newChild(T child)
-    {
-        addChild(child);
-
-        return child;
-    }
-
-    @Override
-    public void toMarkup(PrintWriter writer)
-    {
-        writer.printf("<%s", _name);
-
-        if (_attributes != null)
-        {
-            List<String> keys = newList(_attributes.keySet());
-            Collections.sort(keys);
-
-            for (String key : keys)
-            {
-                String value = _attributes.get(key);
-
-                // TODO: URL encoding of attributes!
-
-                writer.printf(" %s=\"%s\"", key, value);
-            }
-        }
-
-        EndTagStyle style = _document.getMarkupModel().getEndTagStyle(_name);
-
-        boolean hasChildren = hasChildren();
-
-        String close = (!hasChildren && style == EndTagStyle.ABBREVIATE) ? "/>" : ">";
-
-        writer.print(close);
-
-        if (hasChildren)
-            writeChildXML(writer);
-
-        // Dangerous -- perhaps it should be an error for a tag of type OMIT to even have children!
-        // We'll certainly be writing out unbalanced markup in that case.
-
-        if (style == EndTagStyle.OMIT)
-            return;
-
-        if (hasChildren || style == EndTagStyle.REQUIRE)
-            writer.printf("</%s>", _name);
-    }
-}
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tapestry.ioc.internal.util.Defense;
+
+/**
+ * An element that will render with a begin tag and attributes, a body, and an end tag. Also acts as
+ * a factory for enclosed Element, Text and Comment nodes. TODO: Support for CDATA nodes. Do we need
+ * Entity nodes?
+ */
+public final class Element extends Node
+{
+    private final String _name;
+
+    private Map<String, String> _attributes;
+
+    private Element _parent;
+
+    private final Document _document;
+
+    Element(Document container, String name)
+    {
+        super(container);
+
+        _document = container;
+        _name = name;
+    }
+
+    Element(Element parent, String name)
+    {
+        super(parent);
+
+        _parent = parent;
+        _name = name;
+
+        _document = parent.getDocument();
+    }
+
+    public Document getDocument()
+    {
+        return _document;
+    }
+
+    /**
+     * Returns the containing element for this element. This will be null for the root element of a
+     * document.
+     */
+    public Element getParent()
+    {
+        return _parent;
+    }
+
+    /**
+     * Adds an attribute to the element, but only if the attribute name does not already exist.
+     * 
+     * @param name
+     *            the name of the attribute to add
+     * @param value
+     *            the value for the attribute. A value of null is allowed, and no attribute will be
+     *            added to the element.
+     */
+    public void attribute(String name, String value)
+    {
+        notBlank(name, "name");
+
+        if (value == null)
+            return;
+
+        if (_attributes == null)
+            _attributes = newMap();
+
+        if (!_attributes.containsKey(name))
+            _attributes.put(name, value);
+    }
+
+    /**
+     * Convienience for invoking {@link #attribute(String, String)} multiple times.
+     * 
+     * @param namesAndValues
+     *            alternating attribute names and attribute values
+     */
+    public void attributes(String... namesAndValues)
+    {
+        int i = 0;
+        while (i < namesAndValues.length)
+        {
+            String name = namesAndValues[i++];
+            String value = namesAndValues[i++];
+
+            attribute(name, value);
+        }
+    }
+
+    /**
+     * Creates and returns a new Element node as a child of this node.
+     * 
+     * @param name
+     *            the name of the element to create
+     * @param namesAndValues
+     *            alternating attribute names and attribute values
+     */
+    public Element element(String name, String... namesAndValues)
+    {
+        notBlank(name, "name");
+
+        Element child = newChild(new Element(this, name));
+
+        child.attributes(namesAndValues);
+
+        return child;
+    }
+
+    public Comment comment(String text)
+    {
+        return newChild(new Comment(this, text));
+    }
+
+    public Text text(String text)
+    {
+        return newChild(new Text(this, _document, text));
+    }
+
+    private <T extends Node> T newChild(T child)
+    {
+        addChild(child);
+
+        return child;
+    }
+
+    @Override
+    public void toMarkup(PrintWriter writer)
+    {
+        writer.printf("<%s", _name);
+
+        if (_attributes != null)
+        {
+            List<String> keys = newList(_attributes.keySet());
+            Collections.sort(keys);
+
+            for (String key : keys)
+            {
+                String value = _attributes.get(key);
+
+                // TODO: URL encoding of attributes!
+
+                writer.printf(" %s=\"%s\"", key, value);
+            }
+        }
+
+        EndTagStyle style = _document.getMarkupModel().getEndTagStyle(_name);
+
+        boolean hasChildren = hasChildren();
+
+        String close = (!hasChildren && style == EndTagStyle.ABBREVIATE) ? "/>" : ">";
+
+        writer.print(close);
+
+        if (hasChildren)
+            writeChildXML(writer);
+
+        // Dangerous -- perhaps it should be an error for a tag of type OMIT to even have children!
+        // We'll certainly be writing out unbalanced markup in that case.
+
+        if (style == EndTagStyle.OMIT)
+            return;
+
+        if (hasChildren || style == EndTagStyle.REQUIRE)
+            writer.printf("</%s>", _name);
+    }
+
+    /**
+     * Tries to find an element under this element (including itself) whose id is specified.
+     * 
+     * @param id
+     *            the value of the id attribute of the element being looked for
+     * @return the element if found. null if not found.
+     */
+    public Element getElementById(String id)
+    {
+        Defense.notNull(id, "id");
+        if (id.equals(getAttribute("id")))
+        {
+            return this;
+        }
+        for (Node child : getChildren())
+        {
+            if (child instanceof Element)
+            {
+                Element elementChild = (Element) child;
+                Element searchResult = elementChild.getElementById(id);
+                if (searchResult != null)
+                {
+                    return searchResult;
+                }
+            }
+        }
+        return null;
+
+    }
+
+    public String getAttribute(String attributeName)
+    {
+        if (_attributes == null)
+        {
+            return null;
+        }
+        return _attributes.get(attributeName);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Node.java Sun Dec 17 00:34:33 2006
@@ -18,6 +18,7 @@
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -81,6 +82,12 @@
         pw.close();
 
         return stringWriter.toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<Node> getChildren()
+    {
+        return _children == null ? Collections.EMPTY_LIST : _children;
     }
 
     /** Writes the markup for this node to the writer. */

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/TapestryAppInitializer.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,134 @@
+// 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;
+
+import org.apache.tapestry.ioc.IOCUtilities;
+import org.apache.tapestry.ioc.Registry;
+import org.apache.tapestry.ioc.RegistryBuilder;
+import org.apache.tapestry.ioc.internal.util.InternalUtils;
+import org.apache.tapestry.services.ComponentClassResolver;
+import org.apache.tapestry.services.Infrastructure;
+import org.apache.tapestry.services.TapestryModule;
+
+/**
+ * This class is used to build the {@link Registry}. The registry contains
+ * {@link org.apache.tapestry.ioc.services.TapestryIOCModule} and {@link TapestryModule}, any
+ * modules identified by {@link #addModules(RegistryBuilder)}, plus the application module.
+ * <p>
+ * The application module is optional.
+ * <p>
+ * The application module is identified as <em>package</em>.services.<em>appName</em>Module,
+ * where <em>package</em> and the <em>appName</em> are specified by the caller.
+ */
+public class TapestryAppInitializer
+{
+    private String appPackage;
+
+    private String appName;
+
+    private String infrastructureMode;
+
+    private Registry registry;
+
+    private long startTime;
+
+    private long registryCreatedTime;
+
+    public TapestryAppInitializer(String appPackage, String appName, String infrastructureMode)
+    {
+        this.appPackage = appPackage;
+        this.appName = appName;
+        this.infrastructureMode = infrastructureMode;
+        startTime = System.currentTimeMillis();
+        createRegistry();
+        registryCreatedTime = System.currentTimeMillis();
+        setupServices();
+    }
+
+    private void createRegistry()
+    {
+        RegistryBuilder builder = new RegistryBuilder();
+
+        builder.add(TapestryModule.class);
+
+        String className = appPackage + ".services." + InternalUtils.capitalize(appName) + "Module";
+
+        try
+        {
+            // This class is possibly loaded by a parent class loader of the application class
+            // loader. The context class loader should have the approprite view to the module class,
+            // if any.
+
+            Class moduleClass = Thread.currentThread().getContextClassLoader().loadClass(className);
+            builder.add(moduleClass);
+        }
+        catch (ClassNotFoundException ex)
+        {
+            // That's OK, not all applications will have a module class, even though any
+            // non-trivial application will.
+        }
+
+        addModules(builder);
+
+        registry = builder.build();
+    }
+
+    private void setupServices()
+    {
+        Infrastructure infra = registry.getService("tapestry.Infrastructure", Infrastructure.class);
+        infra.setMode(infrastructureMode);
+
+        ComponentClassResolver resolver = registry.getService(
+                "tapestry.ComponentClassResolver",
+                ComponentClassResolver.class);
+
+        resolver.setApplicationPackage(appPackage);
+    }
+
+    /**
+     * Adds additional modules to the builder. This implementation adds any modules identified by
+     * {@link IOCUtilities#addDefaultModules(RegistryBuilder)}. Most subclasses will invoke this
+     * implementation, and add additional modules to the RegistryBuilder besides.
+     * {@link org.apache.tapestry.ioc.services.TapestryIOCModule} and {@link TapestryModule} will
+     * already have been added, as will an application module if present.
+     * 
+     * @param builder
+     */
+    protected void addModules(RegistryBuilder builder)
+    {
+        IOCUtilities.addDefaultModules(builder);
+    }
+
+    public Registry getRegistry()
+    {
+        return registry;
+    }
+
+    /**
+     * @return the system time (in ms) when the registry has been created successfully.
+     */
+    public long getRegistryCreatedTime()
+    {
+        return registryCreatedTime;
+    }
+
+    /**
+     * @return the time when the initialization was started.
+     */
+    public long getStartTime()
+    {
+        return startTime;
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java Sun Dec 17 00:34:33 2006
@@ -240,12 +240,19 @@
     }
 
     public static PageResponseRenderer buildPageResponseRenderer(
+            @InjectService("PageMarkupRenderer")
+            PageMarkupRenderer markupRenderer,
             @InjectService("tapestry.MarkupWriterFactory")
-            MarkupWriterFactory markupWriterFactory,
+            MarkupWriterFactory markupWriterFactory)
+    {
+        return new PageResponseRendererImpl(markupWriterFactory, markupRenderer);
+    }
+
+    public static PageMarkupRenderer buildPageMarkupRenderer(
             @InjectService("tapestry.PageRenderInitializer")
             PageRenderInitializer pageRenderInitializer)
     {
-        return new PageResponseRendererImpl(markupWriterFactory, pageRenderInitializer);
+        return new PageMarkupRendererImpl(pageRenderInitializer);
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java Sun Dec 17 00:34:33 2006
@@ -53,6 +53,11 @@
     public String toString()
     {
         return _document.toString();
+    }
+    
+    public Document getDocument()
+    {
+        return _document;
     }
 
     public void write(String text)

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,24 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+
+public interface PageMarkupRenderer
+{
+    void renderPageMarkup(Page page, MarkupWriter writer);
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,45 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.services.PageRenderInitializer;
+
+public class PageMarkupRendererImpl implements PageMarkupRenderer
+{
+    private final PageRenderInitializer _pageRenderInitializer;
+
+    public PageMarkupRendererImpl(PageRenderInitializer pageRenderInitializer)
+    {
+        _pageRenderInitializer = pageRenderInitializer;
+    }
+
+    public void renderPageMarkup(Page page, MarkupWriter writer)
+    {
+        _pageRenderInitializer.setup();
+
+        RenderQueueImpl queue = new RenderQueueImpl(page.getLog());
+
+        queue.push(page.getRootElement());
+
+        // Run the queue until empty.
+
+        queue.run(writer);
+
+        _pageRenderInitializer.cleanup();
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageResponseRendererImpl.java Sun Dec 17 00:34:33 2006
@@ -20,40 +20,29 @@
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.services.MarkupWriterFactory;
-import org.apache.tapestry.services.PageRenderInitializer;
 import org.apache.tapestry.services.Response;
 
 public class PageResponseRendererImpl implements PageResponseRenderer
 {
-    private final PageRenderInitializer _pageRenderInitializer;
-
+    private final PageMarkupRenderer _markupRenderer;
+    
     private final MarkupWriterFactory _markupWriterFactory;
 
     public PageResponseRendererImpl(MarkupWriterFactory markupWriterFactory,
-            PageRenderInitializer pageRenderInitializer)
+            PageMarkupRenderer markupRenderer)
     {
         _markupWriterFactory = markupWriterFactory;
-        _pageRenderInitializer = pageRenderInitializer;
+        _markupRenderer = markupRenderer;
     }
 
     public void renderPageResponse(Page page, Response response) throws IOException
     {
-        _pageRenderInitializer.setup();
-
         // Eventually we'll have to do work to figure out the correct markup type, content type,
         // whatever. Right now its defaulting to plain HTML.
 
         MarkupWriter writer = _markupWriterFactory.newMarkupWriter();
-
-        RenderQueueImpl queue = new RenderQueueImpl(page.getLog());
-
-        queue.push(page.getRootElement());
-
-        // Run the queue until empty.
-
-        queue.run(writer);
-
-        _pageRenderInitializer.cleanup();
+        
+        _markupRenderer.renderPageMarkup(page, writer);
 
         PrintWriter pw = response.getPrintWriter();
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/pagelevel/PageTester.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,77 @@
+// 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.test.pagelevel;
+
+import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.internal.TapestryAppInitializer;
+import org.apache.tapestry.internal.services.MarkupWriterImpl;
+import org.apache.tapestry.internal.services.PageMarkupRenderer;
+import org.apache.tapestry.internal.services.RequestPageCache;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.ioc.Registry;
+
+/**
+ * This class is used to run a Tapestry app in an in-process testing environment. You can ask it to
+ * render a certain page and check the DOM object created. Because no servlet container is required,
+ * it is very fast and you can directly debug into your code in your IDE.
+ */
+public class PageTester
+{
+    private Registry registry;
+
+    private PageMarkupRenderer renderer;
+
+    private RequestPageCache cache;
+
+    /**
+     * @param appPackage
+     *            the same value you would specify using the tapestry.app-package context parameter.
+     *            As this testing environment is not run in a servlet container, you need to specify
+     *            it.
+     * @param appName
+     *            the same value you would specify as the filter name. It is used to form the name
+     *            of the module builder for your app. If you don't have one, pass an empty string.
+     */
+    public PageTester(String appPackage, String appName)
+    {
+        registry = new TapestryAppInitializer(appPackage, appName, "test").getRegistry();
+        renderer = registry.getService(PageMarkupRenderer.class);
+        cache = registry.getService(RequestPageCache.class);
+    }
+
+    /** You should call it after use */
+    public void shutdown()
+    {
+        if (registry != null)
+        {
+            registry.shutdown();
+        }
+    }
+
+    /**
+     * Renders a page specified by its name.
+     * 
+     * @param pageName
+     *            the name of the page to be rendered.
+     * @return the DOM created. Typically you to assert against it.
+     */
+    public Document renderPage(String pageName)
+    {
+        Page page = cache.get(pageName);
+        MarkupWriterImpl writer = new MarkupWriterImpl();
+        renderer.renderPageMarkup(page, writer);
+        return writer.getDocument();
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/conf/testng.xml Sun Dec 17 00:34:33 2006
@@ -18,10 +18,12 @@
 <suite name="Tapestry Core" parallel="false" thread-count="10" annotations="1.5" verbose="2">
   <test name="Tapestry Core">
     <packages>
+      <package name="org.apache.tapestry.integration.pagelevel"/>
       <package name="org.apache.tapestry.integration"/>
       <package name="org.apache.tapestry"/>
       <package name="org.apache.tapestry.dom"/>
       <package name="org.apache.internal"/>
+      <package name="org.apache.tapestry.internal"/>
       <package name="org.apache.tapestry.internal.aspects"/>
       <package name="org.apache.tapestry.internal.services"/>
       <package name="org.apache.tapestry.internal.structure"/>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java Sun Dec 17 00:34:33 2006
@@ -12,217 +12,229 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.dom;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.LineNumberReader;
-import java.io.Reader;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-/**
- * Tests for a number of DOM node classes, including {@link org.apache.tapestry.dom.Element} and
- * {@link org.apache.tapestry.dom.Document}.
- */
-public class DOMTest extends Assert
-{
-    /**
-     * Reads the content of a file into a string. Each line is trimmed of line separators and
-     * leading/trailing whitespace.
-     */
-    private String readFile(String file) throws Exception
-    {
-        InputStream is = getClass().getResourceAsStream(file);
-        is = new BufferedInputStream(is);
-        Reader reader = new BufferedReader(new InputStreamReader(is));
-        LineNumberReader in = new LineNumberReader(reader);
-
-        StringBuilder buffer = new StringBuilder();
-
-        while (true)
-        {
-            String line = in.readLine();
-
-            if (line == null)
-                break;
-
-            buffer.append(line.trim());
-        }
-
-        in.close();
-
-        return buffer.toString();
-    }
-
-    @Test
-    public void document_with_empty_root_element()
-    {
-        Document d = new Document();
-
-        d.newRootElement("empty");
-
-        assertEquals(d.toString(), "<empty></empty>");
-    }
-
-    @Test
-    public void xml_style_empty_element()
-    {
-        Document d = new Document(new XMLMarkupModel());
-
-        d.newRootElement("empty");
-
-        assertEquals(d.toString(), "<empty/>");
-    }
-
-    /** Also demonstrates that attributes are provided in alphabetical order. */
-    @Test
-    public void document_with_root_element_and_attributes() throws Exception
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("has-attributes");
-
-        e.attribute("fred", "flintstone");
-        e.attribute("barney", "rubble");
-
-        assertEquals(d.toString(), readFile("document_with_root_element_and_attributes.txt"));
-    }
-
-    @Test
-    public void nested_elements() throws Exception
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("population");
-
-        Element p = e.element("person");
-        p.attribute("first-name", "Fred");
-        p.attribute("last-name", "Flintstone");
-
-        assertSame(p.getParent(), e);
-
-        p = e.element("person");
-        p.attribute("first-name", "Barney");
-        p.attribute("last-name", "Rubble");
-
-        assertSame(p.getParent(), e);
-
-        assertEquals(d.toString(), readFile("nested_elements.txt"));
-    }
-
-    @Test
-    public void to_string_on_empty_document()
-    {
-        Document d = new Document();
-
-        assertEquals(d.toString(), "[empty Document]");
-    }
-
-    @Test(expectedExceptions = IllegalArgumentException.class)
-    public void attribute_names_may_not_be_blank()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("fred");
-
-        e.attribute("", "value");
-    }
-
-    @Test
-    public void element_name_may_not_be_blank()
-    {
-        Document d = new Document();
-
-        d.newRootElement("");
-    }
-
-    @Test
-    public void attribute_value_null_is_no_op()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("root");
-
-        e.attribute("foo", "bar");
-
-        final String expected = "<root foo=\"bar\"></root>";
-
-        assertEquals(d.toString(), expected);
-
-        e.attribute("foo", null);
-
-        assertEquals(d.toString(), expected);
-
-        e.attribute("gnip", null);
-
-        assertEquals(d.toString(), expected);
-    }
-
-    @Test
-    public void comments() throws Exception
-    {
-        Document d = new Document();
-
-        // Can't add comments to the document, not yet.
-
-        Element e = d.newRootElement("html");
-
-        e.comment("Created by Tapestry 5.0");
-
-        assertEquals(d.toString(), "<html><!-- Created by Tapestry 5.0 --></html>");
-    }
-
-    @Test
-    public void text()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("body");
-
-        e.text("Tapestry does DOM.");
-
-        assertEquals(d.toString(), "<body>Tapestry does DOM.</body>");
-    }
-
-    @Test
-    public void text_with_control_characters()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("root");
-
-        e.text("<this> & <that>");
-
-        assertEquals(d.toString(), "<root>&lt;this&gt; &amp; &lt;that&gt;</root>");
-    }
-
-    @Test
-    public void specify_attributes_with_new_element()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("root");
-
-        e.element("foo", "alpha", "legion");
-
-        assertEquals(d.toString(), "<root><foo alpha=\"legion\"></foo></root>");
-    }
-
-    @Test
-    public void writef_with_text()
-    {
-        Document d = new Document();
-
-        Element e = d.newRootElement("root");
-
-        Text t = e.text("Start: ");
-
-        t.writef("** %s: %d **", "foo", 5);
-
-        assertEquals(d.toString(), "<root>Start: ** foo: 5 **</root>");
-    }
-}
+package org.apache.tapestry.dom;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.Reader;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for a number of DOM node classes, including {@link org.apache.tapestry.dom.Element} and
+ * {@link org.apache.tapestry.dom.Document}.
+ */
+public class DOMTest extends Assert
+{
+    /**
+     * Reads the content of a file into a string. Each line is trimmed of line separators and
+     * leading/trailing whitespace.
+     */
+    private String readFile(String file) throws Exception
+    {
+        InputStream is = getClass().getResourceAsStream(file);
+        is = new BufferedInputStream(is);
+        Reader reader = new BufferedReader(new InputStreamReader(is));
+        LineNumberReader in = new LineNumberReader(reader);
+
+        StringBuilder buffer = new StringBuilder();
+
+        while (true)
+        {
+            String line = in.readLine();
+
+            if (line == null)
+                break;
+
+            buffer.append(line.trim());
+        }
+
+        in.close();
+
+        return buffer.toString();
+    }
+
+    @Test
+    public void document_with_empty_root_element()
+    {
+        Document d = new Document();
+
+        d.newRootElement("empty");
+
+        assertEquals(d.toString(), "<empty></empty>");
+    }
+
+    @Test
+    public void xml_style_empty_element()
+    {
+        Document d = new Document(new XMLMarkupModel());
+
+        d.newRootElement("empty");
+
+        assertEquals(d.toString(), "<empty/>");
+    }
+
+    /** Also demonstrates that attributes are provided in alphabetical order. */
+    @Test
+    public void document_with_root_element_and_attributes() throws Exception
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("has-attributes");
+
+        e.attribute("fred", "flintstone");
+        e.attribute("barney", "rubble");
+
+        assertEquals(d.toString(), readFile("document_with_root_element_and_attributes.txt"));
+    }
+
+    @Test
+    public void nested_elements() throws Exception
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("population");
+
+        Element p = e.element("person");
+        p.attribute("first-name", "Fred");
+        p.attribute("last-name", "Flintstone");
+
+        assertSame(p.getParent(), e);
+
+        p = e.element("person");
+        p.attribute("first-name", "Barney");
+        p.attribute("last-name", "Rubble");
+
+        assertSame(p.getParent(), e);
+
+        assertEquals(d.toString(), readFile("nested_elements.txt"));
+    }
+
+    @Test
+    public void to_string_on_empty_document()
+    {
+        Document d = new Document();
+
+        assertEquals(d.toString(), "[empty Document]");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void attribute_names_may_not_be_blank()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("fred");
+
+        e.attribute("", "value");
+    }
+
+    @Test
+    public void element_name_may_not_be_blank()
+    {
+        Document d = new Document();
+
+        d.newRootElement("");
+    }
+
+    @Test
+    public void attribute_value_null_is_no_op()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("root");
+
+        e.attribute("foo", "bar");
+
+        final String expected = "<root foo=\"bar\"></root>";
+
+        assertEquals(d.toString(), expected);
+
+        e.attribute("foo", null);
+
+        assertEquals(d.toString(), expected);
+
+        e.attribute("gnip", null);
+
+        assertEquals(d.toString(), expected);
+    }
+
+    @Test
+    public void comments() throws Exception
+    {
+        Document d = new Document();
+
+        // Can't add comments to the document, not yet.
+
+        Element e = d.newRootElement("html");
+
+        e.comment("Created by Tapestry 5.0");
+
+        assertEquals(d.toString(), "<html><!-- Created by Tapestry 5.0 --></html>");
+    }
+
+    @Test
+    public void text()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("body");
+
+        e.text("Tapestry does DOM.");
+
+        assertEquals(d.toString(), "<body>Tapestry does DOM.</body>");
+    }
+
+    @Test
+    public void text_with_control_characters()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("root");
+
+        e.text("<this> & <that>");
+
+        assertEquals(d.toString(), "<root>&lt;this&gt; &amp; &lt;that&gt;</root>");
+    }
+
+    @Test
+    public void specify_attributes_with_new_element()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("root");
+
+        e.element("foo", "alpha", "legion");
+
+        assertEquals(d.toString(), "<root><foo alpha=\"legion\"></foo></root>");
+    }
+
+    @Test
+    public void writef_with_text()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("root");
+
+        Text t = e.text("Start: ");
+
+        t.writef("** %s: %d **", "foo", 5);
+
+        assertEquals(d.toString(), "<root>Start: ** foo: 5 **</root>");
+    }
+
+    @Test
+    public void get_element_by_id()
+    {
+        Document d = new Document();
+        Element e = d.newRootElement("root");
+        Element e1 = e.element("e1", "id", "x");
+        Element e2 = e.element("e2", "id", "y");
+        assertSame(e1.getElementById("x"), e1);
+        assertSame(e.getElementById("y"), e2);
+        assertNull(e.getElementById("z"));
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/FooModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/FooModule.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/FooModule.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app0/services/FooModule.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,29 @@
+// 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.integration.app0.services;
+
+import org.apache.tapestry.ioc.annotations.Id;
+import org.apache.tapestry.util.Transformer;
+import org.apache.tapestry.util.UppercaseTransformer;
+
+@Id("m1")
+public class FooModule
+{
+    public static Transformer buildService1()
+    {
+        return new UppercaseTransformer();
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/Main.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/Main.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/Main.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/Main.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,25 @@
+// 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.integration.app1;
+
+import org.apache.tapestry.integration.IntegrationTests;
+
+public class Main
+{
+    public static void main(String[] args) throws Exception
+    {
+        new IntegrationTests().startupBackground();
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForIf.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForIf.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForIf.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app2/pages/TestPageForIf.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,22 @@
+package org.apache.tapestry.integration.app2.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+
+@ComponentClass
+public class TestPageForIf
+{
+    private boolean property1 = true;
+
+    private boolean property2 = false;
+
+    public boolean isProperty1()
+    {
+        return property1;
+    }
+
+    public boolean isProperty2()
+    {
+        return property2;
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/pagelevel/IfTest.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,46 @@
+// 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.integration.pagelevel;
+
+import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.test.pagelevel.PageTester;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class IfTest extends Assert
+{
+    private PageTester tester;
+
+    @Test
+    public void testRender()
+    {
+        String appPackage = "org.apache.tapestry.integration.app2";
+        String appName = "";
+        tester = new PageTester(appPackage, appName);
+        Document doc = tester.renderPage("TestPageForIf");
+        assertNotNull(doc.getElementById("1"));
+        assertNotNull(doc.getElementById("3"));
+        assertNull(doc.getElementById("2"));
+        assertNull(doc.getElementById("4"));
+    }
+
+    public void after()
+    {
+        if (tester != null)
+        {
+            tester.shutdown();
+        }
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryAppInitializerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryAppInitializerTest.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryAppInitializerTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/TapestryAppInitializerTest.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,52 @@
+// 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;
+
+import org.apache.tapestry.ioc.Registry;
+import org.apache.tapestry.util.Transformer;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+@Test
+public class TapestryAppInitializerTest extends Assert
+{
+    private Registry registry;
+
+    @Test
+    public void testLoadAppModule()
+    {
+        registry = new TapestryAppInitializer("org.apache.tapestry.integration.app0", "foo", "")
+                .getRegistry();
+        @SuppressWarnings("unchecked")
+        Transformer<String> s1 = registry.getService("m1.Service1", Transformer.class);
+        assertEquals(s1.transform("a"), "A");
+    }
+
+    @Test
+    public void testNoAppModule()
+    {
+        registry = new TapestryAppInitializer("non_existing.package", "foo", "").getRegistry();
+    }
+
+    @AfterMethod
+    public void after()
+    {
+        if (registry != null)
+        {
+            registry.shutdown();
+        }
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParserExperiment.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParserExperiment.java?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParserExperiment.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ParserExperiment.java Sun Dec 17 00:34:33 2006
@@ -54,7 +54,7 @@
 
         // Doesn't seem to do anything:
         factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
-
+
         // A non-validation parser is fine!
 
         SAXParser parser = factory.newSAXParser();

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IdentifyTransformer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IdentifyTransformer.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IdentifyTransformer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/IdentifyTransformer.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,23 @@
+// 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.util;
+
+public class IdentifyTransformer<T> implements Transformer<T>
+{
+    public T transform(T input)
+    {
+        return input;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/Transformer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/Transformer.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/Transformer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/Transformer.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,20 @@
+// 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.util;
+
+public interface Transformer<T>
+{
+    T transform(T input);
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/UppercaseTransformer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/UppercaseTransformer.java?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/UppercaseTransformer.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/util/UppercaseTransformer.java Sun Dec 17 00:34:33 2006
@@ -0,0 +1,25 @@
+// 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.util;
+
+
+public class UppercaseTransformer implements Transformer<String>
+{
+    public String transform(String input)
+    {
+        return input.toUpperCase();
+    }
+}
+

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForIf.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForIf.html?view=auto&rev=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForIf.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app2/pages/TestPageForIf.html Sun Dec 17 00:34:33 2006
@@ -0,0 +1,14 @@
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+<t:comp type="If" test="true">
+	<p id="1">abc.</p>
+</t:comp>
+<t:comp type="If" test="false">
+	<p id="2">def.</p>
+</t:comp>
+<t:comp type="If" test="property1">
+	<p id="3">111.</p>
+</t:comp>
+<t:comp type="If" test="property2">
+	<p id="4">222.</p>
+</t:comp>
+</html>
\ No newline at end of file

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/basic.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/basic.html?view=diff&rev=487949&r1=487948&r2=487949
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/basic.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/basic.html Sun Dec 17 00:34:33 2006
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd" xmlns:bar="bar">
     <head>
         <title>Test</title>