IsActualWithinToleranceOfExpectedTimestampValueComparer.java
package org.dbunit.assertion.comparer.value;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.sql.Timestamp;
import org.dbunit.DatabaseUnitException;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.TypeCastException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link ValueComparer} implementation for {@link Timestamp}s that verifies
* actual value is within a low and high milliseconds tolerance range of
* expected value.
*
* Note: If actual and expected values are both null, the comparison passes.
*
* @author Jeff Jensen
* @since 2.6.0
*/
public class IsActualWithinToleranceOfExpectedTimestampValueComparer
extends ValueComparerTemplateBase
{
private final Logger log = LoggerFactory.getLogger(getClass());
public static final long ONE_SECOND_IN_MILLIS = 1000;
public static final long TWO_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 2;
public static final long THREE_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 3;
public static final long FOUR_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 4;
public static final long FIVE_SECONDS_IN_MILLIS = ONE_SECOND_IN_MILLIS * 5;
public static final long ONE_MINUTE_IN_MILLIS = ONE_SECOND_IN_MILLIS * 60;
public static final long TWO_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 2;
public static final long THREE_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 3;
public static final long FOUR_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 4;
public static final long FIVE_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 5;
public static final long TEN_MINUTES_IN_MILLIS = ONE_MINUTE_IN_MILLIS * 10;
private long lowToleranceValueInMillis;
private long highToleranceValueInMillis;
/**
* Create instance specifying the allowed actual time difference range from
* expected.
*
* @param lowToleranceValueInMillis
* The minimum time difference allowed.
* @param highToleranceValueInMillis
* The maximum time difference allowed.
*/
public IsActualWithinToleranceOfExpectedTimestampValueComparer(
final long lowToleranceValueInMillis,
final long highToleranceValueInMillis)
{
this.lowToleranceValueInMillis = lowToleranceValueInMillis;
this.highToleranceValueInMillis = highToleranceValueInMillis;
}
@Override
protected boolean isExpected(final ITable expectedTable,
final ITable actualTable, final int rowNum, final String columnName,
final DataType dataType, final Object expectedValue,
final Object actualValue) throws DatabaseUnitException
{
final boolean isExpected;
// handle nulls: prevent NPE and isExpected=true when both null
if (expectedValue == null || actualValue == null)
{
isExpected = isExpectedWithNull(expectedValue, actualValue);
} else
{
isExpected =
isExpectedWithoutNull(expectedValue, actualValue, dataType);
}
return isExpected;
}
/** Since one is a known null, isExpected=true when they equal. */
protected boolean isExpectedWithNull(final Object expectedValue,
final Object actualValue)
{
final boolean isExpected = expectedValue == actualValue;
log.debug("isExpectedWithNull: {}, actualValue={}, expectedValue={}",
isExpected, actualValue, expectedValue);
return isExpected;
}
/** Neither is null so compare values with tolerance. */
protected boolean isExpectedWithoutNull(final Object expectedValue, final Object actualValue,
final DataType dataType) throws TypeCastException {
assertNotNull(expectedValue, "expectedValue is null.");
assertNotNull(actualValue, "actualValue is null.");
final Object actualTimestamp = getCastedValue(actualValue, dataType);
final long actualTime = convertValueToTimeInMillis(actualTimestamp);
final Object expectedTimestamp =
getCastedValue(expectedValue, dataType);
final long expectedTime = convertValueToTimeInMillis(expectedTimestamp);
final long diffTime = calcTimeDifference(actualTime, expectedTime);
return isTolerant(diffTime);
}
protected Object getCastedValue(final Object value, final DataType type)
throws TypeCastException
{
final Object castedValue;
if (type == null || type == DataType.UNKNOWN)
{
castedValue = value;
} else
{
castedValue = type.typeCast(value);
}
return castedValue;
}
protected boolean isTolerant(final long diffTime)
{
final boolean isLowTolerant = diffTime >= lowToleranceValueInMillis;
final boolean isHighTolerant = diffTime <= highToleranceValueInMillis;
final boolean isTolerant = isLowTolerant && isHighTolerant;
log.debug(
"isTolerant: {},"
+ " diffTime={}, lowToleranceValueInMillis={},"
+ " highToleranceValueInMillis={}",
isTolerant, diffTime, lowToleranceValueInMillis,
highToleranceValueInMillis);
return isTolerant;
}
protected long convertValueToTimeInMillis(final Object timestampValue)
{
final Timestamp timestamp = (Timestamp) timestampValue;
return timestamp.getTime();
}
protected long calcTimeDifference(final long actualTimeInMillis,
final long expectedTimeInMillis)
{
final long diffTime = actualTimeInMillis - expectedTimeInMillis;
final long diffTimeAbs = Math.abs(diffTime);
log.debug(
"calcTimeDifference: "
+ "actualTimeInMillis={}, expectedTimeInMillis={},"
+ " diffInMillisTime={}, diffTimeInMillisAbs={}",
actualTimeInMillis, expectedTimeInMillis, diffTime,
diffTimeAbs);
return diffTimeAbs;
}
@Override
protected String getFailPhrase()
{
return "not within tolerance range of " + lowToleranceValueInMillis
+ " - " + highToleranceValueInMillis + " milliseconds of";
}
}