From 2e527433f8d9342b8143adf19300603171f961a5 Mon Sep 17 00:00:00 2001 From: Alexandr Gorshenin Date: Tue, 24 Dec 2024 16:31:34 +0000 Subject: [PATCH] Update tests of DecimalType/DecimalValue --- .../ydb/table/integration/ValuesReadTest.java | 66 ++++++++ .../ydb/table/values/DecimalValueTest.java | 143 +++++++++++++----- 2 files changed, 174 insertions(+), 35 deletions(-) diff --git a/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java b/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java index a5e8400b..4141275f 100644 --- a/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java +++ b/table/src/test/java/tech/ydb/table/integration/ValuesReadTest.java @@ -17,6 +17,8 @@ import tech.ydb.table.result.ValueReader; import tech.ydb.table.rpc.grpc.GrpcTableRpc; import tech.ydb.table.transaction.TxControl; +import tech.ydb.table.values.DecimalType; +import tech.ydb.table.values.DecimalValue; import tech.ydb.table.values.NullType; import tech.ydb.table.values.NullValue; import tech.ydb.table.values.PrimitiveType; @@ -157,4 +159,68 @@ public void timestampReadTest() { Assert.assertEquals("Invalid value \"2106-01-01T00:00:00.000000Z\" for type Timestamp", issues[1].getMessage()); } + + @Test + public void decimalReadTest() { + DataQueryResult result = CTX.supplyResult( + s -> s.executeDataQuery("SELECT " + + "Decimal('9', 1, 0) AS d1, " + + "Decimal('-9', 1, 0) AS d2, " + + "Decimal('99999999999999999999999999999999999', 35, 0) AS d3, " + + "Decimal('-99999999999999999999999999999999999', 35, 0) AS d4, " + + "Decimal('9999999999999999999999999.9999999999', 35, 10) AS d5, " + + "Decimal('-9999999999999999999999999.9999999999', 35, 10) AS d6, " + + "Decimal('9.6', 1, 0) AS d7, " + + "Decimal('-9.6', 1, 0) AS d8, " + + "Decimal('99999999999999999999999999999999999.6', 35, 0) AS d9, " + + "Decimal('-99999999999999999999999999999999999.6', 35, 0) AS d10, " + + "Decimal('9999999999999999999999999.99999999996', 35, 10) AS d11, " + + "Decimal('-9999999999999999999999999.99999999996', 35, 10) AS d12;", + TxControl.serializableRw() + ) + ).join().getValue(); + + Assert.assertEquals(1, result.getResultSetCount()); + + ResultSetReader rs = result.getResultSet(0); + Assert.assertTrue(rs.next()); + + DecimalValue d1 = rs.getColumn("d1").getDecimal(); + DecimalValue d2 = rs.getColumn("d2").getDecimal(); + DecimalValue d3 = rs.getColumn("d3").getDecimal(); + DecimalValue d4 = rs.getColumn("d4").getDecimal(); + DecimalValue d5 = rs.getColumn("d5").getDecimal(); + DecimalValue d6 = rs.getColumn("d6").getDecimal(); + DecimalValue d7 = rs.getColumn("d7").getDecimal(); + DecimalValue d8 = rs.getColumn("d8").getDecimal(); + DecimalValue d9 = rs.getColumn("d9").getDecimal(); + DecimalValue d10 = rs.getColumn("d10").getDecimal(); + DecimalValue d11 = rs.getColumn("d11").getDecimal(); + DecimalValue d12 = rs.getColumn("d12").getDecimal(); + + Assert.assertEquals(DecimalType.of(1).newValue(9), d1); + Assert.assertEquals(DecimalType.of(1).newValue(-9), d2); + Assert.assertEquals(DecimalType.of(35).newValue("99999999999999999999999999999999999"), d3); + Assert.assertEquals(DecimalType.of(35).newValue("-99999999999999999999999999999999999"), d4); + Assert.assertEquals(DecimalType.of(35, 10).newValue("9999999999999999999999999.9999999999"), d5); + Assert.assertEquals(DecimalType.of(35, 10).newValue("-9999999999999999999999999.9999999999"), d6); + + Assert.assertEquals(DecimalType.of(1).getInf(), d7); + Assert.assertEquals(DecimalType.of(1).getNegInf(), d8); + Assert.assertEquals(DecimalType.of(35).getInf(), d9); + Assert.assertEquals(DecimalType.of(35).getNegInf(), d10); + Assert.assertEquals(DecimalType.of(35, 10).getInf(), d11); + Assert.assertEquals(DecimalType.of(35, 10).getNegInf(), d12); + + // All infinity values have the same high & low parts + Assert.assertEquals(d7.getHigh(), d9.getHigh()); + Assert.assertEquals(d7.getHigh(), d11.getHigh()); + Assert.assertEquals(d7.getLow(), d9.getLow()); + Assert.assertEquals(d7.getLow(), d11.getLow()); + + Assert.assertEquals(d8.getHigh(), d10.getHigh()); + Assert.assertEquals(d8.getHigh(), d12.getHigh()); + Assert.assertEquals(d8.getLow(), d10.getLow()); + Assert.assertEquals(d8.getLow(), d12.getLow()); + } } diff --git a/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java b/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java index 0768d790..a8debfce 100644 --- a/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java +++ b/table/src/test/java/tech/ydb/table/values/DecimalValueTest.java @@ -67,35 +67,35 @@ public void bigDecimalConv() { @Test public void contract() { - DecimalType type = DecimalType.of(13, 2); + DecimalType type = DecimalType.of(20, 2); DecimalValue value = DecimalValue.fromBits(type, 0x0001, 0x0002); - Assert.assertEquals(DecimalType.of(13, 2), value.getType()); + Assert.assertEquals(DecimalType.of(20, 2), value.getType()); Assert.assertEquals(0x0001, value.getHigh()); Assert.assertEquals(0x0002, value.getLow()); // equals Assert.assertEquals(value, DecimalValue.fromBits(type, 0x0001, 0x0002)); - Assert.assertEquals(value, DecimalValue.fromBits(DecimalType.of(13, 2), 0x0001, 0x0002)); + Assert.assertEquals(value, DecimalValue.fromBits(DecimalType.of(20, 2), 0x0001, 0x0002)); Assert.assertNotEquals(value, DecimalValue.fromBits(type, 0x0001, 0x0003)); Assert.assertNotEquals(value, DecimalValue.fromBits(type, 0x0002, 0x0002)); - Assert.assertNotEquals(value, DecimalValue.fromBits(DecimalType.of(12, 2), 0x0001, 0x0002)); - Assert.assertNotEquals(value, DecimalValue.fromBits(DecimalType.of(13, 1), 0x0001, 0x0002)); + Assert.assertNotEquals(value, DecimalValue.fromBits(DecimalType.of(21, 2), 0x0001, 0x0002)); + Assert.assertNotEquals(value, DecimalValue.fromBits(DecimalType.of(20, 1), 0x0001, 0x0002)); // hashCode Assert.assertEquals(value.hashCode(), DecimalValue.fromBits(type, 0x0001, 0x0002).hashCode()); - Assert.assertEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(13, 2), 0x0001, 0x0002).hashCode()); + Assert.assertEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(20, 2), 0x0001, 0x0002).hashCode()); Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(type, 0x0001, 0x0003).hashCode()); Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(type, 0x0002, 0x0002).hashCode()); - Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(12, 2), 0x0001, 0x0002).hashCode()); - Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(13, 1), 0x0001, 0x0002).hashCode()); + Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(21, 2), 0x0001, 0x0002).hashCode()); + Assert.assertNotEquals(value.hashCode(), DecimalValue.fromBits(DecimalType.of(20, 1), 0x0001, 0x0002).hashCode()); } @Test public void protobuf() { - DecimalType type = DecimalType.of(13, 2); + DecimalType type = DecimalType.of(20, 2); DecimalValue value = DecimalValue.fromBits(type, 0x0001, 0x0002); ValueProtos.Value valuePb = value.toPb(); @@ -128,11 +128,83 @@ public void inf() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isInf()); Assert.assertFalse(value.isNegative()); - Assert.assertEquals(DecimalValue.INF, value); + Assert.assertEquals(type.getInf(), value); inf = inf.add(k); } } + private void assertIsValid(DecimalValue v) { + Assert.assertFalse("Non expected Nan for " + v, v.isNan()); + Assert.assertFalse("Non expected Inf for " + v, v.isInf()); + Assert.assertFalse("Non expected -Inf for " + v, v.isNegativeInf()); + } + + private void assertIsNan(DecimalValue v) { + Assert.assertTrue("Expected Nan for " + v, v.isNan()); + Assert.assertFalse("Non expected Inf for " + v, v.isInf()); + Assert.assertFalse("Non expected -Inf for " + v, v.isNegativeInf()); + + Assert.assertEquals(DecimalValue.NAN_LOW, v.getLow()); + Assert.assertEquals(DecimalValue.NAN_HIGH, v.getHigh()); + } + + private void assertIsInf(DecimalValue v) { + Assert.assertFalse("Non expected Nan for " + v, v.isNan()); + Assert.assertTrue("Expected Inf for " + v, v.isInf()); + Assert.assertFalse("Non expected -Inf for " + v, v.isNegativeInf()); + + Assert.assertEquals(DecimalValue.INF_LOW, v.getLow()); + Assert.assertEquals(DecimalValue.INF_HIGH, v.getHigh()); + } + + private void assertIsNegInf(DecimalValue v) { + Assert.assertFalse("Non expected Nan for " + v, v.isNan()); + Assert.assertFalse("Non expected Inf for " + v, v.isInf()); + Assert.assertTrue("Expected -Inf for " + v, v.isNegativeInf()); + + Assert.assertEquals(DecimalValue.NEG_INF_LOW, v.getLow()); + Assert.assertEquals(DecimalValue.NEG_INF_HIGH, v.getHigh()); + } + + @Test + public void allTypeInfiniteAndNan() { + BigInteger inf = BigInteger.ONE; + BigInteger nan = new BigInteger("100000000000000000000000000000000001"); + int[] scales = new int[] { 1, 9, 35 }; + for (int precision = 1; precision <= DecimalType.MAX_PRECISION; precision++) { + inf = inf.multiply(BigInteger.TEN); + + DecimalType type = DecimalType.of(precision); + + assertIsInf(type.newValue(inf)); + assertIsNegInf(type.newValue(inf.negate())); + assertIsNan(type.newValue(nan)); + + assertIsValid(type.newValue(inf.subtract(BigInteger.ONE))); + assertIsValid(type.newValue(inf.negate().add(BigInteger.ONE))); + + for (int scale : scales) { + if (scale > precision) { + continue; + } + + DecimalType scaled = DecimalType.of(precision, scale); + BigDecimal scaledInf = new BigDecimal(inf, scale); + BigDecimal scaledNan = new BigDecimal(nan, scale); + + System.out.println("Nan for " + scaled + " -> " + scaledNan); + + assertIsInf(scaled.newValue(scaledInf)); + assertIsNegInf(scaled.newValue(scaledInf.negate())); + + assertIsValid(scaled.newValue(scaledInf.subtract(BigDecimal.valueOf(1, scale)))); + assertIsValid(scaled.newValue(scaledInf.negate().add(BigDecimal.valueOf(1, scale)))); + + assertIsNan(scaled.newValue(scaledNan)); + } + } + } + @Test public void infDefaulttype() { DecimalType type = DecimalType.getDefault(); @@ -143,7 +215,7 @@ public void infDefaulttype() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isInf()); Assert.assertFalse(value.isNegative()); - Assert.assertNotEquals(DecimalValue.INF, value); + Assert.assertEquals(type.getInf(), value); inf = inf.add(k); } } @@ -158,7 +230,7 @@ public void negativeInf() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isNegativeInf()); Assert.assertTrue(value.isNegative()); - Assert.assertEquals(DecimalValue.NEG_INF, value); + Assert.assertEquals(type.getNegInf(), value); inf = inf.subtract(k); } } @@ -173,7 +245,7 @@ public void negativeInfDefaultType() { DecimalValue value = type.newValue(inf); Assert.assertTrue(value.isNegativeInf()); Assert.assertTrue(value.isNegative()); - Assert.assertNotEquals(DecimalValue.NEG_INF, value); + Assert.assertEquals(type.getNegInf(), value); inf = inf.subtract(k); } } @@ -258,7 +330,7 @@ public void ofString() { @Test public void ofUnsigned() { - DecimalType t = DecimalType.getDefault(); + DecimalType t = DecimalType.of(31, 9); String zeros = "." + String.join("", Collections.nCopies(t.getScale(), "0")); Assert.assertTrue(t.newValueUnsigned(0).isZero()); @@ -278,7 +350,7 @@ public void ofUnsigned() { @Test public void ofLong() { - DecimalType t = DecimalType.getDefault(); + DecimalType t = DecimalType.of(31, 9); String zeros = "." + String.join("", Collections.nCopies(t.getScale(), "0")); Assert.assertTrue(t.newValue(0).isZero()); @@ -575,7 +647,7 @@ public void toUnscaledBigInteger() { // (2) positive numbers: 1, 12, 123, ... String s = ""; - for (int i = 1; i < DecimalType.MAX_PRECISION; i++) { + for (int i = 1; i < t.getPrecision(); i++) { s += Integer.toString(i % 10); BigInteger value = new BigInteger(s); Assert.assertEquals(value, t.newValueUnscaled(value).toUnscaledBigInteger()); @@ -583,7 +655,7 @@ public void toUnscaledBigInteger() { // (3) negative numbers: -1, -12, -123, ... s = "-"; - for (int i = 1; i < DecimalType.MAX_PRECISION; i++) { + for (int i = 1; i < t.getPrecision(); i++) { s += Integer.toString(i % 10); BigInteger value = new BigInteger(s); Assert.assertEquals(value, t.newValueUnscaled(value).toUnscaledBigInteger()); @@ -591,9 +663,9 @@ public void toUnscaledBigInteger() { // (4) -inf, +inf, nan BigInteger inf = BigInteger.TEN.pow(DecimalType.MAX_PRECISION); - Assert.assertEquals(DecimalValue.INF.toUnscaledBigInteger(), inf); - Assert.assertEquals(DecimalValue.NEG_INF.toUnscaledBigInteger(), inf.negate()); - Assert.assertEquals(DecimalValue.NAN.toUnscaledBigInteger(), inf.add(BigInteger.ONE)); + Assert.assertEquals(t.getInf().toUnscaledBigInteger(), inf); + Assert.assertEquals(t.getNegInf().toUnscaledBigInteger(), inf.negate()); + Assert.assertEquals(t.getNaN().toUnscaledBigInteger(), inf.add(BigInteger.ONE)); } @Test @@ -627,18 +699,19 @@ public void toBigInteger() { // (4) -inf, +inf, nan BigInteger inf = BigInteger.TEN.pow(DecimalType.MAX_PRECISION); - Assert.assertEquals(DecimalValue.INF.toBigInteger(), inf); - Assert.assertEquals(DecimalValue.NEG_INF.toBigInteger(), inf.negate()); - Assert.assertEquals(DecimalValue.NAN.toBigInteger(), inf.add(BigInteger.ONE)); + Assert.assertEquals(t.getInf().toBigInteger(), inf); + Assert.assertEquals(t.getNegInf().toBigInteger(), inf.negate()); + Assert.assertEquals(t.getNaN().toBigInteger(), inf.add(BigInteger.ONE)); } @Test public void toBigDecimal() { // (1) special values - BigDecimal inf = BigDecimal.TEN.pow(DecimalType.MAX_PRECISION); - Assert.assertEquals(DecimalValue.INF.toBigDecimal(), inf); - Assert.assertEquals(DecimalValue.NEG_INF.toBigDecimal(), inf.negate()); - Assert.assertEquals(DecimalValue.NAN.toBigDecimal(), inf.add(BigDecimal.ONE)); + BigDecimal inf = BigDecimal.ONE.scaleByPowerOfTen(DecimalType.MAX_PRECISION); + DecimalType type = DecimalType.getDefault(); + Assert.assertEquals(type.getInf().toBigDecimal(), inf.setScale(type.getScale())); + Assert.assertEquals(type.getNegInf().toBigDecimal(), inf.negate().setScale(type.getScale())); + Assert.assertEquals(type.getNaN().toBigDecimal(), inf.add(BigDecimal.ONE).setScale(type.getScale())); // (2) positive numbers Assert.assertEquals(newDecimal(1234567890L, 0).toBigDecimal(), BigDecimal.valueOf(1234567890L, 0)); @@ -682,30 +755,30 @@ public void toUnscaledString() { // (2) positive numbers: 1, 12, 123, ... String s = ""; - for (int i = 1; i < DecimalType.MAX_PRECISION; i++) { + for (int i = 1; i < t.getPrecision(); i++) { s += Integer.toString(i % 10); Assert.assertEquals(s, t.newValueUnscaled(new BigInteger(s)).toUnscaledString()); } // (3) negative numbers: -1, -12, -123, ... s = "-"; - for (int i = 1; i < DecimalType.MAX_PRECISION; i++) { + for (int i = 1; i < t.getPrecision(); i++) { s += Integer.toString(i % 10); Assert.assertEquals(s, t.newValueUnscaled(new BigInteger(s)).toUnscaledString()); } // (4) -inf, +inf, nan - Assert.assertEquals("100000000000000000000000000000000000", DecimalValue.INF.toUnscaledString()); // 10^35 - Assert.assertEquals("-100000000000000000000000000000000000", DecimalValue.NEG_INF.toUnscaledString()); // -10^35 - Assert.assertEquals("100000000000000000000000000000000001", DecimalValue.NAN.toUnscaledString()); // 10^35 + 1 + Assert.assertEquals("100000000000000000000000000000000000", t.getInf().toUnscaledString()); // 10^35 + Assert.assertEquals("-100000000000000000000000000000000000", t.getNegInf().toUnscaledString()); // -10^35 + Assert.assertEquals("100000000000000000000000000000000001", t.getNaN().toUnscaledString()); // 10^35 + 1 } @Test public void toStringTest() { // (1) special values - Assert.assertEquals("inf", DecimalValue.INF.toString()); - Assert.assertEquals("-inf", DecimalValue.NEG_INF.toString()); - Assert.assertEquals("nan", DecimalValue.NAN.toString()); + Assert.assertEquals("inf", DecimalType.getDefault().getInf().toString()); + Assert.assertEquals("-inf", DecimalType.getDefault().getNegInf().toString()); + Assert.assertEquals("nan", DecimalType.getDefault().getNaN().toString()); // (2) positive numbers Assert.assertEquals("1234567890", newDecimal(1234567890L, 0).toString());