<?xml version="1.0"?>

<!--
 * ========================================================================
 * 
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * ========================================================================
-->

<document id="howto_testcase_filter">

  <properties>
    <title>FilterTestCase Principles</title>
  </properties>

  <body>

    <section title="When to use?">

      <p>
        Your test case class should extend <code>FilterTestCase</code>
        whenever you are unit testing:
      </p>
      <ul>
        <li>
          Servlet Filters,
        </li>
        <li>
          Any java code that uses Filter API objects
          (<code>FilterConfig</code>, ...)
        </li>
      </ul>

      <note>
        <strong>As filters only exist in Servlet API 2.3, you must use the
        Cactus version for Servlet API 2.3 if you wish to write tests for
        them.</strong>
      </note>
      <note>
        <strong>Filter unit testing is only available in Cactus 1.2 and
        above.</strong>
      </note>

    </section>

    <section title="Provided Implicit Objects">

      <p>
        Cactus automatically initializes the implicit objects for you and
        they are made available to your <code>setUp()</code>,
        <code>testXXX()</code> and <code>tearDown()</code> methods as
        instance variables of the <code>FilterTestCase</code> class (and thus
        as instance variables of your test case class as it extends
        <code>FilterTestCase</code>).
      </p>
      <note>
        You may ask yourself how Cactus initializes these objects. The
        mechanism is described in the <link href="site:how_it_works">How it
        works</link> guide.
      </note>

      <p>
        The provided implicit objects are:
      </p>

      <anchor id="filter_request"/>
      <section title="request">

        <p>
         See <code>ServletTestCase</code><code>
         <jump href="site:howto_testcase_servlet" anchor="servlet_request">request
         </jump></code> implicit object for documentation.
       </p>

      </section>

      <anchor id="filter_response"/>
      <section title="response">

        <p>
         See <code>ServletTestCase</code><code>
         <jump href="site:howto_testcase_servlet" anchor="servlet_response">response
         </jump></code> implicit object for documentation.
       </p>

      </section>

      <anchor id="filter_config"/>
      <section title="config">

        <table>
          <tr>
            <td>
              Instance variable name
            </td>
            <td>
              <strong><code>config</code></strong>
            </td>
          </tr>
          <tr>
            <td>
              Class name
            </td>
            <td>
              <code>org.apache.cactus.server.FilterConfigWrapper
              </code>, which inherits from
              <code>javax.servlet.FilterConfig</code>
            </td>
          </tr>
        </table>

        <p>
          Cactus wraps the original Filter Config for two reasons:
        </p>
        <ul>
          <li>
            In order to provide additional methods. For example, it is
            possible to initialise filter parameters without setting them in
            <code>web.xml</code>, etc...,
          </li>
          <li>
            So that it can return a wrapped Servlet Context instead of the
            original one. This is because the Servlet Context is used
            to perform forwards and includes and we need to pass to these
            methods the original request and response. As we have wrapped
            the request, we need to wrap the Servlet Context to pass the
            original request (and not the wrapped one).
          </li>
        </ul>
        <p>
          The <code>config</code> implicit object will contain all
          initialisation parameters defined in <code>web.xml</code>
          under the Filter Redirector filter definition.
        </p>
        <p>
          See the javadoc for the
          <code>org.apache.cactus.server.FilterConfigWrapper</code>
          class for all details. You should also look at the
          samples provided in the Cactus distribution.
        </p>

        <section title="Additional methods">

          <p>
            Additional methods provided:
          </p>
          <ul>
            <li>
              <code>setInitParameter()</code>: sets an initialisation
              parameter (as if it has been defined in the <code>web.xml</code>
              file),
            </li>
            <li>
              <code>setFilterName()</code>: sets the Filter name that will be
              returned by <code>getFilterName()</code> (if not set, the
              Cactus Filter redirector name will be returned).
            </li>
          </ul>

        </section>

      </section>

      <anchor id="filter_filterChain"/>
      <section title="filterChain">

        <table>
          <tr>
            <td>
              Instance variable name
            </td>
            <td>
              <strong><code>filterChain</code></strong>
            </td>
          </tr>
          <tr>
            <td>
              Class name
            </td>
            <td>
              <code>javax.servlet.FilterChain</code>
            </td>
          </tr>
        </table>

        <note>
          Cactus does not wrap the filter chain.
        </note>

      </section>

    </section>

    <section title="Tips and Tricks">

      <section title="Simulating the next fitler in chain">

        <p>
          As you are performing unit testing of your filter, you may wish
          to simulate the next filter in the filter chain so that you can
          decide, as part of your unit test, what this other filter returns
          to your filter under test. Here is how you could do that:
        </p>

<source><![CDATA[
public void testDoFilterOK() throws ServletException, IOException
{
    SampleFilter filter = new SampleFilter();
    filter.init(config);
[...]

    FilterChain mockFilterChain = new FilterChain() {
        public void doFilter(ServletRequest theRequest,
            ServletResponse theResponse) throws IOException, ServletException
        {
            PrintWriter writer = theResponse.getWriter();
            writer.print("<p>some content</p>");
            writer.close();
        }
        public void init(FilterConfig theConfig)
        {
        }
        public void destroy()
        {
        }
    };

    filter.doFilter(request, response, mockFilterChain);
[...]
}
]]></source>

        <p>
          See the samples provided as part of the Cactus distribution.
        </p>

      </section>

    </section>

    <section title="Sample">

      <p>
        This is a very basic sample intended to give you a flavour of Filter
        unit testing. Check the distribution samples for extensive
        examples. The filter we are testing here simply adds a header and
        a footer to the response. The header and footer texts are
        defined as a parameter defined in <code>web.xml</code>.
      </p>

<source><![CDATA[
public void testXXX() throws ServletException, IOException
{
    SampleFilter filter = new SampleFilter();
    config.setInitParameter("header", "<h1>header</h1>");
    config.setInitParameter("footer", "<h1>footer</h1>");
    filter.init(config);

    FilterChain mockFilterChain = new FilterChain() {
        public void doFilter(ServletRequest theRequest,
            ServletResponse theResponse) throws IOException, ServletException
        {
            PrintWriter writer = theResponse.getWriter();
            writer.print("<p>some content</p>");
            writer.close();
        }
        public void init(FilterConfig theConfig)
        {
        }
        public void destroy()
        {
        }
    };

    filter.doFilter(request, response, mockFilterChain);
}

public void endXXX(WebResponse theResponse)
{
    assertEquals("<h1>header</h1><p>some content</p><h1>footer</h1>",
        theResponse.getText());
}
]]></source>

    </section>

  </body>
</document>
