Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ public boolean maxValue(final BigInteger value, final long max) {
* <p>
* This overrides the {@link Number} overload inherited from the superclass, which narrows the value to a {@code long} before comparing and so loses
* magnitude for a {@code BigInteger} outside the long range. The operands are compared as {@code BigDecimal} so a non-integer bound keeps its fractional
* part instead of being truncated towards zero.
* part instead of being truncated towards zero. A non-finite {@link Double} or {@link Float} operand keeps the {@code doubleValue()} comparison, since
* {@code BigDecimal} cannot represent {@code NaN} or an infinity.
* </p>
*
* @param value The value validation is being performed on.
Expand All @@ -161,7 +162,7 @@ public boolean maxValue(final BigInteger value, final long max) {
*/
@Override
public boolean maxValue(final Number value, final Number max) {
return toBigDecimal(value).compareTo(toBigDecimal(max)) <= 0;
return isFinite(value) && isFinite(max) ? compareTo(value, max) <= 0 : value.doubleValue() <= max.doubleValue();
}

/**
Expand All @@ -181,7 +182,8 @@ public boolean minValue(final BigInteger value, final long min) {
* <p>
* This overrides the {@link Number} overload inherited from the superclass, which narrows the value to a {@code long} before comparing and so loses
* magnitude for a {@code BigInteger} outside the long range. The operands are compared as {@code BigDecimal} so a non-integer bound keeps its fractional
* part instead of being truncated towards zero.
* part instead of being truncated towards zero. A non-finite {@link Double} or {@link Float} operand keeps the {@code doubleValue()} comparison, since
* {@code BigDecimal} cannot represent {@code NaN} or an infinity.
* </p>
*
* @param value The value validation is being performed on.
Expand All @@ -190,7 +192,7 @@ public boolean minValue(final BigInteger value, final long min) {
*/
@Override
public boolean minValue(final Number value, final Number min) {
return toBigDecimal(value).compareTo(toBigDecimal(min)) >= 0;
return isFinite(value) && isFinite(min) ? compareTo(value, min) >= 0 : value.doubleValue() >= min.doubleValue();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,30 @@ void testNumberRangeOutsideLongRange() {
assertEquals(50L, wrapsIntoRange.longValue());
assertFalse(instance.isInRange(wrapsIntoRange, min, max));
}

/**
* A non-finite {@link Double} bound must not be routed through {@link BigDecimal}, which cannot represent {@code NaN} or an infinity. The {@link Number}
* overloads previously converted every bound to a {@code BigDecimal} and so threw {@code NumberFormatException} for such a bound, whereas the sibling
* {@link BigDecimalValidator} already handled it. The behaviour now matches: a {@code NaN} bound is never satisfied, and an infinity is an open bound.
*/
@Test
void testNumberRangeNonFiniteBound() {
final AbstractNumberValidator instance = BigIntegerValidator.getInstance();
final Number value = BigInteger.valueOf(100);

// NaN bound: nothing compares against NaN
assertFalse(instance.maxValue(value, Double.NaN));
assertFalse(instance.minValue(value, Double.NaN));
assertFalse(instance.isInRange(value, 0, Double.NaN));
assertFalse(instance.isInRange(value, Double.NaN, 200));

// POSITIVE_INFINITY as a maximum / NEGATIVE_INFINITY as a minimum are open bounds any finite value meets
assertTrue(instance.maxValue(value, Double.POSITIVE_INFINITY));
assertTrue(instance.minValue(value, Double.NEGATIVE_INFINITY));
assertTrue(instance.isInRange(value, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));

// POSITIVE_INFINITY as a minimum / NEGATIVE_INFINITY as a maximum cannot be met
assertFalse(instance.minValue(value, Double.POSITIVE_INFINITY));
assertFalse(instance.maxValue(value, Double.NEGATIVE_INFINITY));
}
}
Loading