package com.wesabe.servlet.tests; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import com.wesabe.servlet.BadResponseException; import com.wesabe.servlet.SafeResponse; @RunWith(Enclosed.class) public class SafeResponseTest { private static abstract class Context { protected SafeResponse response; protected HttpServletResponse servletResponse; public void setup() throws Exception { this.servletResponse = mock(HttpServletResponse.class); this.response = new SafeResponse(servletResponse); } } public static class Adding_A_Valid_Cookie extends Context { private Cookie cookie; @Before @Override public void setup() throws Exception { super.setup(); this.cookie = new Cookie("sessionid", "blorp"); } @Test public void itAddsTheCookie() throws Exception { response.addCookie(cookie); verify(servletResponse).addCookie(argThat(new BaseMatcher<Cookie>() { @Override public boolean matches(Object obj) { if (obj instanceof Cookie) { final Cookie cookie = (Cookie) obj; return cookie.getName().equals("sessionid") && cookie.getValue().equals("blorp"); } return false; } @Override public void describeTo(Description desc) { desc.appendText("a normalized cookie"); } })); } } public static class Adding_An_Invalid_Cookie extends Context { private Cookie cookie; @Before @Override public void setup() throws Exception { super.setup(); this.cookie = mock(Cookie.class); when(cookie.getName()).thenReturn("\0\0\0\0DEATH"); } @Test public void itThrowsABadResponseException() throws Exception { try { response.addCookie(cookie); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).addCookie(cookie); } } public static class Adding_A_Valid_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itAddsTheHeader() throws Exception { response.addHeader("Server", "Dingomatic v4.2"); verify(servletResponse).addHeader("Server", "Dingomatic v4.2"); } } public static class Adding_A_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.addHeader("Se\0rver", "Dingomatic v4.2"); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).addHeader("Se\0rver", "Dingomatic v4.2"); } } public static class Adding_A_Header_With_An_Invalid_Value extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.addHeader("Server", "Ding\0omatic v4.2"); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).addHeader("Server", "Ding\0omatic v4.2"); } } public static class Setting_A_Valid_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itSetsTheHeader() throws Exception { response.setHeader("Server", "Dingomatic v4.2"); verify(servletResponse).setHeader("Server", "Dingomatic v4.2"); } } public static class Setting_A_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.setHeader("Se\0rver", "Dingomatic v4.2"); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).setHeader("Se\0rver", "Dingomatic v4.2"); } } public static class Setting_A_Header_With_An_Invalid_Value extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.setHeader("Server", "Ding\0omatic v4.2"); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).setHeader("Server", "Ding\0omatic v4.2"); } } public static class Adding_A_Valid_Date_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itAddsTheHeader() throws Exception { response.addDateHeader("Last-Modified-At", 200L); verify(servletResponse).addDateHeader("Last-Modified-At", 200L); } } public static class Adding_A_Date_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.addDateHeader("Last-\0Modified-At", 200L); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).addDateHeader("Last-\0Modified-At", 200L); } } public static class Setting_A_Valid_Date_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itSetsTheHeader() throws Exception { response.setDateHeader("Last-Modified-At", 200L); verify(servletResponse).setDateHeader("Last-Modified-At", 200L); } } public static class Setting_A_Date_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.setDateHeader("Last-\0Modified-At", 200L); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).setDateHeader("Last-\0Modified-At", 200L); } } public static class Adding_A_Valid_Integer_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itAddsTheHeader() throws Exception { response.addIntHeader("X-Fun-Times", 200); verify(servletResponse).addIntHeader("X-Fun-Times", 200); } } public static class Adding_An_Integer_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.addIntHeader("X\0-Fun-Times", 200); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).addIntHeader("X\0-Fun-Times", 200); } } public static class Setting_A_Valid_Integer_Header extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itSetsTheHeader() throws Exception { response.setIntHeader("X-Fun-Times", 200); verify(servletResponse).setIntHeader("X-Fun-Times", 200); } } public static class Setting_An_Integer_Header_With_An_Invalid_Name extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itThrowsABadResponseException() throws Exception { try { response.setIntHeader("X\0-Fun-Times", 200); fail("should have thrown a BadResponseException but didn't"); } catch (BadResponseException e) { assertThat(e.getBadResponse(), is(sameInstance(servletResponse))); } verify(servletResponse, never()).setIntHeader("X\0-Fun-Times", 200); } } public static class Encoding_URLs extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itPassesThemStraightThrough() throws Exception { final String url = "url"; assertThat(response.encodeRedirectUrl(url), is(sameInstance(url))); assertThat(response.encodeRedirectURL(url), is(sameInstance(url))); assertThat(response.encodeUrl(url), is(sameInstance(url))); assertThat(response.encodeURL(url), is(sameInstance(url))); } } public static class Getting_A_Human_Readable_Representation extends Context { @Before @Override public void setup() throws Exception { super.setup(); } @Test public void itPassesThrough() throws Exception { assertThat(response.toString(), is(servletResponse.toString())); } } }