JsonNodeDoubleValueTest.java
package tools.jackson.databind.node;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.OptionalDouble;
import org.junit.jupiter.api.Test;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.exc.JsonNodeException;
import tools.jackson.databind.util.RawValue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for [databind#4958], JsonNode.doubleValue() (and related) parts
* over all types.
*/
public class JsonNodeDoubleValueTest
extends NodeTestBase
{
private final JsonNodeFactory NODES = newJsonMapper().getNodeFactory();
// // // doubleValue()
// from Integers
@Test
public void doubleValueFromNumberIntOk()
{
final double ONE_D = (double) 1;
_assertDoubleValue(ONE_D, NODES.numberNode((byte) 1));
_assertDoubleValue((double)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertDoubleValue((double)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertDoubleValue(ONE_D, NODES.numberNode((short) 1));
_assertDoubleValue((double)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertDoubleValue((double)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertDoubleValue(ONE_D, NODES.numberNode(1));
_assertDoubleValue((double) Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertDoubleValue((double) Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
_assertDoubleValue(ONE_D, NODES.numberNode(1L));
_assertDoubleValue((double) Long.MIN_VALUE, NODES.numberNode(Long.MIN_VALUE));
_assertDoubleValue((double) Long.MAX_VALUE, NODES.numberNode(Long.MAX_VALUE));
_assertDoubleValue(ONE_D, NODES.numberNode(BigInteger.valueOf(1)));
_assertDoubleValue((double) Long.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MIN_VALUE)));
_assertDoubleValue((double) Long.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MAX_VALUE)));
}
@Test
public void failDoubleValueFromNumberIntRange() {
// Can only fail for underflow/overflow: and that only for / BigInteger
// (neither Integer nor Long is outside of range of even Float).
final BigInteger tooBig = BigInteger.TEN.pow(310);
final BigInteger tooSmall = tooBig.negate();
_assertDoubleValueFailForValueRange(NODES.numberNode(tooBig));
_assertDoubleValueFailForValueRange(NODES.numberNode(tooSmall));
}
// From FPs
@Test
public void doubleValueFromNumberFPOk()
{
_assertDoubleValue(1.0, NODES.numberNode(1.0f));
_assertDoubleValue(100_000.0, NODES.numberNode(100_000.0f));
_assertDoubleValue(-100_000.0, NODES.numberNode(-100_000.0f));
_assertDoubleValue(1.0, NODES.numberNode(1.0d));
_assertDoubleValue(100_000.0, NODES.numberNode(100_000.0d));
_assertDoubleValue(-100_000.0, NODES.numberNode(-100_000.0d));
_assertDoubleValue(1.0,
NODES.numberNode(BigDecimal.valueOf(1.0d)));
_assertDoubleValue((double) Long.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MIN_VALUE)));
_assertDoubleValue((double) Long.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MAX_VALUE)));
}
@Test
public void failDoubleValueFromNumberFPRange()
{
// Can only fail from BigDecimal (similar to ints vs BigInteger)
final BigDecimal tooBig = new BigDecimal(BigInteger.TEN.pow(310))
.add(BigDecimal.valueOf(0.125));
final BigDecimal tooSmall = tooBig.negate();
_assertDoubleValueFailForValueRange(NODES.numberNode(tooBig));
_assertDoubleValueFailForValueRange(NODES.numberNode(tooSmall));
}
// from non-Numeric types
@Test
public void failDoubleValueFromNonNumberScalar()
{
_assertDoubleValueFailForNonNumber(NODES.booleanNode(true));
_assertDoubleValueFailForNonNumber(NODES.binaryNode(new byte[3]));
_assertDoubleValueFailForNonNumber(NODES.stringNode("123"));
_assertDoubleValueFailForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertDoubleValueFailForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertDoubleValueFailForNonNumber(NODES.pojoNode(3.8d));
}
@Test
public void failDoubleValueFromStructural()
{
_assertDoubleValueFailForNonNumber(NODES.arrayNode(3));
_assertDoubleValueFailForNonNumber(NODES.objectNode());
}
@Test
public void failDoubleValueFromMiscOther()
{
_assertDoubleValueFailForNonNumber(NODES.nullNode());
_assertDoubleValueFailForNonNumber(NODES.missingNode());
}
// // // asDouble()
// from Integers
@Test
public void asDoubleFromNumberIntOk()
{
final double ONE_D = (double) 1;
_assertAsDouble(ONE_D, NODES.numberNode((byte) 1));
_assertAsDouble((double)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertAsDouble((double)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertAsDouble(ONE_D, NODES.numberNode((short) 1));
_assertAsDouble((double)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertAsDouble((double)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertAsDouble(ONE_D, NODES.numberNode(1));
_assertAsDouble((double) Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertAsDouble((double) Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
_assertAsDouble(ONE_D, NODES.numberNode(1L));
_assertAsDouble((double) Long.MIN_VALUE, NODES.numberNode(Long.MIN_VALUE));
_assertAsDouble((double) Long.MAX_VALUE, NODES.numberNode(Long.MAX_VALUE));
_assertAsDouble(ONE_D, NODES.numberNode(BigInteger.valueOf(1)));
_assertAsDouble((double) Long.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MIN_VALUE)));
_assertAsDouble((double) Long.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MAX_VALUE)));
}
@Test
public void asDoubleFailFromNumberIntRange() {
// Can only fail for underflow/overflow: and that only for / BigInteger
// (neither Integer nor Long is outside of range of even Float).
final BigInteger tooBig = BigInteger.TEN.pow(310);
final BigInteger tooSmall = tooBig.negate();
_assertAsDoubleFailForValueRange(NODES.numberNode(tooBig));
_assertAsDoubleFailForValueRange(NODES.numberNode(tooSmall));
}
// Numbers/FPs
@Test
public void asDoubleFromNumberFPOk()
{
_assertAsDouble(1.0, NODES.numberNode(1.0f));
_assertAsDouble(100_000.0, NODES.numberNode(100_000.0f));
_assertAsDouble(-100_000.0, NODES.numberNode(-100_000.0f));
_assertAsDouble(1.0, NODES.numberNode(1.0d));
_assertAsDouble(100_000.0, NODES.numberNode(100_000.0d));
_assertAsDouble(-100_000.0, NODES.numberNode(-100_000.0d));
_assertAsDouble(1.0,
NODES.numberNode(BigDecimal.valueOf(1.0d)));
_assertAsDouble((double) Long.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MIN_VALUE)));
_assertAsDouble((double) Long.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MAX_VALUE)));
}
@Test
public void asDoubleFromNumberFPRangeFail()
{
// Can only fail from BigDecimal (similar to ints vs BigInteger)
final BigDecimal tooBig = new BigDecimal(BigInteger.TEN.pow(310))
.add(BigDecimal.valueOf(0.125));
final BigDecimal tooSmall = tooBig.negate();
_assertAsDoubleFailForValueRange(NODES.numberNode(tooBig));
_assertAsDoubleFailForValueRange(NODES.numberNode(tooSmall));
}
// from non-Numeric types
@Test
public void asDoubleFromNonNumberScalar()
{
// First, failing cases:
_assertAsDoubleFailForNonNumber(NODES.booleanNode(true));
_assertAsDoubleFailForNonNumber(NODES.binaryNode(new byte[3]));
_assertAsDoubleFailForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertAsDoubleFailForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertAsDoubleFailForNonNumber(NODES.stringNode("abc"),
"not a valid String representation of `double`");
_assertAsDoubleFailForNonNumber(NODES.pojoNode(new String[0]));
_assertAsDoubleFailForValueRange(NODES.pojoNode(new BigDecimal(BigInteger.TEN.pow(310))));
// Then passing ones:
_assertAsDouble(0.5d, NODES.stringNode("0.5"));
_assertAsDouble(2.5d, NODES.pojoNode(2.5d));
_assertAsDouble(1e40, NODES.pojoNode(1e40));
}
@Test
public void asDoubleFromStructuralFail()
{
_assertAsDoubleFailForNonNumber(NODES.arrayNode(3));
_assertAsDoubleFailForNonNumber(NODES.objectNode());
}
@Test
public void asDoubleFromMiscOther()
{
// Null node converts to 0.0d; missing fails
_assertAsDouble((double) 0, NODES.nullNode());
_assertAsDoubleFailForNonNumber(NODES.missingNode());
}
// // // Shared helper methods
private void _assertDoubleValue(double expected, JsonNode node) {
assertEquals(expected, node.doubleValue());
// and defaults
assertEquals(expected, node.doubleValue(-9999.5));
assertEquals(expected, node.doubleValueOpt().getAsDouble());
}
private void _assertDoubleValueFailForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.doubleValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("cannot convert value")
.contains("value not in 64-bit `double` range");
assertEquals(-2.25d, node.doubleValue(-2.25d));
assertEquals(OptionalDouble.empty(), node.doubleValueOpt());
}
private void _assertDoubleValueFailForNonNumber(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.doubleValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("cannot convert value")
.contains("value type not numeric");
assertEquals(1.5d, node.doubleValue(1.5d));
assertEquals(OptionalDouble.empty(), node.doubleValueOpt());
}
private void _assertAsDouble(double expected, JsonNode node) {
assertEquals(expected, node.asDouble());
// and defaults
assertEquals(expected, node.asDouble(-9999.5));
assertEquals(expected, node.asDoubleOpt().getAsDouble());
}
private void _assertAsDoubleFailForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asDouble(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asDouble()")
.contains("cannot convert value")
.contains("value not in 64-bit `double` range");
assertEquals(-2.25d, node.asDouble(-2.25d));
assertEquals(OptionalDouble.empty(), node.asDoubleOpt());
}
private void _assertAsDoubleFailForNonNumber(JsonNode node) {
_assertAsDoubleFailForNonNumber(node, "value type not numeric");
}
private void _assertAsDoubleFailForNonNumber(JsonNode node, String extraMatch) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asDouble(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asDouble()")
.contains("cannot convert value")
.contains(extraMatch);
assertEquals(1.5d, node.asDouble(1.5d));
assertEquals(OptionalDouble.empty(), node.asDoubleOpt());
}
// Just for manual verification
/*
public static void main(String[] args) {
System.out.println("Long.MIN == "+Long.MIN_VALUE);
System.out.println("Long.MAX == "+Long.MAX_VALUE);
System.out.println("Long.MIN -> double == "+(double) Long.MIN_VALUE);
System.out.println("Long.MAX -> double == "+(double) Long.MAX_VALUE);
System.out.println("Long.MIN -> float == "+(float) Long.MIN_VALUE);
System.out.println("Long.MAX -> float == "+(float) Long.MAX_VALUE);
}
*/
}