package test.mockobjects.dynamic;

import com.mockobjects.dynamic.*;
import com.mockobjects.util.*;

import junit.framework.*;


public class CallOnceExpectationTest extends TestCase {

	final String RESULT = "result!";
	final String METHOD_NAME = "methodName";
	final Object[] ARGS = { "arg1", "arg2" }; 
	final String DECORATED_DESCRIPTION = DynamicUtil.methodToString( METHOD_NAME, ARGS );
	
	Mock ignoredMock = null;
	MockCallable mockCallable = new MockCallable();
	CallOnceExpectation call = new CallOnceExpectation( mockCallable );
	
	public CallOnceExpectationTest(String name) {
		super(name);
	}

	public void setUp() {
		mockCallable.setupGetDescription(DECORATED_DESCRIPTION);
	}
	
	public void testDescription() {
		AssertMo.assertIncludes( "should contain decorated's description",
								 DECORATED_DESCRIPTION, call.getDescription() );
		AssertMo.assertIncludes( "should say that decorated call has called status",
								 "called", call.getDescription() );
	}
	
	public void testDoesNotVerifyIfNotCalled() {
		try {
			call.verify();
		}
		catch( AssertionFailedError ex ) {
			AssertMo.assertIncludes( "should include description of expected call",
									 DECORATED_DESCRIPTION, ex.getMessage() );
			return;
		}
		
		fail( "verify did not fail when expected call not called");
	}
	
	public void testVerifiesIfCalled() throws Throwable {
		mockCallable.setupCallReturn( RESULT );
		mockCallable.setExpectedVerifyCalls(1);
		
		call.call( ignoredMock, METHOD_NAME, ARGS );
		call.verify();
		
		mockCallable.verifyExpectations();
	}
	
	public void testMatchesDelegated() throws Throwable {
		mockCallable.setExpectedMatches( METHOD_NAME, ARGS );
		mockCallable.setupMatchesReturn(true);
		assertTrue( "returns matches to be true", call.matches( METHOD_NAME, ARGS ) );
		mockCallable.verifyExpectations();
	}
	
	public void testCallArgumentsPassedThrough() throws Throwable {
		mockCallable.setExpectedCall(ignoredMock, METHOD_NAME, ARGS);
		mockCallable.setupCallReturn(RESULT);
		
		call.call( ignoredMock, METHOD_NAME, ARGS );
		mockCallable.verifyExpectations();
	}
	
    public void testDoesNotMatchAfterMethodCalled() throws Throwable
    {
        mockCallable.setupMatchesReturn(true);
        mockCallable.setupCallReturn(RESULT);
        
        assertTrue( "First time should match", call.matches(METHOD_NAME, ARGS));
        call.call(ignoredMock, METHOD_NAME, ARGS);
        assertFalse( "Second time should not match", call.matches(METHOD_NAME, ARGS));
    }
    
	public void testDecoratedResultPassedThrough() throws Throwable {
		mockCallable.setupCallReturn(RESULT);
		
		assertSame( "should return decorated's result",
				    RESULT, call.call( ignoredMock, METHOD_NAME, ARGS ) );
		mockCallable.verifyExpectations();
	}

	
	public void testDecoratedExceptionPassedThrough() throws Throwable {
		final Throwable exception = new DummyThrowable();
		
		mockCallable.setupCallThrow(exception);
		
		try {
			call.call( ignoredMock, METHOD_NAME, ARGS );
			fail("expected decorated's throwable to be thrown");
		}
		catch( DummyThrowable ex ) {
			// expected
		}
		
		mockCallable.verifyExpectations();
	}
}
