/*
 * Copyright 2002-2004 the original author or authors.
 *
 * 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.springframework.web.flow;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import junit.framework.TestCase;
import org.easymock.MockControl;

import org.springframework.mock.web.MockHttpServletRequest;

/**
 * @author Keith Donald
 * @author Rod Johnson
 */
public class FlowTests extends TestCase {

    private static String PERSON_DETAILS = "personDetails";

    private static String PET_DETAILS = "petDetails";

    public void testCreateFlowWithListener() {
        testCreateFlow(true);
    }

    public void testCreateFlowWithoutListener() {
        // test for npe's implementation if no listener is set
        testCreateFlow(false);
    }

    private void testCreateFlow(boolean listen) {
        final String flowId = "testFlow";

        String viewPersonDetailsStateId = "personDetails.view";
        String getPersonDetailsStateId = "personDetails.get";
        String submitEventId = "submit";
        String submitAction = "personDetails.bindAndValidate";
        String finish = "finish";

        HttpServletRequest req1 = new MockHttpServletRequest();
        HttpServletRequest req2 = new MockHttpServletRequest();

        TestFlow flow = new TestFlow(flowId);
        MockControl flowDaoMc = MockControl.createControl(FlowDao.class);
        FlowDao dao = (FlowDao) flowDaoMc.getMock();
        dao.getActionBean("personDetails.get");
        flowDaoMc.setReturnValue(new NoOpActionBean("success"));
        dao.getActionBean("personDetails.bindAndValidate");
        flowDaoMc.setReturnValue(new NoOpActionBean("success"));
        flowDaoMc.replay();
        flow.setFlowDao(dao);

        FlowSessionExecutionStack fes = new FlowSessionExecutionStack();

        MockControl flowListenerMc = MockControl.createControl(FlowLifecycleListener.class);
        FlowLifecycleListener mockListener = (FlowLifecycleListener) flowListenerMc.getMock();

        mockListener.flowStarted(flow, fes, req1);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, null, flow
                .getRequiredState(getPersonDetailsStateId), fes, req1);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, flow
                .getRequiredState(getPersonDetailsStateId), flow
                .getRequiredState(viewPersonDetailsStateId), fes, req1);
        flowListenerMc.setVoidCallable();

        mockListener.flowEventSignaled(flow, submitEventId, flow
                .getRequiredState(viewPersonDetailsStateId), fes, req2);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, flow
                .getRequiredState(viewPersonDetailsStateId), flow
                .getRequiredState(submitAction), fes, req2);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, flow.getRequiredState(submitAction), flow
                .getRequiredState(finish), fes, req2);
        flowListenerMc.setVoidCallable();

        mockListener.flowEventProcessed(flow, submitEventId, null, fes, req2);
        flowListenerMc.setVoidCallable();

        // NO WAY TO KNOW VALUE OF 2ND FLOW SESSION ARG AHEAD OF TIME AS ITS
        // CREATED DURING RUN - what do I do here?
        mockListener.flowEnded(flow, null, fes, req2);
        flowListenerMc.setVoidCallable();

        flowListenerMc.replay();

        if (listen) {
            flow.setFlowLifecycleListener(mockListener);
        }

        assertEquals(1, flow.getViewStateCount());

        ViewDescriptor vdesc = flow.start(fes, req1, null, null);

        assertEquals(viewPersonDetailsStateId, vdesc.getViewName());
        assertEquals(0, vdesc.getModel().size());

        // ignoring now b/c this is failing on the above flowEnded() call that
        // is currently untestable (that is indeed working correctly)
        try {
            vdesc = flow.execute(submitEventId, viewPersonDetailsStateId, fes, req2, null);
            assertEquals(viewPersonDetailsStateId, vdesc.getViewName());
            assertEquals(0, vdesc.getModel().size());

            flowDaoMc.verify();

            if (listen) {
                flowListenerMc.verify();
            }
        }
        catch (Throwable e) {

        }
    }

    public void testResume() {

        boolean listen = true;

        final String flowId = "testFlow";

        String viewPersonDetailsStateId = "personDetails.view";
        String getPersonDetailsStateId = "personDetails.get";
        String getPetDetailsStateId = "petDetails.get";
        String viewPetDetailsStateId = "petDetails.view";

        String finish = "finish";

        HttpServletRequest req1 = new MockHttpServletRequest();
        HttpServletRequest req2 = new MockHttpServletRequest();

        ResumingFlow flow = new ResumingFlow(flowId);
        MockControl flowDaoMc = MockControl.createControl(FlowDao.class);
        FlowDao dao = (FlowDao) flowDaoMc.getMock();
        dao.getActionBean("petDetails.get");
        flowDaoMc.setReturnValue(new NoOpActionBean("success"));
        flowDaoMc.replay();
        flow.setFlowDao(dao);

        FlowSessionExecutionStack fes = new FlowSessionExecutionStack();

        MockControl flowListenerMc = MockControl.createControl(FlowLifecycleListener.class);
        FlowLifecycleListener mockListener = (FlowLifecycleListener) flowListenerMc.getMock();

        mockListener.flowStarted(flow, fes, req1);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, null, flow
                .getRequiredState(getPetDetailsStateId), fes, req1);
        flowListenerMc.setVoidCallable();

        mockListener.flowStateTransitioned(flow, flow.getRequiredState(getPetDetailsStateId),
                flow.getRequiredState(viewPetDetailsStateId), fes, req1);
        flowListenerMc.setVoidCallable();

        flowListenerMc.replay();

        if (listen) {
            flow.setFlowLifecycleListener(mockListener);
        }

        assertEquals(2, flow.getViewStateCount());

        ViewDescriptor vdesc = flow.resume(fes, getPetDetailsStateId, req1, null, null);

        assertEquals(viewPetDetailsStateId, vdesc.getViewName());
        assertEquals(0, vdesc.getModel().size());

        flowDaoMc.verify();

        if (listen) {
            flowListenerMc.verify();
        }
    }

    private class TestFlow extends Flow {

        public TestFlow(String id) {
            super(id);
        }

        protected void initFlow() {
            add(createGetState(PERSON_DETAILS));
            add(createViewState(PERSON_DETAILS));
            add(createBindAndValidateState(PERSON_DETAILS));
            add(createFinishEndState("viewPersonDetails"));
        }
    };

    private class ResumingFlow extends Flow {

        public ResumingFlow(String id) {
            super(id);
        }

        protected void initFlow() {
            add(createGetState(PERSON_DETAILS));
            add(createViewState(PERSON_DETAILS));
            add(createBindAndValidateState(PERSON_DETAILS));
            add(createGetState(PET_DETAILS, onSuccessView(PET_DETAILS)));
            add(createViewState(PET_DETAILS));

            add(createFinishEndState("viewPersonDetails"));
        }
    };

    /**
     * Does nothing, just returns "success"
     */
    private final class NoOpActionBean implements ActionBean {

        private String retVal;

        public NoOpActionBean(String retVal) {
            this.retVal = retVal;
        }

        public ActionBeanEvent execute(HttpServletRequest request,
                HttpServletResponse response, MutableAttributesAccessor attributes)
                throws RuntimeException {
            return new ActionBeanEvent(this, retVal);
        }
    }

}
@@ -927,16 +927,44 @@
 Johnson%0A
+ * @author Colin Sampaleanu%0A
  */%0Apubl

add resume call to flow