package org.seasar.cubby.filter;

import static org.junit.Assert.*;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.getCurrentArguments;
import static org.easymock.EasyMock.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.easymock.IAnswer;
import org.junit.Test;

public class EncodingFilterTest {

	@Test
	public void setEncoding1() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn(null);
		expect(config.getInitParameter("URIEncoding")).andReturn(null);
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn(null);
		request.setCharacterEncoding("UTF-8");

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void setEncoding2() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn(null);
		expect(config.getInitParameter("URIEncoding")).andReturn(null);
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn("Shift_JIS");

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void setForceEncoding1() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn("true");
		expect(config.getInitParameter("URIEncoding")).andReturn(null);
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn("Shift_JIS");
		request.setCharacterEncoding("UTF-8");

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void setForceEncoding2() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn("true");
		expect(config.getInitParameter("URIEncoding")).andReturn(null);
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn("Shift_JIS");
		request.setCharacterEncoding("UTF-8");

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void setForceEncoding3() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn("false");
		expect(config.getInitParameter("URIEncoding")).andReturn(null);
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn("Shift_JIS");

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void doURIEncoding1() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn("false");
		expect(config.getInitParameter("URIEncoding")).andReturn("UTF-8");
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(null);

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn(null);
		request.setCharacterEncoding("UTF-8");
		expect(request.getServletPath()).andReturn(
				new String("あいうえおABC123".getBytes("UTF-8"), "ISO-8859-1"));
		expect(request.getPathInfo()).andReturn(
				new String("かきくけこXYZ987".getBytes("UTF-8"), "ISO-8859-1"));

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());
		expectLastCall().andAnswer(new IAnswer<Object>() {

			public Object answer() throws Throwable {
				HttpServletRequest request = (HttpServletRequest) getCurrentArguments()[0];
				assertEquals("あいうえおABC123", request.getServletPath());
				assertEquals("かきくけこXYZ987", request.getPathInfo());
				return null;
			}

		});

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	@Test
	public void doURIEncoding2() throws ServletException, IOException {
		FilterConfig config = createMock(FilterConfig.class);
		expect(config.getInitParameter("encoding")).andReturn("UTF-8");
		expect(config.getInitParameter("forceEncoding")).andReturn("false");
		expect(config.getInitParameter("URIEncoding")).andReturn("UTF-8");
		expect(config.getInitParameter("URIBytesEncoding")).andReturn(
				"ISO-8859-1");

		HttpServletRequest request = createMockHttpServletRequest();
		expect(request.getCharacterEncoding()).andReturn(null);
		request.setCharacterEncoding("UTF-8");
		expect(request.getServletPath()).andReturn(
				new String("あいうえおABC123".getBytes("UTF-8"), "ISO-8859-1"));
		expect(request.getPathInfo()).andReturn(
				new String("かきくけこXYZ987".getBytes("UTF-8"), "ISO-8859-1"));

		HttpServletResponse response = createMock(HttpServletResponse.class);

		FilterChain chain = createMock(FilterChain.class);
		chain.doFilter((ServletRequest) anyObject(),
				(ServletResponse) anyObject());
		expectLastCall().andAnswer(new IAnswer<Object>() {

			public Object answer() throws Throwable {
				HttpServletRequest request = (HttpServletRequest) getCurrentArguments()[0];
				assertEquals("あいうえおABC123", request.getServletPath());
				assertEquals("かきくけこXYZ987", request.getPathInfo());
				return null;
			}

		});

		replay(config, request, response, chain);

		EncodingFilter filter = new EncodingFilter();
		filter.init(config);
		filter.doFilter(request, response, chain);
		filter.destroy();

		verify(config, request, response, chain);
	}

	private HttpServletRequest createMockHttpServletRequest() {
		final Map<String, Object> requestAttributes = new HashMap<String, Object>();

		HttpServletRequest request = createMock(HttpServletRequest.class);

		expect(request.getAttribute((String) anyObject())).andAnswer(
				new IAnswer<Object>() {

					public Object answer() throws Throwable {
						return requestAttributes.get(getCurrentArguments()[0]);
					}

				});

		request.setAttribute((String) anyObject(), anyObject());
		expectLastCall().andAnswer(new IAnswer<Object>() {

			public Object answer() throws Throwable {
				requestAttributes.put((String) getCurrentArguments()[0],
						getCurrentArguments()[1]);
				return null;
			}

		});

		request.removeAttribute((String) anyObject());
		expectLastCall().andAnswer(new IAnswer<Object>() {

			public Object answer() throws Throwable {
				requestAttributes.remove((String) getCurrentArguments()[0]);
				return null;
			}

		});

		return request;
	}

}
