/*
 * Copyright (c) 2010. All rights reserved.
 */
package ro.isdc.wro.http;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import ro.isdc.wro.config.Context;
import ro.isdc.wro.config.jmx.WroConfiguration;
import ro.isdc.wro.http.support.ServletContextAttributeHelper;


/**
 * Test for {@link WroFilter} class.
 *
 * @author Alex Objelean
 * @created Created on Jul 13, 2009
 */
public class TestWroContextFilter {
  private WroContextFilter victim;
  @Mock
  private FilterConfig mockFilterConfig;
  @Mock
  private ServletContext mockServletContext;
  @Mock
  private HttpServletRequest mockRequest;
  @Mock
  private HttpServletResponse mockResponse;
  @Mock
  private FilterChain mockFilterChain;
  @Mock
  private ServletContextAttributeHelper mockServletContextAttributeHelper;

  @BeforeClass
  public static void onBeforeClass() {
    assertEquals(0, Context.countActive());
  }
  
  @Before
  public void setUp()
    throws Exception {
    MockitoAnnotations.initMocks(this);
    victim = new WroContextFilter() {
      @Override
      ServletContextAttributeHelper getServletContextAttributeHelper() {
        return mockServletContextAttributeHelper;
      }
    };
    when(mockFilterConfig.getServletContext()).thenReturn(mockServletContext);
    victim.init(mockFilterConfig);
  }

  @Test
  public void shouldInitializeContextForChainedFilters() throws Exception {
    doAnswer(new Answer<Void>() {
      public Void answer(InvocationOnMock invocation)
          throws Throwable {
        assertTrue(Context.isContextSet());
        return null;
      }
    }).when(mockFilterChain).doFilter(Mockito.any(HttpServletRequest.class), Mockito.any(HttpServletResponse.class));
    victim.doFilter(mockRequest, mockResponse, mockFilterChain);
    verify(mockFilterChain, times(1)).doFilter(Mockito.any(HttpServletRequest.class),
        Mockito.any(HttpServletResponse.class));
    //After chain processing, the context must be unset
    assertFalse(Context.isContextSet());
  }
  
  @Test
  public void shouldUseWroConfigurationFoundInServletContext() throws Exception {
    final WroConfiguration config = new WroConfiguration();
    config.setCacheUpdatePeriod(1000L);
    
    when(mockServletContextAttributeHelper.getWroConfiguration()).thenReturn(config);
    doAnswer(new Answer<Void>() {
      public Void answer(InvocationOnMock invocation)
          throws Throwable {
        assertSame(config, Context.get().getConfig());
        return null;
      }
    }).when(mockFilterChain).doFilter(Mockito.any(HttpServletRequest.class), Mockito.any(HttpServletResponse.class));
    victim.doFilter(mockRequest, mockResponse, mockFilterChain);
    verify(mockFilterChain, Mockito.times(1)).doFilter(Mockito.any(HttpServletRequest.class),
        Mockito.any(HttpServletResponse.class));
  }
  
  /**
   * Test for issue824 (https://code.google.com/p/wro4j/issues/detail?id=824).
   * Checks that nested requests are properly cleaned up. 
   */
  @Test
  public void shouldNotLeakContextForNestedRequest()
      throws Exception {
    
    final WroFilter innerFilter = new WroFilter();
    innerFilter.init(mockFilterConfig);

    final FilterChain chain = new FilterChain() {
      public void doFilter(ServletRequest req, ServletResponse res)
          throws IOException, ServletException {
        victim.doFilter(req, res, mockFilterChain);
      }
    };
    
    victim.init(mockFilterConfig);
    victim.doFilter(mockRequest, mockResponse, chain);
    assertEquals(0, Context.countActive());
  }
}
