JsonNodeFloatValueTest.java
package tools.jackson.databind.node;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Optional;
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.floatValue() (and related) parts
* over all types.
*/
public class JsonNodeFloatValueTest
extends NodeTestBase
{
private final JsonNodeFactory NODES = newJsonMapper().getNodeFactory();
// // // floatValue() + Numbers/Integers
@Test
public void floatValueFromNumberIntOk()
{
final float ONE_F = 1.0f;
// Then other integer types
_assertFloatValue(ONE_F, NODES.numberNode((byte) 1));
_assertFloatValue((float)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertFloatValue((float)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertFloatValue(ONE_F, NODES.numberNode((short) 1));
_assertFloatValue((float)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertFloatValue((float)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertFloatValue(ONE_F, NODES.numberNode(1));
_assertFloatValue((float) Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertFloatValue((float) Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
_assertFloatValue(ONE_F, NODES.numberNode(1L));
_assertFloatValue((float) Long.MIN_VALUE, NODES.numberNode(Long.MIN_VALUE));
_assertFloatValue((float) Long.MAX_VALUE, NODES.numberNode(Long.MAX_VALUE));
_assertFloatValue(ONE_F, NODES.numberNode(BigInteger.valueOf(1)));
_assertFloatValue((float) Long.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MIN_VALUE)));
_assertFloatValue((float) Long.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MAX_VALUE)));
}
@Test
public void failfloatValueFromNumberIntRange() {
// Can only fail for underflow/overflow: and that only for / BigInteger
// (neither Integer nor Long is outside of range Float).
final BigInteger tooBig = BigInteger.TEN.pow(310);
final BigInteger tooSmall = tooBig.negate();
_assertFailFloatForValueRange(NODES.numberNode(tooBig));
_assertFailFloatForValueRange(NODES.numberNode(tooSmall));
}
// // // floatValue() + Numbers/FPs
@Test
public void floatValueFromNumberFPOk()
{
_assertFloatValue(1.0f, NODES.numberNode(1.0f));
_assertFloatValue(100_000.25f, NODES.numberNode(100_000.25f));
_assertFloatValue(-100_000.25f, NODES.numberNode(-100_000.25f));
_assertFloatValue(1.0f, NODES.numberNode(1.0d));
_assertFloatValue(100_000.25f, NODES.numberNode(100_000.25d));
_assertFloatValue(-100_000.25f, NODES.numberNode(-100_000.25d));
_assertFloatValue(1.25f,
NODES.numberNode(BigDecimal.valueOf(1.25d)));
_assertFloatValue((float) Long.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MIN_VALUE)));
_assertFloatValue((float) Long.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((double) Long.MAX_VALUE)));
}
@Test
public void failFloatValueFromNumberFPRange()
{
final double tooBigD = 1e40; // 10^40, larger than Float.MAX_VALUE
final double tooSmallD = -tooBigD;
_assertFailFloatForValueRange(NODES.numberNode(tooBigD));
_assertFailFloatForValueRange(NODES.numberNode(tooSmallD));
// and similarly for BigDecimal
final BigDecimal tooBigDec = new BigDecimal(BigInteger.TEN.pow(50))
.add(BigDecimal.valueOf(0.125));
final BigDecimal tooSmallDec = tooBigDec.negate();
_assertFailFloatForValueRange(NODES.numberNode(tooBigDec));
_assertFailFloatForValueRange(NODES.numberNode(tooSmallDec));
}
// // // floatValue() + non-Numeric types
@Test
public void failFloatValueFromNonNumberScalar()
{
_assertFailFloatForNonNumber(NODES.booleanNode(true));
_assertFailFloatForNonNumber(NODES.binaryNode(new byte[3]));
_assertFailFloatForNonNumber(NODES.stringNode("123"));
_assertFailFloatForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertFailFloatForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertFailFloatForNonNumber(NODES.pojoNode(3.8f));
}
@Test
public void failFloatValueFromStructural()
{
_assertFailFloatForNonNumber(NODES.arrayNode(3));
_assertFailFloatForNonNumber(NODES.objectNode());
}
@Test
public void failFloatValueFromMiscOther()
{
_assertFailFloatForNonNumber(NODES.nullNode());
_assertFailFloatForNonNumber(NODES.missingNode());
}
// // // asFloat()
// from Integers
@Test
public void asFloatFromNumberIntOk()
{
final float ONE_F = (float) 1;
_assertAsFloat(ONE_F, NODES.numberNode((byte) 1));
_assertAsFloat((float)Byte.MIN_VALUE, NODES.numberNode(Byte.MIN_VALUE));
_assertAsFloat((float)Byte.MAX_VALUE, NODES.numberNode(Byte.MAX_VALUE));
_assertAsFloat(ONE_F, NODES.numberNode((short) 1));
_assertAsFloat((float)Short.MIN_VALUE, NODES.numberNode(Short.MIN_VALUE));
_assertAsFloat((float)Short.MAX_VALUE, NODES.numberNode(Short.MAX_VALUE));
_assertAsFloat(ONE_F, NODES.numberNode(1));
_assertAsFloat((float) Integer.MIN_VALUE, NODES.numberNode(Integer.MIN_VALUE));
_assertAsFloat((float) Integer.MAX_VALUE, NODES.numberNode(Integer.MAX_VALUE));
_assertAsFloat(ONE_F, NODES.numberNode(1L));
_assertAsFloat((float) Long.MIN_VALUE, NODES.numberNode(Long.MIN_VALUE));
_assertAsFloat((float) Long.MAX_VALUE, NODES.numberNode(Long.MAX_VALUE));
_assertAsFloat(ONE_F, NODES.numberNode(BigInteger.valueOf(1)));
_assertAsFloat((float) Long.MIN_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MIN_VALUE)));
_assertAsFloat((float) Long.MAX_VALUE, NODES.numberNode(BigInteger.valueOf(Long.MAX_VALUE)));
}
@Test
public void asFloatFailFromNumberIntRange() {
// 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();
_assertAsFloatFailForValueRange(NODES.numberNode(tooBig));
_assertAsFloatFailForValueRange(NODES.numberNode(tooSmall));
}
// Numbers/FPs
@Test
public void asFloatFromNumberFPOk()
{
_assertAsFloat(1.0f, NODES.numberNode(1.0f));
_assertAsFloat(100_000.0f, NODES.numberNode(100_000.0f));
_assertAsFloat(-100_000.0f, NODES.numberNode(-100_000.0f));
_assertAsFloat(1.0f, NODES.numberNode(1.0d));
_assertAsFloat(100_000.0f, NODES.numberNode(100_000.0d));
_assertAsFloat(-100_000.0f, NODES.numberNode(-100_000.0d));
_assertAsFloat(1.0f,
NODES.numberNode(BigDecimal.valueOf(1.0d)));
_assertAsFloat((float) Long.MIN_VALUE,
NODES.numberNode(BigDecimal.valueOf((float) Long.MIN_VALUE)));
_assertAsFloat((float) Long.MAX_VALUE,
NODES.numberNode(BigDecimal.valueOf((float) Long.MAX_VALUE)));
}
@Test
public void asFloatFromNumberFPRangeFail()
{
// 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();
_assertAsFloatFailForValueRange(NODES.numberNode(tooBig));
_assertAsFloatFailForValueRange(NODES.numberNode(tooSmall));
}
// from non-Numeric types
@Test
public void asFloatFromNonNumberScalar()
{
// First, failing cases:
_assertAsFloatFailForNonNumber(NODES.booleanNode(true));
_assertAsFloatFailForNonNumber(NODES.binaryNode(new byte[3]));
_assertAsFloatFailForNonNumber(NODES.rawValueNode(new RawValue("abc")));
_assertAsFloatFailForNonNumber(NODES.pojoNode(Boolean.TRUE));
_assertAsFloatFailForNonNumber(NODES.stringNode("abc"),
"not a valid String representation of `float`");
_assertAsFloatFailForValueRange(NODES.pojoNode(1e40));
// Then passing ones:
_assertAsFloat(2.5f, NODES.pojoNode(2.5f));
_assertAsFloat(0.5f, NODES.stringNode("0.5"));
}
@Test
public void asFloatFromStructuralFail()
{
_assertAsFloatFailForNonNumber(NODES.arrayNode(3));
_assertAsFloatFailForNonNumber(NODES.objectNode());
}
@Test
public void asFloatFromMiscOther()
{
// Null node converts to 0.0f; missing fails
_assertAsFloat((float) 0, NODES.nullNode());
_assertAsFloatFailForNonNumber(NODES.missingNode());
}
// // // Shared helper methods
private void _assertFloatValue(float expected, JsonNode node) {
assertEquals(expected, node.floatValue());
// and defaults
assertEquals(expected, node.floatValue(-9999.5f));
assertEquals(expected, node.floatValueOpt().get());
}
private void _assertFailFloatForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.floatValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("cannot convert value")
.contains("value not in 32-bit `float` range");
assertEquals(-2.25f, node.floatValue(-2.25f));
assertEquals(Optional.empty(), node.floatValueOpt());
}
private void _assertFailFloatForNonNumber(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.floatValue(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("cannot convert value")
.contains("value type not numeric");
assertEquals(-2.25f, node.floatValue(-2.25f));
assertEquals(Optional.empty(), node.floatValueOpt());
}
private void _assertAsFloat(float expected, JsonNode node) {
assertEquals(expected, node.asFloat());
// and defaults
assertEquals(expected, node.asFloat(-9999.5f));
assertEquals(expected, node.asFloatOpt().get());
}
private void _assertAsFloatFailForValueRange(JsonNode node) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asFloat(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asFloat()")
.contains("cannot convert value")
.contains("value not in 32-bit `float` range");
assertEquals(-2.25f, node.asFloat(-2.25f));
assertEquals(Optional.empty(), node.asFloatOpt());
}
private void _assertAsFloatFailForNonNumber(JsonNode node) {
_assertAsFloatFailForNonNumber(node, "value type not numeric");
}
private void _assertAsFloatFailForNonNumber(JsonNode node, String extraMatch) {
Exception e = assertThrows(JsonNodeException.class,
() -> node.asFloat(),
"For ("+node.getClass().getSimpleName()+") value: "+node);
assertThat(e.getMessage())
.contains("asFloat()")
.contains("cannot convert value")
.contains(extraMatch);
assertEquals(1.5f, node.asFloat(1.5f));
assertEquals(Optional.empty(), node.asFloatOpt());
}
}