package org.mockejb.interceptor.test;

import java.lang.reflect.*;
import java.util.LinkedList;
import java.util.List;

import org.mockejb.interceptor.*;

import junit.framework.TestCase;

/**
 * @author Alexander Ananiev
 */
public class InvocationContextTest extends TestCase  {

    private InvocationContext invocationContext;
    private List interceptorList;

    /**
     * Constructor for InvocationContextTest.
     * @param name
     */
    public InvocationContextTest( String name ) {
        super( name );
    }

        
    public void setUp() throws Exception {
        
        interceptorList = new LinkedList();           
        
        invocationContext = createInvocationContext( interceptorList );
        
    }
    
    public void testInvocation() throws Exception {
 
        // Run w/o interceptors, make sure no errors
        invocationContext.proceed();
        assertTrue( ! invocationContext.getInterceptorIterator().hasNext() );
        
        // add one
        TestInterceptor interceptor1 = new TestInterceptor(); 
        interceptorList.add( interceptor1 );
        
        invocationContext.proceed();
        assertTrue( interceptor1.wasInvoked() );        
        
        // add two
        TestInterceptor interceptor2 = new TestInterceptor(); 
        interceptorList.add( interceptor2 );

        invocationContext.proceed();
        // make sure that they both were called
        assertTrue( interceptor1.wasInvoked() );        
        assertTrue( interceptor2.wasInvoked() );        

        // call again and make sure they were called again        
        invocationContext.proceed();
        assertTrue( interceptor1.wasInvoked() );        
        assertTrue( interceptor2.wasInvoked() );        
        
        // make sure they were called in the right order
        assertEquals( 0, interceptor1.getCallIndexBefore() );
        assertEquals( 0, interceptor1.getCallIndexAfter() );
        assertEquals( 1, interceptor2.getCallIndexBefore() );
        assertEquals( 1, interceptor2.getCallIndexAfter() );
    }
    
    public void testException() throws Exception {

        // add one
        TestInterceptor interceptor1 = new TestInterceptor(); 
        interceptorList.add( interceptor1 );
        // add two
        TestInterceptor interceptor2 = new TestInterceptor(); 
        interceptorList.add( interceptor2 );
        
        interceptor2.setThrowException( new RuntimeException());
        
        try {
            invocationContext.proceed();
            fail( "Expected RuntimeExeption" );
        }
        catch( RuntimeException ex ){
        }
        
        assertTrue( interceptor1.wasInvoked() );        
        assertTrue( interceptor2.wasInvoked() );        
        // make sure the "finally" worked
        assertTrue( ! invocationContext.getInterceptorIterator().hasPrevious() );
                        
    }
    
    public void testContext() throws Exception {

        invocationContext.setContext( TestInterceptor.TEST_CONTEXT, "test");

        TestInterceptor interceptor1 = new TestInterceptor(); 
        interceptorList.add( interceptor1 );

        invocationContext.proceed();
        
        assertEquals("test", interceptor1.getContext());
                
    }
    
    /**
     * Creates InvocationContext for dummy methods
     * @param interceptorList
     * @return
     * @throws Exception
     */
    public InvocationContext createInvocationContext( List interceptorList) throws Exception {
        
        Method ifaceMethod = TestIface.class.getMethod( "test", null ); 
        Method objMethod = TestImpl.class.getMethod( "test", null ); 
        
        InvocationContext invocationContext = new InvocationContext( interceptorList, null, ifaceMethod, 
                new TestImpl(), objMethod, null );
        
        return invocationContext;
    }
}