diff --git a/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTestCase.java b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTestCase.java
new file mode 100644
index 00000000..63f9565f
--- /dev/null
+++ b/servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTestCase.java
@@ -0,0 +1,346 @@
+package com.twelvemonkeys.servlet;
+
+import org.junit.Test;
+import org.mockito.Matchers;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * ServletConfiguratorTestCase
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: haraldk$
+ * @version $Id: ServletConfiguratorTestCase.java,v 1.0 May 2, 2010 3:08:33 PM haraldk Exp$
+ */
+public class ServletConfiguratorTestCase {
+
+ // TODO: Test error conditions:
+ // - Missing name = ... or non-bean conforming method
+ // - Non-accessible? How..?
+ // - Missing required value
+
+ // TODO: Clean up tests to test only one thing at a time
+ // - Public method
+ // - Public method with override
+ // - Public method overridden without annotation
+ // - Protected method
+ // - Protected method with override
+ // - Protected method overridden without annotation
+ // - Package protected method
+ // - Package protected method with override
+ // - Package protected method overridden without annotation
+ // - Private method
+ // - Multiple private methods with same signature (should invoke all, as private methods can't be overridden)
+
+ @Test
+ public void testConfigureAnnotatedServlet() throws ServletConfigException {
+ AnnotatedServlet servlet = mock(AnnotatedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar")));
+ when(config.getInitParameter("x")).thenReturn("99");
+ when(config.getInitParameter("foo")).thenReturn("Foo");
+ when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setX(99);
+ verify(servlet, times(1)).setFoo("Foo");
+ verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
+ }
+
+ @Test
+ public void testConfigureAnnotatedFilter() throws ServletConfigException {
+ AnnotatedServlet servlet = mock(AnnotatedServlet.class);
+
+ FilterConfig config = mock(FilterConfig.class);
+ when(config.getFilterName()).thenReturn("FooFilter");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar")));
+ when(config.getInitParameter("x")).thenReturn("99");
+ when(config.getInitParameter("foo")).thenReturn("Foo");
+ when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setX(99);
+ verify(servlet, times(1)).setFoo("Foo");
+ verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
+ }
+
+ @Test
+ public void testConfigurePrivateMethod() throws ServletConfigException {
+ AnnotatedServlet servlet = mock(AnnotatedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("private")));
+ when(config.getInitParameter("private")).thenReturn("99");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ assertEquals(servlet.priv, "99");
+ }
+
+ @Test
+ public void testConfigurePrivateShadowedMethod() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @InitParam(name = "package-private")
+ abstract void setPrivate(String priv);
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("private")));
+ when(config.getInitParameter("private")).thenReturn("private");
+ when(config.getInitParameter("package-private")).thenReturn("package");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ assertEquals(servlet.priv, "private");
+ verify(servlet, times(1)).setPrivate("package");
+ }
+
+ @Test
+ public void testConfigureSubclassedServlet() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @InitParam(name = "flag")
+ abstract void configureMeToo(boolean flag);
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo", "bar", "flag")));
+ when(config.getInitParameter("x")).thenReturn("99");
+ when(config.getInitParameter("foo")).thenReturn("Foo");
+ when(config.getInitParameter("bar")).thenReturn("-1, 2, 0, 42");
+ when(config.getInitParameter("flag")).thenReturn("true");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setX(99);
+ verify(servlet, times(1)).setFoo("Foo");
+ verify(servlet, times(1)).configTheBar(-1, 2, 0, 42);
+ verify(servlet, times(1)).configureMeToo(true);
+ }
+
+ @Test
+ public void testConfigureAnnotatedServletWithLispStyle() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @InitParam(name = "the-explicit-x")
+ abstract public void setExplicitX(int x);
+
+ @InitParam
+ abstract public void setTheOtherX(int x);
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("the-explicit-x", "the-other-x")));
+ when(config.getInitParameter("the-explicit-x")).thenReturn("-1");
+ when(config.getInitParameter("the-other-x")).thenReturn("42");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setExplicitX(-1);
+ verify(servlet, times(1)).setTheOtherX(42);
+ }
+
+ @Test
+ public void testConfigureSubclassedServletWithOverride() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @Override
+ @InitParam(name = "y")
+ public void setX(int x) {
+ }
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "y")));
+ when(config.getInitParameter("x")).thenReturn("99");
+ when(config.getInitParameter("y")).thenReturn("-66");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setX(-66);
+ verify(servlet, times(1)).setX(anyInt()); // We don't want multiple invocations, only the overridden method
+ }
+
+ @Test
+ public void testConfigureSubclassedServletWithOverrideNoParam() throws ServletConfigException {
+ // NOTE: We must allow overriding the methods without annotation present, in order to allow CGLib/proxies of the class...
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @Override
+ @InitParam(name = "")
+ public void setX(int x) {
+ }
+
+ @Override
+ public void setFoo(String foo) {
+ }
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("x", "foo")));
+ when(config.getInitParameter("x")).thenReturn("99");
+ when(config.getInitParameter("foo")).thenReturn("Foo");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, never()).setX(anyInt());
+ verify(servlet, times(1)).setFoo("Foo");
+ verify(servlet, times(1)).setFoo(Matchers.any()); // We don't want multiple invocations
+ }
+
+ // Test interface
+ @Test
+ public void testConfigureServletWithInterface() throws ServletConfigException {
+ abstract class InterfacedServlet implements Servlet, Annotated {
+ }
+
+ InterfacedServlet servlet = mock(InterfacedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("foo")));
+ when(config.getInitParameter("foo")).thenReturn("Foo");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).annotated("Foo");
+ }
+
+ // TODO: Test override/shadow of package protected method outside package
+
+ @Test
+ public void testRequiredParameter() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @InitParam(required = true)
+ abstract void setRequired(String value);
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Arrays.asList("required")));
+ when(config.getInitParameter("required")).thenReturn("the required value");
+
+ ServletConfigurator.configure(servlet, config);
+
+ // Verify
+ verify(servlet, times(1)).setRequired("the required value");
+ verify(servlet, times(1)).setRequired(Matchers.any()); // We don't want multiple invocations
+ }
+
+ @Test
+ public void testMissingParameter() throws ServletConfigException {
+ abstract class SubclassedServlet extends AnnotatedServlet {
+ @InitParam()
+ abstract void setNonRequired(String value);
+ }
+
+ SubclassedServlet servlet = mock(SubclassedServlet.class);
+
+ ServletConfig config = mock(ServletConfig.class);
+ when(config.getServletName()).thenReturn("FooServlet");
+ when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.