NumberTolerantDataType.java
- /*
- *
- * The DbUnit Database Testing Framework
- * Copyright (C)2002-2004, DbUnit.org
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- package org.dbunit.dataset.datatype;
- import java.math.BigDecimal;
- import org.dbunit.dataset.datatype.ToleratedDeltaMap.Precision;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * Extended version of the {@link NumberDataType}. Extends the
- * {@link #compare(Object, Object)} method in order to respect precision
- * tolerance. This is comparable to the JUnit method
- * <code>assert(double val1, double val2, double toleratedDelta)</code>.
- *
- * @author gommma
- * @author Last changed by: $Author$
- * @version $Revision$ $Date$
- * @since 2.3.0
- */
- public class NumberTolerantDataType extends NumberDataType
- {
- /**
- * Logger for this class
- */
- private static final Logger logger =
- LoggerFactory.getLogger(NumberTolerantDataType.class);
- private static final BigDecimal C_100 = new BigDecimal("100");
- /**
- * The allowed/tolerated difference
- */
- private Precision toleratedDelta;
- /**
- * Creates a new number tolerant datatype
- *
- * @param name
- * @param sqlType
- * @param delta
- * The tolerated delta to be used for the comparison
- */
- NumberTolerantDataType(String name, int sqlType, Precision delta)
- {
- super(name, sqlType);
- if (delta == null)
- {
- throw new NullPointerException(
- "The parameter 'delta' must not be null");
- }
- this.toleratedDelta = delta;
- }
- public Precision getToleratedDelta()
- {
- return toleratedDelta;
- }
- /**
- * The only method overwritten from the base implementation to compare
- * numbers allowing a tolerance
- *
- * @see org.dbunit.dataset.datatype.AbstractDataType#compareNonNulls(java.lang.Object,
- * java.lang.Object)
- */
- protected int compareNonNulls(Object value1cast, Object value2cast)
- throws TypeCastException
- {
- logger.debug("compareNonNulls(value1={}, value2={}) - start",
- value1cast, value2cast);
- try
- {
- // Start of special handling
- if (value1cast instanceof BigDecimal
- && value2cast instanceof BigDecimal)
- {
- BigDecimal bdValue1 = (BigDecimal) value1cast;
- BigDecimal bdValue2 = (BigDecimal) value2cast;
- BigDecimal diff = bdValue1.subtract(bdValue2);
- // Exact match
- if (isZero(diff))
- {
- return 0;
- }
- BigDecimal toleratedDeltaValue = this.toleratedDelta.getDelta();
- if (!this.toleratedDelta.isPercentage())
- {
- if (diff.abs().compareTo(toleratedDeltaValue) <= 0)
- {
- // within tolerance delta, so accept
- if (logger.isDebugEnabled())
- logger.debug(
- "Values val1={}, val2={} differ but are within tolerated delta {}",
- new Object[] {bdValue1, bdValue2,
- toleratedDeltaValue});
- return 0;
- } else
- {
- // TODO it would be beautiful to report a precise
- // description about difference and tolerated delta
- // values in the assertion
- // Therefore think about introducing a method
- // "DataType.getCompareInfo()"
- return diff.signum();
- }
- } else
- {
- // percentage comparison
- int scale = toleratedDeltaValue.scale() + 2;
- BigDecimal toleratedValue =
- bdValue1.multiply(toleratedDeltaValue.divide(C_100,
- scale, BigDecimal.ROUND_HALF_UP));
- if (diff.abs().compareTo(toleratedValue) <= 0)
- {
- // within tolerance delta, so accept
- if (logger.isDebugEnabled())
- logger.debug(
- "Values val1={}, val2={} differ but are within tolerated delta {}",
- new Object[] {bdValue1, bdValue2,
- toleratedValue});
- return 0;
- } else
- {
- // TODO it would be beautiful to report a precise
- // description about difference and tolerated delta
- // values in the assertion
- // Therefore think about introducing a method
- // "DataType.getCompareInfo()"
- return diff.signum();
- }
- }
- } else
- {
- Comparable value1 = (Comparable) value1cast;
- Comparable value2 = (Comparable) value2cast;
- return value1.compareTo(value2);
- }
- } catch (ClassCastException e)
- {
- throw new TypeCastException(e);
- }
- }
- /**
- * Checks if the given value is zero.
- *
- * @param value
- * @return <code>true</code> if and only if the given value is zero.
- */
- public static final boolean isZero(BigDecimal value)
- {
- return value.signum() == 0;
- }
- }