View Javadoc
1   package org.dbunit.assertion.comparer.value;
2   
3   import static org.junit.jupiter.api.Assertions.assertNotNull;
4   
5   import java.sql.Timestamp;
6   
7   import org.dbunit.DatabaseUnitException;
8   import org.dbunit.dataset.ITable;
9   import org.dbunit.dataset.datatype.DataType;
10  import org.dbunit.dataset.datatype.TypeCastException;
11  import org.slf4j.Logger;
12  import org.slf4j.LoggerFactory;
13  
14  /**
15   * {@link ValueComparer} implementation for {@link Timestamp}s that verifies
16   * actual value is within a low and high milliseconds tolerance range of
17   * expected value.
18   *
19   * Note: If actual and expected values are both null, the comparison passes.
20   *
21   * @author Jeff Jensen
22   * @since 2.6.0
23   */
24  public class IsActualWithinToleranceOfExpectedTimestampValueComparer
25          extends ValueComparerTemplateBase
26  {
27      private final Logger log = LoggerFactory.getLogger(getClass());
28  
29      public static final long ONE_SECOND_IN_MILLIS = 1000;
30      public static final long TWO_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 2;
31      public static final long THREE_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 3;
32      public static final long FOUR_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 4;
33      public static final long FIVE_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 5;
34  
35      public static final long ONE_MINUTE_IN_MILLIS = ONE_SECOND_IN_MILLIS * 60;
36      public static final long TWO_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 2;
37      public static final long THREE_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 3;
38      public static final long FOUR_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 4;
39      public static final long FIVE_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 5;
40      public static final long TEN_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 10;
41  
42      private long lowToleranceValueInMillis;
43      private long highToleranceValueInMillis;
44  
45      /**
46       * Create instance specifying the allowed actual time difference range from
47       * expected.
48       *
49       * @param lowToleranceValueInMillis
50       *            The minimum time difference allowed.
51       * @param highToleranceValueInMillis
52       *            The maximum time difference allowed.
53       */
54      public IsActualWithinToleranceOfExpectedTimestampValueComparer(
55              final long lowToleranceValueInMillis,
56              final long highToleranceValueInMillis)
57      {
58          this.lowToleranceValueInMillis = lowToleranceValueInMillis;
59          this.highToleranceValueInMillis = highToleranceValueInMillis;
60      }
61  
62      @Override
63      protected boolean isExpected(final ITable expectedTable,
64              final ITable actualTable, final int rowNum, final String columnName,
65              final DataType dataType, final Object expectedValue,
66              final Object actualValue) throws DatabaseUnitException
67      {
68          final boolean isExpected;
69  
70          // handle nulls: prevent NPE and isExpected=true when both null
71          if (expectedValue == null || actualValue == null)
72          {
73              isExpected = isExpectedWithNull(expectedValue, actualValue);
74          } else
75          {
76              isExpected =
77                      isExpectedWithoutNull(expectedValue, actualValue, dataType);
78          }
79  
80          return isExpected;
81      }
82  
83      /** Since one is a known null, isExpected=true when they equal. */
84      protected boolean isExpectedWithNull(final Object expectedValue,
85              final Object actualValue)
86      {
87          final boolean isExpected = expectedValue == actualValue;
88  
89          log.debug("isExpectedWithNull: {}, actualValue={}, expectedValue={}",
90                  isExpected, actualValue, expectedValue);
91  
92          return isExpected;
93      }
94  
95      /** Neither is null so compare values with tolerance. */
96      protected boolean isExpectedWithoutNull(final Object expectedValue, final Object actualValue,
97              final DataType dataType) throws TypeCastException {
98          assertNotNull(expectedValue, "expectedValue is null.");
99          assertNotNull(actualValue, "actualValue is null.");
100 
101         final Object actualTimestamp = getCastedValue(actualValue, dataType);
102         final long actualTime = convertValueToTimeInMillis(actualTimestamp);
103 
104         final Object expectedTimestamp =
105                 getCastedValue(expectedValue, dataType);
106         final long expectedTime = convertValueToTimeInMillis(expectedTimestamp);
107 
108         final long diffTime = calcTimeDifference(actualTime, expectedTime);
109         return isTolerant(diffTime);
110     }
111 
112     protected Object getCastedValue(final Object value, final DataType type)
113             throws TypeCastException
114     {
115         final Object castedValue;
116 
117         if (type == null || type == DataType.UNKNOWN)
118         {
119             castedValue = value;
120         } else
121         {
122             castedValue = type.typeCast(value);
123         }
124 
125         return castedValue;
126     }
127 
128     protected boolean isTolerant(final long diffTime)
129     {
130         final boolean isLowTolerant = diffTime >= lowToleranceValueInMillis;
131         final boolean isHighTolerant = diffTime <= highToleranceValueInMillis;
132         final boolean isTolerant = isLowTolerant && isHighTolerant;
133 
134         log.debug(
135                 "isTolerant: {},"
136                         + " diffTime={}, lowToleranceValueInMillis={},"
137                         + " highToleranceValueInMillis={}",
138                 isTolerant, diffTime, lowToleranceValueInMillis,
139                 highToleranceValueInMillis);
140 
141         return isTolerant;
142     }
143 
144     protected long convertValueToTimeInMillis(final Object timestampValue)
145     {
146         final Timestamp timestamp = (Timestamp) timestampValue;
147         return timestamp.getTime();
148     }
149 
150     protected long calcTimeDifference(final long actualTimeInMillis,
151             final long expectedTimeInMillis)
152     {
153         final long diffTime = actualTimeInMillis - expectedTimeInMillis;
154         final long diffTimeAbs = Math.abs(diffTime);
155         log.debug(
156                 "calcTimeDifference: "
157                         + "actualTimeInMillis={}, expectedTimeInMillis={},"
158                         + " diffInMillisTime={}, diffTimeInMillisAbs={}",
159                 actualTimeInMillis, expectedTimeInMillis, diffTime,
160                 diffTimeAbs);
161 
162         return diffTimeAbs;
163     }
164 
165     @Override
166     protected String getFailPhrase()
167     {
168         return "not within tolerance range of " + lowToleranceValueInMillis
169                 + " - " + highToleranceValueInMillis + " milliseconds of";
170     }
171 }