private static int CompareCurrentReadersPKValues( DbDataReaderComparer comparer, IDataReader expectedData, IDataReader actualData, bool expectedReaderHasMoreData, bool actualReaderHasMoreData) { int pkCompareResult; if (expectedReaderHasMoreData && actualReaderHasMoreData) { // With both readers having data, compare PK values pkCompareResult = comparer.Compare(expectedData, actualData); } else if (!expectedReaderHasMoreData && !actualReaderHasMoreData) { // Neither reader has data throw new InvalidOperationException("Neither IDataReader instance has data."); } else if (!expectedReaderHasMoreData) { // Expected values reader ran out of data // (Unexpected actual row in actual values reader) pkCompareResult = 1; } else // !actualReaderHasMoreData { // Actual values reader ran out of data // (Missing a row in actual values reader) pkCompareResult = -1; } return(pkCompareResult); }
private void CompareAndDisposeDataReaders( DbDataReaderComparer comparer, DataComparerResults dataComparerResults, IDataReader actualData, IDataReader expectedData, IEnumerable <string> additionalColumnNamesToIgnore) { try { bool expectedReaderHasMoreData = ReadDataReader(expectedData); bool actualReaderHasMoreData = ReadDataReader(actualData); // No data? Quit now if (!actualReaderHasMoreData && !expectedReaderHasMoreData) { return; } Dictionary <string, bool> additionalFieldsToIgnore = GetAdditionalFieldsToIgnoreAsDictionary(additionalColumnNamesToIgnore); do { // Using primary key values, determine whether readers are on same record, or one is "ahead" of the other int pkCompareResult = CompareCurrentReadersPKValues( comparer, expectedData, actualData, expectedReaderHasMoreData, actualReaderHasMoreData); ProcessComparisonResults( dataComparerResults, pkCompareResult, expectedData, actualData, ref expectedReaderHasMoreData, ref actualReaderHasMoreData, additionalFieldsToIgnore); }while ((expectedReaderHasMoreData || actualReaderHasMoreData) && dataComparerResults.RowDifferences.Count < MaximumDifferences); } finally { // Make sure the the data readers are properly disposed actualData.Dispose(); expectedData.Dispose(); } }
/// <summary> /// Compares the contents of two IDataReader instances, ignoring the specified columns, optionally creating DataTables for further inspection of the data. /// </summary> /// <param name="tableName">The name of the table for which the data comparison was performed.</param> /// <param name="expectedData">A <see cref="IDataReader"/> containing the expected data.</param> /// <param name="actualData">A <see cref="IDataReader"/> containing the actual data.</param> /// <param name="uniqueConstraintFieldNames">An array of the names of the primary key fields to use as the basis for identifying corresponding rows between the two readers.</param> /// <param name="isPrimaryKey"></param> /// <param name="dataCopyMode">Indicates whether or not a <see cref="DataTable"/> should be created for each <see cref="IDataReader"/> (expected and actual) and the data copied in while processing the readers.</param> /// <param name="additionalFieldsToIgnore">Fields to ignore for the current comparison (mismatches in data values will not be counted as failures).</param> /// <returns>The results of the comparison.</returns> public DataComparerResults Compare( string tableName, IDataReader expectedData, IDataReader actualData, string[] uniqueConstraintFieldNames, bool isPrimaryKey, DataCopyMode dataCopyMode, string[] additionalFieldsToIgnore) { //Initialize an empty array if the parameter is null. additionalFieldsToIgnore = additionalFieldsToIgnore ?? new string[0]; var dataComparerResults = new DataComparerResults { TableName = tableName }; this.dataCopyMode = dataCopyMode; // Prepare data tables, if necessary if (dataCopyMode == DataCopyMode.All || dataCopyMode == DataCopyMode.DifferencesOnly) { DataTable expectedTable = InitializeDataTable(expectedData, uniqueConstraintFieldNames, isPrimaryKey); expectedTable.TableName = "ExpectedDataTable"; tablesByReader[expectedData] = expectedTable; dataComparerResults.ExpectedData = expectedTable; DataTable actualTable = InitializeDataTable(actualData, uniqueConstraintFieldNames, isPrimaryKey); actualTable.TableName = "ActualDataTable"; tablesByReader[actualData] = actualTable; dataComparerResults.ActualData = actualTable; } primaryKeyFields = new List <string>(uniqueConstraintFieldNames); InitializeColumnNamesFromReader(dataComparerResults.ColumnNames, actualData); VerifyThatAllNonTestColumnsFromExpectedDataArePresent( dataComparerResults.TableName, dataComparerResults.ColumnNames, expectedData, additionalFieldsToIgnore); // Initialize counts rowCountsByReader[expectedData] = 0; rowCountsByReader[actualData] = 0; int[] expectedPKOrdinals = (from field in uniqueConstraintFieldNames select expectedData.GetOrdinal(field)).ToArray(); actualPKOrdinals = (from field in uniqueConstraintFieldNames select actualData.GetOrdinal(field)).ToArray(); DbDataReaderComparer comparer = new DbDataReaderComparer(expectedPKOrdinals, actualPKOrdinals); CompareAndDisposeDataReaders(comparer, dataComparerResults, actualData, expectedData, additionalFieldsToIgnore); // Set counts dataComparerResults.ExpectedRowCount = rowCountsByReader[expectedData]; dataComparerResults.ActualRowCount = rowCountsByReader[actualData]; return(dataComparerResults); }