View Javadoc
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.assertion;
22  
23  import java.sql.SQLException;
24  import java.util.Map;
25  
26  import org.dbunit.Assertion;
27  import org.dbunit.DatabaseUnitException;
28  import org.dbunit.assertion.comparer.value.ValueComparer;
29  import org.dbunit.assertion.comparer.value.ValueComparers;
30  import org.dbunit.database.IDatabaseConnection;
31  import org.dbunit.dataset.Column;
32  import org.dbunit.dataset.IDataSet;
33  import org.dbunit.dataset.ITable;
34  import org.dbunit.dataset.datatype.DataType;
35  import org.dbunit.dataset.datatype.UnknownDataType;
36  import org.dbunit.dataset.filter.DefaultColumnFilter;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * Default implementation of DbUnit assertions, based on the original methods
42   * present at {@link Assertion}.
43   *
44   * All are equality comparisons.
45   *
46   * @author Felipe Leme (dbunit@felipeal.net)
47   * @author gommma (gommma AT users.sourceforge.net)
48   * @version $Revision$ $Date$
49   * @since 2.4.0
50   */
51  public class DbUnitAssert_New extends DbUnitAssertBase
52  {
53      private static final Logger logger =
54              LoggerFactory.getLogger(DbUnitAssert_New.class);
55  
56      /**
57       * Compare one table present in two datasets ignoring specified columns.
58       *
59       * @param expectedDataset
60       *            First dataset.
61       * @param actualDataset
62       *            Second dataset.
63       * @param tableName
64       *            Table name of the table to be compared.
65       * @param ignoreCols
66       *            Columns to be ignored in comparison.
67       * @throws org.dbunit.DatabaseUnitException
68       *             If an error occurs.
69       */
70      public void assertEqualsIgnoreCols(final IDataSet expectedDataset,
71              final IDataSet actualDataset, final String tableName,
72              final String[] ignoreCols) throws DatabaseUnitException
73      {
74          logger.debug(
75                  "assertEqualsIgnoreCols(expectedDataset={}, actualDataset={}, tableName={}, ignoreCols={}) - start",
76                  expectedDataset, actualDataset, tableName, ignoreCols);
77  
78          assertEqualsIgnoreCols(expectedDataset.getTable(tableName),
79                  actualDataset.getTable(tableName), ignoreCols);
80      }
81  
82      /**
83       * Compare the given tables ignoring specified columns.
84       *
85       * @param expectedTable
86       *            First table.
87       * @param actualTable
88       *            Second table.
89       * @param ignoreCols
90       *            Columns to be ignored in comparison.
91       * @throws org.dbunit.DatabaseUnitException
92       *             If an error occurs.
93       */
94      public void assertEqualsIgnoreCols(final ITable expectedTable,
95              final ITable actualTable, final String[] ignoreCols)
96              throws DatabaseUnitException
97      {
98          logger.debug(
99                  "assertEqualsIgnoreCols(expectedTable={}, actualTable={}, ignoreCols={}) - start",
100                 expectedTable, actualTable, ignoreCols);
101 
102         final ITable expectedTableFiltered = DefaultColumnFilter
103                 .excludedColumnsTable(expectedTable, ignoreCols);
104         final ITable actualTableFiltered = DefaultColumnFilter
105                 .excludedColumnsTable(actualTable, ignoreCols);
106         assertEquals(expectedTableFiltered, actualTableFiltered);
107     }
108 
109     /**
110      * Compare a table from a dataset with a table generated from an sql query.
111      *
112      * @param expectedDataset
113      *            Dataset to retrieve the first table from.
114      * @param connection
115      *            Connection to use for the SQL statement.
116      * @param sqlQuery
117      *            SQL query that will build the data in returned second table
118      *            rows.
119      * @param tableName
120      *            Table name of the table to compare.
121      * @param ignoreCols
122      *            Columns to be ignored in comparison.
123      * @throws DatabaseUnitException
124      *             If an error occurs while performing the comparison.
125      * @throws java.sql.SQLException
126      *             If an SQL error occurs.
127      */
128     public void assertEqualsByQuery(final IDataSet expectedDataset,
129             final IDatabaseConnection connection, final String sqlQuery,
130             final String tableName, final String[] ignoreCols)
131             throws DatabaseUnitException, SQLException
132     {
133         logger.debug(
134                 "assertEqualsByQuery(expectedDataset={}, connection={}, tableName={}, sqlQuery={}, ignoreCols={}) - start",
135                 expectedDataset, connection, tableName, sqlQuery, ignoreCols);
136 
137         final ITable expectedTable = expectedDataset.getTable(tableName);
138         assertEqualsByQuery(expectedTable, connection, tableName, sqlQuery,
139                 ignoreCols);
140     }
141 
142     /**
143      * Compare a table with a table generated from an sql query.
144      *
145      * @param expectedTable
146      *            Table containing all expected results.
147      * @param connection
148      *            Connection to use for the SQL statement.
149      * @param tableName
150      *            The name of the table to query from the database.
151      * @param sqlQuery
152      *            SQL query that will build the data in returned second table
153      *            rows.
154      * @param ignoreCols
155      *            Columns to be ignored in comparison.
156      * @throws DatabaseUnitException
157      *             If an error occurs while performing the comparison.
158      * @throws java.sql.SQLException
159      *             If an SQL error occurs.
160      */
161     public void assertEqualsByQuery(final ITable expectedTable,
162             final IDatabaseConnection connection, final String tableName,
163             final String sqlQuery, final String[] ignoreCols)
164             throws DatabaseUnitException, SQLException
165     {
166         logger.debug(
167                 "assertEqualsByQuery(expectedTable={}, connection={}, tableName={}, sqlQuery={}, ignoreCols={}) - start",
168                 expectedTable, connection, tableName, sqlQuery, ignoreCols);
169 
170         final ITable expected = DefaultColumnFilter
171                 .excludedColumnsTable(expectedTable, ignoreCols);
172         final ITable queriedTable =
173                 connection.createQueryTable(tableName, sqlQuery);
174         final ITable actual = DefaultColumnFilter
175                 .excludedColumnsTable(queriedTable, ignoreCols);
176         assertEquals(expected, actual);
177     }
178 
179     /**
180      * Asserts that the two specified dataset are equals. This method ignore the
181      * tables order.
182      */
183     public void assertEquals(final IDataSet expectedDataSet,
184             final IDataSet actualDataSet) throws DatabaseUnitException
185     {
186         logger.debug(
187                 "assertEquals(expectedDataSet={}, actualDataSet={}) - start",
188                 expectedDataSet, actualDataSet);
189         assertEquals(expectedDataSet, actualDataSet, null);
190     }
191 
192     /**
193      * Asserts that the two specified dataset are equals. This method ignore the
194      * tables order.
195      *
196      * @since 2.4
197      */
198     public void assertEquals(final IDataSet expectedDataSet,
199             final IDataSet actualDataSet, final FailureHandler failureHandler)
200             throws DatabaseUnitException
201     {
202         logger.debug(
203                 "assertEquals(expectedDataSet={}, actualDataSet={}, failureHandler={}) - start",
204                 expectedDataSet, actualDataSet, failureHandler);
205 
206         final ValueComparer defaultValueComparer =
207                 ValueComparers.isActualEqualToExpectedWithEmptyFailMessage;
208         final Map<String, Map<String, ValueComparer>> tableColumnValueComparers =
209                 getDefaultTableColumnValueComparerMap();
210         assertWithValueComparer(expectedDataSet, actualDataSet, failureHandler,
211                 defaultValueComparer, tableColumnValueComparers);
212     }
213 
214     /**
215      * Asserts that the two specified tables are equals. This method ignores the
216      * table names, the columns order, the columns data type and which columns
217      * are composing the primary keys.
218      *
219      * @param expectedTable
220      *            Table containing all expected results.
221      * @param actualTable
222      *            Table containing all actual results.
223      * @throws DatabaseUnitException
224      */
225     public void assertEquals(final ITable expectedTable,
226             final ITable actualTable) throws DatabaseUnitException
227     {
228         logger.debug("assertEquals(expectedTable={}, actualTable={}) - start",
229                 expectedTable, actualTable);
230         assertEquals(expectedTable, actualTable, (Column[]) null);
231     }
232 
233     /**
234      * Asserts that the two specified tables are equals. This method ignores the
235      * table names, the columns order, the columns data type and which columns
236      * are composing the primary keys. <br />
237      * Example: <code><pre>
238      * ITable actualTable = ...;
239      * ITable expectedTable = ...;
240      * ITableMetaData metaData = actualTable.getTableMetaData();
241      * Column[] additionalInfoCols = Columns.getColumns(new String[] {"MY_PK_COLUMN"}, metaData.getColumns());
242      * assertEquals(expectedTable, actualTable, additionalInfoCols);
243      * </pre></code>
244      *
245      * @param expectedTable
246      *            Table containing all expected results.
247      * @param actualTable
248      *            Table containing all actual results.
249      * @param additionalColumnInfo
250      *            The columns to be printed out if the assert fails because of a
251      *            data mismatch. Provides some additional column values that may
252      *            be useful to quickly identify the columns for which the
253      *            mismatch occurred (for example a primary key column). Can be
254      *            <code>null</code>.
255      * @throws DatabaseUnitException
256      */
257     public void assertEquals(final ITable expectedTable,
258             final ITable actualTable, final Column[] additionalColumnInfo)
259             throws DatabaseUnitException
260     {
261         logger.debug(
262                 "assertEquals(expectedTable={}, actualTable={}, additionalColumnInfo={}) - start",
263                 expectedTable, actualTable, additionalColumnInfo);
264 
265         FailureHandler failureHandler = null;
266         if (additionalColumnInfo != null)
267         {
268             failureHandler = getDefaultFailureHandler(additionalColumnInfo);
269         }
270 
271         assertEquals(expectedTable, actualTable, failureHandler);
272     }
273 
274     /**
275      * Asserts that the two specified tables are equals. This method ignores the
276      * table names, the columns order, the columns data type and which columns
277      * are composing the primary keys. <br />
278      * Example: <code><pre>
279      * ITable actualTable = ...;
280      * ITable expectedTable = ...;
281      * ITableMetaData metaData = actualTable.getTableMetaData();
282      * FailureHandler failureHandler = new DefaultFailureHandler();
283      * assertEquals(expectedTable, actualTable, failureHandler);
284      * </pre></code>
285      *
286      * @param expectedTable
287      *            Table containing all expected results.
288      * @param actualTable
289      *            Table containing all actual results.
290      * @param failureHandler
291      *            The failure handler used if the assert fails because of a data
292      *            mismatch. Provides some additional information that may be
293      *            useful to quickly identify the rows for which the mismatch
294      *            occurred (for example by printing an additional primary key
295      *            column). Can be <code>null</code>.
296      * @throws DatabaseUnitException
297      * @since 2.4
298      */
299     public void assertEquals(final ITable expectedTable,
300             final ITable actualTable, final FailureHandler failureHandler)
301             throws DatabaseUnitException
302     {
303         final ValueComparer defaultValueComparer =
304                 ValueComparers.isActualEqualToExpectedWithEmptyFailMessage;
305         final Map<String, ValueComparer> columnValueComparers = null;
306         assertWithValueComparer(expectedTable, actualTable, failureHandler,
307                 defaultValueComparer, columnValueComparers);
308     }
309 
310     /**
311      * Represents a single column to be used for the comparison of table data.
312      * It contains the {@link DataType} to be used for comparing the given
313      * column. This {@link DataType} matches the expected and actual column's
314      * datatype.
315      *
316      * @author gommma (gommma AT users.sourceforge.net)
317      * @author Last changed by: $Author: gommma $
318      * @version $Revision: 864 $ $Date: 2008-11-07 06:27:26 -0800 (Fri, 07 Nov
319      *          2008) $
320      * @since 2.4.0
321      */
322     public static class ComparisonColumn
323     {
324         private static final Logger logger =
325                 LoggerFactory.getLogger(ComparisonColumn.class);
326 
327         private String columnName;
328         private DataType dataType;
329 
330         /**
331          * @param tableName
332          *            The table name which is only needed for debugging output.
333          * @param expectedColumn
334          *            The expected column needed to resolve the {@link DataType}
335          *            to use for the actual comparison.
336          * @param actualColumn
337          *            The actual column needed to resolve the {@link DataType}
338          *            to use for the actual comparison.
339          * @param failureHandler
340          *            The {@link FailureHandler} to be used when no datatype can
341          *            be determined.
342          */
343         public ComparisonColumn(final String tableName,
344                 final Column expectedColumn, final Column actualColumn,
345                 final FailureHandler failureHandler)
346         {
347             this.columnName = expectedColumn.getColumnName();
348             this.dataType = getComparisonDataType(tableName, expectedColumn,
349                     actualColumn, failureHandler);
350         }
351 
352         /**
353          * @return The column actually being compared.
354          */
355         public String getColumnName()
356         {
357             return this.columnName;
358         }
359 
360         /**
361          * @return The {@link DataType} to use for the actual comparison.
362          */
363         public DataType getDataType()
364         {
365             return this.dataType;
366         }
367 
368         /**
369          * @param tableName
370          *            The table name which is only needed for debugging output.
371          * @param expectedColumn
372          * @param actualColumn
373          * @param failureHandler
374          *            The {@link FailureHandler} to be used when no datatype can
375          *            be determined.
376          * @return The dbunit {@link DataType} to use for comparing the given
377          *         column.
378          */
379         private DataType getComparisonDataType(final String tableName,
380                 final Column expectedColumn, final Column actualColumn,
381                 final FailureHandler failureHandler)
382         {
383             logger.debug(
384                     "getComparisonDataType(tableName={}, expectedColumn={}, actualColumn={}, failureHandler={}) - start",
385                     tableName, expectedColumn, actualColumn, failureHandler);
386 
387             final DataType expectedDataType = expectedColumn.getDataType();
388             final DataType actualDataType = actualColumn.getDataType();
389 
390             // The two columns have different data type
391             if (!expectedDataType.getClass().isInstance(actualDataType))
392             {
393                 // Expected column data type is unknown, use actual column data
394                 // type
395                 if (expectedDataType instanceof UnknownDataType)
396                 {
397                     return actualDataType;
398                 }
399 
400                 // Actual column data type is unknown, use expected column data
401                 // type
402                 if (actualDataType instanceof UnknownDataType)
403                 {
404                     return expectedDataType;
405                 }
406 
407                 // Impossible to determine which data type to use
408                 final String msg = "Incompatible data types: (table="
409                         + tableName + ", col=" + expectedColumn.getColumnName()
410                         + ")";
411                 throw failureHandler.createFailure(msg,
412                         String.valueOf(expectedDataType),
413                         String.valueOf(actualDataType));
414             }
415 
416             // Both columns have same data type, return any one of them
417             return expectedDataType;
418         }
419     }
420 }