1 package org.dbunit.assertion;
2
3 import java.util.Arrays;
4 import java.util.Map;
5
6 import org.dbunit.DatabaseUnitException;
7 import org.dbunit.assertion.DbUnitAssert.ComparisonColumn;
8 import org.dbunit.assertion.comparer.value.DefaultValueComparerDefaults;
9 import org.dbunit.assertion.comparer.value.ValueComparer;
10 import org.dbunit.assertion.comparer.value.ValueComparerDefaults;
11 import org.dbunit.dataset.Column;
12 import org.dbunit.dataset.Columns;
13 import org.dbunit.dataset.DataSetException;
14 import org.dbunit.dataset.IDataSet;
15 import org.dbunit.dataset.ITable;
16 import org.dbunit.dataset.ITableMetaData;
17 import org.dbunit.dataset.datatype.DataType;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21
22
23
24
25
26
27 public class DbUnitAssertBase
28 {
29 private final Logger log = LoggerFactory.getLogger(DbUnitAssertBase.class);
30
31 private FailureFactory junitFailureFactory = getJUnitFailureFactory();
32
33 protected ValueComparerDefaults valueComparerDefaults =
34 new DefaultValueComparerDefaults();
35
36
37
38
39
40 protected FailureHandler getDefaultFailureHandler()
41 {
42 return getDefaultFailureHandler(null);
43 }
44
45
46
47
48
49 protected FailureHandler getDefaultFailureHandler(
50 final Column[] additionalColumnInfo)
51 {
52 final DefaultFailureHandler failureHandler =
53 new DefaultFailureHandler(additionalColumnInfo);
54 if (junitFailureFactory != null)
55 {
56 failureHandler.setFailureFactory(junitFailureFactory);
57 }
58 return failureHandler;
59 }
60
61
62
63
64
65 private FailureFactory getJUnitFailureFactory()
66 {
67 try
68 {
69 Class.forName("junit.framework.Assert");
70
71 return new JUnitFailureFactory();
72 } catch (final ClassNotFoundException e)
73 {
74
75 log.debug("JUnit does not seem to be on the classpath. " + e);
76 }
77 return null;
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91 protected ComparisonColumn[] getComparisonColumns(
92 final String expectedTableName, final Column[] expectedColumns,
93 final Column[] actualColumns, final FailureHandler failureHandler)
94 {
95 final ComparisonColumn[] result =
96 new ComparisonColumn[expectedColumns.length];
97
98 for (int j = 0; j < expectedColumns.length; j++)
99 {
100 final Column expectedColumn = expectedColumns[j];
101 final Column actualColumn = actualColumns[j];
102 result[j] = new ComparisonColumn(expectedTableName, expectedColumn,
103 actualColumn, failureHandler);
104 }
105 return result;
106 }
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 protected boolean skipCompare(final String columnName,
123 final Object expectedValue, final Object actualValue)
124 {
125 return false;
126 }
127
128 protected FailureHandler determineFailureHandler(
129 final FailureHandler failureHandler)
130 {
131 final FailureHandler validFailureHandler;
132
133 if (failureHandler == null)
134 {
135 log.debug("FailureHandler is null. Using default implementation");
136 validFailureHandler = getDefaultFailureHandler();
137 } else
138 {
139 validFailureHandler = failureHandler;
140 }
141
142 return validFailureHandler;
143 }
144
145 protected boolean compareRowCounts(final ITable expectedTable,
146 final ITable actualTable, final FailureHandler failureHandler,
147 final String expectedTableName) throws Error
148 {
149 boolean isTablesEmpty;
150
151 final int expectedRowsCount = expectedTable.getRowCount();
152 int actualRowsCount = 0;
153 boolean skipRowComparison = false;
154 try
155 {
156 actualRowsCount = actualTable.getRowCount();
157 } catch (final UnsupportedOperationException exception)
158 {
159 skipRowComparison = true;
160 }
161
162 if (skipRowComparison)
163 {
164 isTablesEmpty = false;
165 } else
166 {
167 if (expectedRowsCount != actualRowsCount)
168 {
169 final String msg =
170 "row count (table=" + expectedTableName + ")";
171 final Error error = failureHandler.createFailure(msg,
172 String.valueOf(expectedRowsCount),
173 String.valueOf(actualRowsCount));
174 log.error(error.toString());
175 throw error;
176 }
177
178
179
180
181 if (expectedRowsCount == 0 && actualRowsCount == 0)
182 {
183 log.debug("Tables are empty, hence equals.");
184 isTablesEmpty = true;
185 } else
186 {
187 isTablesEmpty = false;
188 }
189 }
190
191 return isTablesEmpty;
192 }
193
194 protected void compareColumns(final Column[] expectedColumns,
195 final Column[] actualColumns, final ITableMetaData expectedMetaData,
196 final ITableMetaData actualMetaData,
197 final FailureHandler failureHandler) throws DataSetException, Error
198 {
199 final Columns.ColumnDiff columnDiff =
200 Columns.getColumnDiff(expectedMetaData, actualMetaData);
201 if (columnDiff.hasDifference())
202 {
203 final String message = columnDiff.getMessage();
204 final Error error = failureHandler.createFailure(message,
205 Columns.getColumnNamesAsString(expectedColumns),
206 Columns.getColumnNamesAsString(actualColumns));
207 log.error(error.toString());
208 throw error;
209 }
210 }
211
212 protected void compareTableCounts(final String[] expectedNames,
213 final String[] actualNames, final FailureHandler failureHandler)
214 throws Error
215 {
216 if (expectedNames.length != actualNames.length)
217 {
218 throw failureHandler.createFailure("table count",
219 String.valueOf(expectedNames.length),
220 String.valueOf(actualNames.length));
221 }
222 }
223
224 protected void compareTableNames(final String[] expectedNames,
225 final String[] actualNames, final FailureHandler failureHandler)
226 throws Error
227 {
228 for (int i = 0; i < expectedNames.length; i++)
229 {
230 if (!actualNames[i].equals(expectedNames[i]))
231 {
232 throw failureHandler.createFailure("tables",
233 Arrays.asList(expectedNames).toString(),
234 Arrays.asList(actualNames).toString());
235 }
236 }
237 }
238
239 protected String[] getSortedTableNames(final IDataSet dataSet)
240 throws DataSetException
241 {
242 log.debug("getSortedTableNames(dataSet={}) - start", dataSet);
243
244 final String[] names = dataSet.getTableNames();
245 if (!dataSet.isCaseSensitiveTableNames())
246 {
247 for (int i = 0; i < names.length; i++)
248 {
249 names[i] = names[i].toUpperCase();
250 }
251 }
252 Arrays.sort(names);
253 return names;
254 }
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 public void assertWithValueComparer(final IDataSet expectedDataSet,
290 final IDataSet actualDataSet, final FailureHandler failureHandler,
291 final ValueComparer defaultValueComparer,
292 final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
293 throws DatabaseUnitException
294 {
295 log.debug(
296 "assertWithValueComparer(expectedDataSet={}, actualDataSet={},"
297 + " failureHandler={}, defaultValueComparer={},"
298 + " tableColumnValueComparers={}) - start",
299 expectedDataSet, actualDataSet, failureHandler,
300 defaultValueComparer, tableColumnValueComparers);
301
302
303 if (expectedDataSet == actualDataSet)
304 {
305 log.debug("The given datasets reference the same object."
306 + " Skipping comparisons.");
307 return;
308 }
309
310 final FailureHandler validFailureHandler =
311 determineFailureHandler(failureHandler);
312
313 final String[] expectedNames = getSortedTableNames(expectedDataSet);
314 final String[] actualNames = getSortedTableNames(actualDataSet);
315
316 compareTableCounts(expectedNames, actualNames, validFailureHandler);
317
318
319 compareTableNames(expectedNames, actualNames, validFailureHandler);
320
321 compareTables(expectedDataSet, actualDataSet, expectedNames,
322 validFailureHandler, defaultValueComparer,
323 tableColumnValueComparers);
324 }
325
326 protected void compareTables(final IDataSet expectedDataSet,
327 final IDataSet actualDataSet, final String[] expectedNames,
328 final FailureHandler failureHandler,
329 final ValueComparer defaultValueComparer,
330 final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
331 throws DatabaseUnitException
332 {
333 final Map<String, Map<String, ValueComparer>> validTableColumnValueComparers =
334 determineValidTableColumnValueComparers(
335 tableColumnValueComparers);
336
337 for (int i = 0; i < expectedNames.length; i++)
338 {
339 final String tableName = expectedNames[i];
340
341 final ITable expectedTable = expectedDataSet.getTable(tableName);
342 final ITable actualTable = actualDataSet.getTable(tableName);
343 final Map<String, ValueComparer> columnValueComparers =
344 validTableColumnValueComparers.get(tableName);
345
346 assertWithValueComparer(expectedTable, actualTable, failureHandler,
347 defaultValueComparer, columnValueComparers);
348 }
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 public void assertWithValueComparer(final ITable expectedTable,
385 final ITable actualTable, final FailureHandler failureHandler,
386 final ValueComparer defaultValueComparer,
387 final Map<String, ValueComparer> columnValueComparers)
388 throws DatabaseUnitException
389 {
390 log.trace("assertWithValueComparer(expectedTable, actualTable,"
391 + " failureHandler, defaultValueComparer,"
392 + " columnValueComparers) - start");
393 log.debug("assertWithValueComparer: expectedTable={}", expectedTable);
394 log.debug("assertWithValueComparer: actualTable={}", actualTable);
395 log.debug("assertWithValueComparer: failureHandler={}", failureHandler);
396 log.debug("assertWithValueComparer: defaultValueComparer={}",
397 defaultValueComparer);
398 log.debug("assertWithValueComparer: columnValueComparers={}",
399 columnValueComparers);
400
401
402 if (expectedTable == actualTable)
403 {
404 log.debug("The given tables reference the same object."
405 + " Skipping comparisons.");
406 return;
407 }
408
409 final FailureHandler validFailureHandler =
410 determineFailureHandler(failureHandler);
411
412 final ITableMetaData expectedMetaData =
413 expectedTable.getTableMetaData();
414 final ITableMetaData actualMetaData = actualTable.getTableMetaData();
415 final String expectedTableName = expectedMetaData.getTableName();
416
417 final boolean isTablesEmpty = compareRowCounts(expectedTable,
418 actualTable, validFailureHandler, expectedTableName);
419 if (isTablesEmpty)
420 {
421 return;
422 }
423
424
425 final Column[] expectedColumns =
426 Columns.getSortedColumns(expectedMetaData);
427 final Column[] actualColumns = Columns.getSortedColumns(actualMetaData);
428
429
430 compareColumns(expectedColumns, actualColumns, expectedMetaData,
431 actualMetaData, validFailureHandler);
432
433
434 final ComparisonColumn[] comparisonCols =
435 getComparisonColumns(expectedTableName, expectedColumns,
436 actualColumns, validFailureHandler);
437
438
439 compareData(expectedTable, actualTable, comparisonCols,
440 validFailureHandler, defaultValueComparer,
441 columnValueComparers);
442 }
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 protected void compareData(final ITable expectedTable,
462 final ITable actualTable, final ComparisonColumn[] comparisonCols,
463 final FailureHandler failureHandler) throws DataSetException
464 {
465 final ValueComparer defaultValueComparer = null;
466 final Map<String, ValueComparer> columnValueComparers = null;
467 try
468 {
469 compareData(expectedTable, actualTable, comparisonCols,
470 failureHandler, defaultValueComparer, columnValueComparers);
471 } catch (final DatabaseUnitException e)
472 {
473
474 throw new DataSetException(e);
475 }
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 protected void compareData(final ITable expectedTable,
511 final ITable actualTable, final ComparisonColumn[] comparisonCols,
512 final FailureHandler failureHandler,
513 final ValueComparer defaultValueComparer,
514 final Map<String, ValueComparer> columnValueComparers)
515 throws DatabaseUnitException
516 {
517 log.debug(
518 "compareData(expectedTable={}, actualTable={}, "
519 + "comparisonCols={}, failureHandler={},"
520 + " defaultValueComparer={}, columnValueComparers={})"
521 + " - start",
522 expectedTable, actualTable, comparisonCols, failureHandler,
523 defaultValueComparer, columnValueComparers);
524
525 if (expectedTable == null)
526 {
527 throw new IllegalArgumentException(
528 "The parameter 'expectedTable' is null");
529 }
530 if (actualTable == null)
531 {
532 throw new IllegalArgumentException(
533 "The parameter 'actualTable' is null");
534 }
535 if (comparisonCols == null)
536 {
537 throw new IllegalArgumentException(
538 "The parameter 'comparisonCols' is null");
539 }
540 if (failureHandler == null)
541 {
542 throw new IllegalArgumentException(
543 "The parameter 'failureHandler' is null");
544 }
545
546 final ValueComparer validDefaultValueComparer =
547 determineValidDefaultValueComparer(defaultValueComparer);
548 final String expectedTableName =
549 expectedTable.getTableMetaData().getTableName();
550 final Map<String, ValueComparer> validColumnValueComparers =
551 determineValidColumnValueComparers(columnValueComparers,
552 expectedTableName);
553
554
555 for (int rowNum = 0; rowNum < expectedTable.getRowCount(); rowNum++)
556 {
557
558 final int columnCount = comparisonCols.length;
559 for (int columnNum = 0; columnNum < columnCount; columnNum++)
560 {
561 compareData(expectedTable, actualTable, comparisonCols,
562 failureHandler, validDefaultValueComparer,
563 validColumnValueComparers, rowNum, columnNum);
564 }
565 }
566 }
567
568 protected void compareData(final ITable expectedTable,
569 final ITable actualTable, final ComparisonColumn[] comparisonCols,
570 final FailureHandler failureHandler,
571 final ValueComparer defaultValueComparer,
572 final Map<String, ValueComparer> columnValueComparers,
573 final int rowNum, final int columnNum) throws DatabaseUnitException
574 {
575 final ComparisonColumn compareColumn = comparisonCols[columnNum];
576
577 final String columnName = compareColumn.getColumnName();
578 final DataType dataType = compareColumn.getDataType();
579
580 final Object expectedValue = expectedTable.getValue(rowNum, columnName);
581 final Object actualValue = actualTable.getValue(rowNum, columnName);
582
583
584 if (skipCompare(columnName, expectedValue, actualValue))
585 {
586 log.trace(
587 "skipCompare: ignoring comparison" + " {}={} on column={}",
588 expectedValue, actualValue, columnName);
589 } else
590 {
591 final ValueComparer valueComparer = determineValueComparer(
592 columnName, defaultValueComparer, columnValueComparers);
593
594 log.debug(
595 "compareData: comparing actualValue={}"
596 + " to expectedValue={} with valueComparer={}",
597 actualValue, expectedValue, valueComparer);
598 final String failMessage =
599 valueComparer.compare(expectedTable, actualTable, rowNum,
600 columnName, dataType, expectedValue, actualValue);
601
602 failIfNecessary(expectedTable, actualTable, failureHandler, rowNum,
603 columnName, expectedValue, actualValue, failMessage);
604 }
605 }
606
607 protected void failIfNecessary(final ITable expectedTable,
608 final ITable actualTable, final FailureHandler failureHandler,
609 final int rowNum, final String columnName,
610 final Object expectedValue, final Object actualValue,
611 final String failMessage)
612 {
613 if (failMessage != null)
614 {
615 final Difference diff = new Difference(expectedTable, actualTable,
616 rowNum, columnName, expectedValue, actualValue,
617 failMessage);
618
619 failureHandler.handle(diff);
620 }
621 }
622
623 protected ValueComparer determineValueComparer(final String columnName,
624 final ValueComparer defaultValueComparer,
625 final Map<String, ValueComparer> columnValueComparers)
626 {
627 ValueComparer valueComparer = columnValueComparers.get(columnName);
628 if (valueComparer == null)
629 {
630 log.debug(
631 "determineValueComparer: using defaultValueComparer='{}'"
632 + " as columnName='{}' not found"
633 + " in columnValueComparers='{}'",
634 defaultValueComparer, columnName, columnValueComparers);
635 valueComparer = defaultValueComparer;
636 }
637
638 return valueComparer;
639 }
640
641 protected ValueComparer determineValidDefaultValueComparer(
642 final ValueComparer defaultValueComparer)
643 {
644 final ValueComparer validValueComparer;
645
646 if (defaultValueComparer == null)
647 {
648 validValueComparer =
649 valueComparerDefaults.getDefaultValueComparer();
650 log.debug(
651 "determineValidDefaultValueComparer:"
652 + " using getDefaultValueComparer()={}"
653 + " as defaultValueComparer={}",
654 validValueComparer, defaultValueComparer);
655 } else
656 {
657 validValueComparer = defaultValueComparer;
658 }
659
660 return validValueComparer;
661 }
662
663 protected Map<String, Map<String, ValueComparer>> determineValidTableColumnValueComparers(
664 final Map<String, Map<String, ValueComparer>> tableColumnValueComparers)
665 {
666 final Map<String, Map<String, ValueComparer>> validMap;
667
668 if (tableColumnValueComparers == null)
669 {
670 validMap = valueComparerDefaults
671 .getDefaultTableColumnValueComparerMap();
672 log.debug(
673 "determineValidTableColumnValueComparers:"
674 + " using getDefaultTableColumnValueComparerMap()={}"
675 + " as tableColumnValueComparers={}",
676 validMap, tableColumnValueComparers);
677 } else
678 {
679 validMap = tableColumnValueComparers;
680 }
681
682 return validMap;
683 }
684
685 protected Map<String, ValueComparer> determineValidColumnValueComparers(
686 final Map<String, ValueComparer> columnValueComparers,
687 final String tableName)
688 {
689 final Map<String, ValueComparer> validMap;
690
691 if (columnValueComparers == null)
692 {
693 validMap = valueComparerDefaults
694 .getDefaultColumnValueComparerMapForTable(tableName);
695 log.debug(
696 "determineValidColumnValueComparers:"
697 + " using getDefaultValueComparerMap()={}"
698 + " as columnValueComparers={} for tableName={}",
699 validMap, columnValueComparers, tableName);
700 } else
701 {
702 validMap = columnValueComparers;
703 }
704
705 return validMap;
706 }
707
708 public void setValueComparerDefaults(
709 final ValueComparerDefaults valueComparerDefaults)
710 {
711 this.valueComparerDefaults = valueComparerDefaults;
712 }
713 }