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

namespace DotNetMock.Framework.Tests.Data
{
	[TestFixture]
	public class MockDataReaderTests
	{
		private MockDataReader _reader = null;

		[SetUp]
		public void Init()
		{
			_reader = new MockDataReader();
		}

		[TearDown]
		public void Destroy() 
		{
			Verifier.ResetVerifier();
			_reader = null;
		}
		[Test]
		public void RecordsAffectedSuccess()
		{
			_reader.SetRecordsAffectedCount(1);
			Assertion.AssertEquals("Records affected not equal.", 1, _reader.RecordsAffected);
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void RecordsAffectedFails()
		{
			_reader.SetRecordsAffectedCount(2);
			Assertion.AssertEquals(3, _reader.RecordsAffected);
		}
		[Test]
		public void CloseCountCallsSuccess()
		{
			_reader.SetExpectedCloseCalls(3);
			_reader.Close();
			_reader.Close();
			_reader.Close();
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void CloseCountCallsFails()
		{
			_reader.SetExpectedCloseCalls(1);
			_reader.Close();
			_reader.Close();
			_reader.Verify();
		}
		[Test]
		public void GetSchemsTableSuccess()
		{
			DataTable dataTable = new DataTable();
			dataTable.Columns.Add(new DataColumn("ID", typeof(int)));
			dataTable.Columns.Add(new DataColumn("Password", typeof(string)));
			dataTable.Columns.Add(new DataColumn("Email", typeof(string)));
			_reader.SetSchemaTable(dataTable);
			DataTable dataTable2 = new DataTable();
			dataTable2.Columns.Add(new DataColumn("ID", typeof(int)));
			dataTable2.Columns.Add(new DataColumn("Password", typeof(string)));
			dataTable2.Columns.Add(new DataColumn("Email", typeof(string)));
			Assertion.Equals(dataTable2, _reader.GetSchemaTable());
		}
		[Test]
		public void GetSchemaTableFails()
		{
			Assertion.AssertNull("Schema Table isn't empty.", _reader.GetSchemaTable());
		}
		[Test]
		public void IsClosedSuccess()
		{
			_reader.SetIsClosedValue(true);
			Assertion.Assert(_reader.IsClosed);
		}
		[Test]
		public void IsCloseDefaultValue()
		{
			Assertion.Assert(!_reader.IsClosed);
		}
		[Test]
		public void ReadCountCallsSuccess()
		{
			_reader.SetExpectedReadCalls(3);
			_reader.Read();
			_reader.Read();
			_reader.Read();
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void ReadCountCallsFails()
		{
			_reader.SetExpectedReadCalls(2);
			_reader.Read();
			_reader.Read();
			_reader.Read();
			_reader.Verify();
		}
		[Test]
		public void ReadSuccess() 
		{
			_reader.SetExpectedReadCalls(3);

			_reader.SetRows(createObjectValues());

			while (_reader.Read()) 
			{

			}
			_reader.Verify();
		}

		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void ReadFailure() 
		{
			_reader.SetExpectedReadCalls(2);

			_reader.SetRows(createObjectValues());

			while (_reader.Read()) 
			{

			}
			_reader.Verify();
		}
		[Test]
		public void GetValueSuccess() 
		{
			_reader.SetExpectedReadCalls(3);
			_reader.SetRows(createObjectValues());

			int rowCount = 0;
			while (_reader.Read()) 
			{
				for (int i = 0; i <= 1; i++) 
				{
					Assertion.AssertEquals("Items not equal.", "Row " + rowCount + ", Column " + i, _reader.GetValue(i));
				}
				rowCount++;
			}
			_reader.Verify();
		}
		[Test]
		public void IndexerIntSuccess() 
		{
			_reader.SetExpectedReadCalls(3);
			_reader.SetRows(createObjectValues());

			int rowCount = 0;
			while (_reader.Read()) 
			{
				for (int i = 0; i <= 1; i++) 
				{
					Assertion.AssertEquals("Items not equal.", "Row " + rowCount + ", Column " + i, _reader[i]);
				}
				rowCount++;
			}
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void IndexerIntFails() 
		{
			_reader.SetExpectedReadCalls(3);
			_reader.SetRows(createObjectValues());

			int rowCount = 0;
			while (_reader.Read()) 
			{
				for (int i = 0; i <= 1; i++) 
				{
					Assertion.AssertEquals("Items not equal.", "Row " + rowCount + ", Column " + i, _reader[i + 3]);
				}
				rowCount++;
			}
			_reader.Verify();
		}
		[Test]
		public void GetIntSuccess()
		{
			object[,] values = new object[2,2];
			values[0,0] = 0;
			values[0,1] = 1;
			values[1,0] = 0;
			values[1,1] = 1;
			_reader.SetRows(values);
			_reader.SetExpectedReadCalls(3);

			while (_reader.Read())
			{
				Assertion.AssertEquals(0, _reader.GetInt32(0));
				Assertion.AssertEquals(1, _reader.GetInt32(1));
			}
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetIntFails() 
		{
			object[,] values = new object[2,2];
			values[0,0] = 0;
			values[0,1] = 1;
			values[1,0] = 0;
			values[1,1] = 1;
			_reader.SetRows(values);
			_reader.SetExpectedReadCalls(3);

			while (_reader.Read())
			{
				Assertion.AssertEquals(0, _reader.GetInt32(3));
				Assertion.AssertEquals(1, _reader.GetInt32(4));
			}
			_reader.Verify();
		}
		[Test]
		public void IndexerStringSuccess() 
		{
			_reader.SetExpectedReadCalls(2);
			_reader.SetSchemaTable(getCommonSchemaTable());
			
			object[,] values = new object[1,2];
			values[0,0] = 123456;
			values[0,1] = "password";
			_reader.SetRows(values);

			while (_reader.Read()) 
			{
				Assertion.AssertEquals(123456, _reader["ID"]);
				Assertion.AssertEquals("password", _reader["Password"]);
			}
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void IndexerStringFails()
		{
			_reader.SetSchemaTable(getCommonSchemaTable());
			
			object[,] values = new object[2,2];
			values[0,0] = 123456;
			values[0,1] = "password";
			_reader.SetRows(values);

			while (_reader.Read()) 
			{
				Assertion.AssertEquals(123456, _reader["Fakes"]);
			}
			_reader.Verify();
		}
		[Test]
		public void GetFieldTypeSuccess()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );

			Assertion.AssertEquals( "ID", typeof( int ), _reader.GetFieldType( 0 ) );
			Assertion.AssertEquals( "Password", typeof( string ), _reader.GetFieldType( 1 ) );
			_reader.Verify();
		}
		[Test]
		public void GetFieldTypeFailed()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );

			try 
			{
				Assertion.AssertEquals( "ID", typeof( string ), _reader.GetFieldType( 0 ) );
				Assertion.Fail( "Should throw an exception" );
			} 
			catch 
			{

			}
			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetFieldTypeIndexOutOfRange()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );
			_reader.GetFieldType( 2 );
		}
		[Test]
		[ExpectedException(typeof(DotNetMockException))]
		public void GetFieldTypeWithNoSchemaTable()
		{
			_reader.GetFieldType( 0 );
		}
		[Test]
		public void NextResultNumberOfCalls()
		{
			_reader.SetRows(  createObjectValues() );
			_reader.SetExpectedNextResultCalls( 3 );

			int rowCounter = 0;
			while ( _reader.NextResult() ) {
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 0", _reader.GetString(0) );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 1", _reader.GetString(1) );
				rowCounter++;
			}

			_reader.Verify();
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void NextResultNumberOfCallsFails()
		{
			_reader.SetExpectedNextResultCalls( 2 );

			while ( _reader.NextResult() ) {
				
			}
			_reader.Verify();
		}
		[Test]
		public void IsDBNullTesting()
		{
			object[,] values = new object[1,2];
			values[0,0] = DBNull.Value;
			values[0,1] = "Hello";
			
			_reader.SetRows(values);

			_reader.Read();
			Assertion.Assert( "Is not dbnull", _reader.IsDBNull(0) );
			Assertion.Assert( "Is not dbnull", !_reader.IsDBNull(1) );

		}

		[Test]
		public void GetValuesArraySameSizeAsColumns()
		{
			_reader.SetRows( createObjectValues(3, 2) );
			object[] newValues = new object[2];

			int rowCounter = 0;
			while ( _reader.Read() ) 
			{
				int columnCount = _reader.GetValues( newValues );
				Assertion.AssertEquals( "number of columns don't equal", 2, columnCount );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 0", newValues[0] );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 1", newValues[1] );
				rowCounter++;
			}
			_reader.Verify();
		}
		[Test]
		public void GetValuesArrayShorter()
		{
			_reader.SetRows( createObjectValues(3, 2) );
			object[] newValues = new object[1];

			int rowCounter = 0;
			while ( _reader.Read() ) 
			{
				int columnCount = _reader.GetValues( newValues );
				Assertion.AssertEquals( "number of columns don't equal", 1, columnCount );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 0", newValues[0] );
				rowCounter++;
			}
			_reader.Verify();
		}
		[Test]
		public void GetValuesArrayLongerThanColumns()
		{
			_reader.SetRows( createObjectValues(3, 2) );
			object[] newValues = new object[3];

			int rowCounter = 0;
			while ( _reader.Read() ) 
			{
				int columnCount = _reader.GetValues( newValues );
				Assertion.AssertEquals( "number of columns don't equal", 2, columnCount );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 0", newValues[0] );
				Assertion.AssertEquals( "Row" + rowCounter, "Row " + rowCounter + ", Column 1", newValues[1] );
				Assertion.AssertEquals( "Null?", null, newValues[2] );
				rowCounter++;
			}
			_reader.Verify();
		}
		[Test]
		public void GetNameValidInstance()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );

			Assertion.AssertEquals( "No ID column", "ID", _reader.GetName(0) );
			Assertion.AssertEquals( "No Password column", "Password", _reader.GetName(1) );
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetNameInvalidIndexValue()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );
			_reader.GetName(5);
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void GetNameNoSchemaTable()
		{
			_reader.GetName(0);
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetNameNegativeNumber()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );
			_reader.GetName( -1 );
		}
		[Test]
		public void FieldCountNoRowsDefaultCount()
		{
			Assertion.AssertEquals( "Default value", -1, _reader.FieldCount );
		}
		[Test]
		public void FieldCountValidRows()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );
			Assertion.AssertEquals( "No rows", 2, _reader.FieldCount );
		}
		[Test]
		public void GetFloatSuccess()
		{
			object[,] data = new object[1,2];
			data[0,0] = (float)1.2345;
			data[0,1] = (float)6.7890;
			_reader.SetRows( data );

			_reader.Read();
			Assertion.AssertEquals( "no float", 1.2345, _reader.GetFloat(0) );
			Assertion.AssertEquals( "no float", 6.7890, _reader.GetFloat(1) );
		}
		[Test]
		public void GetOrdinalSuccess()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );

			Assertion.AssertEquals( "No Id column", 0, _reader.GetOrdinal("ID") );
			Assertion.AssertEquals( "No password column", 1, _reader.GetOrdinal("Password") );
		}
		[Test]
		public void GetOrdinalSuccessCaseInsensitive()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );

			Assertion.AssertEquals( "No Id column", 0, _reader.GetOrdinal("id") );
			Assertion.AssertEquals( "No password column", 1, _reader.GetOrdinal("PaSSWord") );
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetOrdinalNoIndex()
		{
			_reader.SetSchemaTable( getCommonSchemaTable() );
			_reader.GetOrdinal( "Fake" );
		}
		[Test]
		[ExpectedException(typeof(AssertionException))]
		public void GetOrdinalWithNoSchemaTable()
		{
			_reader.GetOrdinal( "ID" );
		}
		[Test]
		public void GetGuidSuccess()
		{
			object[,] values = new object[1,2];
			Guid newGuid = Guid.NewGuid();
			values[0,0] = newGuid;
			values[0,1] = Guid.Empty;

			_reader.SetRows( values );
			_reader.Read();

			Assertion.AssertEquals( "No guid", newGuid, _reader.GetGuid(0) );
			Assertion.AssertEquals( "No empty guid", Guid.Empty, _reader.GetGuid(1) );
		}
		[Test]
		[ExpectedException(typeof(IndexOutOfRangeException))]
		public void GetGuidFailureIndexOutOfRange()
		{
			object[,] values = new object[1,2];
			Guid newGuid = Guid.NewGuid();
			values[0,0] = newGuid;
			values[0,1] = Guid.Empty;
			
			_reader.Read();
			_reader.GetGuid( 2 );
		}
		[Test]
		public void GetDataReaderFromGetData()
		{
			object[,] values = new object[1,2];
			values[0,0] = 12345;
			MockDataReader expectedReader = new MockDataReader();
			values[0,1] = expectedReader;

			_reader.SetRows( values );

			_reader.Read();

			Assertion.AssertEquals( "no id", 12345, _reader.GetInt32( 0 ) );
			Assertion.AssertEquals( "No Reader", expectedReader, _reader.GetData( 1 ) );
		}
		#region Private Helper methods
		private DataTable getCommonSchemaTable() 
		{
			DataTable dataTable = new DataTable();
			dataTable.Columns.Add( new DataColumn( "ID", typeof( int ) ) );
			dataTable.Columns.Add( new DataColumn( "Password", typeof( string ) ) );

			return dataTable;
		}
		private object[,] createObjectValues() 
		{
			return createObjectValues(2, 2);
		}
		private object[,] createObjectValues(int rows, int columns)
		{
			object[,] values = new object[rows,columns];
			for (int row = 0; row < rows; row++)
			{
				for (int column = 0; column < columns; column++)
				{
					values[row,column] = String.Format(
						"Row {0}, Column {1}",
						row,
						column);
				}
			}
			return values;
		}

		#endregion
	}
}
