View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2002-2004, 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 static org.assertj.core.api.Assertions.assertThat;
24  import static org.assertj.core.api.Assertions.assertThatThrownBy;
25  import static org.assertj.core.api.Assertions.catchThrowableOfType;
26  
27  import java.io.StringReader;
28  import java.math.BigDecimal;
29  import java.util.Map;
30  
31  import org.dbunit.DatabaseEnvironment;
32  import org.dbunit.assertion.comparer.value.ValueComparer;
33  import org.dbunit.assertion.comparer.value.ValueComparers;
34  import org.dbunit.assertion.comparer.value.builder.ColumnValueComparerMapBuilder;
35  import org.dbunit.database.IDatabaseConnection;
36  import org.dbunit.dataset.Column;
37  import org.dbunit.dataset.CompositeDataSet;
38  import org.dbunit.dataset.CompositeTable;
39  import org.dbunit.dataset.DataSetException;
40  import org.dbunit.dataset.DataSetUtils;
41  import org.dbunit.dataset.DefaultDataSet;
42  import org.dbunit.dataset.DefaultTable;
43  import org.dbunit.dataset.FilteredDataSet;
44  import org.dbunit.dataset.IDataSet;
45  import org.dbunit.dataset.ITable;
46  import org.dbunit.dataset.ITableMetaData;
47  import org.dbunit.dataset.SortedTable;
48  import org.dbunit.dataset.datatype.DataType;
49  import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
50  import org.dbunit.dataset.xml.XmlDataSet;
51  import org.dbunit.operation.DatabaseOperation;
52  import org.dbunit.testutil.TestUtils;
53  import org.junit.jupiter.api.Test;
54  
55  /**
56   * @author Manuel Laflamme
57   * @version $Revision$
58   * @since Mar 22, 2002
59   */
60  public class DbUnitAssertIT
61  {
62      public static final String FILE_PATH = "xml/assertionTest.xml";
63  
64      private DbUnitAssert assertion = new DbUnitAssert();
65  
66      private IDataSet getDataSet() throws Exception
67      {
68          return new FlatXmlDataSetBuilder()
69                  .build(TestUtils.getFileReader(FILE_PATH));
70      }
71  
72      ////////////////////////////////////////////////////////////////////////////
73      // Test methods
74  
75      @Test
76      void testAssertTablesEquals_withSameValueTable_assertsSuccessfully() throws Exception
77      {
78          final IDataSet dataSet = getDataSet();
79          assertion.assertEquals(dataSet.getTable("TEST_TABLE"),
80                  dataSet.getTable("TEST_TABLE_WITH_SAME_VALUE"),
81                  new Column[] {new Column("COLUMN0", DataType.VARCHAR)});
82      }
83  
84      @Test
85      void testAssertTablesEmtpyEquals_withTwoEmptyDataSets_assertsSuccessfully() throws Exception
86      {
87          final IDataSet empty1 = new XmlDataSet(
88                  TestUtils.getFileReader("xml/assertionTest-empty1.xml"));
89          final IDataSet empty2 = new FlatXmlDataSetBuilder()
90                  .build(TestUtils.getFileReader("xml/assertionTest-empty2.xml"));
91          assertion.assertEquals(empty1, empty2);
92      }
93  
94      @Test
95      void testAssertTablesEqualsColumnNamesCaseInsensitive_withDifferentCaseColumnNames_assertsSuccessfully() throws Exception
96      {
97          final IDataSet dataSet = getDataSet();
98          assertion.assertEquals(dataSet.getTable("TEST_TABLE"),
99                  dataSet.getTable("TEST_TABLE_WITH_LOWER_COLUMN_NAMES"));
100     }
101 
102     @Test
103     void testAssertTablesAndNamesNotEquals_withDifferentTableNames_assertsSuccessfully() throws Exception
104     {
105         final IDataSet dataSet = getDataSet();
106         assertion.assertEquals(dataSet.getTable("TEST_TABLE"),
107                 dataSet.getTable("TEST_TABLE_WITH_DIFFERENT_NAME"));
108     }
109 
110     @Test
111     void testAssertTablesAndColumnCountNotEquals_withDifferentColumnCount_throwsDbComparisonFailure() throws Exception
112     {
113         final IDataSet dataSet = getDataSet();
114         final ITable testTable = dataSet.getTable("TEST_TABLE");
115         final ITable testTable3 = dataSet.getTable("TEST_TABLE_WITH_3_COLUMNS");
116         final String expectedMsg =
117                 "column count (table=TEST_TABLE, expectedColCount=4, actualColCount=3) expected:<[COLUMN0, COLUMN1, COLUMN2, COLUMN3]> but was:<[COLUMN0, COLUMN1, COLUMN2]>";
118         assertThatThrownBy(() -> assertion.assertEquals(testTable, testTable3))
119                 .as("Should throw an DbComparisonFailure")
120                 .isInstanceOf(DbComparisonFailure.class)
121                 .hasMessageContaining(expectedMsg)
122                 .extracting("expected", "actual").asString()
123                 .contains("[COLUMN0, COLUMN1, COLUMN2, COLUMN3]",
124                         "[COLUMN0, COLUMN1, COLUMN2]");
125     }
126 
127     @Test
128     void testAssertTablesAndColumnSequenceNotEquals_withDifferentColumnOrder_assertsSuccessfully() throws Exception
129     {
130         final IDataSet dataSet = getDataSet();
131 
132         assertion.assertEquals(dataSet.getTable("TEST_TABLE"),
133                 dataSet.getTable("TEST_TABLE_WITH_DIFFERENT_COLUMN_SEQUENCE"));
134     }
135 
136     @Test
137     void testAssertTablesAndColumnNamesNotEquals_withDifferentColumnNames_throwsDbComparisonFailure() throws Exception
138     {
139         final IDataSet dataSet = getDataSet();
140         final ITable testTable = dataSet.getTable("TEST_TABLE");
141         final ITable testTable2 =
142                 dataSet.getTable("TEST_TABLE_WITH_DIFFERENT_COLUMN_NAMES");
143         final String expectedMsg =
144                 "column mismatch (table=TEST_TABLE) expected:<[COLUMN0, COLUMN1, COLUMN2, COLUMN3]> but was:<[COLUMN4, COLUMN5, COLUMN6, COLUMN7]>";
145         assertThatThrownBy(() -> assertion.assertEquals(testTable, testTable2))
146                 .as("Should throw an DbComparisonFailure")
147                 .isInstanceOf(DbComparisonFailure.class)
148                 .hasMessageContaining(expectedMsg)
149                 .extracting("expected", "actual").asString()
150                 .contains("[COLUMN0, COLUMN1, COLUMN2, COLUMN3]",
151                         "[COLUMN4, COLUMN5, COLUMN6, COLUMN7]");
152 
153     }
154 
155     @Test
156     void testAssertTablesAndRowCountNotEquals_withDifferentRowCount_throwsDbComparisonFailure() throws Exception
157     {
158         final IDataSet dataSet = getDataSet();
159         final ITable testTable = dataSet.getTable("TEST_TABLE");
160         final ITable testTable2 = dataSet.getTable("TEST_TABLE_WITH_ONE_ROW");
161         final String expectedMsg =
162                 "row count (table=TEST_TABLE) expected:<2> but was:<1>";
163         assertThatThrownBy(() -> assertion.assertEquals(testTable, testTable2))
164                 .as("Should throw an DbComparisonFailure")
165                 .isInstanceOf(DbComparisonFailure.class)
166                 .hasMessageContaining(expectedMsg)
167                 .extracting("expected", "actual").asString().contains("2", "1");
168 
169     }
170 
171     @Test
172     void testAssertTablesAndValuesNotEquals_withWrongValue_throwsDbComparisonFailure() throws Exception
173     {
174         final IDataSet dataSet = getDataSet();
175 
176         final ITable testTable = dataSet.getTable("TEST_TABLE");
177         final ITable testTable2 =
178                 dataSet.getTable("TEST_TABLE_WITH_WRONG_VALUE");
179         final String expectedMsg =
180                 "value (table=TEST_TABLE, row=1, col=COLUMN2) expected:<row 1 col 2> but was:<wrong value>";
181         assertThatThrownBy(() -> assertion.assertEquals(testTable, testTable2))
182                 .as("Should throw an DbComparisonFailure")
183                 .isInstanceOf(DbComparisonFailure.class)
184                 .hasMessageContaining(expectedMsg)
185                 .extracting("expected", "actual").asString()
186                 .contains("row 1 col 2", "wrong value");
187 
188     }
189 
190     @Test
191     void testAssertTablesWithColFilter_withWrongValueColumnExcluded_assertsSuccessfully()
192             throws Exception
193     {
194         final IDataSet dataSet = getDataSet();
195 
196         // Column2 has the wrong value, so exclude -> test should run
197         // successfully
198         final String[] allColumnsThatAreNotEqual = new String[] {"COLUMN2"};
199         assertion.assertEqualsIgnoreCols(dataSet.getTable("TEST_TABLE"),
200                 dataSet.getTable("TEST_TABLE_WITH_WRONG_VALUE"),
201                 allColumnsThatAreNotEqual);
202     }
203 
204     @Test
205     void testAssertTablesWithColFilter_withWrongValueColumnNotExcluded_throwsDbComparisonFailure()
206             throws Exception
207     {
208         final IDataSet dataSet = getDataSet();
209 
210         // Column0 has correct value. Column2 has the wrong value but is not
211         // filtered.
212         // -> test should fail
213         final String[] filteredColumns = new String[] {"COLUMN0"};
214         final ITable testTable = dataSet.getTable("TEST_TABLE");
215         final ITable testTable3 =
216                 dataSet.getTable("TEST_TABLE_WITH_WRONG_VALUE");
217         final String expectedMsg =
218                 "value (table=TEST_TABLE, row=1, col=COLUMN2) expected:<row 1 col 2> but was:<wrong value>";
219         assertThatThrownBy(() -> assertion.assertEqualsIgnoreCols(testTable,
220                 testTable3, filteredColumns))
221                         .as("Should throw an DbComparisonFailure")
222                         .isInstanceOf(DbComparisonFailure.class)
223                         .hasMessageContaining(expectedMsg)
224                         .extracting("expected", "actual").asString()
225                         .contains("row 1 col 2", "wrong value");
226 
227     }
228 
229     @Test
230     void testAssertTablesAndValuesNotEquals_AdditionalColumnInfo()
231             throws Exception
232     {
233         final IDataSet dataSet = getDataSet();
234 
235         final ITable testTable = dataSet.getTable("TEST_TABLE");
236         final ITable testTable3 =
237                 dataSet.getTable("TEST_TABLE_WITH_WRONG_VALUE");
238         final Column[] additionalColInfo =
239                 new Column[] {new Column("COLUMN0", DataType.VARCHAR)};
240         final String expectedMsg =
241                 "org.dbunit.assertion.DbComparisonFailure[value (table=TEST_TABLE, row=1, col=COLUMN2, "
242                         + "Additional row info: ('COLUMN0': expected=<row 1 col 0>, actual=<row 1 col 0>))"
243                         + "expected:<row 1 col 2> but was:<wrong value>]";
244         assertThatThrownBy(() -> assertion.assertEquals(testTable, testTable3,
245                 additionalColInfo)).as("Should throw an DbComparisonFailure")
246                         .isInstanceOf(DbComparisonFailure.class)
247                         .hasToString(expectedMsg)
248                         .extracting("expected", "actual").asString()
249                         .contains("row 1 col 2", "wrong value");
250 
251     }
252 
253     @Test
254     void testAssertTablesEqualsAndIncompatibleDataType_withBooleanVsVarchar_throwsDbComparisonFailure() throws Exception
255     {
256         final String tableName = "TABLE_NAME";
257 
258         // Setup actual table
259         final Column[] actualColumns =
260                 new Column[] {new Column("BOOLEAN", DataType.BOOLEAN),};
261         final Object[] actualRow = new Object[] {Boolean.TRUE,};
262         final DefaultTable actualTable =
263                 new DefaultTable(tableName, actualColumns);
264         actualTable.addRow(actualRow);
265 
266         // Setup expected table
267         final Column[] expectedColumns =
268                 new Column[] {new Column("BOOLEAN", DataType.VARCHAR),};
269         final Object[] expectedRow = new Object[] {"1",};
270         final DefaultTable expectedTable =
271                 new DefaultTable(tableName, expectedColumns);
272         expectedTable.addRow(expectedRow);
273         final String expectedMsg =
274                 "Incompatible data types: (table=TABLE_NAME, col=BOOLEAN) expected:<VARCHAR> but was:<BOOLEAN>";
275         assertThatThrownBy(
276                 () -> assertion.assertEquals(expectedTable, actualTable))
277                         .isInstanceOf(DbComparisonFailure.class)
278                         .hasMessageContaining(expectedMsg)
279                         .extracting("expected", "actual").asString()
280                         .contains("VARCHAR", "BOOLEAN");
281 
282     }
283 
284     @Test
285     void testAssertTablesByQueryWithColFilter_withWrongValueColumnExcluded_assertsSuccessfully()
286             throws Exception
287     {
288         final DatabaseEnvironment env = DatabaseEnvironment.getInstance();
289         final IDatabaseConnection connection = env.getConnection();
290 
291         final IDataSet dataSet = env.getInitDataSet();
292         final ITable expectedTable = dataSet.getTable("TEST_TABLE");
293 
294         final ITable table = dataSet.getTable("TEST_TABLE");
295         final ITable filteredTable = new ModifyingTable(table, "COLUMN2");
296         DatabaseOperation.CLEAN_INSERT.execute(connection,
297                 new DefaultDataSet(filteredTable));
298 
299         // Ignore COLUMN2 which has been modified by the "ModifyingTable" above
300         // and
301         // hence does not match.
302         // When we ignore this column, the assertion should work without failure
303         final String[] ignoreCols = new String[] {"COLUMN2"};
304         assertion.assertEqualsByQuery(expectedTable, connection, "TEST_TABLE",
305                 "select * from TEST_TABLE order by 1", ignoreCols);
306     }
307 
308     @Test
309     void testAssertTablesByQueryWithColFilter_withWrongValueColumnNotExcluded_throwsDbComparisonFailure()
310             throws Exception
311     {
312         final DatabaseEnvironment env = DatabaseEnvironment.getInstance();
313         final IDatabaseConnection connection = env.getConnection();
314 
315         final IDataSet dataSet = env.getInitDataSet();
316         final ITable expectedTable = dataSet.getTable("TEST_TABLE");
317 
318         final ITable table = dataSet.getTable("TEST_TABLE");
319         final ITable filteredTable = new ModifyingTable(table, "COLUMN2");
320         DatabaseOperation.CLEAN_INSERT.execute(connection,
321                 new DefaultDataSet(filteredTable));
322 
323         // Ignore COLUMN1 which has NOT been modified by the "ModifyingTable".
324         // The
325         // modified COLUMN2 does
326         // not match and is not ignored. So the assertion should fail.
327         final String[] ignoreCols = new String[] {"COLUMN1"};
328         final String expectedMsg =
329                 "value (table=TEST_TABLE, row=0, col=COLUMN2) expected:<row 0 col 2> but was:<row 0 col 2 (modified COLUMN2)>";
330         assertThatThrownBy(() -> assertion.assertEqualsByQuery(expectedTable,
331                 connection, "TEST_TABLE", "select * from TEST_TABLE order by 1",
332                 ignoreCols)).as("The assertion should not work")
333                         .isInstanceOf(DbComparisonFailure.class)
334                         .hasMessageContaining(expectedMsg)
335                         .extracting("expected", "actual").asString()
336                         .contains("row 0 col 2",
337                                 "row 0 col 2 (modified COLUMN2)");
338 
339     }
340 
341     @Test
342     void testAssertTablesEqualsAndCompatibleDataType_withUnknownVsCompatibleTypes_assertsSuccessfully() throws Exception
343     {
344         final String tableName = "TABLE_NAME";
345         final java.sql.Timestamp now =
346                 new java.sql.Timestamp(System.currentTimeMillis());
347 
348         // Setup actual table
349         final Column[] actualColumns =
350                 new Column[] {new Column("BOOLEAN", DataType.BOOLEAN),
351                         new Column("TIMESTAMP", DataType.TIMESTAMP),
352                         new Column("STRING", DataType.CHAR),
353                         new Column("NUMERIC", DataType.NUMERIC),};
354         final Object[] actualRow =
355                 new Object[] {Boolean.TRUE, now, "0", new BigDecimal("123.4"),};
356         final DefaultTable actualTable =
357                 new DefaultTable(tableName, actualColumns);
358         actualTable.addRow(actualRow);
359 
360         // Setup expected table
361         final Column[] expectedColumns =
362                 new Column[] {new Column("BOOLEAN", DataType.UNKNOWN),
363                         new Column("TIMESTAMP", DataType.UNKNOWN),
364                         new Column("STRING", DataType.UNKNOWN),
365                         new Column("NUMERIC", DataType.UNKNOWN),};
366         final Object[] expectedRow = new Object[] {"1",
367                 Long.valueOf(now.getTime()), Integer.valueOf("0"), "123.4000",};
368         final DefaultTable expectedTable =
369                 new DefaultTable(tableName, expectedColumns);
370         expectedTable.addRow(expectedRow);
371 
372         assertion.assertEquals(expectedTable, actualTable);
373     }
374 
375     @Test
376     void testAssertDataSetsEquals_withReorderedTableNames_assertsSuccessfully() throws Exception
377     {
378         final IDataSet dataSet1 = getDataSet();
379 
380         // change table names order
381         final String[] names = DataSetUtils.getReverseTableNames(dataSet1);
382         final IDataSet dataSet2 = new FilteredDataSet(names, dataSet1);
383 
384         assertThat(dataSet2).as("Datasets are the same instances.")
385                 .isNotSameAs(dataSet1);
386         assertion.assertEquals(dataSet1, dataSet2);
387     }
388 
389     @Test
390     void testAssertDataSetsEqualsTableNamesCaseInsensitive_withLowerCaseTableNames_assertsSuccessfully() throws Exception
391     {
392         final IDataSet dataSet1 = getDataSet();
393 
394         // change table names case
395         final String[] names = dataSet1.getTableNames();
396         for (int i = 0; i < names.length; i++)
397         {
398             names[i] = names[i].toLowerCase();
399         }
400         final IDataSet dataSet2 = new FilteredDataSet(names, dataSet1);
401 
402         assertThat(dataSet2).as("Datasets are the same instances.")
403                 .isNotSameAs(dataSet1);
404         assertion.assertEquals(dataSet1, dataSet2);
405     }
406 
407     @Test
408     void testAssertDataSetsTableNamesCaseSensitiveNotEquals_withCaseSensitiveDifferentCaseNames_throwsDbComparisonFailure() throws Exception
409     {
410         final IDataSet dataSet1 = new FlatXmlDataSetBuilder()
411                 .setCaseSensitiveTableNames(true).build(TestUtils.getFileReader(
412                         "xml/assertion_table_name_case_sensitive_1.xml"));
413         final IDataSet dataSet2 = new FlatXmlDataSetBuilder()
414                 .setCaseSensitiveTableNames(true).build(TestUtils.getFileReader(
415                         "xml/assertion_table_name_case_sensitive_2.xml"));
416         final DbComparisonFailure expected2 = catchThrowableOfType(
417                 () -> assertion.assertEquals(dataSet1, dataSet2),
418                 DbComparisonFailure.class);
419         assertThat(expected2.getExpected())
420                 .as("[TEST_TABLE_WITH_CASE_SENSITIVE_NAME]").toString()
421                 .contains("Expected table name did not match.");
422         assertThat(expected2.getActual()).as("Actual table name did not match.")
423                 .toString().contains("[test_table_with_case_sensitive_name]");
424 
425     }
426 
427     @Test
428     void testAssertDataSetsTableNamesCaseSensitiveWithLowerCaseEquals_withCaseSensitiveSameNames_assertsSuccessfully()
429             throws Exception
430     {
431         final IDataSet dataSet1 = new FlatXmlDataSetBuilder()
432                 .setCaseSensitiveTableNames(true).build(TestUtils.getFileReader(
433                         "xml/assertion_table_name_case_sensitive_with_lower_case.xml"));
434         final IDataSet dataSet2 = new FlatXmlDataSetBuilder()
435                 .setCaseSensitiveTableNames(true).build(TestUtils.getFileReader(
436                         "xml/assertion_table_name_case_sensitive_with_lower_case.xml"));
437         assertThat(dataSet2).as("Datasets are the same instances.")
438                 .isNotSameAs(dataSet1);
439         assertion.assertEquals(dataSet1, dataSet2);
440     }
441 
442     @Test
443     void testAssertDataSetsAndTableCountNotEquals_withFewerTablesInActual_throwsDbComparisonFailure() throws Exception
444     {
445         final IDataSet dataSet1 = getDataSet();
446 
447         // only one table
448         final String[] names = new String[] {dataSet1.getTableNames()[0]};
449         final IDataSet dataSet2 = new FilteredDataSet(names, dataSet1);
450 
451         assertThat(dataSet2).as("Datasets are the same instances.")
452                 .isNotSameAs(dataSet1);
453 
454         assertThatThrownBy(() -> assertion.assertEquals(dataSet1, dataSet2))
455                 .as("Should throw an DbComparisonFailure")
456                 .isInstanceOf(DbComparisonFailure.class)
457                 .hasMessageContaining("table count expected:<10> but was:<1>")
458                 .extracting("expected", "actual").asString()
459                 .contains("10", "1");
460 
461     }
462 
463     @Test
464     void testAssertDataSetsAndTableNamesNotEquals_withReversedTableNames_throwsDbComparisonFailure() throws Exception
465     {
466         final IDataSet dataSet1 = getDataSet();
467 
468         // reverse table names
469         final String[] names = dataSet1.getTableNames();
470         final ITable[] tables = new ITable[names.length];
471         for (int i = 0; i < names.length; i++)
472         {
473             final String reversedName =
474                     new StringBuilder(names[i]).reverse().toString();
475             tables[i] = new CompositeTable(reversedName,
476                     dataSet1.getTable(names[i]));
477         }
478         final IDataSet dataSet2 = new DefaultDataSet(tables);
479 
480         assertThat(dataSet2).as("Datasets are the same instances.")
481                 .isNotSameAs(dataSet1);
482         assertThat(dataSet2.getTableNames()).as("table count")
483                 .hasSameSizeAs(dataSet1.getTableNames());
484 
485         assertThatThrownBy(() -> assertion.assertEquals(dataSet1, dataSet2))
486                 .as("Should throw an DbComparisonFailure")
487                 .isInstanceOf(DbComparisonFailure.class);
488     }
489 
490     @Test
491     void testAssertDataSetsAndTablesNotEquals_withDoubledRowCounts_throwsDbComparisonFailure() throws Exception
492     {
493         final IDataSet dataSet1 = getDataSet();
494 
495         // different row counts (double)
496         final IDataSet dataSet2 = new CompositeDataSet(dataSet1, dataSet1);
497 
498         assertThat(dataSet2).as("Datasets are the same instances.")
499                 .isNotSameAs(dataSet1);
500         assertThat(dataSet2.getTableNames()).as("table count")
501                 .hasSameSizeAs(dataSet1.getTableNames());
502 
503         assertThatThrownBy(() -> assertion.assertEquals(dataSet1, dataSet2))
504                 .as("Should throw an DbComparisonFailure")
505                 .isInstanceOf(DbComparisonFailure.class)
506                 .hasMessageContaining(
507                         "row count (table=TEST_TABLE) expected:<2> but was:<4>")
508                 .extracting("expected", "actual").asString().contains("2", "4");
509 
510     }
511 
512     @Test
513     void testAssertDataSetsWithFailureHandler_withMismatchedValues_collectsTwoDifferences() throws Exception
514     {
515         final DiffCollectingFailureHandler fh =
516                 new DiffCollectingFailureHandler();
517 
518         final String xml1 = "<dataset>\n"
519                 + "<TEST_TABLE COLUMN0='row 0 col 0' COLUMN1='row 0 col 1'/>\n"
520                 + "</dataset>\n";
521         final IDataSet dataSet1 =
522                 new FlatXmlDataSetBuilder().build(new StringReader(xml1));
523         final String xml2 = "<dataset>\n"
524                 + "<TEST_TABLE COLUMN0='row 0 col somthing' COLUMN1='row 0 col something mysterious'/>\n"
525                 + "</dataset>\n";
526         final IDataSet dataSet2 =
527                 new FlatXmlDataSetBuilder().build(new StringReader(xml2));
528 
529         // Invoke the assertion
530         assertion.assertEquals(dataSet1, dataSet2, fh);
531         // We expect that no failure was thrown even if the dataSets were not
532         // equal.
533         // This is because our custom failureHandler
534         assertThat(fh.getDiffList()).hasSize(2);
535     }
536 
537     @Test
538     void testGetComparisonDataType_ExpectedTypeUnknown()
539     {
540         final Column expectedColumn = new Column("COL1", DataType.UNKNOWN);
541         final Column actualColumn = new Column("COL1", DataType.VARCHAR);
542         final DataType dataType = new DbUnitAssert.ComparisonColumn(
543                 "BLABLA_TABLE_NOT_NEEDED_HERE", expectedColumn, actualColumn,
544                 assertion.getDefaultFailureHandler()).getDataType();
545         assertThat(dataType).isEqualTo(DataType.VARCHAR);
546     }
547 
548     @Test
549     void testGetComparisonDataType_ActualTypeUnknown()
550     {
551         final Column expectedColumn = new Column("COL1", DataType.VARCHAR);
552         final Column actualColumn = new Column("COL1", DataType.UNKNOWN);
553         final DataType dataType = new DbUnitAssert.ComparisonColumn(
554                 "BLABLA_TABLE_NOT_NEEDED_HERE", expectedColumn, actualColumn,
555                 assertion.getDefaultFailureHandler()).getDataType();
556         assertThat(dataType).isEqualTo(DataType.VARCHAR);
557     }
558 
559     @Test
560     void testGetComparisonDataType_BothTypesSetIncompatible()
561     {
562         final Column expectedColumn = new Column("COL1", DataType.VARCHAR);
563         final Column actualColumn = new Column("COL1", DataType.NUMERIC);
564         final String expectedMsg =
565                 "Incompatible data types: (table=BLABLA_TABLE_NOT_NEEDED_HERE, col=COL1) expected:<VARCHAR> but was:<NUMERIC>";
566         final FailureHandler failureHandler =
567                 assertion.getDefaultFailureHandler();
568         assertThatThrownBy(() -> new DbUnitAssert.ComparisonColumn(
569                 "BLABLA_TABLE_NOT_NEEDED_HERE", expectedColumn, actualColumn,
570                 failureHandler)).as("Incompatible datatypes should not work")
571                         .isInstanceOf(DbComparisonFailure.class)
572                         .hasMessageContaining(expectedMsg)
573                         .extracting("expected", "actual").asString()
574                         .contains("VARCHAR", "NUMERIC");
575     }
576 
577     @Test
578     void testGetComparisonDataType_BothTypesSetToSame()
579     {
580         final Column expectedColumn = new Column("COL1", DataType.VARCHAR);
581         final Column actualColumn = new Column("COL1", DataType.VARCHAR);
582         final DataType dataType = new DbUnitAssert.ComparisonColumn(
583                 "BLABLA_TABLE_NOT_NEEDED_HERE", expectedColumn, actualColumn,
584                 assertion.getDefaultFailureHandler()).getDataType();
585         assertThat(dataType).isEqualTo(DataType.VARCHAR);
586     }
587 
588     @Test
589     void testGetComparisonDataType_BothTypesUnknown()
590     {
591         final Column expectedColumn = new Column("COL1", DataType.UNKNOWN);
592         final Column actualColumn = new Column("COL1", DataType.UNKNOWN);
593         final DataType dataType = new DbUnitAssert.ComparisonColumn(
594                 "BLABLA_TABLE_NOT_NEEDED_HERE", expectedColumn, actualColumn,
595                 assertion.getDefaultFailureHandler()).getDataType();
596         assertThat(dataType).isEqualTo(DataType.UNKNOWN);
597     }
598 
599     @Test
600     void testAssertEquals_withSortedTable_toleratesDbRowOrder() throws Exception
601     {
602         final DatabaseEnvironment env = DatabaseEnvironment.getInstance();
603         final IDatabaseConnection connection = env.getConnection();
604 
605         final Column[] columns = new Column[]{
606                 new Column("COLUMN0", DataType.VARCHAR),
607                 new Column("COLUMN1", DataType.VARCHAR),
608                 new Column("COLUMN2", DataType.VARCHAR),
609                 new Column("COLUMN3", DataType.VARCHAR)
610         };
611         final DefaultTable insertTable = new DefaultTable("TEST_TABLE", columns);
612         insertTable.addRow(new Object[]{"gamma", "3", "3", "3"});
613         insertTable.addRow(new Object[]{"alpha", "1", "1", "1"});
614         insertTable.addRow(new Object[]{"beta", "2", "2", "2"});
615         DatabaseOperation.CLEAN_INSERT.execute(connection,
616                 new DefaultDataSet(insertTable));
617 
618         final DefaultTable expectedTable = new DefaultTable("TEST_TABLE", columns);
619         expectedTable.addRow(new Object[]{"alpha", "1", "1", "1"});
620         expectedTable.addRow(new Object[]{"beta", "2", "2", "2"});
621         expectedTable.addRow(new Object[]{"gamma", "3", "3", "3"});
622 
623         final ITable actualDbTable =
624                 connection.createDataSet().getTable("TEST_TABLE");
625         final SortedTable sortedExpected =
626                 new SortedTable(expectedTable, new String[]{"COLUMN0"});
627         final SortedTable sortedActual =
628                 new SortedTable(actualDbTable, new String[]{"COLUMN0"});
629 
630         assertion.assertEquals(sortedExpected, sortedActual);
631     }
632 
633     @Test
634     void testAssertWithValueComparer_greaterThanColumn_passesWhenActualLarger() throws Exception
635     {
636         final Column[] columns = new Column[]{new Column("AMOUNT", DataType.INTEGER)};
637 
638         final DefaultTable expected = new DefaultTable("T", columns);
639         expected.addRow(new Object[]{100});
640 
641         final DefaultTable actual = new DefaultTable("T", columns);
642         actual.addRow(new Object[]{200});
643 
644         new DbUnitValueComparerAssert().assertWithValueComparer(expected, actual,
645                 ValueComparers.isActualGreaterThanExpected);
646     }
647 
648     @Test
649     void testAssertWithValueComparer_globalDefaultAndPerColumnOverride_correctComparerUsed()
650             throws Exception
651     {
652         final Column[] columns = new Column[]{
653                 new Column("ID", DataType.INTEGER),
654                 new Column("SCORE", DataType.INTEGER)
655         };
656 
657         final DefaultTable expected = new DefaultTable("T", columns);
658         expected.addRow(new Object[]{1, 50});
659 
660         final DefaultTable actual = new DefaultTable("T", columns);
661         actual.addRow(new Object[]{1, 99});
662 
663         final Map<String, ValueComparer> columnComparers =
664                 new ColumnValueComparerMapBuilder()
665                         .add("SCORE", ValueComparers.isActualGreaterThanExpected)
666                         .build();
667 
668         new DbUnitValueComparerAssert().assertWithValueComparer(expected, actual,
669                 ValueComparers.isActualEqualToExpected, columnComparers);
670     }
671 
672     /**
673      * Test utility that modifies all values for a specific column arbitrarily
674      */
675     protected static class ModifyingTable implements ITable
676     {
677         private ITable _wrappedTable;
678         private String _columnToModify;
679 
680         public ModifyingTable(final ITable originalTable,
681                 final String columnToModify)
682         {
683             this._wrappedTable = originalTable;
684             this._columnToModify = columnToModify;
685         }
686 
687         @Override
688         public int getRowCount()
689         {
690             return this._wrappedTable.getRowCount();
691         }
692 
693         @Override
694         public ITableMetaData getTableMetaData()
695         {
696             return this._wrappedTable.getTableMetaData();
697         }
698 
699         @Override
700         public Object getValue(final int row, final String column)
701                 throws DataSetException
702         {
703             final Object originalValue = _wrappedTable.getValue(row, column);
704 
705             // Modify the value if column name matches
706             if (column.equalsIgnoreCase(this._columnToModify))
707             {
708                 return String.valueOf(originalValue) + " (modified "
709                         + _columnToModify + ")";
710             }
711             return originalValue;
712         }
713 
714     }
715 
716 }