/*
 * $Id: TestRequestUtils.java 471754 2006-11-06 14:55:09Z husted $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.struts.util;

import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.chain.Constants;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.mock.MockFormBean;
import org.apache.struts.mock.TestMockBase;

import junit.framework.Test;
import junit.framework.TestSuite;

/**
 * <p>Unit tests for <code>org.apache.struts.util.RequestUtils</code>.</p>
 *
 * @version $Rev: 471754 $ $Date: 2005-08-14 17:24:39 -0400 (Sun, 14 Aug 2005)
 *          $
 */
public class TestRequestUtils extends TestMockBase {

    // ----------------------------------------------------------------- Basics

    /**
     * @param name String
     */
    public TestRequestUtils(final String name) {
        super(name);
    }

    /**
     * @param args String[]
     */
    public static void main(final String[] args) {
        junit.textui.TestRunner.main(new String[] {
                TestRequestUtils.class.getName()
            });
    }

    /**
     * @return Test
     */
    public static Test suite() {
        return new TestSuite(TestRequestUtils.class);
    }

    // ------------------------------------------------------- Individual Tests

    // ---------------------------------------------------------- absoluteURL()

    /**
     * testAbsoluteURL
     */
    public void testAbsoluteURL() {
        this.request.setPathElements("/myapp", "/action.do", null, null);

        String url = null;

        url = RequestUtils.absoluteURL(this.request, "/foo/bar.jsp").toString();
        assertEquals("absoluteURL is correct", "http://localhost:8080/myapp/foo/bar.jsp", url);
    }

    // ------------------------------------------------------------ actionURL()

    /**
     * Default application -- extension mapping
     */
    public void testActionURL1() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig);
        this.request.setPathElements("/myapp", "/foo.do", null, null);

        String url = RequestUtils.actionURL(this.request,
                    this.moduleConfig.findActionConfig("/dynamic"), "*.do");

        assertNotNull("URL was returned", url);
        assertEquals("URL value", "/dynamic.do", url);
    }

    /**
     * Second application -- extension mapping
     */
    public void testActionURL2() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig2);
        this.request.setPathElements("/myapp", "/2/foo.do", null, null);

        String url = RequestUtils.actionURL(this.request,
                    this.moduleConfig2.findActionConfig("/dynamic2"), "*.do");

        assertNotNull("URL was returned", url);
        assertEquals("URL value", "/2/dynamic2.do", url);
    }

    /**
     * Default application -- path mapping
     */
    public void testActionURL3() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig);
        this.request.setPathElements("/myapp", "/do/foo", null, null);

        String url = RequestUtils.actionURL(this.request,
                    this.moduleConfig.findActionConfig("/dynamic"), "/do/*");

        assertNotNull("URL was returned", url);
        assertEquals("URL value", "/do/dynamic", url);
    }

    // ----------------------------------------------------- createActionForm()

    /**
     * Default module -- No ActionForm should be created
     */
    public void testCreateActionForm1a() {
        this.request.setPathElements("/myapp", "/noform.do", null, null);

        ActionConfig mapping =
                this.moduleConfig.findActionConfig("/noform");

        assertNotNull("Found /noform mapping", mapping);

        ActionForm form =
            RequestUtils.createActionForm(this.request, mapping, this.moduleConfig, null);

        assertNull("No ActionForm returned", form);
    }

    /**
     * Second module -- No ActionForm should be created
     */
    public void testCreateActionForm1b() {
        this.request.setPathElements("/myapp", "/2/noform.do", null, null);

        ActionConfig mapping =
                this.moduleConfig2.findActionConfig("/noform");

        assertNotNull("Found /noform mapping", mapping);

        ActionForm form =
            RequestUtils.createActionForm(this.request, mapping, this.moduleConfig2, null);

        assertNull("No ActionForm returned", form);
    }

    /**
     * Default module -- Standard ActionForm should be created
     */
    public void testCreateActionForm2a() {
        this.request.setPathElements("/myapp", "/static.do", null, null);

        ActionConfig mapping =
                this.moduleConfig.findActionConfig("/static");

        assertNotNull("Found /static mapping", mapping);
        assertNotNull("Mapping has non-null name", mapping.getName());
        assertEquals("Mapping has correct name", "static", mapping.getName());
        assertNotNull("AppConfig has form bean " + mapping.getName(),
                this.moduleConfig.findFormBeanConfig(mapping.getName()));

        ActionForm form =
            RequestUtils.createActionForm(this.request, mapping, this.moduleConfig, null);

        assertNotNull("ActionForm returned", form);
        assertTrue("ActionForm of correct type", form instanceof MockFormBean);
    }

    /**
     * Second module -- Standard ActionForm should be created
     */
    public void testCreateActionForm2b() {
        this.request.setPathElements("/myapp", "/2/static.do", null, null);

        ActionConfig mapping =
                this.moduleConfig2.findActionConfig("/static");

        assertNotNull("Found /static mapping", mapping);
        assertNotNull("Mapping has non-null name", mapping.getName());
        assertEquals("Mapping has correct name", "static", mapping.getName());
        assertNotNull("AppConfig has form bean " + mapping.getName(),
                this.moduleConfig.findFormBeanConfig(mapping.getName()));

        ActionForm form =
            RequestUtils.createActionForm(this.request, mapping, this.moduleConfig2, null);

        assertNotNull("ActionForm returned", form);
        assertTrue("ActionForm of correct type", form instanceof MockFormBean);
    }

    // ----------------------------------------------------------- forwardURL()

    /**
     * Default module (default forwardPattern)
     */
    public void testForwardURL1() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig);
        this.request.setPathElements("/myapp", "/action.do", null, null);

        ForwardConfig forward = null;
        String result = null;

        // redirect=false, module=null
        forward = this.moduleConfig.findForwardConfig("moduleForward");
        assertNotNull("moduleForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleForward computed", result);
        assertEquals("moduleForward value", "/module/forward", result);

        // redirect=true, module=null
        forward = this.moduleConfig.findForwardConfig("moduleRedirect");
        assertNotNull("moduleRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleRedirect computed", result);
        assertEquals("moduleRedirect value", "/module/redirect", result);

        // redirect=false, module=/context
        forward = this.moduleConfig.findForwardConfig("contextForward");
        assertNotNull("contextForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextForward computed", result);
        assertEquals("contextForward value", "/context/forward", result);

        // redirect=true, module=/context
        forward = this.moduleConfig.findForwardConfig("contextRedirect");
        assertNotNull("contextRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextRedirect computed", result);
        assertEquals("contextRedirct value", "/context/redirect", result);

        // noslash, module=null
        forward = this.moduleConfig.findForwardConfig("moduleNoslash");
        assertNotNull("moduleNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleNoslash computed", result);
        assertEquals("moduleNoslash value", "/module/noslash", result);

        // noslash, module=/
        forward = this.moduleConfig.findForwardConfig("contextNoslash");
        assertNotNull("contextNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextNoslash computed", result);
        assertEquals("contextNoslash value", "/context/noslash", result);
    }

    /**
     * Second module (default forwardPattern)
     */
    public void testForwardURL2() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig2);
        this.request.setPathElements("/myapp", "/2/action.do", null, null);

        ForwardConfig forward = null;
        String result = null;

        // redirect=false, module=null
        forward = this.moduleConfig2.findForwardConfig("moduleForward");
        assertNotNull("moduleForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleForward computed", result);
        assertEquals("moduleForward value", "/2/module/forward", result);

        // redirect=true, module=null
        forward = this.moduleConfig2.findForwardConfig("moduleRedirect");
        assertNotNull("moduleRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleRedirect computed", result);
        assertEquals("moduleRedirect value", "/2/module/redirect", result);

        // redirect=false, module=/context
        forward = this.moduleConfig2.findForwardConfig("contextForward");
        assertNotNull("contextForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextForward computed", result);
        assertEquals("contextForward value", "/context/forward", result);

        // redirect=true, module=/context
        forward = this.moduleConfig2.findForwardConfig("contextRedirect");
        assertNotNull("contextRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextRedirect computed", result);
        assertEquals("contextRedirct value", "/context/redirect", result);

        // noslash, module=null
        forward = this.moduleConfig2.findForwardConfig("moduleNoslash");
        assertNotNull("moduleNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleNoslash computed", result);
        assertEquals("moduleNoslash value", "/2/module/noslash", result);

        // noslash, module=/
        forward = this.moduleConfig2.findForwardConfig("contextNoslash");
        assertNotNull("contextNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextNoslash computed", result);
        assertEquals("contextNoslash value", "/context/noslash", result);
    }

    /**
     * Third module (custom forwardPattern)
     */
    public void testForwardURL3() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig3);
        this.request.setPathElements("/myapp", "/3/action.do", null, null);

        ForwardConfig forward = null;
        String result = null;

        // redirect=false, module=null
        forward = this.moduleConfig3.findForwardConfig("moduleForward");
        assertNotNull("moduleForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleForward computed", result);
        assertEquals("moduleForward value", "/forwarding/3/module/forward",
            result);

        // redirect=true, module=null
        forward = this.moduleConfig3.findForwardConfig("moduleRedirect");
        assertNotNull("moduleRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleRedirect computed", result);
        assertEquals("moduleRedirect value", "/forwarding/3/module/redirect",
            result);

        // redirect=false, module=/context
        forward = this.moduleConfig3.findForwardConfig("contextForward");
        assertNotNull("contextForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextForward computed", result);
        assertEquals("contextForward value", "/forwarding/context/forward",
            result);

        // redirect=true, module=/context
        forward = this.moduleConfig3.findForwardConfig("contextRedirect");
        assertNotNull("contextRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextRedirect computed", result);
        assertEquals("contextRedirct value", "/forwarding/context/redirect",
            result);

        // noslash, module=null
        forward = this.moduleConfig3.findForwardConfig("moduleNoslash");
        assertNotNull("moduleNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("moduleNoslash computed", result);
        assertEquals("moduleNoslash value", "/forwarding/3/module/noslash",
            result);

        // noslash, module=/
        forward = this.moduleConfig3.findForwardConfig("contextNoslash");
        assertNotNull("contextNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, null);
        assertNotNull("contextNoslash computed", result);
        assertEquals("contextNoslash value", "/forwarding/context/noslash",
            result);
    }

    /**
     * Cross module forwards
     */
    public void testForwardURLa() {
        this.request.setAttribute(Globals.MODULE_KEY, this.moduleConfig);
        this.request.setPathElements("/myapp", "/action.do", null, null);

        ForwardConfig forward = null;
        String result = null;

        // redirect=false, contextRelative=false, link to module 3
        forward = this.moduleConfig3.findForwardConfig("moduleForward");
        assertNotNull("moduleForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("moduleForward computed", result);
        assertEquals("moduleForward value", "/forwarding/3/module/forward",
            result);

        // redirect=true, contextRelative=false, link to module 3
        forward = this.moduleConfig3.findForwardConfig("moduleRedirect");
        assertNotNull("moduleRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("moduleRedirect computed", result);
        assertEquals("moduleRedirect value", "/forwarding/3/module/redirect",
            result);

        // redirect=false, module=/context
        forward = this.moduleConfig3.findForwardConfig("contextForward");
        assertNotNull("contextForward found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("contextForward computed", result);
        assertEquals("contextForward value", "/forwarding/context/forward",
            result);

        // redirect=true, module=/context
        forward = this.moduleConfig3.findForwardConfig("contextRedirect");
        assertNotNull("contextRedirect found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("contextRedirect computed", result);
        assertEquals("contextRedirct value", "/forwarding/context/redirect",
            result);

        // noslash, contextRelative=false, link to module 3
        forward = this.moduleConfig3.findForwardConfig("moduleNoslash");
        assertNotNull("moduleNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("moduleNoslash computed", result);
        assertEquals("moduleNoslash value", "/forwarding/3/module/noslash",
            result);

        // noslash, module=/
        forward = this.moduleConfig3.findForwardConfig("contextNoslash");
        assertNotNull("contextNoslash found", forward);
        result = RequestUtils.forwardURL(this.request, forward, this.moduleConfig3);
        assertNotNull("contextNoslash computed", result);
        assertEquals("contextNoslash value", "/forwarding/context/noslash",
            result);
    }

    // ----------------------------------------------------------- requestURL()

    /**
     * testRequestURL
     */
    public void testRequestURL() {
        this.request.setPathElements("/myapp", "/foo.do", null, null);

        String url = null;
        url = RequestUtils.requestURL(this.request).toString();

        assertNotNull("URL was returned", url);
        assertEquals("URL value", "http://localhost:8080/myapp/foo.do", url);
    }

    // ---------------------------------------------------- selectApplication()

    /**
     * Map to the default module -- direct
     */
    public void testSelectApplication1a() {
        this.request.setPathElements("/myapp", "/noform.do", null, null);
        ModuleUtils.getInstance().selectModule(this.request, this.context);

        ModuleConfig actual =
            (ModuleConfig) this.request.getAttribute(Globals.MODULE_KEY);

        assertNotNull("Selected a module", actual);
        assertEquals("Selected correct module", "", actual.getPrefix());

        // FIXME - check module resources?
    }

    /**
     * Map to the second module -- direct
     */
    public void testSelectApplication1b() {
        String[] prefixes = {"/1", "/2"};

        this.context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
        this.request.setPathElements("/myapp", "/2/noform.do", null, null);

        ModuleUtils.getInstance().selectModule(this.request, this.context);

        ModuleConfig actual =
            (ModuleConfig) this.request.getAttribute(Globals.MODULE_KEY);

        assertNotNull("Selected a module", actual);
        assertEquals("Selected correct module", "/2", actual.getPrefix());

        // FIXME - check module resources?
    }

    /**
     * Map to the default module -- include
     */
    public void testSelectApplication2a() {
        this.request.setPathElements("/myapp", "/2/noform.do", null, null);
        this.request.setAttribute(Constants.INCLUDE_SERVLET_PATH, "/noform.do");
        ModuleUtils.getInstance().selectModule(this.request, this.context);

        ModuleConfig actual =
            (ModuleConfig) this.request.getAttribute(Globals.MODULE_KEY);

        assertNotNull("Selected an application", actual);
        assertEquals("Selected correct application", "",
            actual.getPrefix());

        // FIXME - check application resources?
    }

    /**
     * Map to the second module -- include
     */
    public void testSelectApplication2b() {
        String[] prefixes = {"/1", "/2"};

        this.context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
        this.request.setPathElements("/myapp", "/noform.do", null, null);
        this.request.setAttribute(Constants.INCLUDE_SERVLET_PATH, "/2/noform.do");
        ModuleUtils.getInstance().selectModule(this.request, this.context);

        ModuleConfig actual =
            (ModuleConfig) this.request.getAttribute(Globals.MODULE_KEY);

        assertNotNull("Selected a module", actual);
        assertEquals("Selected correct module", "/2", actual.getPrefix());

        // FIXME - check application resources?
    }

    // ------------------------------------------------------------ serverURL()

    /**
     * Basic test on values in mock objects
     */
    public void testServerURL() {
        String url = null;
        url = RequestUtils.serverURL(this.request).toString();

        assertNotNull("serverURL is present", url);
        assertEquals("serverURL value", "http://localhost:8080", url);
    }
}
