Logo Search packages:      
Sourcecode: mojarra version File versions  Download package

UIComponentBaseTestCase.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2010 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package javax.faces.component;

import com.sun.faces.mock.MockValueBinding;
import junit.framework.Test;
import junit.framework.TestSuite;

import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.*;
import javax.faces.validator.ValidatorException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;


/**
 * <p>Base unit tests for all {@link UIComponentBase} subclasses.</p>
 */

00059 public class UIComponentBaseTestCase extends UIComponentTestCase {


    // ------------------------------------------------------ Instance Variables


    // Mock object instances for our tests


    // ------------------------------------------------------------ Constructors


    /**
     * Construct a new instance of this test case.
     *
     * @param name Name of the test case
     */
00076     public UIComponentBaseTestCase(String name) {
        super(name);
    }


    // ---------------------------------------------------- Overall Test Methods


    // Set up instance variables required by this test case.

    public void setUp() {

        // Set up the component under test
        super.setUp();
        component = new TestComponent(expectedId);

    }


    // Return the tests included in this test case.
    public static Test suite() {
        return (new TestSuite(UIComponentBaseTestCase.class));
    }


    // Tear down instance variables required by ths test case
    public void tearDown() {
        externalContext.setRequestParameterMap(null);

        super.tearDown();
        application = null;
        config = null;
        externalContext = null;
        facesContext = null;
        lifecycle = null;
        request = null;
        response = null;
        servletContext = null;
        session = null;

    }


    // ------------------------------------------------- Individual Test Methods


    // Test lifecycle management methods

    public void testLifecycleManagement() {

        checkLifecycleParentRendered();
        checkLifecycleParentUnrendered();
        checkLifecycleSelfRendered();
        checkLifecycleSelfUnrendered();


    }


    public void testComponentToFromEL() {

        final String key = UIComponent.CURRENT_COMPONENT;
        TestComponent c = new TestComponent();
        facesContext.getAttributes().clear();
        assertNull(facesContext.getAttributes().get(key));
        c.pushComponentToEL(facesContext, null);
        assertTrue(facesContext.getAttributes().get(key) == c);
        c.popComponentFromEL(facesContext);
        assertNull(facesContext.getAttributes().get(key));

        // ensure a push/pop seqeunce restores the previous component
        TestComponent c1 = new TestComponent();
        facesContext.getAttributes().put(key, c1);
        c.pushComponentToEL(facesContext, null);
        assertTrue(facesContext.getAttributes().get(key) == c);
        c.popComponentFromEL(facesContext);
        assertTrue(facesContext.getAttributes().get(key) == c1);

    }


    public void testComponentToFromEL2() throws Exception {

        final String key = UIComponent.CURRENT_COMPONENT;
        final FacesContext ctx = facesContext;
        TestComponent c = new TestComponent();
        TestComponent c2 = new TestComponent();
        UIComponent eeo = new UIComponentOverrideEncodeEnd();
        TestComponent c3 = new TestComponent();
        UIComponent ebo = new UIComponentOverrideEncodeBegin();

        c.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c);
        c2.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c2);
        c2.encodeEnd(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c);
        c.encodeEnd(ctx);
        assertNull(UIComponent.getCurrentComponent(ctx));

        // sanity check for the case where a component overrides
        // encodeBegin() without calling super or pushComponentToEL
        c.encodeBegin(ctx);
        c2.encodeBegin(ctx);
        ebo.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c2);
        ebo.encodeEnd(ctx); // if the component wasn't pushed
        // it shouldn't be popped.
        assertEquals(UIComponent.getCurrentComponent(ctx), c2);
        c2.encodeEnd(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c);
        c.encodeEnd(ctx);
        assertNull(UIComponent.getCurrentComponent(ctx));


        // sanity check for the case where a component overrides
        // encodeEnd() without calling super or popComponentFromEL
        c.encodeBegin(ctx);
        c2.encodeBegin(ctx);
        eeo.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
        eeo.encodeEnd(ctx);
        // this is ugly.  Because of a component not doing calling
        // super() or popComponentFromEL, c2 won't be visible
        // as the current component.
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
        c2.encodeEnd(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c);
        c.encodeEnd(ctx);
        assertNull(UIComponent.getCurrentComponent(ctx));

        UIComponent eeo2 = new UIComponentOverrideEncodeEnd();
        c.encodeBegin(ctx);
        c2.encodeBegin(ctx);
        eeo.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
        c3.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c3);
        eeo2.encodeBegin(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
        eeo2.encodeEnd(ctx);
        // this is ugly.
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
        c3.encodeEnd(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
        eeo.encodeEnd(ctx);
        // this is ugly.
        assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
        c2.encodeEnd(ctx);
        assertEquals(UIComponent.getCurrentComponent(ctx), c);
        c.encodeEnd(ctx);
        assertNull(UIComponent.getCurrentComponent(ctx));

    }

    public void testEncodeChildren() throws Exception {
        TestComponent.trace(null);
        UIComponent comp1 = new TestComponent("one");
        UIComponent comp2 = new TestComponent("two");
        UIComponent comp3 = new TestComponent("three");
        UIComponent comp4 = new TestComponent("four");

        comp1.getChildren().add(comp2);
        comp1.getChildren().add(comp3);
        comp1.getChildren().add(comp4);

        comp1.encodeChildren(facesContext);
        System.out.println("Actual:   " + TestComponent.trace());
        System.out.println("Expected: " + "/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four");
        assertEquals("/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four", TestComponent.trace());

    }


    // Test recursive adding and removing child trees with ids
    public void testChildrenRecursive() {

        // Create the components we will need
        UIComponent testComponent = new TestComponent();
        UIComponent child1 = new TestComponent("child1");
        UIComponent child2 = new TestComponent("child2");
        UIComponent child3 = new TestComponent("child3");

        // Prepare ancestry tree before adding to base component
        child1.getChildren().add(child2);
        child2.getChildren().add(child3);

        // Verify that no child ids are visible yet
        assertNull(testComponent.findComponent("child1"));
        assertNull(testComponent.findComponent("child2"));
        assertNull(testComponent.findComponent("child3"));

        // Add the entire tree
        testComponent.getChildren().add(child1);

        // Verify that all named children get added
        assertEquals(child1, testComponent.findComponent("child1"));
        assertEquals(child2, testComponent.findComponent("child2"));
        assertEquals(child3, testComponent.findComponent("child3"));

        // Remove the entire tree
        testComponent.getChildren().remove(child1);

        // Verify that child ids are no longer visible
        assertNull(testComponent.findComponent("child1"));
        assertNull(testComponent.findComponent("child2"));
        assertNull(testComponent.findComponent("child3"));

    }

    public void testChildrenAndFacetsWithNullGetParent() throws Exception {
        TestComponent child = new TestComponent() {
            public UIComponent getParent() {
                return null;
            }
        };
        component.getChildren().add(child);
        assertNull(component.getChildren().get(0).getParent());
        TestComponent facet = new TestComponent() {
            public UIComponent getParent() {
                return null;
            }
        };
        component.getFacets().put("nullParent", facet);
        assertNull(component.getFacets().get("nullParent").getParent());
    }


    // Test reconnecting a child or facet to a different component
    public void testComponentReconnect() {

        UIComponent parent1 = new TestComponent();
        UIComponent parent2 = new TestComponent();

        // Reconnect an existing child as a child
        checkChildCount(parent1, 0);
        checkChildCount(parent2, 0);
        parent1.getChildren().add(component);
        checkChildCount(parent1, 1);
        checkChildCount(parent2, 0);
        checkChildPresent(parent1, component, 0);
        parent2.getChildren().add(component);
        checkChildCount(parent1, 0);
        checkChildCount(parent2, 1);
        checkChildPresent(parent2, component, 0);
        parent2.getChildren().clear();
        checkChildCount(parent1, 0);
        checkChildCount(parent2, 0);

        // Reconnect an existing child as a facet
        checkChildCount(parent1, 0);
        checkFacetCount(parent2, 0);
        parent1.getChildren().add(component);
        checkChildCount(parent1, 1);
        checkFacetCount(parent2, 0);
        checkChildPresent(parent1, component, 0);
        parent2.getFacets().put("facet", component);
        checkChildCount(parent1, 0);
        checkFacetCount(parent2, 1);
        checkFacetPresent(parent2, "facet", component);
        parent2.getFacets().clear();
        checkChildCount(parent1, 0);
        checkFacetCount(parent2, 0);

        // Reconnect an existing facet as a child
        checkFacetCount(parent1, 0);
        checkChildCount(parent2, 0);
        parent1.getFacets().put("facet", component);
        checkFacetCount(parent1, 1);
        checkChildCount(parent2, 0);
        checkFacetPresent(parent1, "facet", component);
        parent2.getChildren().add(component);
        checkFacetCount(parent1, 0);
        checkChildCount(parent2, 1);
        checkChildPresent(parent2, component, 0);
        parent2.getChildren().clear();
        checkFacetCount(parent1, 0);
        checkChildCount(parent2, 0);

    }


    // Test removing components from our naming container.
    public void testComponentRemoval() {

        UIComponent testComponent = new TestComponent();
        UIComponent child1 = new TestComponent("child1");
        UIComponent child2 = new TestComponent("child2");
        UIComponent child3 = new TestComponent("child3");
        UIComponent child = null;

        //adding children to naming container
        testComponent.getChildren().add(child1);
        testComponent.getChildren().add(child2);
        testComponent.getChildren().add(child3);

        // make sure children are stored in naming container properly
        Iterator kidItr = null;

        kidItr = testComponent.getFacetsAndChildren();

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child1));

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child2));

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child3));

        //make sure child is removed from component and naming container
        //pass in a component to remove method
        testComponent.getChildren().remove(child1);

        kidItr = testComponent.getFacetsAndChildren();

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child2));

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child3));

        //make sure child is removed from component and naming container
        //pass an index to remove method
        testComponent.getChildren().remove(0);

        kidItr = testComponent.getFacetsAndChildren();

        child = (UIComponent) kidItr.next();
        assertTrue(child.equals(child3));

        //make sure child is removed from component and naming container
        //remove all children
        testComponent.getChildren().clear();

        kidItr = testComponent.getFacetsAndChildren();
        assertTrue(!kidItr.hasNext());
    }


    public void testStateHolder() throws Exception {

        // Set up the components we will need
        UIComponent parent = new TestComponent("root");
        UIComponent preSave = createComponent();
        UIComponent facet1 = createComponent();
        facet1.setId("facet1");
        preSave.getFacets().put("facet1 key", facet1);
        UIComponent facet2 = createComponent();
        facet2.setId("facet2");
        preSave.getFacets().put("facet2 key", facet2);
        parent.getChildren().add(preSave);
        populateComponent(preSave);
        UIComponent postSave = createComponent();

        // Save and restore state and compare the results
        Object state = preSave.saveState(facesContext);
        assertNotNull(state);
        postSave.restoreState(facesContext, state);
        checkComponents(preSave, postSave);
        checkValueBindings(preSave, postSave);
        checkComponentListeners(preSave, postSave);
    }


    public void testStateHolder2() throws Exception {

        UIComponent c = new UIComponentListener();
        c.subscribeToEvent(PostAddToViewEvent.class, (ComponentSystemEventListener) c);
        Object state = c.saveState(facesContext);
        c = new UIComponentListener();
        c.pushComponentToEL(facesContext, c);
        c.restoreState(facesContext, state);
        c.popComponentFromEL(facesContext);
        assertTrue(c.getListenersForEventClass(PostAddToViewEvent.class).size() == 1);

    }


    public void testValueBindings() {

        UIComponentBase test = (UIComponentBase) component;

        // generic attributes
        request.setAttribute("foo", "bar");
        Object result = test.getAttributes().get("childCount");
        test.getAttributes().clear();
        assertNull(test.getAttributes().get("baz"));
        test.setValueBinding("baz", application.createValueBinding("#{foo}"));
        assertEquals("bar", test.getAttributes().get("baz"));
        test.getAttributes().put("baz", "bop");
        assertEquals("bop", test.getAttributes().get("baz"));
        test.getAttributes().remove("baz");
        assertEquals("bar", test.getAttributes().get("baz"));
        test.setValueBinding("baz", null);
        assertNull(test.getAttributes().get("baz"));

        // "id" property
        try {
            test.setValueBinding("id",
                    application.createValueBinding("#{foo}"));
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            ; // Expected response
        }

        // "parent" property
        try {
            test.setValueBinding("parent",
                    application.createValueBinding("#{foo}"));
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            ; // Expected response
        }

        // "rendered" property
        request.setAttribute("foo", Boolean.FALSE);
        boolean initial = test.isRendered();
        if (initial) {
            request.setAttribute("foo", Boolean.FALSE);
        } else {
            request.setAttribute("foo", Boolean.TRUE);
        }
        test.setValueBinding("rendered", application.createValueBinding("#{foo}"));
        assertEquals(!initial, test.isRendered());
        test.setRendered(initial);
        assertEquals(initial, test.isRendered());
        assertNotNull(test.getValueBinding("rendered"));

        // "rendererType" property
        request.setAttribute("foo", "bar");
        test.setRendererType(null);
        assertNull(test.getRendererType());
        test.setValueBinding("rendererType", application.createValueBinding("#{foo}"));
        assertNotNull(test.getValueBinding("rendererType"));
        assertEquals("bar", test.getRendererType());
        test.setRendererType("baz");
        assertEquals("baz", test.getRendererType());
        test.setRendererType(null);
        assertEquals("bar", test.getRendererType());
        test.setValueBinding("rendererType", null);
        assertNull(test.getValueBinding("rendererType"));
        assertNull(test.getRendererType());

    }

    public void testValueExpressions() throws Exception {

        UIComponentBase test = (UIComponentBase) component;

        // generic attributes
        request.setAttribute("foo", "bar");
        test.getAttributes().clear();
        assertNull(test.getAttributes().get("baz"));
        test.setValueExpression("baz", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
        assertEquals("bar", test.getAttributes().get("baz"));
        test.getAttributes().put("baz", "bop");
        assertEquals("bop", test.getAttributes().get("baz"));
        test.getAttributes().remove("baz");
        assertEquals("bar", test.getAttributes().get("baz"));
        test.setValueExpression("baz", null);
        assertNull(test.getAttributes().get("baz"));

        // "id" property
        try {
            test.setValueExpression("id",
                    application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            ; // Expected response
        }

        // "parent" property
        try {
            test.setValueExpression("parent",
                    application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", UIComponent.class));
            fail("Should have thrown IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            ; // Expected response
        }

        // "rendered" property
        request.setAttribute("foo", Boolean.FALSE);
        test.setValueExpression("rendered", null);
        boolean initial = test.isRendered();
        if (initial) {
            request.setAttribute("foo", Boolean.FALSE);
        } else {
            request.setAttribute("foo", Boolean.TRUE);
        }
        test.setValueExpression("rendered", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", Boolean.class));
        assertEquals(!initial, test.isRendered());
        test.setRendered(initial);
        assertEquals(initial, test.isRendered());
        assertNotNull(test.getValueExpression("rendered"));

        // "rendererType" property
        request.setAttribute("foo", "bar");
        test.setRendererType(null);
        assertNull(test.getRendererType());
        test.setValueExpression("rendererType", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
        assertNotNull(test.getValueExpression("rendererType"));
        assertEquals("bar", test.getRendererType());
        test.setRendererType("baz");
        assertEquals("baz", test.getRendererType());
        test.setRendererType(null);
        assertEquals("bar", test.getRendererType());
        test.setValueExpression("rendererType", null);
        assertNull(test.getValueExpression("rendererType"));
        assertNull(test.getRendererType());

    }

    public void testValueExpressionValueBindingIdempotency() throws Exception {

        UIComponentBase test = (UIComponentBase) component;

        request.setAttribute("foo", "bar");
        test.getAttributes().clear();
        assertNull(test.getAttributes().get("baz"));
        ValueBinding binding = null;
        ValueExpression expression = null;

        binding = application.createValueBinding("#{foo}");
        test.setValueBinding("baz", binding);
        expression = test.getValueExpression("baz");

        assertEquals(binding.getExpressionString(),
                expression.getExpressionString());
        test.setValueBinding("baz", null);

        expression = application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class);
        test.setValueExpression("baz", expression);
        binding = test.getValueBinding("baz");
        assertEquals(binding.getExpressionString(),
                expression.getExpressionString());
        test.setValueBinding("baz", null);

    }

    public void testMethodBindingAdapterBaseException() throws Exception {
        IllegalThreadStateException itse = new IllegalThreadStateException("The root cause!");
        AbortProcessingException ape = new CustomAbortProcessingException(itse);
        InvocationTargetException ite1 = new InvocationTargetException(ape);
        InvocationTargetException ite2 = new InvocationTargetException(ite1);
        InvocationTargetException ite3 = new InvocationTargetException(ite2);
        MethodBindingValueChangeListener mbvcl =
                new MethodBindingValueChangeListener();
        Throwable expected =
                mbvcl.getExpectedCause(AbortProcessingException.class, ite3);
        assertEquals(expected, ape);

        ValidatorException ve = new ValidatorException(new FacesMessage(),
                itse);
        ite1 = new InvocationTargetException(ve);
        ite2 = new InvocationTargetException(ite1);
        ite3 = new InvocationTargetException(ite2);

        MethodBindingValidator mbv = new MethodBindingValidator();
        expected =
                mbv.getExpectedCause(ValidatorException.class, ite3);
        assertEquals(expected, ve);
    }


    // --------------------------------------------------------- support Methods


    // Check that the attributes on the specified components are equal

    protected void checkAttributes(UIComponent comp1, UIComponent comp2) {
        assertEquals(comp1.getAttributes(), comp2.getAttributes());
    }


    // Check that the specified components are equal
    protected void checkComponents(UIComponent comp1, UIComponent comp2) {
        checkAttributes(comp1, comp2);
        // checkFacets(comp1, comp2); // Not saved and restored by component
        checkProperties(comp1, comp2);
    }


    // Check lifecycle processing when parent "rendered" property is "true"
    private void checkLifecycleParentRendered() {

        // Put our component under test in a tree under a UIViewRoot
        component.getAttributes().clear();
        component.getChildren().clear();
        component.getFacets().clear();
        component.setRendered(true);
        UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
        UIPanel panel = new UIPanel();
        panel.setRendered(true);
        root.getChildren().add(panel);
        panel.getChildren().add(component);

        // Establish a view with multiple facets and children
        UIComponent facet1 = new TestComponent("f1");
        UIComponent facet2 = new TestComponent("f2");
        UIComponent facet3 = new TestComponent("f3");
        component.getFacets().put("f1", facet1);
        component.getFacets().put("f2", facet2);
        component.getFacets().put("f3", facet3);
        checkFacetCount(component, 3);
        UIComponent child1 = new TestComponent("c1");
        UIComponent child2 = new TestComponent("c2");
        UIComponent child3 = new TestComponent("c3");
        component.getChildren().add(child1);
        component.getChildren().add(child2);
        component.getChildren().add(child3);
        checkChildCount(component, 3);
        UIComponent child2a = new TestComponent("c2a");
        UIComponent child2b = new TestComponent("c2b");
        child2.getChildren().add(child2a);
        child2.getChildren().add(child2b);
        checkChildCount(child2, 2);

        // Enqueue a single FacesEvent for each component
        component.queueEvent(new TestEvent(component));
        component.queueEvent(new TestEvent(facet1));
        component.queueEvent(new TestEvent(facet2));
        component.queueEvent(new TestEvent(facet3));
        component.queueEvent(new TestEvent(child1));
        component.queueEvent(new TestEvent(child2));
        component.queueEvent(new TestEvent(child3));
        component.queueEvent(new TestEvent(child2a));
        component.queueEvent(new TestEvent(child2b));

        // Test processDecodes()
        TestComponent.trace(null);
        component.processDecodes(facesContext);
        assertEquals("processDecodes",
                lifecycleTrace("pD", "d"),
                TestComponent.trace());

        // Test processValidators()
        TestComponent.trace(null);
        component.processValidators(facesContext);
        assertEquals("processValidators",
                lifecycleTrace("pV", null),
                TestComponent.trace());

        // Test processUpdates()
        TestComponent.trace(null);
        component.processUpdates(facesContext);
        assertEquals("processUpdates",
                lifecycleTrace("pU", null),
                TestComponent.trace());

    }


    // Check lifecycle processing when parent "rendered" property is "false"
    private void checkLifecycleParentUnrendered() {

        // Put our component under test in a tree under a UIViewRoot
        component.getAttributes().clear();
        component.getChildren().clear();
        component.getFacets().clear();
        component.setRendered(true);
        UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
        UIPanel panel = new UIPanel();
        panel.setRendered(false);
        root.getChildren().add(panel);
        panel.getChildren().add(component);

        // Establish a view with multiple facets and children
        UIComponent facet1 = new TestComponent("f1");
        UIComponent facet2 = new TestComponent("f2");
        UIComponent facet3 = new TestComponent("f3");
        component.getFacets().put("f1", facet1);
        component.getFacets().put("f2", facet2);
        component.getFacets().put("f3", facet3);
        checkFacetCount(component, 3);
        UIComponent child1 = new TestComponent("c1");
        UIComponent child2 = new TestComponent("c2");
        UIComponent child3 = new TestComponent("c3");
        component.getChildren().add(child1);
        component.getChildren().add(child2);
        component.getChildren().add(child3);
        checkChildCount(component, 3);
        UIComponent child2a = new TestComponent("c2a");
        UIComponent child2b = new TestComponent("c2b");
        child2.getChildren().add(child2a);
        child2.getChildren().add(child2b);
        checkChildCount(child2, 2);

        // Enqueue a single FacesEvent for each component
        component.queueEvent(new TestEvent(component));
        component.queueEvent(new TestEvent(facet1));
        component.queueEvent(new TestEvent(facet2));
        component.queueEvent(new TestEvent(facet3));
        component.queueEvent(new TestEvent(child1));
        component.queueEvent(new TestEvent(child2));
        component.queueEvent(new TestEvent(child3));
        component.queueEvent(new TestEvent(child2a));
        component.queueEvent(new TestEvent(child2b));

        // Test processDecodes()
        TestComponent.trace(null);
        component.processDecodes(facesContext);
        assertEquals("processDecodes",
                lifecycleTrace("pD", "d"),
                TestComponent.trace());

        // Test processValidators()
        TestComponent.trace(null);
        component.processValidators(facesContext);
        assertEquals("processValidators",
                lifecycleTrace("pV", null),
                TestComponent.trace());

        // Test processUpdates()
        TestComponent.trace(null);
        component.processUpdates(facesContext);
        assertEquals("processUpdates",
                lifecycleTrace("pU", null),
                TestComponent.trace());

    }


    // Check lifecycle processing when our "rendered" property is "true"
    private void checkLifecycleSelfRendered() {

        // Put our component under test in a tree under a UIViewRoot
        component.getAttributes().clear();
        component.getChildren().clear();
        component.getFacets().clear();
        component.setRendered(true);
        UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
        root.getChildren().add(component);

        // Establish a view with multiple facets and children
        UIComponent facet1 = new TestComponent("f1");
        UIComponent facet2 = new TestComponent("f2");
        UIComponent facet3 = new TestComponent("f3");
        component.getFacets().put("f1", facet1);
        component.getFacets().put("f2", facet2);
        component.getFacets().put("f3", facet3);
        checkFacetCount(component, 3);
        UIComponent child1 = new TestComponent("c1");
        UIComponent child2 = new TestComponent("c2");
        UIComponent child3 = new TestComponent("c3");
        component.getChildren().add(child1);
        component.getChildren().add(child2);
        component.getChildren().add(child3);
        checkChildCount(component, 3);
        UIComponent child2a = new TestComponent("c2a");
        UIComponent child2b = new TestComponent("c2b");
        child2.getChildren().add(child2a);
        child2.getChildren().add(child2b);
        checkChildCount(child2, 2);

        // Enqueue a single FacesEvent for each component
        component.queueEvent(new TestEvent(component));
        component.queueEvent(new TestEvent(facet1));
        component.queueEvent(new TestEvent(facet2));
        component.queueEvent(new TestEvent(facet3));
        component.queueEvent(new TestEvent(child1));
        component.queueEvent(new TestEvent(child2));
        component.queueEvent(new TestEvent(child3));
        component.queueEvent(new TestEvent(child2a));
        component.queueEvent(new TestEvent(child2b));

        // Test processDecodes()
        TestComponent.trace(null);
        component.processDecodes(facesContext);
        assertEquals("processDecodes",
                lifecycleTrace("pD", "d"),
                TestComponent.trace());

        // Test processValidators()
        TestComponent.trace(null);
        component.processValidators(facesContext);
        assertEquals("processValidators",
                lifecycleTrace("pV", null),
                TestComponent.trace());

        // Test processUpdates()
        TestComponent.trace(null);
        component.processUpdates(facesContext);
        assertEquals("processUpdates",
                lifecycleTrace("pU", null),
                TestComponent.trace());

    }


    // Check lifecycle processing when our "rendered" property is "false"
    private void checkLifecycleSelfUnrendered() {

        // Put our component under test in a tree under a UIViewRoot
        component.getAttributes().clear();
        component.getChildren().clear();
        component.getFacets().clear();
        component.setRendered(false);
        UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
        root.getChildren().add(component);

        // Establish a view with multiple facets and children
        UIComponent facet1 = new TestComponent("f1");
        UIComponent facet2 = new TestComponent("f2");
        UIComponent facet3 = new TestComponent("f3");
        component.getFacets().put("f1", facet1);
        component.getFacets().put("f2", facet2);
        component.getFacets().put("f3", facet3);
        checkFacetCount(component, 3);
        UIComponent child1 = new TestComponent("c1");
        UIComponent child2 = new TestComponent("c2");
        UIComponent child3 = new TestComponent("c3");
        component.getChildren().add(child1);
        component.getChildren().add(child2);
        component.getChildren().add(child3);
        checkChildCount(component, 3);
        UIComponent child2a = new TestComponent("c2a");
        UIComponent child2b = new TestComponent("c2b");
        child2.getChildren().add(child2a);
        child2.getChildren().add(child2b);
        checkChildCount(child2, 2);

        // Enqueue a single FacesEvent for each component
        component.queueEvent(new TestEvent(component));
        component.queueEvent(new TestEvent(facet1));
        component.queueEvent(new TestEvent(facet2));
        component.queueEvent(new TestEvent(facet3));
        component.queueEvent(new TestEvent(child1));
        component.queueEvent(new TestEvent(child2));
        component.queueEvent(new TestEvent(child3));
        component.queueEvent(new TestEvent(child2a));
        component.queueEvent(new TestEvent(child2b));

        // Test processDecodes()
        TestComponent.trace(null);
        component.processDecodes(facesContext);
        assertEquals("processDecodes",
                lifecycleTrace("pD", "d"),
                TestComponent.trace());

        // Test processValidators()
        TestComponent.trace(null);
        component.processValidators(facesContext);
        assertEquals("processValidators",
                lifecycleTrace("pV", null),
                TestComponent.trace());

        // Test processUpdates()
        TestComponent.trace(null);
        component.processUpdates(facesContext);
        assertEquals("processUpdates",
                lifecycleTrace("pU", null),
                TestComponent.trace());

    }


    // Check that the properties on the specified components are equal
    protected void checkProperties(UIComponent comp1, UIComponent comp2) {
        assertEquals(comp1.getClientId(facesContext),
                comp2.getClientId(facesContext));
        assertEquals(comp1.getId(), comp2.getId());
        assertEquals(comp1.isRendered(), comp2.isRendered());
        assertEquals(comp1.getRendererType(), comp2.getRendererType());
        assertEquals(comp1.getRendersChildren(), comp2.getRendersChildren());
    }


    // Check that the configured ValueBindings got restored
    protected void checkValueBindings(UIComponent comp1, UIComponent comp2) {

        ValueBinding vb1, vb2;

        vb1 = comp1.getValueBinding("baz");
        vb2 = comp2.getValueBinding("baz");
        assertEquals(((MockValueBinding) vb1).ref(),
                ((MockValueBinding) vb2).ref());

        vb1 = comp1.getValueBinding("bop");
        vb2 = comp2.getValueBinding("bop");
        assertEquals(((MockValueBinding) vb1).ref(),
                ((MockValueBinding) vb2).ref());

    }


    protected void checkComponentListeners(UIComponent control, UIComponent toValidate) {

        List<SystemEventListener> lc = control.getListenersForEventClass(PostAddToViewEvent.class);
        List<SystemEventListener> tvl = toValidate.getListenersForEventClass(PostAddToViewEvent.class);
        List<SystemEventListener> lc2 = control.getListenersForEventClass(PostConstructViewMapEvent.class);
        List<SystemEventListener> tvl2 = toValidate.getListenersForEventClass(PostConstructViewMapEvent.class);
        assertTrue(lc.size() == tvl.size());
        assertTrue(lc2.size() == tvl2.size());

    }


    // Create a pristine component of the type to be used in state holder tests
    protected UIComponent createComponent() {
        return (new TestComponent());
    }


    // Populate a pristine component to be used in state holder tests
    protected void populateComponent(UIComponent component) {

        component.getAttributes().put("foo", "foo value");
        component.getAttributes().put("bar", "bar value");
        component.setId("componentId");
        component.getClientId(facesContext); // Forces evaluation
        component.setRendered(false);
        component.setRendererType(null); // Since we have no renderers

        component.setValueBinding("baz",
                application.createValueBinding("baz.value"));
        component.setValueBinding("bop",
                application.createValueBinding("bop.value"));
        component.subscribeToEvent(PostAddToViewEvent.class,
                new ComponentListener());
        component.subscribeToEvent(PostAddToViewEvent.class,
                new ComponentListener());
        component.subscribeToEvent(PostConstructViewMapEvent.class,
                new ComponentListener());

    }


    /**
     * Construct and return a lifecycle method call trace for the specified
     * method names.
     *
     * @param lmethod Name of the lifecycle method under test
     * @param cmethod Name of the component method that corresponds
     */
01011     protected String lifecycleTrace(String lmethod, String cmethod) {
        StringBuffer sb = new StringBuffer();
        lifecycleTrace(lmethod, cmethod, component, sb);
        return (sb.toString());
    }

    protected void lifecycleTrace(String lmethod, String cmethod,
                                  UIComponent component, StringBuffer sb) {


        // Append the call for this lifecycle method
        String id = component.getId();
        sb.append("/" + lmethod + "-" + id);
        if (!component.isRendered()) {
            return;
        }

        // Append the calls for each facet
        Iterator names = component.getFacets().keySet().iterator();
        while (names.hasNext()) {
            String name = (String) names.next();
            sb.append("/" + lmethod + "-" + name);
            if ((cmethod != null) &&
                    ((UIComponent) component.getFacets().get(name)).isRendered()) {
                sb.append("/" + cmethod + "-" + name);
            }
        }

        // Append the calls for each child
        Iterator kids = component.getChildren().iterator();
        while (kids.hasNext()) {
            UIComponent kid = (UIComponent) kids.next();
            lifecycleTrace(lmethod, cmethod, kid, sb);
        }

        // Append the call for this component's component method
        if ((cmethod != null) && component.isRendered()) {
            sb.append("/" + cmethod + "-" + id);
        }

    }

    public void testGetFacetsAndChildren() {

        UIComponent testComponent = new TestComponent();
        UIComponent child1 = new TestComponent("child1");
        UIComponent child2 = new TestComponent("child2");
        UIComponent child3 = new TestComponent("child3");
        UIComponent facet1 = new TestComponent("facet1");
        UIComponent facet2 = new TestComponent("facet2");
        UIComponent facet3 = new TestComponent("facet3");

        testComponent.getChildren().add(child1);
        testComponent.getChildren().add(child2);
        testComponent.getChildren().add(child3);
        testComponent.getFacets().put("facet1", facet1);
        testComponent.getFacets().put("facet2", facet2);
        testComponent.getFacets().put("facet3", facet3);

        Iterator iter = testComponent.getFacetsAndChildren();
        Object cur = null;
        boolean exceptionThrown = false;
        assertTrue(iter.hasNext());

        try {
            iter.remove();
        }
        catch (UnsupportedOperationException e) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);

        // facets are returned in an undefined order.
        cur = iter.next();
        assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
        cur = iter.next();
        assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
        cur = iter.next();
        assertTrue(cur == facet1 || cur == facet2 || cur == facet3);

        // followed by components, in the order added
        cur = iter.next();
        assertTrue(cur == child1);
        cur = iter.next();
        assertTrue(cur == child2);
        cur = iter.next();
        assertTrue(cur == child3);

        assertTrue(!iter.hasNext());

    }

    private Object foundComponent = null;

    /**
     * <p>Build a tree with the following layout.</p>
     * <code><pre>
     * root: id: root
     * <p/>
     *   form1: id: form1
     * <p/>
     *     panel1: id: panel
     * <p/>
     *       input1: id: input1
     * <p/>
     *       input2: id: input2
     * <p/>
     *   form2: id: form2
     * <p/>
     *     panel2: id: panel
     * <p/>
     *       input3: id: input1
     * <p/>
     *       input4: id: input2
     * </pre></code>
     *
     * @return a Map<String, UIComponent>.  The key is the string before the
     *         first : in the above layout.  The value is the component instance.
     *         Note that the keys in the map are <b>not</b> the ids.
     */

01132     private Map<String, UIComponent> setupInvokeOnComponentTree() {
        UIViewRoot root = new UIViewRoot();
        UIForm form1 = new UIForm();
        UIPanel panel1 = new UIPanel();
        UIInput input1 = new UIInput();
        UIInput input2 = new UIInput();
        UIForm form2 = new UIForm();
        UIPanel panel2 = new UIPanel();
        UIInput input3 = new UIInput();
        UIInput input4 = new UIInput();

        root.setId("root");
        form1.setId("form1");
        panel1.setId("panel");
        input1.setId("input1");
        input2.setId("input2");

        form2.setId("form2");
        panel2.setId("panel");
        input3.setId("input1");
        input4.setId("input2");

        root.getChildren().add(form1);
        form1.getChildren().add(panel1);
        panel1.getChildren().add(input1);
        panel1.getChildren().add(input2);

        root.getChildren().add(form2);
        form2.getChildren().add(panel2);
        panel2.getChildren().add(input3);
        panel2.getChildren().add(input4);
        Map<String, UIComponent> result = new HashMap<String, UIComponent>();
        result.put("root", root);
        result.put("form1", form1);
        result.put("panel1", panel1);
        result.put("input1", input1);
        result.put("input2", input2);
        result.put("form2", form2);
        result.put("panel2", panel2);
        result.put("input3", input3);
        result.put("input4", input4);

        return result;
    }


    public void testInvokeOnComponentPositive() throws Exception {

        Map<String, UIComponent> tree = setupInvokeOnComponentTree();

        UIViewRoot root = (UIViewRoot) tree.get("root");
        UIInput input1 = (UIInput) tree.get("input1");

        foundComponent = null;
        boolean result = false;

        result = root.invokeOnComponent(facesContext,
                input1.getClientId(facesContext),
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertEquals(input1, foundComponent);
        assertTrue(result);

    }

    public void testInvokeOnComponentNegative() throws Exception {
        Map<String, UIComponent> tree = setupInvokeOnComponentTree();

        UIViewRoot root = (UIViewRoot) tree.get("root");
        UIInput input4 = (UIInput) tree.get("input4");

        foundComponent = null;
        boolean result = false;
        boolean exceptionThrown = false;

        // Negative case 0, null pointers
        exceptionThrown = false;
        FacesContext nullContext = null;
        ContextCallback nullCallback = null;
        try {
            root.invokeOnComponent(nullContext, "form:input7",
                    nullCallback);
        }
        catch (NullPointerException npe) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);

        exceptionThrown = false;
        try {
            root.invokeOnComponent(facesContext, null,
                    nullCallback);
        }
        catch (NullPointerException npe) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);

        exceptionThrown = false;
        try {
            root.invokeOnComponent(nullContext, null,
                    nullCallback);
        }
        catch (NullPointerException npe) {
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);

        // Negative case 1, not found component.
        result = root.invokeOnComponent(facesContext,
                "form:input7",
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertNull(foundComponent);
        assertTrue(!result);

        // Negative case 2A, callback throws exception with found component
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {
            result = root.invokeOnComponent(facesContext,
                    "form2:input2",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            // When else am I going to get the chance to throw this exception?
                            throw new IllegalStateException();
                        }
                    });
        } catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertTrue(exceptionThrown);
        assertEquals(foundComponent, input4);
        assertTrue(!result);

        // Negative case 2B, callback throws exception with not found component
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {
            result = root.invokeOnComponent(facesContext,
                    "form2:input6",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            // When else am I going to get the chance to throw this exception?
                            throw new IllegalStateException();
                        }
                    });
        } catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertTrue(!exceptionThrown);
        assertNull(foundComponent);
        assertTrue(!result);


    }

    public void testInvokeOnComponentWithPrependId() throws Exception {
        Map<String, UIComponent> tree = setupInvokeOnComponentTree();

        UIViewRoot root = (UIViewRoot) tree.get("root");
        UIForm truePrependIdForm = (UIForm) tree.get("form1");
        UIForm falsePrependIdForm = (UIForm) tree.get("form2");
        UIInput truePrependIdInput = (UIInput) tree.get("input2");
        UIInput falsePrependIdInput = (UIInput) tree.get("input3");

        truePrependIdForm.setPrependId(true);
        falsePrependIdForm.setPrependId(false);

        foundComponent = null;
        boolean result = false;
        boolean exceptionThrown = false;

        // Case 1, positive find with prependId == true
        result = root.invokeOnComponent(facesContext,
                "form1:input2",
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertEquals(truePrependIdInput, foundComponent);
        assertTrue(result);

        // Case 2, negative find with prependId == true
        foundComponent = null;
        result = false;

        result = root.invokeOnComponent(facesContext,
                "form9:input5",
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertNull(foundComponent);
        assertTrue(!result);

        // Case 3, exception positive find with prependId == true
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {


            result = root.invokeOnComponent(facesContext,
                    "form1:input2",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            throw new IllegalStateException();
                        }
                    });
        }
        catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertEquals(truePrependIdInput, foundComponent);
        assertTrue(!result);
        assertTrue(exceptionThrown);

        // Case 4, exception negative find with prependId == true
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {


            result = root.invokeOnComponent(facesContext,
                    "formFozzy:inputKermit",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            throw new IllegalStateException();
                        }
                    });
        }
        catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertNull(foundComponent);
        assertTrue(!result);
        assertTrue(!exceptionThrown);

        // Case 5, positive find with prependId == false
        result = root.invokeOnComponent(facesContext,
                "input1",
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertEquals(falsePrependIdInput, foundComponent);
        assertTrue(result);

        // Case 6, negative find with prependId == false
        foundComponent = null;
        result = false;

        result = root.invokeOnComponent(facesContext,
                "input99",
                new ContextCallback() {
                    public void invokeContextCallback(FacesContext context, UIComponent component) {
                        foundComponent = component;
                    }
                });
        assertNull(foundComponent);
        assertTrue(!result);

        // Case 3, exception positive find with prependId == false
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {


            result = root.invokeOnComponent(facesContext,
                    "input1",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            throw new IllegalStateException();
                        }
                    });
        }
        catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertEquals(falsePrependIdInput, foundComponent);
        assertTrue(!result);
        assertTrue(exceptionThrown);

        // Case 4, exception negative find with prependId == false
        foundComponent = null;
        result = false;
        exceptionThrown = false;
        try {


            result = root.invokeOnComponent(facesContext,
                    "inputKermit",
                    new ContextCallback() {
                        public void invokeContextCallback(FacesContext context, UIComponent component) {
                            foundComponent = component;
                            throw new IllegalStateException();
                        }
                    });
        }
        catch (FacesException e) {
            assertTrue(e.getCause() instanceof IllegalStateException);
            exceptionThrown = true;
        }
        assertNull(foundComponent);
        assertTrue(!result);
        assertTrue(!exceptionThrown);


    }


    public void testChildrenListAfterAddPublish() {

        Listener listener = new Listener();
        application.subscribeToEvent(PostAddToViewEvent.class, listener);

        UIComponent c1 = createComponent();
        c1.setInView(true);
        UIComponent c2 = createComponent();
        c2.setInView(true);
        UIComponent c3 = createComponent();
        c3.setInView(true);

        c1.getChildren().add(c2);
        SystemEvent e = listener.getEvent();
        assertNotNull(e);
        assertTrue(e.getSource() == c2);
        assertTrue(((UIComponent) e.getSource()).getParent() == c1);
        listener.reset();
        c2.getChildren().add(c3);
        e = listener.getEvent();
        assertNotNull(e);
        assertTrue(e.getSource() == c3);
        assertTrue(((UIComponent) e.getSource()).getParent() == c2);

        //ensure events are re-published if the event is added
        listener.reset();
        c2.getChildren().remove(c3);
        c1.getChildren().add(c3);
        e = listener.getEvent();
        assertNotNull(e);
        assertTrue(e.getSource() == c3);
        assertTrue(((UIComponent) e.getSource()).getParent() == c1);

        application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);

    }

    public void testFacetMapAfterAddViewPublish() {

        QueueingListener listener = new QueueingListener();
        application.subscribeToEvent(PostAddToViewEvent.class, listener);

        UIComponent c1 = createComponent();
        UIComponent c2 = createComponent();
        UIComponent c3 = createComponent();

        List<SystemEvent> e = listener.getEvents();
        Map<String, UIComponent> facets = c1.getFacets();
        facets.put("c2", c2);
        assertTrue("Expected Event queue size of 0, found: " + e.size(), e.size() == 0);

        UIViewRoot root = new UIViewRoot();
        root.getChildren().add(c1);
        assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
        assertTrue(e.get(0).getSource() == c1);
        assertTrue(e.get(1).getSource() == c2);

        // remove c1 from the root and add c3 as a facet to c1 - no events should be
        // published
        e.clear();
        root.getChildren().remove(c1);
        facets = c1.getFacets();
        facets.put("c3", c3);
        assertTrue("Expected Event queue size of 0, found: " + e.size(), e.size() == 0);

        // reorganize the facet structure to ensure nested facets work
        facets.remove("c3");
        c2.getFacets().put("c3", c3);
        root.getChildren().add(c1);
        assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);
        assertTrue(e.get(0).getSource() == c1);
        assertTrue(e.get(1).getSource() == c2);
        assertTrue(e.get(2).getSource() == c3);

        e.clear();
        // ensure clear() method disconnects the facets from the view
        facets.clear();
        c2.getFacets().remove("c3");
        c2.getFacets().put("c3", c3);
        assertTrue("Expected Event queue size of 0, found: " + e.size(), e.size() == 0);

        application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);

    }

    public void testChildrenListAfterAddViewPublish() {

        QueueingListener listener = new QueueingListener();
        application.subscribeToEvent(PostAddToViewEvent.class, listener);

        UIComponent c1 = createComponent();
        UIComponent c2 = createComponent();
        UIComponent c3 = createComponent();
        UIComponent c4 = createComponent();
        c1.getChildren().add(c2);
        List<SystemEvent> e = listener.getEvents();
        assertTrue(e.isEmpty());
        c2.getChildren().add(c3);
        assertTrue(e.isEmpty());
        UIViewRoot root = new UIViewRoot();
        root.getChildren().add(c1);

        // sub-tree has been added to the view.  Ensure that subsequent additions
        // to that sub-tree cause the PostAddToViewEvent to fire.
        c2.getChildren().add(c4);
        assertTrue("Expected Event queue size of 4, found: " + e.size(), e.size() == 4);

        UIComponent[] comps = {
                c1, c2, c3, c4
        };
        for (int i = 0; i < comps.length; i++) {
            assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps[i]);
        }

        // remove c1 and it's children from the subview, then remove and
        // re-add one of the children in the sub-tree.  No event should
        // be fired
        e.clear();
        root.getChildren().remove(c1);
        c2.getChildren().remove(c4);
        c2.getChildren().add(c4);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());

        c2.getChildren().remove(c4);
        c1.getChildren().add(c4);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());

        // re-wire c1 as a child of root and ensure all children get re-notified
        root.getChildren().add(c1);
        assertTrue("Expected Event queue size of 4, found: " + e.size(), e.size() == 4);

        for (int i = 0; i < comps.length; i++) {
            assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps[i]);
        }

        // validate clearing c1's children (effectively removing them from the view
        // will result in no events being fired of components are added to any of
        // the disconnected children.
        // At this point in the test, c2 and c4 are children of c1, and c3
        // is a child of c2.
        c1.getChildren().clear();
        UIComponent temp = createComponent();
        e.clear();
        c2.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        c2.getChildren().remove(temp);
        c3.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        c3.getChildren().remove(temp);
        c4.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        c4.getChildren().remove(temp);

        // now add c2 and c4 as children of c1.  This should cause three
        // events to fire
        c1.getChildren().add(c2);
        c1.getChildren().add(c4);
        assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);

        UIComponent[] comps2 = {
                c2, c3, c4
        };
        for (int i = 0; i < comps2.length; i++) {
            assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps2[i]);
        }

        // validate add(int, UIComponent) fires events
        e.clear();
        c1.getChildren().remove(c4);
        c1.getChildren().add(0, c4);

        assertTrue(c1.getChildren().get(0) == c4);
        assertTrue(c1.getChildren().get(1) == c2);
        assertTrue("Expected Event queue size of 1, found: " + e.size(), e.size() == 1);
        assertTrue(e.get(0).getSource() == c4);

        // validate addAll(Collection<UIComponent>) fires events
        e.clear();
        c1.getChildren().clear();
        List<UIComponent> children = new ArrayList<UIComponent>(2);
        Collections.addAll(children, c2, c4);
        c1.getChildren().addAll(children);
        assertTrue(c1.getChildren().get(0) == c2);
        assertTrue(c1.getChildren().get(1) == c4);
        assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);
        assertTrue(e.get(0).getSource() == c2);
        assertTrue(e.get(2).getSource() == c4);

        // validate addAll(int, Collection<UIComponent>) fires events
        e.clear();
        children = new ArrayList<UIComponent>(2);
        UIComponent t1 = createComponent();
        UIComponent t2 = createComponent();
        Collections.addAll(children, t1, t2);
        c1.getChildren().addAll(0, children);
        assertTrue(c1.getChildren().get(0) == t1);
        assertTrue(c1.getChildren().get(1) == t2);
        assertTrue(c1.getChildren().get(2) == c2);
        assertTrue(c1.getChildren().get(3) == c4);
        assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
        assertTrue(e.get(0).getSource() == t1);
        assertTrue(e.get(1).getSource() == t2);

        // validate retainAll(Collection<UIComponent> properly disconnects
        // the components from the view such that events aren't fired
        // if children are added to them
        e.clear();
        List<UIComponent> retained = new ArrayList<UIComponent>(2);
        Collections.addAll(retained, c2, c4);
        c1.getChildren().retainAll(retained);
        assertTrue(c1.getChildren().size() == 2);
        assertTrue(c1.getChildren().get(0) == c2);
        assertTrue(c1.getChildren().get(1) == c4);
        t1.getChildren().add(t2);
        assertTrue("Expected Event queue size of 0, found: " + e.size(), e.size() == 0);

        // test set(int, UIComponent) properly fires an event if the parent
        // the component is being added to is wired to the view
        e.clear();
        c1.getChildren().set(0, t1);
        assertTrue(c1.getChildren().size() == 2);
        assertTrue(c1.getChildren().get(0) == t1);
        assertTrue(c1.getChildren().get(1) == c4);
        assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
        assertTrue(e.get(0).getSource() == t1);
        assertTrue(e.get(1).getSource() == t2);

        // c2 was removed by the set operation, so ensure it's marked as
        // having been removed from the view by ensuring events aren't fired.
        e.clear();
        UIComponent t3 = createComponent();
        c2.getChildren().add(t3);
        assertTrue("Expected Event queue size of 0, found: " + e.size(), e.size() == 0);

        application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);

        // validate Iterator.remove() over c1's children correctly disconnects
        // the children from the view
        for (Iterator<UIComponent> i = c1.getChildren().iterator(); i.hasNext();) {
            i.next();
            i.remove();
        }

        // at this point, t1 and c4 should be disconnected meaning adding children
        // to t1, t2, or c4 should result in no events being fired
        e.clear();
        t1.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        t1.getChildren().remove(temp);
        t2.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        t2.getChildren().remove(temp);
        c4.getChildren().add(temp);
        assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
                e.isEmpty());
        c4.getChildren().remove(temp);

    }


    public void testEncodeBeginPublish() throws Exception {

        Listener listener = new Listener();
        application.subscribeToEvent(PreRenderComponentEvent.class, listener);

        UIComponent c1 = createComponent();
        c1.encodeBegin(facesContext);
        SystemEvent e = listener.getEvent();
        assertNotNull(e);
        assertTrue(e.getSource() == c1);
        listener.reset();
        c1.encodeChildren(facesContext);
        assertNull(listener.getEvent());
        c1.encodeEnd(facesContext);
        assertNull(listener.getEvent());

        application.unsubscribeFromEvent(PreRenderComponentEvent.class, listener);

    }


    // --------------------------------------------------------- Private Classes


    public static final class Listener implements SystemEventListener {

        private SystemEvent event;

        public void processEvent(SystemEvent event)
                throws AbortProcessingException {
            this.event = event;
        }

        public boolean isListenerForSource(Object source) {
            return (source instanceof UIComponent);
        }

        public SystemEvent getEvent() {
            return event;
        }

        public void reset() {
            event = null;
        }
    }


    public static final class QueueingListener implements SystemEventListener {

        private List<SystemEvent> events = new ArrayList<SystemEvent>();

        public void processEvent(SystemEvent event)
                throws AbortProcessingException {
            events.add(event);
        }

        public boolean isListenerForSource(Object source) {
            return (source instanceof UIComponent);
        }

        public List<SystemEvent> getEvents() {
            return events;
        }

        public void reset() {
            events.clear();
        }
    }


    public static final class ComponentListener implements ComponentSystemEventListener {

        public void processEvent(ComponentSystemEvent event)
                throws AbortProcessingException {

        }
    }


    public static final class UIComponentListener extends UIComponentBase implements ComponentSystemEventListener {

        public String getFamily() {
            return "family";
        }

        public void processEvent(ComponentSystemEvent event)
                throws AbortProcessingException {
        }

    }


    public static final class UIComponentOverrideEncodeBegin extends UIComponentBase {

        public String getFamily() {
            return "UIComponentOverrideEncodeBegin";
        }

        @Override
        public void encodeBegin(FacesContext context) throws IOException {
            // no-op
        }

    }


    public static final class UIComponentOverrideEncodeEnd extends UIComponentBase {

        public String getFamily() {
            return "UIComponentOverrideEncodeEnd";
        }

        @Override
        public void encodeEnd(FacesContext context) throws IOException {
            // no-op
        }
    }


    public static final class CustomAbortProcessingException extends AbortProcessingException {
        public CustomAbortProcessingException() {
            super();
        }

        public CustomAbortProcessingException(String message) {
            super(message);
        }

        public CustomAbortProcessingException(Throwable cause) {
            super(cause);
        }

        public CustomAbortProcessingException(String message, Throwable cause) {
            super(message, cause);
        }
    }


}

Generated by  Doxygen 1.6.0   Back to index