using System;
using System.Data;
using NUnit.Framework;
using DotNetMock.Framework.Data;

namespace DotNetMock.Framework.Tests.Data
{
	[TestFixture]
	public class MockCommandTests
	{
		private MockCommand _mockCmd = null;
		[TearDown]
		public void Destroy()
		{
			Verifier.ResetVerifier();
			_mockCmd = null;
		}
		[Test]
		public void CommandTextProperty()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandText(@"user id=sa;password=password;Connect Timeout=30");
			_mockCmd.SetExpectedCommandText(@"SQL COMMAND");
			_mockCmd.CommandText = @"user id=sa;password=password;Connect Timeout=30";
			_mockCmd.CommandText = @"SQL COMMAND";
			_mockCmd.Verify();
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void InValidCommandTextProperty()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandText(@"user id=sa;password=password;Connect Timeout=30");
			_mockCmd.Verify();
		}
		[Test]
		public void CommandTimeoutProperty()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandTimeout(0);
			_mockCmd.CommandTimeout = 0;
			_mockCmd.Verify();
		}
		[Test]
		public void CommandTypeProperty()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandType(System.Data.CommandType.Text);
			_mockCmd.CommandType = System.Data.CommandType.Text;
			_mockCmd.Verify();
		}
		[Test]
		public void CommandTypePropertySP()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandType(System.Data.CommandType.StoredProcedure);
			_mockCmd.CommandType = System.Data.CommandType.StoredProcedure;
			_mockCmd.Verify();
		}
		[Test]
		public void ConnectionProperty()
		{
			_mockCmd = new MockCommand();
			MockDbConnection mockConnection = new MockDbConnection();
			MockTransaction mockTransaction = new MockTransaction();

			_mockCmd.Transaction = mockTransaction;
			Assertion.AssertNotNull(_mockCmd.Transaction);
			_mockCmd.Connection = mockConnection;
			Assertion.AssertNotNull(_mockCmd.Connection);
			Assertion.AssertEquals(typeof(MockDbConnection), _mockCmd.Connection.GetType());
			_mockCmd.Verify();
			_mockCmd.Dispose();
		}
		[Test]
		public void ParametersProperty()
		{
			_mockCmd = new MockCommand();
			MockDataParameter mockParameter = new MockDataParameter("@inpID", "123456");
			_mockCmd.SetExpectedParameter(mockParameter);
			_mockCmd.Parameters.Add(mockParameter);
			_mockCmd.Verify();
		}
		[Test]
		[ExpectedException(typeof(DotNetMock.AssertionException))]
		public void InValidParametersProperty()
		{		
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedParameter(new MockDataParameter("@inpID", "123456"));
			_mockCmd.Verify();
		}	
		[Test]
		public void ExecuteCalls()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedExecuteCalls(5);
			_mockCmd.ExecuteNonQuery();
			_mockCmd.ExecuteReader();
			_mockCmd.ExecuteScalar();
			_mockCmd.ExecuteScalar();
			_mockCmd.ExecuteNonQuery();
			_mockCmd.Verify();
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void InValidExecuteCalls()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedExecuteCalls(2);
			_mockCmd.ExecuteNonQuery();
			_mockCmd.Verify();
		}
		[Test]
		public void ValidExecuteScalar()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedExecuteCalls(1);
			_mockCmd.SetExpectedScalar((int)100);

			int scalarValue = (int)_mockCmd.ExecuteScalar();
			Assertion.AssertEquals( "Scalar", (int)100, scalarValue );
			_mockCmd.Verify();
		}
		[Test]
		public void CreateCallsException()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExecuteException( new Exception() );
			_mockCmd.SetExpectedExecuteCalls( 1 );
			try 
			{
				_mockCmd.ExecuteNonQuery();
				Assertion.Fail("Should have thrown an exception.");
			}
			catch {}

			_mockCmd.Verify();
		}
		[Test]
		public void CloseConnectionCommandBehavior()
		{	
			IDbConnection mockConnection = new MockDbConnection();
			((MockDbConnection)mockConnection).SetExpectedCloseCalls(1);
			mockConnection.Open();
			IDbCommand mockCommand = mockConnection.CreateCommand();
			Assertion.AssertEquals( "Connection is closed", ConnectionState.Open, mockConnection.State );
			
			IDataReader mockReader = mockCommand.ExecuteReader( CommandBehavior.CloseConnection );
			((MockDataReader)mockReader).SetExpectedCloseCalls(1);

			Assertion.AssertEquals( "Connection is closed2", ConnectionState.Open, mockConnection.State );
			mockReader.Close();
			Assertion.Assert( "Reader is open", mockReader.IsClosed );
			Assertion.AssertEquals( "Connection is open", ConnectionState.Closed, mockConnection.State );
			((MockCommand)mockCommand).Verify();
			((MockDataReader)mockReader).Verify();
			((MockDbConnection)mockConnection).Verify();
		}
		[Test]
		public void CloseConnectionCommandBehaviorNone()
		{	
			IDbConnection mockConnection = new MockDbConnection();
			
			mockConnection.Open();
			IDbCommand mockCommand = mockConnection.CreateCommand();
			Assertion.AssertEquals( "Connection is closed", ConnectionState.Open, mockConnection.State );
			
			IDataReader mockReader = mockCommand.ExecuteReader( );
			((MockDataReader)mockReader).SetExpectedCloseCalls(1);

			Assertion.AssertEquals( "Connection is closed", ConnectionState.Open, mockConnection.State );
			mockReader.Close();
			Assertion.Assert( "Reader is open", mockReader.IsClosed );
			Assertion.AssertEquals( "Connection is closed", ConnectionState.Open, mockConnection.State );
			((MockCommand)mockCommand).Verify();
			((MockDataReader)mockReader).Verify();
			((MockDbConnection)mockConnection).Verify();
		}
		[Test]
		public void CommandTimeoutValidHigherValues()
		{
			_mockCmd = new MockCommand();
			_mockCmd.SetExpectedCommandTimeout(100);
			_mockCmd.CommandTimeout = 100;
			_mockCmd.Verify();
		}
	}
}
