JsonNodeIntValueTest.java
package tools.jackson.databind.node;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.OptionalInt;
import org.junit.jupiter.api.Test;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.exc.JsonNodeException;
import tools.jackson.databind.testutil.DatabindTestUtil;
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.intValue() (and related) parts
* over all types.
*<p>
* Also contains tests for {@code JsonNode.shortValue()}.
*/
public class JsonNodeIntValueTest
extends DatabindTestUtil
{
private final JsonNodeFactory NODES = newJsonMapper().getNodeFactory();
// // // intValue() + Numbers/Integers
@Test
public void intValueFromNumberIntOk()
{
// First safe from `int`
_assertIntValue(1, NODES.numberNode(1));
_assertIntValue(Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertIntValue(Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
// Then other integer types
_assertIntValue(1, NODES.numberNode((byte) 1));
_assertIntValue((int)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertIntValue((int)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertIntValue(1, NODES.numberNode((short) 1));
_assertIntValue((int)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertIntValue((int)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertIntValue(1, NODES.numberNode(1L));
_assertIntValue(Integer.MIN_VALUE, NODES.numberNode((long) Integer.MIN_VALUE));
_assertIntValue(Integer.MAX_VALUE, NODES.numberNode((long) Integer.MAX_VALUE));
_assertIntValue(1, NODES.numberNode(BigInteger.valueOf(1)));
_assertIntValue(Integer.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Integer.MIN_VALUE)));
_assertIntValue(Integer.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Integer.MAX_VALUE)));
}
@Test
public void intValueFromNumberIntFailRange() {
// Can only fail for underflow/overflow: and that only for Long / BigInteger
final long underflow = -1L + Integer.MIN_VALUE;
final long overflow = +1L + Integer.MAX_VALUE;
_assertIntValueFailForValueRange(NODES.numberNode(underflow));
_assertIntValueFailForValueRange(NODES.numberNode(overflow));
_assertIntValueFailForValueRange(NODES.numberNode(BigInteger.valueOf(underflow)));
_assertIntValueFailForValueRange(NODES.numberNode(BigInteger.valueOf(overflow)));
}
// // // intValue() + Numbers/FPs
@Test
public void intValueFromNumberFPOk()
{
_assertIntValue(1, NODES.numberNode(1.0f));
_assertIntValue(100_000, NODES.numberNode(100_000.0f));
_assertIntValue(-100_000, NODES.numberNode(-100_000.0f));
_assertIntValue(1, NODES.numberNode(1.0d));
_assertIntValue(100_000, NODES.numberNode(100_000.0d));
_assertIntValue(-100_000, NODES.numberNode(-100_000.0d));
_assertIntValue(Integer.MIN_VALUE, NODES.numberNode((double) Integer.MIN_VALUE));
_assertIntValue(Integer.MAX_VALUE, NODES.numberNode((double) Integer.MAX_VALUE));
_assertIntValue(1,
NODES.numberNode(BigDecimal.valueOf(1.0d)));
_assertIntValue(Integer.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Integer.MIN_VALUE)));
_assertIntValue(Integer.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Integer.MAX_VALUE)));
}
@Test
public void intValueFromNumberFPFailRange()
{
// Can only fail for underflow/overflow: and that only for Long / BigInteger
final long underflow = Integer.MIN_VALUE - 1L;
final long overflow = Integer.MAX_VALUE + 1L;
_assertIntValueFailForValueRange(NODES.numberNode((double)underflow));
_assertIntValueFailForValueRange(NODES.numberNode((double)overflow));
// Float is too inexact for using same test as Double, so:
_assertIntValueFailForValueRange(NODES.numberNode(-Float.MAX_VALUE));
_assertIntValueFailForValueRange(NODES.numberNode(Float.MAX_VALUE));
_assertIntValueFailForValueRange(NODES.numberNode(BigDecimal.valueOf(underflow)));
_assertIntValueFailForValueRange(NODES.numberNode(BigDecimal.valueOf(overflow)));
}
@Test
public void intValueFromNumberFPFailFraction()
{
_assertIntValueFailForFraction(NODES.numberNode(100.5f));
_assertIntValueFailForFraction(NODES.numberNode(-0.25f));
_assertIntValueFailForFraction(NODES.numberNode(100.5d));
_assertIntValueFailForFraction(NODES.numberNode(-0.25d));
_assertIntValueFailForFraction(NODES.numberNode(BigDecimal.valueOf(100.5d)));
_assertIntValueFailForFraction(NODES.numberNode(BigDecimal.valueOf(-0.25d)));
}
@Test
public void intValueFromNumberFPFailNaN()
{
_assertIntValueFailForNaN(NODES.numberNode(Float.NaN));
_assertIntValueFailForNaN(NODES.numberNode(Float.NEGATIVE_INFINITY));
_assertIntValueFailForNaN(NODES.numberNode(Float.POSITIVE_INFINITY));
_assertIntValueFailForNaN(NODES.numberNode(Double.NaN));
_assertIntValueFailForNaN(NODES.numberNode(Double.NEGATIVE_INFINITY));
_assertIntValueFailForNaN(NODES.numberNode(Double.POSITIVE_INFINITY));
}
// // // intValue() + non-Numeric types
@Test
public void intValueFromNonNumberScalarFail()
{
_assertIntValueFailForNonNumber(NODES.booleanNode(true));
_assertIntValueFailForNonNumber(NODES.binaryNode(new byte[3]));
_assertIntValueFailForNonNumber(NODES.stringNode("123"));
_assertIntValueFailForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertIntValueFailForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertIntValueFailForNonNumber(NODES.pojoNode(456));
}
@Test
public void intValueFromStructuralFail()
{
_assertIntValueFailForNonNumber(NODES.arrayNode(3));
_assertIntValueFailForNonNumber(NODES.objectNode());
}
@Test
public void intValueFromMiscOtherFail()
{
_assertIntValueFailForNonNumber(NODES.nullNode());
_assertIntValueFailForNonNumber(NODES.missingNode());
}
// // // asInt()
// Numbers/Integers
@Test
public void asIntFromNumberIntOk()
{
// First safe from `int`
_assertAsInt(1, NODES.numberNode(1));
_assertAsInt(Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertAsInt(Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
// Then other integer types
_assertAsInt(1, NODES.numberNode((byte) 1));
_assertAsInt((int)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertAsInt((int)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertAsInt(1, NODES.numberNode((short) 1));
_assertAsInt((int)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertAsInt((int)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertAsInt(1, NODES.numberNode(1L));
_assertAsInt(Integer.MIN_VALUE, NODES.numberNode((long) Integer.MIN_VALUE));
_assertAsInt(Integer.MAX_VALUE, NODES.numberNode((long) Integer.MAX_VALUE));
_assertAsInt(1, NODES.numberNode(BigInteger.valueOf(1)));
_assertAsInt(Integer.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Integer.MIN_VALUE)));
_assertAsInt(Integer.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Integer.MAX_VALUE)));
}
@Test
public void asIntFromNumberIntFailRange() {
// Can only fail for underflow/overflow: and that only for Long / BigInteger
final long underflow = -1L + Integer.MIN_VALUE;
final long overflow = +1L + Integer.MAX_VALUE;
_assertAsIntFailForValueRange(NODES.numberNode(underflow));
_assertAsIntFailForValueRange(NODES.numberNode(overflow));
_assertAsIntFailForValueRange(NODES.numberNode(BigInteger.valueOf(underflow)));
_assertAsIntFailForValueRange(NODES.numberNode(BigInteger.valueOf(overflow)));
}
// Numbers/FPs
@Test
public void asIntFromNumberFPOk()
{
_assertAsInt(1, NODES.numberNode(1.0f));
_assertAsInt(100_000, NODES.numberNode(100_000.0f));
_assertAsInt(-100_000, NODES.numberNode(-100_000.0f));
_assertAsInt(1, NODES.numberNode(1.0d));
_assertAsInt(100_000, NODES.numberNode(100_000.0d));
_assertAsInt(-100_000, NODES.numberNode(-100_000.0d));
_assertAsInt(Integer.MIN_VALUE, NODES.numberNode((double) Integer.MIN_VALUE));
_assertAsInt(Integer.MAX_VALUE, NODES.numberNode((double) Integer.MAX_VALUE));
_assertAsInt(1,
NODES.numberNode(BigDecimal.valueOf(1.0d)));
_assertAsInt(Integer.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Integer.MIN_VALUE)));
_assertAsInt(Integer.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Integer.MAX_VALUE)));
}
@Test
public void asIntFromNumberFPFailRange()
{
// Can only fail for underflow/overflow: and that only for Long / BigInteger
final long underflow = Integer.MIN_VALUE - 1L;
final long overflow = Integer.MAX_VALUE + 1L;
_assertAsIntFailForValueRange(NODES.numberNode((double)underflow));
_assertAsIntFailForValueRange(NODES.numberNode((double)overflow));
// Float is too inexact for using same test as Double, so:
_assertAsIntFailForValueRange(NODES.numberNode(-Float.MAX_VALUE));
_assertAsIntFailForValueRange(NODES.numberNode(Float.MAX_VALUE));
_assertAsIntFailForValueRange(NODES.numberNode(BigDecimal.valueOf(underflow)));
_assertAsIntFailForValueRange(NODES.numberNode(BigDecimal.valueOf(overflow)));
}
@Test
public void asIntFromNumberFPWithFraction()
{
_assertAsInt(100, NODES.numberNode(100.75f));
_assertAsInt(-1, NODES.numberNode(-1.25f));
_assertAsInt(100, NODES.numberNode(100.75d));
_assertAsInt(-1, NODES.numberNode(-1.25d));
_assertAsInt(100, NODES.numberNode(BigDecimal.valueOf(100.75d)));
_assertAsInt(-1, NODES.numberNode(BigDecimal.valueOf(-1.25d)));
}
@Test
public void asIntFromNumberFPFailNaN()
{
_assertAsIntFailForNaN(NODES.numberNode(Float.NaN));
_assertAsIntFailForNaN(NODES.numberNode(Float.NEGATIVE_INFINITY));
_assertAsIntFailForNaN(NODES.numberNode(Float.POSITIVE_INFINITY));
_assertAsIntFailForNaN(NODES.numberNode(Double.NaN));
_assertAsIntFailForNaN(NODES.numberNode(Double.NEGATIVE_INFINITY));
_assertAsIntFailForNaN(NODES.numberNode(Double.POSITIVE_INFINITY));
}
// non-Numeric types
@Test
public void asIntFromNonNumberScalar()
{
// Some fail:
_assertAsIntFailForNonNumber(NODES.booleanNode(true));
_assertAsIntFailForNonNumber(NODES.binaryNode(new byte[3]));
_assertAsIntFailForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertAsIntFailForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertAsIntFailForNonNumber(NODES.stringNode("abc"),
"value not a valid String representation of `int`");
_assertAsIntFailForValueRange(NODES.pojoNode(123_456_789_000L));
// Some pass:
_assertAsInt(123, NODES.stringNode("123"));
_assertAsInt(456, NODES.pojoNode(456L));
_assertAsInt(789, NODES.pojoNode(BigInteger.valueOf(789)));
}
@Test
public void asIntFromStructuralFail()
{
_assertAsIntFailForNonNumber(NODES.arrayNode(3));
_assertAsIntFailForNonNumber(NODES.objectNode());
}
@Test
public void asIntFromMiscOther()
{
// NullNode -> 0 but "missing" still fails
_assertAsInt(0, NODES.nullNode());
_assertAsIntFailForNonNumber(NODES.missingNode());
}
// // // Shared helper methods: intValue()
private void _assertIntValue(int expected, JsonNode node) {
assertEquals(expected, node.intValue());
// and defaulting
assertEquals(expected, node.intValue(999_999));
assertEquals(expected, node.intValueOpt().getAsInt());
}
private void _assertIntValueFailForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.intValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("intValue()")
.contains("cannot convert value")
.contains("value not in 32-bit `int` range");
// assert defaulting
assertEquals(99, node.intValue(99));
assertEquals(OptionalInt.empty(), node.intValueOpt());
}
private void _assertIntValueFailForFraction(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.intValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("intValue()")
.contains("cannot convert value")
.contains("to `int`: value has fractional part");
// assert defaulting
assertEquals(99, node.intValue(99));
assertEquals(OptionalInt.empty(), node.intValueOpt());
}
private void _assertIntValueFailForNonNumber(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.intValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("intValue()")
.contains("cannot convert value")
.contains("value type not numeric");
// assert defaulting
assertEquals(99, node.intValue(99));
assertEquals(OptionalInt.empty(), node.intValueOpt());
}
private void _assertIntValueFailForNaN(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.intValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("intValue()")
.contains("cannot convert value")
.contains("value non-Finite");
// Verify default value handling
assertEquals(1, node.intValue(1));
assertFalse(node.intValueOpt().isPresent());
}
// // // Shared helper methods: asInt()
private void _assertAsInt(int expected, JsonNode node) {
assertEquals(expected, node.asInt());
// and defaulting
assertEquals(expected, node.asInt(999_999));
assertEquals(expected, node.asIntOpt().getAsInt());
}
private void _assertAsIntFailForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asInt(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asInt()")
.contains("cannot convert value")
.contains("value not in 32-bit `int` range");
// assert defaulting
assertEquals(99, node.asInt(99));
assertEquals(OptionalInt.empty(), node.asIntOpt());
}
private void _assertAsIntFailForNonNumber(JsonNode node) {
_assertAsIntFailForNonNumber(node, "value type not numeric");
}
private void _assertAsIntFailForNonNumber(JsonNode node, String extraFailMsg) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asInt(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asInt()")
.contains("cannot convert value")
.contains(extraFailMsg);
// assert defaulting
assertEquals(99, node.asInt(99));
assertEquals(OptionalInt.empty(), node.asIntOpt());
}
private void _assertAsIntFailForNaN(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asInt(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asInt()")
.contains("cannot convert value")
.contains("value non-Finite");
// Verify default value handling
assertEquals(1, node.asInt(1));
assertFalse(node.asIntOpt().isPresent());
}
}