package org.springframework.faces.webflow;
import java.io.IOException;
import java.io.StringWriter;
import javax.faces.FacesException;
import javax.faces.component.UIForm;
import javax.faces.component.UIInput;
import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlForm;
import javax.faces.component.html.HtmlInputText;
import javax.faces.context.FacesContext;
import javax.faces.lifecycle.Lifecycle;
import junit.framework.TestCase;
import org.apache.myfaces.test.mock.MockResponseWriter;
import org.apache.myfaces.test.mock.MockStateManager;
import org.easymock.EasyMock;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.execution.FlowExecutionContext;
import org.springframework.webflow.execution.FlowExecutionKey;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.RequestContextHolder;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockParameterMap;
public class JsfViewTests extends TestCase {
private static final String VIEW_ID = "testView.xhtml";
private final MockExternalContext extContext = new MockExternalContext();
private JsfView view;
private final JSFMockHelper jsfMock = new JSFMockHelper();
private final StringWriter output = new StringWriter();
private final String event = "foo";
private final RequestContext context = EasyMock.createMock(RequestContext.class);
private final FlowExecutionContext flowExecutionContext = EasyMock.createMock(FlowExecutionContext.class);
@SuppressWarnings("unchecked")
private final MutableAttributeMap<Object> flashScope = EasyMock.createMock(MutableAttributeMap.class);
@SuppressWarnings("unchecked")
private final MutableAttributeMap<Object> flowMap = EasyMock.createMock(MutableAttributeMap.class);
private final FlowExecutionKey key = new FlowExecutionKey() {
public String toString() {
return "MOCK_KEY";
}
public boolean equals(Object o) {
return true;
}
public int hashCode() {
return 0;
}
};
protected void setUp() throws Exception {
this.jsfMock.setUp();
this.jsfMock.facesContext().getApplication().setViewHandler(new MockViewHandler());
this.jsfMock.facesContext().getApplication().setStateManager(new TestStateManager());
this.jsfMock.facesContext().setResponseWriter(new MockResponseWriter(this.output, null, null));
UIViewRoot viewToRender = new UIViewRoot();
viewToRender.setRenderKitId("HTML_BASIC");
viewToRender.setViewId(VIEW_ID);
this.jsfMock.facesContext().setViewRoot(viewToRender);
UIForm form = new HtmlForm();
form.setId("myForm");
UIInput input = new HtmlInputText();
input.setId("foo");
form.getChildren().add(input);
viewToRender.getChildren().add(form);
RequestContextHolder.setRequestContext(this.context);
EasyMock.expect(this.context.getExternalContext()).andStubReturn(this.extContext);
EasyMock.expect(this.context.getFlashScope()).andStubReturn(this.flashScope);
EasyMock.expect(this.context.getFlowScope()).andStubReturn(this.flowMap);
EasyMock.expect(this.context.getFlowExecutionContext()).andStubReturn(this.flowExecutionContext);
EasyMock.expect(this.flowExecutionContext.getKey()).andStubReturn(this.key);
this.view = new JsfView(viewToRender, this.jsfMock.lifecycle(), this.context);
}
protected void tearDown() throws Exception {
super.tearDown();
this.jsfMock.tearDown();
RequestContextHolder.setRequestContext(null);
}
public final void testSaveState() {
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
this.view.saveState();
}
public final void testRender() throws IOException {
EasyMock.expect(this.flashScope.put(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY), EasyMock.anyObject()))
.andStubReturn(null);
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
this.view.render();
}
public final void testRenderException() throws IOException {
EasyMock.expect(this.flashScope.put(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY), EasyMock.anyObject()))
.andStubReturn(null);
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
this.jsfMock.application().setViewHandler(new ExceptionalViewHandler());
try {
this.view.render();
} catch (Exception ex) {
}
}
/**
* View already exists in view scope and must be restored and the lifecycle executed, no event signaled
*/
public final void testProcessUserEvent_Restored_NoEvent() {
EasyMock.expect(this.flashScope.getBoolean(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY))).andStubReturn(
false);
EasyMock.expect(this.flashScope.put(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY), EasyMock.anyObject()))
.andStubReturn(null);
Lifecycle lifecycle = new NoEventLifecycle(this.jsfMock.lifecycle());
UIViewRoot existingRoot = new UIViewRoot();
existingRoot.setViewId(VIEW_ID);
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
JsfView restoredView = new JsfView(existingRoot, lifecycle, this.context);
restoredView.processUserEvent();
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
assertTrue("The lifecycle should have been invoked", ((NoEventLifecycle) lifecycle).executed);
}
/**
* View already exists in view scope and must be restored and the lifecycle executed, an event is signaled
*/
public final void testProcessUserEvent_Restored_EventSignaled() {
EasyMock.expect(this.flashScope.getBoolean(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY))).andStubReturn(
false);
EasyMock.expect(this.flashScope.put(EasyMock.matches(FlowFacesContext.RENDER_RESPONSE_KEY), EasyMock.anyObject()))
.andStubReturn(null);
Lifecycle lifecycle = new EventSignalingLifecycle(this.jsfMock.lifecycle());
UIViewRoot existingRoot = new UIViewRoot();
existingRoot.setViewId(VIEW_ID);
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
JsfView restoredView = new JsfView(existingRoot, lifecycle, this.context);
restoredView.processUserEvent();
assertTrue("No event was signaled,", restoredView.hasFlowEvent());
assertEquals("Event should be " + this.event, this.event, restoredView.getFlowEvent().getId());
assertTrue("The lifecycle should have been invoked", ((EventSignalingLifecycle) lifecycle).executed);
}
public final void testUserEventQueued_GETRefresh() {
MockParameterMap requestParameterMap = new MockParameterMap();
requestParameterMap.put("execution", "e1s1");
EasyMock.expect(this.context.getRequestParameters()).andStubReturn(requestParameterMap);
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
JsfView createdView = new JsfView(new UIViewRoot(), this.jsfMock.lifecycle(), this.context);
assertFalse("No user event should be queued", createdView.userEventQueued());
}
public final void testUserEventQueued_FormSubmitted() {
this.jsfMock.request().addParameter("execution", "e1s1");
this.jsfMock.request().addParameter("javax.faces.ViewState", "e1s1");
EasyMock.replay(new Object[] { this.context, this.flowExecutionContext, this.flowMap, this.flashScope });
JsfView createdView = new JsfView(new UIViewRoot(), this.jsfMock.lifecycle(), this.context);
assertTrue("User event should be queued", createdView.userEventQueued());
}
private class ExceptionalViewHandler extends MockViewHandler {
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException {
throw new IOException("Rendering blew up");
}
}
private class TestStateManager extends MockStateManager {
public SerializedView saveSerializedView(FacesContext context) {
SerializedView state = new SerializedView(new Object[] { "tree_state" }, new Object[] { "component_state" });
return state;
}
}
private class NoEventLifecycle extends FlowLifecycle {
boolean executed = false;
public NoEventLifecycle(Lifecycle delegate) {
super(delegate);
}
public void execute(FacesContext context) throws FacesException {
assertFalse("Lifecycle executed more than once", this.executed);
super.execute(context);
this.executed = true;
}
}
private class EventSignalingLifecycle extends FlowLifecycle {
boolean executed = false;
public EventSignalingLifecycle(Lifecycle delegate) {
super(delegate);
}
public void execute(FacesContext context) throws FacesException {
assertFalse("Lifecycle executed more than once", this.executed);
super.execute(context);
JsfViewTests.this.extContext.getRequestMap().put(JsfView.EVENT_KEY, JsfViewTests.this.event);
this.executed = true;
}
}
}