From: Robert Varga Date: Sun, 13 Mar 2022 13:04:24 +0000 (+0100) Subject: Require scale for integral conversions and RoundingMode for float X-Git-Tag: v8.0.0~2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=yangtools.git;a=commitdiff_plain;h=a468678519c5b5390892997917cd3935f683a657 Require scale for integral conversions and RoundingMode for float Integral conversions need to check range and take the intended scale, otherwise we are left guessing as to what we need to do. Similarly, float/double need to take RoudingMode, so that they can figure out what to do with excess precision. JIRA: YANGTOOLS-1405 Change-Id: I2a6eef9c987dcceec8de7e2aa5bbf43062301cf9 Signed-off-by: Robert Varga --- diff --git a/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java index 1905d2c145..c91e42f417 100644 --- a/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java +++ b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64.java @@ -14,6 +14,7 @@ import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -140,7 +141,7 @@ public class Decimal64 extends Number implements CanonicalValue { private static final int MAX_SCALE = 18; - private static final long[] SCALE = { + private static final long[] FACTOR = { 10, 100, 1000, @@ -161,11 +162,13 @@ public class Decimal64 extends Number implements CanonicalValue { 1000000000000000000L }; + private static final Decimal64Conversion[] CONVERSION = Decimal64Conversion.values(); private static final Decimal64[] MIN_VALUE; private static final Decimal64[] MAX_VALUE; static { - verify(SCALE.length == MAX_SCALE); + verify(CONVERSION.length == MAX_SCALE); + verify(FACTOR.length == MAX_SCALE); MIN_VALUE = new Decimal64[MAX_SCALE]; MAX_VALUE = new Decimal64[MAX_SCALE]; @@ -175,24 +178,30 @@ public class Decimal64 extends Number implements CanonicalValue { } } - private final byte scaleOffset; + private final byte offset; private final long value; @VisibleForTesting Decimal64(final int scale, final long intPart, final long fracPart, final boolean negative) { - scaleOffset = offsetOf(scale); + offset = offsetOf(scale); - final long bits = intPart * SCALE[scaleOffset] + fracPart; + final long bits = intPart * FACTOR[offset] + fracPart; value = negative ? -bits : bits; } - private Decimal64(final byte scaleOffset, final long value) { - this.scaleOffset = scaleOffset; + private Decimal64(final byte offset, final long intPart, final boolean negative) { + this.offset = offset; + final long bits = intPart * FACTOR[offset]; + value = negative ? -bits : bits; + } + + private Decimal64(final byte offset, final long value) { + this.offset = offset; this.value = value; } protected Decimal64(final Decimal64 other) { - this(other.scaleOffset, other.value); + this(other.offset, other.value); } /** @@ -229,29 +238,58 @@ public class Decimal64 extends Number implements CanonicalValue { return MAX_VALUE[offsetOf(scale)]; } - // >>> FIXME: these need to take a scale value and perform a range check. we also need truncating counterparts - public static Decimal64 valueOf(final byte byteVal) { - return byteVal < 0 ? new Decimal64(1, -byteVal, 0, true) : new Decimal64(1, byteVal, 0, false); + // >>> FIXME: these need truncating counterparts + public static Decimal64 valueOf(final int scale, final byte byteVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (byteVal < conv.minByte || byteVal > conv.maxByte) { + throw new IllegalArgumentException("Value " + byteVal + " is not in range [" + + conv.minByte + ".." + conv.maxByte + "] to fit scale " + scale); + } + return byteVal < 0 ? new Decimal64(offset, -byteVal, true) : new Decimal64(offset, byteVal, false); + } + + public static Decimal64 valueOf(final int scale, final short shortVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (shortVal < conv.minShort || shortVal > conv.maxShort) { + throw new IllegalArgumentException("Value " + shortVal + " is not in range [" + + conv.minShort + ".." + conv.maxShort + "] to fit scale " + scale); + } + return shortVal < 0 ? new Decimal64(offset, -shortVal, true) : new Decimal64(offset, shortVal, false); } - public static Decimal64 valueOf(final short shortVal) { - return shortVal < 0 ? new Decimal64(1, -shortVal, 0, true) : new Decimal64(1, shortVal, 0, false); + public static Decimal64 valueOf(final int scale, final int intVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (intVal < conv.minInt || intVal > conv.maxInt) { + throw new IllegalArgumentException("Value " + intVal + " is not in range [" + + conv.minInt + ".." + conv.maxInt + "] to fit scale " + scale); + } + return intVal < 0 ? new Decimal64(offset, - (long)intVal, true) : new Decimal64(offset, intVal, false); } - public static Decimal64 valueOf(final int intVal) { - return intVal < 0 ? new Decimal64(1, - (long)intVal, 0, true) : new Decimal64(1, intVal, 0, false); + public static Decimal64 valueOf(final int scale, final long longVal) { + final byte offset = offsetOf(scale); + final var conv = CONVERSION[offset]; + if (longVal < conv.minLong || longVal > conv.maxLong) { + throw new IllegalArgumentException("Value " + longVal + " is not in range [" + + conv.minLong + ".." + conv.maxLong + "] to fit scale " + scale); + } + return longVal < 0 ? new Decimal64(offset, -longVal, true) : new Decimal64(offset, longVal, false); } + // <<< FIXME - public static Decimal64 valueOf(final long longVal) { + // FIXME: this should take a RoundingMode and perform rounding + // FIXME: this should have a truncating counterpart + public static Decimal64 valueOf(final float floatVal, final RoundingMode rounding) { // XXX: we should be able to do something smarter here - return valueOf(Long.toString(longVal)); + return valueOf(Float.toString(floatVal)); } - // <<< FIXME // FIXME: this should take a RoundingMode and perform rounding - // FIXME: this should have a float counterpart - // FIXME: this should have a truncating - public static Decimal64 valueOf(final double doubleVal) { + // FIXME: this should have a truncating counterpart + public static Decimal64 valueOf(final double doubleVal, final RoundingMode rounding) { // XXX: we should be able to do something smarter here return valueOf(Double.toString(doubleVal)); } @@ -286,7 +324,7 @@ public class Decimal64 extends Number implements CanonicalValue { * @return This decimal's scale */ public final int scale() { - return scaleOffset + 1; + return offset + 1; } /** @@ -319,7 +357,7 @@ public class Decimal64 extends Number implements CanonicalValue { @Override public final double doubleValue() { - return 1.0 * value / SCALE[scaleOffset]; + return 1.0 * value / FACTOR[offset]; } /** @@ -393,7 +431,7 @@ public class Decimal64 extends Number implements CanonicalValue { if (this == o) { return 0; } - if (scaleOffset == o.scaleOffset) { + if (offset == o.offset) { return Long.compare(value, o.value); } @@ -454,17 +492,17 @@ public class Decimal64 extends Number implements CanonicalValue { } private boolean equalsImpl(final Decimal64 other) { - return scaleOffset == other.scaleOffset ? value == other.value + return offset == other.offset ? value == other.value // We need to normalize both : intPart() == other.intPart() && fracPart() == other.fracPart(); } private long intPart() { - return value / SCALE[scaleOffset]; + return value / FACTOR[offset]; } private long fracPart() { - return Math.abs(value % SCALE[scaleOffset]); + return Math.abs(value % FACTOR[offset]); } private static byte offsetOf(final int scale) { diff --git a/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64Conversion.java b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64Conversion.java new file mode 100644 index 0000000000..466995ab08 --- /dev/null +++ b/common/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/Decimal64Conversion.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.common; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Conversion constants for all scales supported by Decimal64. + */ +@NonNullByDefault +enum Decimal64Conversion { + SCALE_1(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -922337203685477580L, 922337203685477580L, + -922337203685477580.8F, 922337203685477580.7F, + -922337203685477580.8D, 922337203685477580.7D), + SCALE_2(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -92233720368547758L, 92233720368547758L, + -92233720368547758.08F, 92233720368547758.07F, + -92233720368547758.08F, 92233720368547758.07D), + SCALE_3(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -9223372036854775L, 9223372036854775L, + -9223372036854775.808F, 9223372036854775.807F, + -9223372036854775.808D, 9223372036854775.807D), + SCALE_4(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -922337203685477L, 922337203685477L, + -922337203685477.5808F, 922337203685477.5807F, + -922337203685477.5808D, 922337203685477.5807D), + SCALE_5(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -92233720368547L, 92233720368547L, + -92233720368547.75808F, 92233720368547.75807F, + -92233720368547.75808D, 92233720368547.75807D), + SCALE_6(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -9223372036854L, 9223372036854L, + -9223372036854.775808F, 9223372036854.775807F, + -9223372036854.775808D, 9223372036854.775807D), + SCALE_7(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -922337203685L, 922337203685L, + -922337203685.4775808F, 922337203685.4775807F, + -922337203685.4775808D, 922337203685.4775807D), + SCALE_8(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -92233720368L, 92233720368L, + -92233720368.54775808F, 92233720368.54775807F, + -92233720368.54775808D, 92233720368.54775807D), + SCALE_9(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, + -9223372036L, 9223372036L, + -9223372036.854775808F, 9223372036.854775807F, + -9223372036.854775808D, 9223372036.854775807D), + SCALE_10(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, -922337203, 922337203, + -922337203L, 922337203L, + -922337203.6854775808F, 922337203.6854775807F, + -922337203.6854775808D, 922337203.6854775807D), + SCALE_11(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, -92233720, 92233720, + -92233720L, 92233720L, + -92233720.36854775808F, 92233720.36854775807F, + -92233720.36854775808D, 92233720.36854775807D), + SCALE_12(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, -9223372, 9223372, -9223372L, 9223372L, + -9223372.036854775808F, 9223372.036854775807F, + -9223372.036854775808D, 9223372.036854775807D), + SCALE_13(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, -922337, 922337, -922337L, 922337L, + -922337.2036854775808F, 922337.2036854775807F, + -922337.2036854775808D, 922337.2036854775807D), + SCALE_14(Byte.MIN_VALUE, Byte.MAX_VALUE, Short.MIN_VALUE, Short.MAX_VALUE, -92233, 92233, -92233L, 92233L, + -92233.72036854775808F, 92233.72036854775807F, + -92233.72036854775808D, 92233.72036854775807D), + SCALE_15(Byte.MIN_VALUE, Byte.MAX_VALUE, (short) -9223, (short) 9223, -9223, 9223, -9223L, 9223L, + -9223.372036854775808F, 9223.372036854775807F, + -9223.372036854775808D, 9223.372036854775807D), + SCALE_16(Byte.MIN_VALUE, Byte.MAX_VALUE, (short) -922, (short) 922, -922, 922, -922L, 922L, + -922.3372036854775808F, 922.3372036854775807F, + -922.3372036854775808D, 922.3372036854775807D), + SCALE_17((byte) -92, (byte)92, (short) -92, (short) 92, -92, 92, -92L, 92L, + -92.23372036854775808F, 92.23372036854775807F, + -92.23372036854775808D, 92.23372036854775807D), + SCALE_18((byte) -9, (byte)9, (short) -9, (short) 9, -9, 9, -9L, 9L, + -9.223372036854775808F, 9.223372036854775807F, + -9.223372036854775808D, 9.223372036854775807D); + + final byte minByte; + final byte maxByte; + + final short minShort; + final short maxShort; + + final int minInt; + final int maxInt; + + final long minLong; + final long maxLong; + + final float minFloat; + final float maxFloat; + + final double minDouble; + final double maxDouble; + + Decimal64Conversion( + final byte minByte, final byte maxByte, + final short minShort, final short maxShort, + final int minInt, final int maxInt, + final long minLong, final long maxLong, + final float minFloat, final float maxFloat, + final double minDouble, final double maxDouble) { + this.minByte = minByte; + this.maxByte = maxByte; + this.minShort = minShort; + this.maxShort = maxShort; + this.minInt = minInt; + this.maxInt = maxInt; + this.minLong = minLong; + this.maxLong = maxLong; + this.minFloat = minFloat; + this.maxFloat = maxFloat; + this.minDouble = minDouble; + this.maxDouble = maxDouble; + } +} diff --git a/common/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/Decimal64Test.java b/common/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/Decimal64Test.java index e2b01871d7..8735a930da 100644 --- a/common/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/Decimal64Test.java +++ b/common/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/Decimal64Test.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import java.math.BigDecimal; +import java.math.RoundingMode; import org.junit.Test; public class Decimal64Test { @@ -192,25 +193,29 @@ public class Decimal64Test { @Test public void testFactories() { - assertEquals("0.0", Decimal64.valueOf((byte) 0).toString()); - assertEquals("1.0", Decimal64.valueOf((byte) 1).toString()); - assertEquals("-1.0", Decimal64.valueOf((byte) -1).toString()); + assertEquals("0.0", Decimal64.valueOf(1, (byte) 0).toString()); + assertEquals("1.0", Decimal64.valueOf(1, (byte) 1).toString()); + assertEquals("-1.0", Decimal64.valueOf(1, (byte) -1).toString()); - assertEquals("0.0", Decimal64.valueOf((short) 0).toString()); - assertEquals("1.0", Decimal64.valueOf((short) 1).toString()); - assertEquals("-1.0", Decimal64.valueOf((short) -1).toString()); + assertEquals("0.0", Decimal64.valueOf(1, (short) 0).toString()); + assertEquals("1.0", Decimal64.valueOf(1, (short) 1).toString()); + assertEquals("-1.0", Decimal64.valueOf(1, (short) -1).toString()); - assertEquals("0.0", Decimal64.valueOf(0).toString()); - assertEquals("1.0", Decimal64.valueOf(1).toString()); - assertEquals("-1.0", Decimal64.valueOf(-1).toString()); + assertEquals("0.0", Decimal64.valueOf(1, 0).toString()); + assertEquals("1.0", Decimal64.valueOf(1, 1).toString()); + assertEquals("-1.0", Decimal64.valueOf(1, -1).toString()); - assertEquals("0.0", Decimal64.valueOf(0L).toString()); - assertEquals("1.0", Decimal64.valueOf(1L).toString()); - assertEquals("-1.0", Decimal64.valueOf(-1L).toString()); + assertEquals("0.0", Decimal64.valueOf(1, 0L).toString()); + assertEquals("1.0", Decimal64.valueOf(1, 1L).toString()); + assertEquals("-1.0", Decimal64.valueOf(1, -1L).toString()); - assertEquals("0.0", Decimal64.valueOf(0.0).toString()); - assertEquals("1.0", Decimal64.valueOf(1.0).toString()); - assertEquals("-1.0", Decimal64.valueOf(-1.0).toString()); + assertEquals("0.0", Decimal64.valueOf(0.0F, RoundingMode.UNNECESSARY).toString()); + assertEquals("1.0", Decimal64.valueOf(1.0F, RoundingMode.UNNECESSARY).toString()); + assertEquals("-1.0", Decimal64.valueOf(-1.0F, RoundingMode.UNNECESSARY).toString()); + + assertEquals("0.0", Decimal64.valueOf(0.0D, RoundingMode.UNNECESSARY).toString()); + assertEquals("1.0", Decimal64.valueOf(1.0D, RoundingMode.UNNECESSARY).toString()); + assertEquals("-1.0", Decimal64.valueOf(-1.0D, RoundingMode.UNNECESSARY).toString()); assertEquals("0.0", Decimal64.valueOf(BigDecimal.ZERO).toString()); assertEquals("1.0", Decimal64.valueOf(BigDecimal.ONE).toString()); @@ -219,18 +224,18 @@ public class Decimal64Test { @Test public void testBoundaries() { - assertEquals(-128L, Decimal64.valueOf(Byte.MIN_VALUE).longValue()); - assertEquals(127L, Decimal64.valueOf(Byte.MAX_VALUE).longValue()); - assertEquals(-32768L, Decimal64.valueOf(Short.MIN_VALUE).longValue()); - assertEquals(32767L, Decimal64.valueOf(Short.MAX_VALUE).longValue()); - assertEquals(-2147483648L, Decimal64.valueOf(Integer.MIN_VALUE).longValue()); - assertEquals(2147483647L, Decimal64.valueOf(Integer.MAX_VALUE).longValue()); + assertEquals(-128L, Decimal64.valueOf(1, Byte.MIN_VALUE).longValue()); + assertEquals(127L, Decimal64.valueOf(1, Byte.MAX_VALUE).longValue()); + assertEquals(-32768L, Decimal64.valueOf(2, Short.MIN_VALUE).longValue()); + assertEquals(32767L, Decimal64.valueOf(2, Short.MAX_VALUE).longValue()); + assertEquals(-2147483648L, Decimal64.valueOf(3, Integer.MIN_VALUE).longValue()); + assertEquals(2147483647L, Decimal64.valueOf(3, Integer.MAX_VALUE).longValue()); } @Test public void testByteValueExact() { - assertEquals(Byte.MIN_VALUE, Decimal64.valueOf(Byte.MIN_VALUE).byteValueExact()); - assertEquals(Byte.MAX_VALUE, Decimal64.valueOf(Byte.MAX_VALUE).byteValueExact()); + assertEquals(Byte.MIN_VALUE, Decimal64.valueOf(1, Byte.MIN_VALUE).byteValueExact()); + assertEquals(Byte.MAX_VALUE, Decimal64.valueOf(1, Byte.MAX_VALUE).byteValueExact()); } @Test @@ -241,14 +246,14 @@ public class Decimal64Test { @Test public void testByteValueExactRange() { - final Decimal64 dec = Decimal64.valueOf(Byte.MAX_VALUE + 1); + final Decimal64 dec = Decimal64.valueOf(1, Byte.MAX_VALUE + 1); assertThrows(ArithmeticException.class, () -> dec.byteValueExact()); } @Test public void testShortValueExact() { - assertEquals(Short.MIN_VALUE, Decimal64.valueOf(Short.MIN_VALUE).shortValueExact()); - assertEquals(Short.MAX_VALUE, Decimal64.valueOf(Short.MAX_VALUE).shortValueExact()); + assertEquals(Short.MIN_VALUE, Decimal64.valueOf(1, Short.MIN_VALUE).shortValueExact()); + assertEquals(Short.MAX_VALUE, Decimal64.valueOf(1, Short.MAX_VALUE).shortValueExact()); } @Test @@ -259,14 +264,14 @@ public class Decimal64Test { @Test public void testShortValueExactRange() { - final Decimal64 dec = Decimal64.valueOf(Short.MAX_VALUE + 1); + final Decimal64 dec = Decimal64.valueOf(1, Short.MAX_VALUE + 1); assertThrows(ArithmeticException.class, () -> dec.shortValueExact()); } @Test public void testIntValueExact() { - assertEquals(Integer.MIN_VALUE, Decimal64.valueOf(Integer.MIN_VALUE).intValueExact()); - assertEquals(Integer.MAX_VALUE, Decimal64.valueOf(Integer.MAX_VALUE).intValueExact()); + assertEquals(Integer.MIN_VALUE, Decimal64.valueOf(1, Integer.MIN_VALUE).intValueExact()); + assertEquals(Integer.MAX_VALUE, Decimal64.valueOf(1, Integer.MAX_VALUE).intValueExact()); } @Test @@ -277,7 +282,7 @@ public class Decimal64Test { @Test public void testIntValueExactRange() { - final Decimal64 dec = Decimal64.valueOf(Integer.MAX_VALUE + 1L); + final Decimal64 dec = Decimal64.valueOf(1, Integer.MAX_VALUE + 1L); assertThrows(ArithmeticException.class, () -> dec.intValueExact()); } @@ -287,6 +292,68 @@ public class Decimal64Test { assertThrows(ArithmeticException.class, () -> dec.longValueExact()); } + @Test + public void testLongValueOfBits() { + final Decimal64 dec = Decimal64.valueOf(2, 25552555555L); + assertEquals(2, dec.scale()); + assertEquals(2555255555500L, dec.unscaledValue()); + } + + @Test + public void testLongValueOfNegativeBits() { + final Decimal64 dec = Decimal64.valueOf(2, -25552555555L); + assertEquals(2, dec.scale()); + assertEquals(-2555255555500L, dec.unscaledValue()); + } + + @Test + public void testByteRange() { + for (int i = 1; i <= 16; ++i) { + assertEquals(Byte.MIN_VALUE, Decimal64.valueOf(i, Byte.MIN_VALUE).byteValueExact()); + assertEquals(Byte.MAX_VALUE, Decimal64.valueOf(i, Byte.MAX_VALUE).byteValueExact()); + } + for (int i = 17; i <= 18; ++i) { + int scale = i; + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Byte.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Byte.MAX_VALUE)); + } + } + + @Test + public void testShortRange() { + for (int i = 1; i <= 14; ++i) { + assertEquals(Short.MIN_VALUE, Decimal64.valueOf(i, Short.MIN_VALUE).shortValueExact()); + assertEquals(Short.MAX_VALUE, Decimal64.valueOf(i, Short.MAX_VALUE).shortValueExact()); + } + for (int i = 15; i <= 18; ++i) { + int scale = i; + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Short.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Short.MAX_VALUE)); + } + } + + @Test + public void testIntRange() { + for (int i = 1; i <= 9; ++i) { + assertEquals(Integer.MIN_VALUE, Decimal64.valueOf(i, Integer.MIN_VALUE).intValueExact()); + assertEquals(Integer.MAX_VALUE, Decimal64.valueOf(i, Integer.MAX_VALUE).intValueExact()); + } + for (int i = 10; i <= 18; ++i) { + int scale = i; + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Integer.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Integer.MAX_VALUE)); + } + } + + @Test + public void testLongRange() { + for (int i = 1; i <= 18; ++i) { + int scale = i; + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Long.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> Decimal64.valueOf(scale, Long.MAX_VALUE)); + } + } + private static void assertCanonicalVariants(final String str, final long intPart, final long fracPart, final int digits) { assertCanonicalString(str, intPart, fracPart, digits, false); diff --git a/model/yang-model-ri/src/main/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtil.java b/model/yang-model-ri/src/main/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtil.java index a96815fa0b..e34e7d8e9f 100644 --- a/model/yang-model-ri/src/main/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtil.java +++ b/model/yang-model-ri/src/main/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtil.java @@ -92,7 +92,8 @@ final class NumberUtil { return input; } if (input instanceof Byte || input instanceof Short || input instanceof Integer || input instanceof Long) { - return Decimal64.valueOf(input.longValue()); + // FIXME: this is not right, as we need to know fraction-digits + return Decimal64.valueOf(1, input.longValue()); } return Decimal64.valueOf(input.toString()); diff --git a/model/yang-model-ri/src/test/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtilTest.java b/model/yang-model-ri/src/test/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtilTest.java index 787c8c7c19..791f3dc353 100644 --- a/model/yang-model-ri/src/test/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtilTest.java +++ b/model/yang-model-ri/src/test/java/org/opendaylight/yangtools/yang/model/ri/type/NumberUtilTest.java @@ -44,10 +44,10 @@ public class NumberUtilTest { @Test public void testRangeCoveredForDecimal64() { - final Decimal64 min = Decimal64.valueOf(100.0); - final Decimal64 superMin = Decimal64.valueOf(50.0); - final Decimal64 max = Decimal64.valueOf(200.0); - final Decimal64 superMax = Decimal64.valueOf(300.0); + final Decimal64 min = Decimal64.valueOf("100.0"); + final Decimal64 superMin = Decimal64.valueOf("50.0"); + final Decimal64 max = Decimal64.valueOf("200.0"); + final Decimal64 superMax = Decimal64.valueOf("300.0"); assertTrue(NumberUtil.isRangeCovered(min, max, superMin, superMax)); } @@ -138,7 +138,7 @@ public class NumberUtilTest { @Test public void testConverterToBigDecimal() { - Decimal64 bigDecNum = Decimal64.valueOf(20.0); + final Decimal64 bigDecNum = Decimal64.valueOf("20.0"); final Function numberFunction = NumberUtil.converterTo(Decimal64.class); assertEquals(bigDecNum, numberFunction.apply(bigDecNum)); @@ -146,7 +146,6 @@ public class NumberUtilTest { assertEquals(bigDecNum, numberFunction.apply(intNum)); double doubleNum = 20.0; - bigDecNum = Decimal64.valueOf("20.0"); assertEquals(bigDecNum, numberFunction.apply(doubleNum)); } diff --git a/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/TypedefConstraintsTest.java b/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/TypedefConstraintsTest.java index 33406be696..fb5cf74e7a 100644 --- a/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/TypedefConstraintsTest.java +++ b/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/TypedefConstraintsTest.java @@ -64,8 +64,8 @@ public class TypedefConstraintsTest { assertEquals(1, decRangeConstraints.size()); final Range range = decRangeConstraints.iterator().next(); - assertEquals(Decimal64.valueOf(1.5), range.lowerEndpoint()); - assertEquals(Decimal64.valueOf(5.5), range.upperEndpoint()); + assertEquals(Decimal64.valueOf("1.5"), range.lowerEndpoint()); + assertEquals(Decimal64.valueOf("5.5"), range.upperEndpoint()); assertEquals(TypeDefinitions.DECIMAL64.bindTo(leafDecimal.getQName().getModule()), decType.getQName()); assertNull(decType.getBaseType());