DbUnitAssertBase.java
- package org.dbunit.assertion;
- import java.util.Arrays;
- import java.util.Map;
- import org.dbunit.DatabaseUnitException;
- import org.dbunit.assertion.DbUnitAssert.ComparisonColumn;
- import org.dbunit.assertion.comparer.value.DefaultValueComparerDefaults;
- import org.dbunit.assertion.comparer.value.ValueComparer;
- import org.dbunit.assertion.comparer.value.ValueComparerDefaults;
- import org.dbunit.dataset.Column;
- import org.dbunit.dataset.Columns;
- import org.dbunit.dataset.DataSetException;
- import org.dbunit.dataset.IDataSet;
- import org.dbunit.dataset.ITable;
- import org.dbunit.dataset.ITableMetaData;
- import org.dbunit.dataset.datatype.DataType;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * Base class for DbUnit assert classes containing common methods.
- *
- * @author Jeff Jensen
- * @since 2.6.0
- */
- public class DbUnitAssertBase
- {
- private final Logger log = LoggerFactory.getLogger(DbUnitAssertBase.class);
- private FailureFactory junitFailureFactory = getJUnitFailureFactory();
- protected ValueComparerDefaults valueComparerDefaults =
- new DefaultValueComparerDefaults();
- /**
- * @return The default failure handler
- * @since 2.4
- */
- protected FailureHandler getDefaultFailureHandler()
- {
- return getDefaultFailureHandler(null);
- }
- /**
- * @return The default failure handler
- * @since 2.4
- */
- protected FailureHandler getDefaultFailureHandler(
- final Column[] additionalColumnInfo)
- {
- final DefaultFailureHandler failureHandler =
- new DefaultFailureHandler(additionalColumnInfo);
- if (junitFailureFactory != null)
- {
- failureHandler.setFailureFactory(junitFailureFactory);
- }
- return failureHandler;
- }
- /**
- * @return the JUnitFailureFactory if JUnit is on the classpath or
- * <code>null</code> if JUnit is not on the classpath.
- */
- private FailureFactory getJUnitFailureFactory()
- {
- try
- {
- Class.forName("junit.framework.Assert");
- // JUnit available
- return new JUnitFailureFactory();
- } catch (final ClassNotFoundException e)
- {
- // JUnit not available on the classpath return null
- log.debug("JUnit does not seem to be on the classpath. " + e);
- }
- return null;
- }
- /**
- * @param expectedTableName
- * @param expectedColumns
- * @param actualColumns
- * @param failureHandler
- * The {@link FailureHandler} to be used when no datatype can be
- * determined
- * @return The columns to be used for the assertion, including the correct
- * datatype
- * @since 2.4
- */
- protected ComparisonColumn[] getComparisonColumns(
- final String expectedTableName, final Column[] expectedColumns,
- final Column[] actualColumns, final FailureHandler failureHandler)
- {
- final ComparisonColumn[] result =
- new ComparisonColumn[expectedColumns.length];
- for (int j = 0; j < expectedColumns.length; j++)
- {
- final Column expectedColumn = expectedColumns[j];
- final Column actualColumn = actualColumns[j];
- result[j] = new ComparisonColumn(expectedTableName, expectedColumn,
- actualColumn, failureHandler);
- }
- return result;
- }
- /**
- * Method to last-minute intercept the comparison of a single expected and
- * actual value. Designed to be overridden in order to skip cell comparison
- * by specific cell values.
- *
- * @param columnName
- * The column being compared
- * @param expectedValue
- * The expected value to be compared
- * @param actualValue
- * The actual value to be compared
- * @return <code>false</code> always so that the comparison is never skipped
- * @since 2.4
- */
- protected boolean skipCompare(final String columnName,
- final Object expectedValue, final Object actualValue)
- {
- return false;
- }
- protected FailureHandler determineFailureHandler(
- final FailureHandler failureHandler)
- {
- final FailureHandler validFailureHandler;
- if (failureHandler == null)
- {
- log.debug("FailureHandler is null. Using default implementation");
- validFailureHandler = getDefaultFailureHandler();
- } else
- {
- validFailureHandler = failureHandler;
- }
- return validFailureHandler;
- }
- protected boolean compareRowCounts(final ITable expectedTable,
- final ITable actualTable, final FailureHandler failureHandler,
- final String expectedTableName) throws Error
- {
- boolean isTablesEmpty;
- final int expectedRowsCount = expectedTable.getRowCount();
- int actualRowsCount = 0;
- boolean skipRowComparison = false;
- try
- {
- actualRowsCount = actualTable.getRowCount();
- } catch (final UnsupportedOperationException exception)
- {
- skipRowComparison = true;
- }
- if (skipRowComparison)
- {
- isTablesEmpty = false;
- } else
- {
- if (expectedRowsCount != actualRowsCount)
- {
- final String msg =
- "row count (table=" + expectedTableName + ")";
- final Error error = failureHandler.createFailure(msg,
- String.valueOf(expectedRowsCount),
- String.valueOf(actualRowsCount));
- log.error(error.toString());
- throw error;
- }
- // if both tables are empty, it is not necessary to compare columns,
- // as such comparison can fail if column metadata is different
- // (which could occurs when comparing empty tables)
- if (expectedRowsCount == 0 && actualRowsCount == 0)
- {
- log.debug("Tables are empty, hence equals.");
- isTablesEmpty = true;
- } else
- {
- isTablesEmpty = false;
- }
- }
- return isTablesEmpty;
- }
- protected void compareColumns(final Column[] expectedColumns,
- final Column[] actualColumns, final ITableMetaData expectedMetaData,
- final ITableMetaData actualMetaData,
- final FailureHandler failureHandler) throws DataSetException, Error
- {
- final Columns.ColumnDiff columnDiff =
- Columns.getColumnDiff(expectedMetaData, actualMetaData);
- if (columnDiff.hasDifference())
- {
- final String message = columnDiff.getMessage();
- final Error error = failureHandler.createFailure(message,
- Columns.getColumnNamesAsString(expectedColumns),
- Columns.getColumnNamesAsString(actualColumns));
- log.error(error.toString());
- throw error;
- }
- }
- protected void compareTableCounts(final String[] expectedNames,
- final String[] actualNames, final FailureHandler failureHandler)
- throws Error
- {
- if (expectedNames.length != actualNames.length)
- {
- throw failureHandler.createFailure("table count",
- String.valueOf(expectedNames.length),
- String.valueOf(actualNames.length));
- }
- }
- protected void compareTableNames(final String[] expectedNames,
- final String[] actualNames, final FailureHandler failureHandler)
- throws Error
- {
- for (int i = 0; i < expectedNames.length; i++)
- {
- if (!actualNames[i].equals(expectedNames[i]))
- {
- throw failureHandler.createFailure("tables",
- Arrays.asList(expectedNames).toString(),
- Arrays.asList(actualNames).toString());
- }
- }
- }
- protected String[] getSortedTableNames(final IDataSet dataSet)
- throws DataSetException
- {
- log.debug("getSortedTableNames(dataSet={}) - start", dataSet);
- final String[] names = dataSet.getTableNames();
- if (!dataSet.isCaseSensitiveTableNames())
- {
- for (int i = 0; i < names.length; i++)
- {
- names[i] = names[i].toUpperCase();
- }
- }
- Arrays.sort(names);
- return names;
- }
- /**
- * Asserts the two specified {@link IDataSet}s comparing their columns using
- * the specified columnValueComparers or defaultValueComparer and handles
- * failures using the specified failureHandler. This method ignores the
- * table names, the columns order, the columns data type, and which columns
- * are composing the primary keys.
- *
- * @param expectedDataSet
- * {@link IDataSet} containing all expected results.
- * @param actualDataSet
- * {@link IDataSet} containing all actual results.
- * @param failureHandler
- * The failure handler used if the assert fails because of a data
- * mismatch. Provides some additional information that may be
- * useful to quickly identify the rows for which the mismatch
- * occurred (for example by printing an additional primary key
- * column). Can be <code>null</code>.
- * @param defaultValueComparer
- * {@link ValueComparer} to use with column value comparisons
- * when the column name for the table is not in the
- * tableColumnValueComparers {@link Map}. Can be
- * <code>null</code> and will default to
- * {@link #getDefaultValueComparer()}.
- * @param tableColumnValueComparers
- * {@link Map} of {@link ValueComparer}s to use for specific
- * tables and columns. Key is table name, value is {@link Map} of
- * column name in the table to {@link ValueComparer}s. Can be
- * <code>null</code> and will default to using
- * {@link #getDefaultColumnValueComparerMapForTable(String)} or,
- * if that is empty, defaultValueComparer for all columns in all
- * tables.
- * @throws DatabaseUnitException
- */
- public void assertWithValueComparer(final IDataSet expectedDataSet,
- final IDataSet actualDataSet, final FailureHandler failureHandler,
- final ValueComparer defaultValueComparer,
- final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
- throws DatabaseUnitException
- {
- log.debug(
- "assertWithValueComparer(expectedDataSet={}, actualDataSet={},"
- + " failureHandler={}, defaultValueComparer={},"
- + " tableColumnValueComparers={}) - start",
- expectedDataSet, actualDataSet, failureHandler,
- defaultValueComparer, tableColumnValueComparers);
- // do not continue if same instance
- if (expectedDataSet == actualDataSet)
- {
- log.debug("The given datasets reference the same object."
- + " Skipping comparisons.");
- return;
- }
- final FailureHandler validFailureHandler =
- determineFailureHandler(failureHandler);
- final String[] expectedNames = getSortedTableNames(expectedDataSet);
- final String[] actualNames = getSortedTableNames(actualDataSet);
- compareTableCounts(expectedNames, actualNames, validFailureHandler);
- // table names in no specific order
- compareTableNames(expectedNames, actualNames, validFailureHandler);
- compareTables(expectedDataSet, actualDataSet, expectedNames,
- validFailureHandler, defaultValueComparer,
- tableColumnValueComparers);
- }
- protected void compareTables(final IDataSet expectedDataSet,
- final IDataSet actualDataSet, final String[] expectedNames,
- final FailureHandler failureHandler,
- final ValueComparer defaultValueComparer,
- final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
- throws DatabaseUnitException
- {
- final Map<String, Map<String, ValueComparer>> validTableColumnValueComparers =
- determineValidTableColumnValueComparers(
- tableColumnValueComparers);
- for (int i = 0; i < expectedNames.length; i++)
- {
- final String tableName = expectedNames[i];
- final ITable expectedTable = expectedDataSet.getTable(tableName);
- final ITable actualTable = actualDataSet.getTable(tableName);
- final Map<String, ValueComparer> columnValueComparers =
- validTableColumnValueComparers.get(tableName);
- assertWithValueComparer(expectedTable, actualTable, failureHandler,
- defaultValueComparer, columnValueComparers);
- }
- }
- /**
- * Asserts the two specified {@link ITable}s comparing their columns using
- * the specified columnValueComparers or defaultValueComparer and handles
- * failures using the specified failureHandler. This method ignores the
- * table names, the columns order, the columns data type, and which columns
- * are composing the primary keys.
- *
- * @param expectedTable
- * {@link ITable} containing all expected results.
- * @param actualTable
- * {@link ITable} containing all actual results.
- * @param failureHandler
- * The failure handler used if the assert fails because of a data
- * mismatch. Provides some additional information that may be
- * useful to quickly identify the rows for which the mismatch
- * occurred (for example by printing an additional primary key
- * column). Can be <code>null</code>.
- * @param defaultValueComparer
- * {@link ValueComparer} to use with column value comparisons
- * when the column name for the table is not in the
- * columnValueComparers {@link Map}. Can be <code>null</code> and
- * will default to {@link #getDefaultValueComparer()}.
- * @param columnValueComparers
- * {@link Map} of {@link ValueComparer}s to use for specific
- * columns. Key is column name in the table, value is
- * {@link ValueComparer} to use in comparing expected to actual
- * column values. Can be <code>null</code> and will default to
- * using
- * {@link #getDefaultColumnValueComparerMapForTable(String)} or,
- * if that is empty, defaultValueComparer for all columns in the
- * table.
- * @throws DatabaseUnitException
- */
- public void assertWithValueComparer(final ITable expectedTable,
- final ITable actualTable, final FailureHandler failureHandler,
- final ValueComparer defaultValueComparer,
- final Map<String, ValueComparer> columnValueComparers)
- throws DatabaseUnitException
- {
- log.trace("assertWithValueComparer(expectedTable, actualTable,"
- + " failureHandler, defaultValueComparer,"
- + " columnValueComparers) - start");
- log.debug("assertWithValueComparer: expectedTable={}", expectedTable);
- log.debug("assertWithValueComparer: actualTable={}", actualTable);
- log.debug("assertWithValueComparer: failureHandler={}", failureHandler);
- log.debug("assertWithValueComparer: defaultValueComparer={}",
- defaultValueComparer);
- log.debug("assertWithValueComparer: columnValueComparers={}",
- columnValueComparers);
- // Do not continue if same instance
- if (expectedTable == actualTable)
- {
- log.debug("The given tables reference the same object."
- + " Skipping comparisons.");
- return;
- }
- final FailureHandler validFailureHandler =
- determineFailureHandler(failureHandler);
- final ITableMetaData expectedMetaData =
- expectedTable.getTableMetaData();
- final ITableMetaData actualMetaData = actualTable.getTableMetaData();
- final String expectedTableName = expectedMetaData.getTableName();
- final boolean isTablesEmpty = compareRowCounts(expectedTable,
- actualTable, validFailureHandler, expectedTableName);
- if (isTablesEmpty)
- {
- return;
- }
- // Put the columns into the same order
- final Column[] expectedColumns =
- Columns.getSortedColumns(expectedMetaData);
- final Column[] actualColumns = Columns.getSortedColumns(actualMetaData);
- // Verify columns
- compareColumns(expectedColumns, actualColumns, expectedMetaData,
- actualMetaData, validFailureHandler);
- // Get the datatypes to be used for comparing the sorted columns
- final ComparisonColumn[] comparisonCols =
- getComparisonColumns(expectedTableName, expectedColumns,
- actualColumns, validFailureHandler);
- // Finally compare the data
- compareData(expectedTable, actualTable, comparisonCols,
- validFailureHandler, defaultValueComparer,
- columnValueComparers);
- }
- /**
- * @param expectedTable
- * Table containing all expected results.
- * @param actualTable
- * Table containing all actual results.
- * @param comparisonCols
- * The columns to be compared, also including the correct
- * {@link DataType}s for comparison
- * @param failureHandler
- * The failure handler used if the assert fails because of a data
- * mismatch. Provides some additional information that may be
- * useful to quickly identify the rows for which the mismatch
- * occurred (for example by printing an additional primary key
- * column). Must not be <code>null</code> at this stage
- * @throws DataSetException
- * @since 2.4
- */
- protected void compareData(final ITable expectedTable,
- final ITable actualTable, final ComparisonColumn[] comparisonCols,
- final FailureHandler failureHandler) throws DataSetException
- {
- final ValueComparer defaultValueComparer = null;
- final Map<String, ValueComparer> columnValueComparers = null;
- try
- {
- compareData(expectedTable, actualTable, comparisonCols,
- failureHandler, defaultValueComparer, columnValueComparers);
- } catch (final DatabaseUnitException e)
- {
- // not-private method, signature change breaks compatability
- throw new DataSetException(e);
- }
- }
- /**
- * @param expectedTable
- * {@link ITable} containing all expected results.
- * @param actualTable
- * {@link ITable} containing all actual results.
- * @param comparisonCols
- * The columns to be compared, also including the correct
- * {@link DataType}s for comparison
- * @param failureHandler
- * The failure handler used if the assert fails because of a data
- * mismatch. Provides some additional information that may be
- * useful to quickly identify the rows for which the mismatch
- * occurred (for example by printing an additional primary key
- * column). Must not be <code>null</code> at this stage.
- * @param defaultValueComparer
- * {@link ValueComparer} to use with column value comparisons
- * when the column name for the table is not in the
- * columnValueComparers {@link Map}. Can be <code>null</code> and
- * will default to {@link #getDefaultValueComparer()}.
- * @param columnValueComparers
- * {@link Map} of {@link ValueComparer}s to use for specific
- * columns. Key is column name in the table, value is
- * {@link ValueComparer} to use in comparing expected to actual
- * column values. Can be <code>null</code> and will default to
- * using
- * {@link #getDefaultColumnValueComparerMapForTable(String)} or,
- * if that is empty, defaultValueComparer for all columns in the
- * table.
- * @throws DataSetException
- * @since 2.4
- * @since 2.6.0
- */
- protected void compareData(final ITable expectedTable,
- final ITable actualTable, final ComparisonColumn[] comparisonCols,
- final FailureHandler failureHandler,
- final ValueComparer defaultValueComparer,
- final Map<String, ValueComparer> columnValueComparers)
- throws DatabaseUnitException
- {
- log.debug(
- "compareData(expectedTable={}, actualTable={}, "
- + "comparisonCols={}, failureHandler={},"
- + " defaultValueComparer={}, columnValueComparers={})"
- + " - start",
- expectedTable, actualTable, comparisonCols, failureHandler,
- defaultValueComparer, columnValueComparers);
- if (expectedTable == null)
- {
- throw new IllegalArgumentException(
- "The parameter 'expectedTable' is null");
- }
- if (actualTable == null)
- {
- throw new IllegalArgumentException(
- "The parameter 'actualTable' is null");
- }
- if (comparisonCols == null)
- {
- throw new IllegalArgumentException(
- "The parameter 'comparisonCols' is null");
- }
- if (failureHandler == null)
- {
- throw new IllegalArgumentException(
- "The parameter 'failureHandler' is null");
- }
- final ValueComparer validDefaultValueComparer =
- determineValidDefaultValueComparer(defaultValueComparer);
- final String expectedTableName =
- expectedTable.getTableMetaData().getTableName();
- final Map<String, ValueComparer> validColumnValueComparers =
- determineValidColumnValueComparers(columnValueComparers,
- expectedTableName);
- // iterate over all rows
- for (int rowNum = 0; rowNum < expectedTable.getRowCount(); rowNum++)
- {
- // iterate over all columns of the current row
- final int columnCount = comparisonCols.length;
- for (int columnNum = 0; columnNum < columnCount; columnNum++)
- {
- compareData(expectedTable, actualTable, comparisonCols,
- failureHandler, validDefaultValueComparer,
- validColumnValueComparers, rowNum, columnNum);
- }
- }
- }
- protected void compareData(final ITable expectedTable,
- final ITable actualTable, final ComparisonColumn[] comparisonCols,
- final FailureHandler failureHandler,
- final ValueComparer defaultValueComparer,
- final Map<String, ValueComparer> columnValueComparers,
- final int rowNum, final int columnNum) throws DatabaseUnitException
- {
- final ComparisonColumn compareColumn = comparisonCols[columnNum];
- final String columnName = compareColumn.getColumnName();
- final DataType dataType = compareColumn.getDataType();
- final Object expectedValue = expectedTable.getValue(rowNum, columnName);
- final Object actualValue = actualTable.getValue(rowNum, columnName);
- // Compare the values
- if (skipCompare(columnName, expectedValue, actualValue))
- {
- log.trace(
- "skipCompare: ignoring comparison" + " {}={} on column={}",
- expectedValue, actualValue, columnName);
- } else
- {
- final ValueComparer valueComparer = determineValueComparer(
- columnName, defaultValueComparer, columnValueComparers);
- log.debug(
- "compareData: comparing actualValue={}"
- + " to expectedValue={} with valueComparer={}",
- actualValue, expectedValue, valueComparer);
- final String failMessage =
- valueComparer.compare(expectedTable, actualTable, rowNum,
- columnName, dataType, expectedValue, actualValue);
- failIfNecessary(expectedTable, actualTable, failureHandler, rowNum,
- columnName, expectedValue, actualValue, failMessage);
- }
- }
- protected void failIfNecessary(final ITable expectedTable,
- final ITable actualTable, final FailureHandler failureHandler,
- final int rowNum, final String columnName,
- final Object expectedValue, final Object actualValue,
- final String failMessage)
- {
- if (failMessage != null)
- {
- final Difference diff = new Difference(expectedTable, actualTable,
- rowNum, columnName, expectedValue, actualValue,
- failMessage);
- failureHandler.handle(diff);
- }
- }
- protected ValueComparer determineValueComparer(final String columnName,
- final ValueComparer defaultValueComparer,
- final Map<String, ValueComparer> columnValueComparers)
- {
- ValueComparer valueComparer = columnValueComparers.get(columnName);
- if (valueComparer == null)
- {
- log.debug(
- "determineValueComparer: using defaultValueComparer='{}'"
- + " as columnName='{}' not found"
- + " in columnValueComparers='{}'",
- defaultValueComparer, columnName, columnValueComparers);
- valueComparer = defaultValueComparer;
- }
- return valueComparer;
- }
- protected ValueComparer determineValidDefaultValueComparer(
- final ValueComparer defaultValueComparer)
- {
- final ValueComparer validValueComparer;
- if (defaultValueComparer == null)
- {
- validValueComparer =
- valueComparerDefaults.getDefaultValueComparer();
- log.debug(
- "determineValidDefaultValueComparer:"
- + " using getDefaultValueComparer()={}"
- + " as defaultValueComparer={}",
- validValueComparer, defaultValueComparer);
- } else
- {
- validValueComparer = defaultValueComparer;
- }
- return validValueComparer;
- }
- protected Map<String, Map<String, ValueComparer>> determineValidTableColumnValueComparers(
- final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
- {
- final Map<String, Map<String, ValueComparer>> validMap;
- if (tableColumnValueComparers == null)
- {
- validMap = valueComparerDefaults
- .getDefaultTableColumnValueComparerMap();
- log.debug(
- "determineValidTableColumnValueComparers:"
- + " using getDefaultTableColumnValueComparerMap()={}"
- + " as tableColumnValueComparers={}",
- validMap, tableColumnValueComparers);
- } else
- {
- validMap = tableColumnValueComparers;
- }
- return validMap;
- }
- protected Map<String, ValueComparer> determineValidColumnValueComparers(
- final Map<String, ValueComparer> columnValueComparers,
- final String tableName)
- {
- final Map<String, ValueComparer> validMap;
- if (columnValueComparers == null)
- {
- validMap = valueComparerDefaults
- .getDefaultColumnValueComparerMapForTable(tableName);
- log.debug(
- "determineValidColumnValueComparers:"
- + " using getDefaultValueComparerMap()={}"
- + " as columnValueComparers={} for tableName={}",
- validMap, columnValueComparers, tableName);
- } else
- {
- validMap = columnValueComparers;
- }
- return validMap;
- }
- public void setValueComparerDefaults(
- final ValueComparerDefaults valueComparerDefaults)
- {
- this.valueComparerDefaults = valueComparerDefaults;
- }
- }