1package org.hamcrest.number;
2
3import org.hamcrest.Description;
4import org.hamcrest.Matcher;
5import org.hamcrest.TypeSafeMatcher;
6
7import java.math.BigDecimal;
8import java.math.MathContext;
9
10public class BigDecimalCloseTo extends TypeSafeMatcher<BigDecimal> {
11
12  private final BigDecimal delta;
13  private final BigDecimal value;
14
15  public BigDecimalCloseTo(BigDecimal value, BigDecimal error) {
16      this.delta = error;
17      this.value = value;
18  }
19
20  @Override
21  public boolean matchesSafely(BigDecimal item) {
22      return actualDelta(item).compareTo(BigDecimal.ZERO) <= 0;
23  }
24
25  @Override
26  public void describeMismatchSafely(BigDecimal item, Description mismatchDescription) {
27      mismatchDescription.appendValue(item)
28              .appendText(" differed by ")
29              .appendValue(actualDelta(item))
30              .appendText(" more than delta ")
31              .appendValue(delta);
32  }
33
34  @Override
35  public void describeTo(Description description) {
36      description.appendText("a numeric value within ")
37              .appendValue(delta)
38              .appendText(" of ")
39              .appendValue(value);
40  }
41
42  private BigDecimal actualDelta(BigDecimal item) {
43      return item.subtract(value, MathContext.DECIMAL128).abs().subtract(delta, MathContext.DECIMAL128).stripTrailingZeros();
44  }
45
46  /**
47   * Creates a matcher of {@link java.math.BigDecimal}s that matches when an examined BigDecimal is equal
48   * to the specified <code>operand</code>, within a range of +/- <code>error</code>. The comparison for equality
49   * is done by BigDecimals {@link java.math.BigDecimal#compareTo(java.math.BigDecimal)} method.
50   * For example:
51   * <pre>assertThat(new BigDecimal("1.03"), is(closeTo(new BigDecimal("1.0"), new BigDecimal("0.03"))))</pre>
52   *
53   * @param operand
54   *     the expected value of matching BigDecimals
55   * @param error
56   *     the delta (+/-) within which matches will be allowed
57   */
58  public static Matcher<BigDecimal> closeTo(BigDecimal operand, BigDecimal error) {
59      return new BigDecimalCloseTo(operand, error);
60  }
61
62}
63
64