From 1433a24052c1d02cd5a9fdcade083bccd1969583 Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Thu, 17 Feb 2011 12:49:07 +0100 Subject: [PATCH] New Servlet configurator. --- .../servlet/ServletConfiguratorTestCase.java | 346 ++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 servlet/src/test/java/com/twelvemonkeys/servlet/ServletConfiguratorTestCase.java 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.emptyList())); + + ServletConfigurator.configure(servlet, config); + + // Verify + verify(servlet, never()).setNonRequired(Matchers.any()); // Simply not configured + } + + @Test(expected = ServletConfigException.class) + public void testMissingRequiredParameter() throws ServletConfigException { + abstract class SubclassedServlet extends AnnotatedServlet { + @Override + @InitParam(required = true) + protected abstract void setFoo(String value); + } + + SubclassedServlet servlet = mock(SubclassedServlet.class); + + ServletConfig config = mock(ServletConfig.class); + when(config.getServletName()).thenReturn("FooServlet"); + when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.emptyList())); + + ServletConfigurator.configure(servlet, config); // Should throw exception + } + + @Test + public void testMissingParameterDefaultValue() throws ServletConfigException { + abstract class SubclassedServlet extends AnnotatedServlet { + @InitParam(defaultValue = "1, 2, 3") + abstract void setNonRequired(int[] value); + } + + SubclassedServlet servlet = mock(SubclassedServlet.class); + + ServletConfig config = mock(ServletConfig.class); + when(config.getServletName()).thenReturn("FooServlet"); + when(config.getInitParameterNames()).thenReturn(Collections.enumeration(Collections.emptyList())); + + ServletConfigurator.configure(servlet, config); + + // Verify + verify(servlet, times(1)).setNonRequired(new int[] {1, 2, 3}); + verify(servlet, times(1)).setNonRequired(Matchers.any()); + } + + + public interface Annotated { + @InitParam(name = "foo") + public void annotated(String an); + } + + public abstract class AnnotatedServlet implements Servlet, Filter { + String priv; + + // Implicit name "x" + @InitParam + public abstract void setX(int x); + + // Implicit name "foo" + @InitParam + protected abstract void setFoo(String foo); + + @InitParam(name = "bar") + abstract void configTheBar(int... bar); + + @InitParam(name = "private") + private void setPrivate(String priv) { + this.priv = priv; + } + } +}