DefaultPrepAndExpectedTestCase.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2008, DbUnit.org
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  */
  21. package org.dbunit;

  22. import static org.junit.jupiter.api.Assertions.assertNotNull;

  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.stream.Collectors;

  29. import org.dbunit.assertion.comparer.value.ValueComparer;
  30. import org.dbunit.database.DatabaseConfig;
  31. import org.dbunit.database.IDatabaseConnection;
  32. import org.dbunit.dataset.Column;
  33. import org.dbunit.dataset.CompositeDataSet;
  34. import org.dbunit.dataset.DataSetException;
  35. import org.dbunit.dataset.DefaultDataSet;
  36. import org.dbunit.dataset.IDataSet;
  37. import org.dbunit.dataset.ITable;
  38. import org.dbunit.dataset.ITableMetaData;
  39. import org.dbunit.dataset.SortedTable;
  40. import org.dbunit.dataset.datatype.DataType;
  41. import org.dbunit.dataset.filter.DefaultColumnFilter;
  42. import org.dbunit.operation.DatabaseOperation;
  43. import org.dbunit.util.TableFormatter;
  44. import org.dbunit.util.fileloader.DataFileLoader;
  45. import org.slf4j.Logger;
  46. import org.slf4j.LoggerFactory;

  47. /**
  48.  * Test case base class supporting prep data and expected data. Prep data is the
  49.  * data needed for the test to run. Expected data is the data needed to compare
  50.  * if the test ran successfully.
  51.  *
  52.  * @see org.dbunit.DefaultPrepAndExpectedTestCaseDiIT
  53.  * @see org.dbunit.DefaultPrepAndExpectedTestCaseExtIT
  54.  *
  55.  * @author Jeff Jensen jeffjensen AT users.sourceforge.net
  56.  * @author Last changed by: $Author$
  57.  * @version $Revision$ $Date$
  58.  * @since 2.4.8
  59.  */
  60. public class DefaultPrepAndExpectedTestCase extends DBTestCase
  61.         implements PrepAndExpectedTestCase
  62. {
  63.     private final Logger log =
  64.             LoggerFactory.getLogger(DefaultPrepAndExpectedTestCase.class);

  65.     private static final String DATABASE_TESTER_IS_NULL_MSG =
  66.             "databaseTester is null; must configure or set it first";

  67.     public static final String TEST_ERROR_MSG = "DbUnit test error.";

  68.     private IDatabaseTester databaseTester;
  69.     private DataFileLoader dataFileLoader;

  70.     // per test data
  71.     private IDataSet prepDataSet = new DefaultDataSet();
  72.     private IDataSet expectedDataSet = new DefaultDataSet();
  73.     private VerifyTableDefinition[] verifyTableDefs = {};

  74.     private ExpectedDataSetAndVerifyTableDefinitionVerifier expectedDataSetAndVerifyTableDefinitionVerifier =
  75.             new DefaultExpectedDataSetAndVerifyTableDefinitionVerifier();

  76.     final TableFormatter tableFormatter = new TableFormatter();

  77.     /** Create new instance. */
  78.     public DefaultPrepAndExpectedTestCase()
  79.     {
  80.     }

  81.     /**
  82.      * Create new instance with specified dataFileLoader and databaseTester.
  83.      *
  84.      * @param dataFileLoader
  85.      *            Load to use for loading the data files.
  86.      * @param databaseTester
  87.      *            Tester to use for database manipulation.
  88.      */
  89.     public DefaultPrepAndExpectedTestCase(final DataFileLoader dataFileLoader,
  90.             final IDatabaseTester databaseTester)
  91.     {
  92.         this.dataFileLoader = dataFileLoader;
  93.         this.databaseTester = databaseTester;
  94.     }

  95.     /**
  96.      * Create new instance with specified test case name.
  97.      *
  98.      * @param name
  99.      *            The test case name.
  100.      */
  101.     public DefaultPrepAndExpectedTestCase(final String name)
  102.     {
  103.         super(name);
  104.     }

  105.     /**
  106.      * {@inheritDoc} This implementation returns the databaseTester set by the
  107.      * test.
  108.      */
  109.     @Override
  110.     public IDatabaseTester newDatabaseTester() throws Exception
  111.     {
  112.         // questionable, but there is not a "setter" for any parent...
  113.         return databaseTester;
  114.     }

  115.     /**
  116.      * {@inheritDoc} Returns the prep dataset.
  117.      */
  118.     @Override
  119.     public IDataSet getDataSet() throws Exception
  120.     {
  121.         return prepDataSet;
  122.     }

  123.     /**
  124.      * {@inheritDoc}
  125.      */
  126.     @Override
  127.     public void configureTest(
  128.             final VerifyTableDefinition[] verifyTableDefinitions,
  129.             final String[] prepDataFiles, final String[] expectedDataFiles)
  130.             throws Exception
  131.     {
  132.         log.info("configureTest: saving instance variables");

  133.         final boolean isCaseSensitiveTableNames = lookupFeatureValue(
  134.                 DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES);
  135.         log.info("configureTest: using case sensitive table names={}",
  136.                 isCaseSensitiveTableNames);

  137.         this.prepDataSet = makeCompositeDataSet(prepDataFiles, "prep",
  138.                 isCaseSensitiveTableNames);
  139.         this.expectedDataSet = makeCompositeDataSet(expectedDataFiles,
  140.                 "expected", isCaseSensitiveTableNames);

  141.         this.verifyTableDefs = verifyTableDefinitions;
  142.     }

  143.     private boolean lookupFeatureValue(final String featureName)
  144.             throws Exception
  145.     {
  146.         boolean featureValue;

  147.         IDatabaseConnection connection = null;
  148.         try
  149.         {
  150.             connection = getConnection();
  151.             final DatabaseConfig config = connection.getConfig();
  152.             featureValue = config.getFeature(featureName);
  153.         } finally
  154.         {
  155.             if (connection != null)
  156.             {
  157.                 connection.close();
  158.             }
  159.         }

  160.         return featureValue;
  161.     }

  162.     /**
  163.      * {@inheritDoc}
  164.      */
  165.     @Override
  166.     public void preTest() throws Exception
  167.     {
  168.         setupData();
  169.     }

  170.     /**
  171.      * {@inheritDoc}
  172.      */
  173.     @Override
  174.     public void preTest(final VerifyTableDefinition[] tables,
  175.             final String[] prepDataFiles, final String[] expectedDataFiles)
  176.             throws Exception
  177.     {
  178.         configureTest(tables, prepDataFiles, expectedDataFiles);
  179.         preTest();
  180.     }

  181.     /**
  182.      * {@inheritDoc}
  183.      */
  184.     @Override
  185.     public Object runTest(final VerifyTableDefinition[] verifyTables,
  186.             final String[] prepDataFiles, final String[] expectedDataFiles,
  187.             final PrepAndExpectedTestCaseSteps testSteps) throws Exception
  188.     {
  189.         final Object result;

  190.         try
  191.         {
  192.             preTest(verifyTables, prepDataFiles, expectedDataFiles);
  193.             log.info("runTest: running test steps");
  194.             result = testSteps.run();
  195.         } catch (final Throwable e)
  196.         {
  197.             log.error(TEST_ERROR_MSG, e);
  198.             // don't verify table data when test execution has errors as:
  199.             // * a verify data failure masks the test error exception
  200.             // * tables in unknown state and therefore probably not accurate
  201.             postTest(false);
  202.             throw e;
  203.         }

  204.         postTest();

  205.         return result;
  206.     }

  207.     /**
  208.      * {@inheritDoc}
  209.      */
  210.     @Override
  211.     public void postTest() throws Exception
  212.     {
  213.         postTest(true);
  214.     }

  215.     /**
  216.      * {@inheritDoc}
  217.      */
  218.     @Override
  219.     public void postTest(final boolean verifyData) throws Exception
  220.     {
  221.         try
  222.         {
  223.             if (verifyData)
  224.             {
  225.                 verifyData();
  226.             }
  227.         } finally
  228.         {
  229.             // it is deliberate to have cleanup exceptions shadow verify
  230.             // failures so user knows db is probably in unknown state (for
  231.             // those not using an in-memory db or transaction rollback),
  232.             // otherwise would mask probable cause of subsequent test failures
  233.             cleanupData();
  234.         }
  235.     }

  236.     /**
  237.      * {@inheritDoc}
  238.      */
  239.     @Override
  240.     public void cleanupData() throws Exception
  241.     {
  242.         try
  243.         {
  244.             final boolean isCaseSensitiveTableNames = lookupFeatureValue(
  245.                     DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES);
  246.             log.info("cleanupData: using case sensitive table names={}",
  247.                     isCaseSensitiveTableNames);

  248.             final IDataSet[] dataSets =
  249.                     new IDataSet[] {prepDataSet, expectedDataSet};
  250.             final IDataSet dataset = new CompositeDataSet(dataSets, true,
  251.                     isCaseSensitiveTableNames);
  252.             final String[] tableNames = dataset.getTableNames();
  253.             final int count = tableNames.length;
  254.             log.info("cleanupData: about to clean up {} tables={}", count,
  255.                     tableNames);

  256.             if (databaseTester == null)
  257.             {
  258.                 throw new IllegalStateException(DATABASE_TESTER_IS_NULL_MSG);
  259.             }

  260.             databaseTester.setTearDownOperation(getTearDownOperation());
  261.             databaseTester.setDataSet(dataset);
  262.             databaseTester.setOperationListener(getOperationListener());
  263.             databaseTester.onTearDown();
  264.             log.debug("cleanupData: Clean up done");
  265.         } catch (final Exception e)
  266.         {
  267.             log.error("cleanupData: Exception:", e);
  268.             throw e;
  269.         }
  270.     }

  271.     @Override
  272.     protected void tearDown() throws Exception
  273.     {
  274.         // parent tearDown() only cleans up prep data
  275.         cleanupData();
  276.         super.tearDown();
  277.     }

  278.     /**
  279.      * Use the provided databaseTester to prep the database with the provided
  280.      * prep dataset. See {@link org.dbunit.IDatabaseTester#onSetup()}.
  281.      *
  282.      * @throws Exception
  283.      */
  284.     public void setupData() throws Exception
  285.     {
  286.         log.info("setupData: setting prep dataset and inserting rows");
  287.         if (databaseTester == null)
  288.         {
  289.             throw new IllegalStateException(DATABASE_TESTER_IS_NULL_MSG);
  290.         }

  291.         try
  292.         {
  293.             super.setUp();
  294.         } catch (final Exception e)
  295.         {
  296.             log.error("setupData: Exception with setting up data:", e);
  297.             throw e;
  298.         }
  299.     }

  300.     @Override
  301.     protected DatabaseOperation getSetUpOperation() throws Exception {
  302.         assertNotNull(databaseTester, DATABASE_TESTER_IS_NULL_MSG);
  303.         return databaseTester.getSetUpOperation();
  304.     }

  305.     @Override
  306.     protected DatabaseOperation getTearDownOperation() throws Exception {
  307.         assertNotNull(databaseTester, DATABASE_TESTER_IS_NULL_MSG);
  308.         return databaseTester.getTearDownOperation();
  309.     }

  310.     /**
  311.      * {@inheritDoc} Uses the connection from the provided databaseTester.
  312.      */
  313.     @Override
  314.     public void verifyData() throws Exception
  315.     {
  316.         if (databaseTester == null)
  317.         {
  318.             throw new IllegalStateException(DATABASE_TESTER_IS_NULL_MSG);
  319.         }

  320.         final IDatabaseConnection connection = getConnection();

  321.         final DatabaseConfig config = connection.getConfig();
  322.         expectedDataSetAndVerifyTableDefinitionVerifier.verify(verifyTableDefs,
  323.                 expectedDataSet, config);

  324.         try
  325.         {
  326.             final int tableDefsCount = verifyTableDefs.length;
  327.             log.info(
  328.                     "verifyData: about to verify {} tables"
  329.                             + " using verifyTableDefinitions={}",
  330.                     tableDefsCount, verifyTableDefs);
  331.             if (tableDefsCount == 0)
  332.             {
  333.                 log.warn("verifyData: No tables to verify as"
  334.                         + " no VerifyTableDefinitions specified");
  335.             }

  336.             for (int i = 0; i < tableDefsCount; i++)
  337.             {
  338.                 final VerifyTableDefinition td = verifyTableDefs[i];
  339.                 verifyData(connection, td);
  340.             }
  341.         } catch (final Exception e)
  342.         {
  343.             log.error("verifyData: Exception:", e);
  344.             throw e;
  345.         } finally
  346.         {
  347.             log.debug("verifyData: Verification done, closing connection");
  348.             connection.close();
  349.         }
  350.     }

  351.     protected void verifyData(final IDatabaseConnection connection,
  352.             final VerifyTableDefinition verifyTableDefinition) throws Exception
  353.     {
  354.         final String tableName = verifyTableDefinition.getTableName();
  355.         log.info("verifyData: Verifying table '{}'", tableName);

  356.         final String[] excludeColumns =
  357.                 verifyTableDefinition.getColumnExclusionFilters();
  358.         final String[] includeColumns =
  359.                 verifyTableDefinition.getColumnInclusionFilters();
  360.         final Map<String, ValueComparer> columnValueComparers =
  361.                 verifyTableDefinition.getColumnValueComparers();
  362.         final ValueComparer defaultValueComparer =
  363.                 verifyTableDefinition.getDefaultValueComparer();

  364.         final ITable expectedTable = loadTableDataFromDataSet(tableName);
  365.         final ITable actualTable =
  366.                 loadTableDataFromDatabase(tableName, connection);

  367.         verifyData(expectedTable, actualTable, excludeColumns, includeColumns,
  368.                 defaultValueComparer, columnValueComparers);
  369.     }

  370.     public ITable loadTableDataFromDataSet(final String tableName)
  371.             throws DataSetException
  372.     {
  373.         ITable table = null;

  374.         final String methodName = "loadTableDataFromDataSet";

  375.         log.debug("{}: Loading table {} from expected dataset", methodName,
  376.                 tableName);
  377.         try
  378.         {
  379.             table = expectedDataSet.getTable(tableName);
  380.         } catch (final Exception e)
  381.         {
  382.             final String msg = methodName + ": Problem obtaining table '"
  383.                     + tableName + "' from expected dataset";
  384.             log.error(msg, e);
  385.             throw new DataSetException(msg, e);
  386.         }
  387.         return table;
  388.     }

  389.     public ITable loadTableDataFromDatabase(final String tableName,
  390.             final IDatabaseConnection connection) throws Exception
  391.     {
  392.         ITable table = null;

  393.         final String methodName = "loadTableDataFromDatabase";

  394.         log.debug("{}: Loading table {} from database", methodName, tableName);
  395.         try
  396.         {
  397.             table = connection.createTable(tableName);
  398.         } catch (final Exception e)
  399.         {
  400.             final String msg = methodName + ": Problem obtaining table '"
  401.                     + tableName + "' from database";
  402.             log.error(msg, e);
  403.             throw new DataSetException(msg, e);
  404.         }
  405.         return table;
  406.     }

  407.     /**
  408.      * For the specified expected and actual tables (and excluding and including
  409.      * the specified columns), verify the actual data is as expected.
  410.      *
  411.      * @param expectedTable
  412.      *            The expected table to compare the actual table to.
  413.      * @param actualTable
  414.      *            The actual table to compare to the expected table.
  415.      * @param excludeColumns
  416.      *            The column names to exclude from comparison. See
  417.      *            {@link org.dbunit.dataset.filter.DefaultColumnFilter#excludeColumn(String)}
  418.      *            .
  419.      * @param includeColumns
  420.      *            The column names to only include in comparison. See
  421.      *            {@link org.dbunit.dataset.filter.DefaultColumnFilter#includeColumn(String)}
  422.      *            .
  423.      * @param defaultValueComparer
  424.      *            {@link ValueComparer} to use with column value comparisons
  425.      *            when the column name for the table is not in the
  426.      *            columnValueComparers {@link Map}. Can be <code>null</code> and
  427.      *            will default.
  428.      * @param columnValueComparers
  429.      *            {@link Map} of {@link ValueComparer}s to use for specific
  430.      *            columns. Key is column name, value is the
  431.      *            {@link ValueComparer}. Can be <code>null</code> and will
  432.      *            default to defaultValueComparer for all columns in all tables.
  433.      * @throws DatabaseUnitException
  434.      */
  435.     protected void verifyData(final ITable expectedTable,
  436.             final ITable actualTable, final String[] excludeColumns,
  437.             final String[] includeColumns,
  438.             final ValueComparer defaultValueComparer,
  439.             final Map<String, ValueComparer> columnValueComparers)
  440.             throws DatabaseUnitException
  441.     {
  442.         final String methodName = "verifyData";

  443.         final ITableMetaData actualTableMetaData =
  444.                 actualTable.getTableMetaData();
  445.         final ITableMetaData expectedTableMetaData =
  446.                 expectedTable.getTableMetaData();

  447.         final Column[] actualTableColumns = actualTableMetaData.getColumns();
  448.         final Column[] expectedTableColumns = makeExpectedTableColumns(
  449.                 actualTableColumns, expectedTableMetaData);

  450.         log.debug("{}: Sorting expected table using all columns", methodName);
  451.         final SortedTable expectedSortedTable =
  452.                 new SortedTable(expectedTable, expectedTableColumns, true);
  453.         expectedSortedTable.setUseComparable(true);
  454.         log.debug("{}: Sorted expected table={}", methodName,
  455.                 expectedSortedTable);

  456.         log.debug("{}: Sorting actual table using all columns", methodName);
  457.         final SortedTable actualSortedTable =
  458.                 new SortedTable(actualTable, actualTableColumns);
  459.         actualSortedTable.setUseComparable(true);
  460.         log.debug("{}: Sorted actual table={}", methodName, actualSortedTable);

  461.         // Filter out the columns from the expected and actual results
  462.         log.debug(
  463.                 "{}: Applying column exclude and include filters to sorted expected table",
  464.                 methodName);
  465.         final ITable expectedFilteredTable = applyColumnFilters(
  466.                 expectedSortedTable, excludeColumns, includeColumns);
  467.         log.debug(
  468.                 "{}: Applying column exclude and include filters to sorted actual table",
  469.                 methodName);
  470.         final ITable actualFilteredTable = applyColumnFilters(actualSortedTable,
  471.                 excludeColumns, includeColumns);

  472.         log.debug("{}: Creating additionalColumnInfo for expected table",
  473.                 methodName);
  474.         final Column[] additionalColumnInfo =
  475.                 makeAdditionalColumnInfo(expectedTable, excludeColumns);
  476.         log.debug("{}: additionalColumnInfo={}", methodName,
  477.                 additionalColumnInfo);

  478.         logSortedTables(expectedSortedTable, actualSortedTable);

  479.         log.debug("{}: Comparing expected table to actual table", methodName);
  480.         compareData(expectedFilteredTable, actualFilteredTable,
  481.                 additionalColumnInfo, defaultValueComparer,
  482.                 columnValueComparers);
  483.     }

  484.     /**
  485.      * If expected column definitions exist and are {@link DataType.UNKNOWN},
  486.      * make them from actual table column definitions.
  487.      *
  488.      * @throws DataSetException
  489.      */
  490.     private Column[] makeExpectedTableColumns(final Column[] actualColumns,
  491.             final ITableMetaData expectedTableMetaData) throws DataSetException
  492.     {
  493.         final Column[] expectedTableColumns;

  494.         final Column[] expectedColumns = expectedTableMetaData.getColumns();
  495.         if (expectedColumns.length > 0)
  496.         {
  497.             final DataType dataType = expectedColumns[0].getDataType();
  498.             if (DataType.UNKNOWN.equals(dataType))
  499.             {
  500.                 // all column definitions probably unknown, use actual's
  501.                 expectedTableColumns = makeExpectedTableColumns(actualColumns,
  502.                         expectedColumns);
  503.             } else
  504.             {
  505.                 // all expected column definitions probably known, use them
  506.                 expectedTableColumns = expectedColumns;
  507.             }
  508.         } else
  509.         {
  510.             // no column definitions exist, so don't falsely add any
  511.             expectedTableColumns = expectedColumns;
  512.         }

  513.         return expectedTableColumns;
  514.     }

  515.     /**
  516.      * Make expected Column[] from actual table column definitions so expected
  517.      * data comparisons use data types from database (and expected data columns
  518.      * handled same as actual data in comparisons). Don't include columns from
  519.      * actual that are not in expected.
  520.      */
  521.     private Column[] makeExpectedTableColumns(final Column[] actualColumns,
  522.             final Column[] expectedColumns)
  523.     {
  524.         final Set<String> expectedColumnNames =
  525.                 Arrays.stream(expectedColumns).map(Column::getColumnName)
  526.                         .map(String::toLowerCase).collect(Collectors.toSet());

  527.         final List<Column> expectedColumnsList = Arrays.stream(actualColumns)
  528.                 .filter(col -> expectedColumnNames
  529.                         .contains(col.getColumnName().toLowerCase()))
  530.                 .collect(Collectors.toList());
  531.         return expectedColumnsList
  532.                 .toArray(new Column[expectedColumnsList.size()]);
  533.     }

  534.     private void logSortedTables(final SortedTable expectedSortedTable,
  535.             final SortedTable actualSortedTable)
  536.     {
  537.         if (log.isTraceEnabled())
  538.         {
  539.             logSortedTable("expectedSortedTable", expectedSortedTable);
  540.             logSortedTable("actualSortedTable", actualSortedTable);
  541.         }
  542.     }

  543.     private void logSortedTable(final String tableTypeName,
  544.             final SortedTable table)
  545.     {
  546.         final String methodName = "logSortedTable:";
  547.         final Column[] sortColumns = table.getSortColumns();
  548.         log.trace("{} {} sortColumns={}", methodName, tableTypeName,
  549.                 sortColumns);
  550.         try
  551.         {
  552.             final String tableContents = tableFormatter.format(table);
  553.             log.trace("{} {} tableContents={}", methodName, tableTypeName,
  554.                     tableContents);
  555.         } catch (final DataSetException e)
  556.         {
  557.             log.error("{} Error trying to log table={}", methodName,
  558.                     tableTypeName, e);
  559.         }
  560.     }

  561.     /** Compare the tables, enables easy overriding. */
  562.     protected void compareData(final ITable expectedTable,
  563.             final ITable actualTable, final Column[] additionalColumnInfo,
  564.             final ValueComparer defaultValueComparer,
  565.             final Map<String, ValueComparer> columnValueComparers)
  566.             throws DatabaseUnitException
  567.     {
  568.         Assertion.assertWithValueComparer(expectedTable, actualTable,
  569.                 additionalColumnInfo, defaultValueComparer,
  570.                 columnValueComparers);
  571.     }

  572.     /**
  573.      * Don't add excluded columns to additionalColumnInfo as they are not found
  574.      * and generate a not found message in the fail message.
  575.      *
  576.      * @param expectedTable
  577.      *            Not null.
  578.      * @param excludeColumns
  579.      *            Nullable.
  580.      */
  581.     protected Column[] makeAdditionalColumnInfo(final ITable expectedTable,
  582.             final String[] excludeColumns) throws DataSetException
  583.     {
  584.         final Column[] allColumns =
  585.                 expectedTable.getTableMetaData().getColumns();

  586.         return excludeColumns == null ? allColumns
  587.                 : makeAdditionalColumnInfo(excludeColumns, allColumns);
  588.     }

  589.     /**
  590.      * Don't add excluded columns to additionalColumnInfo as they are not found
  591.      * and generate a not found message in the fail message.
  592.      *
  593.      * @param expectedTable
  594.      *            Not null.
  595.      * @param excludeColumns
  596.      *            Not null.
  597.      */
  598.     protected Column[] makeAdditionalColumnInfo(final String[] excludeColumns,
  599.             final Column[] allColumns)
  600.     {
  601.         final List<Column> keepColumnsList = new ArrayList<>();
  602.         final List<String> excludeColumnsList = Arrays.asList(excludeColumns);

  603.         for (final Column column : allColumns)
  604.         {
  605.             final String columnName = column.getColumnName();
  606.             if (!excludeColumnsList.contains(columnName))
  607.             {
  608.                 keepColumnsList.add(column);
  609.             }
  610.         }

  611.         return keepColumnsList.toArray(new Column[keepColumnsList.size()]);
  612.     }

  613.     /**
  614.      * Make a <code>IDataSet</code> from the specified files with case sensitive
  615.      * table names as false.
  616.      *
  617.      * @param dataFiles
  618.      *            Represents the array of dbUnit data files.
  619.      * @param dataFilesName
  620.      *            Concept name of the data files, e.g. prep, expected.
  621.      * @return The composite dataset.
  622.      * @throws DataSetException
  623.      *             On dbUnit errors.
  624.      */
  625.     public IDataSet makeCompositeDataSet(final String[] dataFiles,
  626.             final String dataFilesName) throws DataSetException
  627.     {
  628.         return makeCompositeDataSet(dataFiles, dataFilesName, false);
  629.     }

  630.     /**
  631.      * Make a <code>IDataSet</code> from the specified files.
  632.      *
  633.      * @param dataFiles
  634.      *            Represents the array of dbUnit data files.
  635.      * @param dataFilesName
  636.      *            Concept name of the data files, e.g. prep, expected.
  637.      * @param isCaseSensitiveTableNames
  638.      *            true if case sensitive table names is on.
  639.      * @return The composite dataset.
  640.      * @throws DataSetException
  641.      *             On dbUnit errors.
  642.      */
  643.     public IDataSet makeCompositeDataSet(final String[] dataFiles,
  644.             final String dataFilesName, final boolean isCaseSensitiveTableNames)
  645.             throws DataSetException
  646.     {
  647.         if (dataFileLoader == null)
  648.         {
  649.             throw new IllegalStateException(
  650.                     "dataFileLoader is null; must configure or set it first");
  651.         }

  652.         final int count = dataFiles.length;
  653.         log.debug("makeCompositeDataSet: {} dataFiles count={}", dataFilesName,
  654.                 count);
  655.         if (count == 0)
  656.         {
  657.             log.info("makeCompositeDataSet: Specified zero {} data files",
  658.                     dataFilesName);
  659.         }

  660.         final List list = new ArrayList();
  661.         for (int i = 0; i < count; i++)
  662.         {
  663.             final IDataSet ds = dataFileLoader.load(dataFiles[i]);
  664.             list.add(ds);
  665.         }

  666.         final IDataSet[] dataSet = (IDataSet[]) list.toArray(new IDataSet[] {});
  667.         final IDataSet compositeDS =
  668.                 new CompositeDataSet(dataSet, true, isCaseSensitiveTableNames);
  669.         return compositeDS;
  670.     }

  671.     /**
  672.      * Apply the specified exclude and include column filters to the specified
  673.      * table.
  674.      *
  675.      * @param table
  676.      *            The table to apply the filters to.
  677.      * @param excludeColumns
  678.      *            The exclude filters; use null or empty array to mean exclude
  679.      *            none.
  680.      * @param includeColumns
  681.      *            The include filters; use null to mean include all.
  682.      * @return The filtered table.
  683.      * @throws DataSetException
  684.      */
  685.     public ITable applyColumnFilters(final ITable table,
  686.             final String[] excludeColumns, final String[] includeColumns)
  687.             throws DataSetException
  688.     {
  689.         ITable filteredTable = table;

  690.         if (table == null)
  691.         {
  692.             throw new IllegalArgumentException("table is null");
  693.         }

  694.         // note: dbunit interprets an empty inclusion filter array as one
  695.         // not wanting to compare anything!
  696.         if (includeColumns == null)
  697.         {
  698.             log.debug("applyColumnFilters: including columns=(all)");
  699.         } else
  700.         {
  701.             log.debug("applyColumnFilters: including columns='{}'",
  702.                     new Object[] {includeColumns});
  703.             filteredTable = DefaultColumnFilter
  704.                     .includedColumnsTable(filteredTable, includeColumns);
  705.         }

  706.         if (excludeColumns == null || excludeColumns.length == 0)
  707.         {
  708.             log.debug("applyColumnFilters: excluding columns=(none)");
  709.         } else
  710.         {
  711.             log.debug("applyColumnFilters: excluding columns='{}'",
  712.                     new Object[] {excludeColumns});
  713.             filteredTable = DefaultColumnFilter
  714.                     .excludedColumnsTable(filteredTable, excludeColumns);
  715.         }

  716.         return filteredTable;
  717.     }

  718.     /**
  719.      * {@inheritDoc}
  720.      */
  721.     @Override
  722.     public IDataSet getPrepDataset()
  723.     {
  724.         return prepDataSet;
  725.     }

  726.     /**
  727.      * {@inheritDoc}
  728.      */
  729.     @Override
  730.     public IDataSet getExpectedDataset()
  731.     {
  732.         return expectedDataSet;
  733.     }

  734.     /**
  735.      * Get the databaseTester.
  736.      *
  737.      * @see {@link #databaseTester}.
  738.      *
  739.      * @return The databaseTester.
  740.      */
  741.     @Override
  742.     public IDatabaseTester getDatabaseTester()
  743.     {
  744.         return databaseTester;
  745.     }

  746.     /**
  747.      * Set the databaseTester.
  748.      *
  749.      * @see {@link #databaseTester}.
  750.      *
  751.      * @param databaseTester
  752.      *            The databaseTester to set.
  753.      */
  754.     public void setDatabaseTester(final IDatabaseTester databaseTester)
  755.     {
  756.         this.databaseTester = databaseTester;
  757.     }

  758.     /**
  759.      * Get the dataFileLoader.
  760.      *
  761.      * @see {@link #dataFileLoader}.
  762.      *
  763.      * @return The dataFileLoader.
  764.      */
  765.     public DataFileLoader getDataFileLoader()
  766.     {
  767.         return dataFileLoader;
  768.     }

  769.     /**
  770.      * Set the dataFileLoader.
  771.      *
  772.      * @see {@link #dataFileLoader}.
  773.      *
  774.      * @param dataFileLoader
  775.      *            The dataFileLoader to set.
  776.      */
  777.     public void setDataFileLoader(final DataFileLoader dataFileLoader)
  778.     {
  779.         this.dataFileLoader = dataFileLoader;
  780.     }

  781.     /**
  782.      * Set the prepDs.
  783.      *
  784.      * @see {@link #prepDataSet}.
  785.      *
  786.      * @param prepDataSet
  787.      *            The prepDs to set.
  788.      */
  789.     public void setPrepDs(final IDataSet prepDataSet)
  790.     {
  791.         this.prepDataSet = prepDataSet;
  792.     }

  793.     /**
  794.      * Set the expectedDs.
  795.      *
  796.      * @see {@link #expectedDataSet}.
  797.      *
  798.      * @param expectedDataSet
  799.      *            The expectedDs to set.
  800.      */
  801.     public void setExpectedDs(final IDataSet expectedDataSet)
  802.     {
  803.         this.expectedDataSet = expectedDataSet;
  804.     }

  805.     /**
  806.      * Get the tableDefs.
  807.      *
  808.      * @see {@link #verifyTableDefs}.
  809.      *
  810.      * @return The tableDefs.
  811.      */
  812.     public VerifyTableDefinition[] getVerifyTableDefs()
  813.     {
  814.         return verifyTableDefs;
  815.     }

  816.     /**
  817.      * Set the tableDefs.
  818.      *
  819.      * @see {@link #verifyTableDefs}.
  820.      *
  821.      * @param verifyTableDefs
  822.      *            The tableDefs to set.
  823.      */
  824.     public void setVerifyTableDefs(
  825.             final VerifyTableDefinition[] verifyTableDefs)
  826.     {
  827.         this.verifyTableDefs = verifyTableDefs;
  828.     }

  829.     public ExpectedDataSetAndVerifyTableDefinitionVerifier getExpectedDataSetAndVerifyTableDefinitionVerifier()
  830.     {
  831.         return expectedDataSetAndVerifyTableDefinitionVerifier;
  832.     }

  833.     public void setExpectedDataSetAndVerifyTableDefinitionVerifier(
  834.             final ExpectedDataSetAndVerifyTableDefinitionVerifier expectedDataSetAndVerifyTableDefinitionVerifier)
  835.     {
  836.         this.expectedDataSetAndVerifyTableDefinitionVerifier =
  837.                 expectedDataSetAndVerifyTableDefinitionVerifier;
  838.     }
  839. }