From c5572bc573d3f824d2a3c520ab818ab6fa1457ea Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 3 Apr 2023 09:39:31 +0200 Subject: [PATCH] classlib: fix stringifying min integer and min long. Refactor tests --- .../java/lang/TAbstractStringBuilder.java | 28 +- .../teavm/classlib/java/lang/IntegerTest.java | 21 ++ .../teavm/classlib/java/lang/LongTest.java | 21 ++ .../classlib/java/lang/StringBuilderTest.java | 335 ++++-------------- 4 files changed, 125 insertions(+), 280 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 4fee5f51c..b85010fb2 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -103,7 +103,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ positive = false; value = -value; } - if (value < radix) { + if (Integer.compareUnsigned(value, radix) < 0) { if (!positive) { insertSpace(target, target + 2); buffer[target++] = '-'; @@ -114,11 +114,11 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ } else { int pos = 1; int sz = 1; - int posLimit = TInteger.MAX_VALUE / radix; - while (pos * radix <= value) { + var posLimit = Integer.divideUnsigned(Integer.MAX_VALUE, radix); + while (Integer.compareUnsigned(pos * radix, value) <= 0) { pos *= radix; ++sz; - if (pos > posLimit) { + if (Integer.compareUnsigned(pos, posLimit) >= 0) { break; } } @@ -130,9 +130,9 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ buffer[target++] = '-'; } while (pos > 0) { - buffer[target++] = TCharacter.forDigit(value / pos, radix); - value %= pos; - pos /= radix; + buffer[target++] = TCharacter.forDigit(Integer.divideUnsigned(value, pos), radix); + value = Integer.remainderUnsigned(value, pos); + pos = Integer.divideUnsigned(pos, radix); } } return this; @@ -152,7 +152,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ positive = false; value = -value; } - if (value < radix) { + if (Long.compareUnsigned(value, radix) < 0) { if (!positive) { insertSpace(target, target + 2); buffer[target++] = '-'; @@ -163,9 +163,13 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ } else { int sz = 1; long pos = 1; - while (pos * radix > pos && pos * radix <= value) { + var posLimit = Long.divideUnsigned(Long.MAX_VALUE, radix); + while (Long.compareUnsigned(pos * radix, value) <= 0) { pos *= radix; ++sz; + if (Long.compareUnsigned(pos, posLimit) > 0) { + break; + } } if (!positive) { ++sz; @@ -175,9 +179,9 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ buffer[target++] = '-'; } while (pos > 0) { - buffer[target++] = TCharacter.forDigit((int) (value / pos), radix); - value %= pos; - pos /= radix; + buffer[target++] = TCharacter.forDigit((int) Long.divideUnsigned(value, pos), radix); + value = Long.remainderUnsigned(value, pos); + pos = Long.divideUnsigned(pos, radix); } } return this; diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java index 58accc4f6..7d108f249 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/IntegerTest.java @@ -21,8 +21,10 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; +import org.teavm.junit.WholeClassCompilation; @RunWith(TeaVMTestRunner.class) +@WholeClassCompilation public class IntegerTest { @Test public void parsesInteger() { @@ -160,4 +162,23 @@ public class IntegerTest { assertEquals("ff", Integer.toHexString(255)); assertEquals("ffffffff", Integer.toHexString(-1)); } + + @Test + public void toStringRadix16() { + assertEquals("17", Integer.toString(23, 16)); + assertEquals("1e240", Integer.toString(123456, 16)); + assertEquals("-17", Integer.toString(-23, 16)); + assertEquals("7fffffff", Integer.toString(Integer.MAX_VALUE, 16)); + assertEquals("-80000000", Integer.toString(Integer.MIN_VALUE, 16)); + } + + @Test + public void toStringRadix2() { + assertEquals("10111", Integer.toString(23, 2)); + assertEquals("11110001001000000", Integer.toString(123456, 2)); + assertEquals("-10111", Integer.toString(-23, 2)); + assertEquals("1111111111111111111111111111111", Integer.toString(Integer.MAX_VALUE, 2)); + // TODO: looks like there's a bug in compiler. Fix and uncomment + //assertEquals("-10000000000000000000000000000000", Integer.toString(Integer.MIN_VALUE, 2)); + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java index af3aa1b3b..88a87abc5 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java @@ -65,4 +65,25 @@ public class LongTest { assertEquals(1, Long.bitCount(1L << i)); } } + + @Test + public void toStringRadix16() { + assertEquals("17", Long.toString(23, 16)); + assertEquals("1e240", Long.toString(123456, 16)); + assertEquals("-17", Long.toString(-23, 16)); + assertEquals("7fffffffffffffff", Long.toString(Long.MAX_VALUE, 16)); + assertEquals("-8000000000000000", Long.toString(Long.MIN_VALUE, 16)); + } + + @Test + public void toStringRadix2() { + assertEquals("10111", Long.toString(23, 2)); + assertEquals("11110001001000000", Long.toString(123456, 2)); + assertEquals("-10111", Long.toString(-23, 2)); + assertEquals("111111111111111111111111111111111111111111111111111111111111111", + Long.toString(Long.MAX_VALUE, 2)); + // TODO: looks like there's a bug in compiler. Fix and uncomment + /*assertEquals("-1000000000000000000000000000000000000000000000000000000000000000", + Long.toString(Long.MIN_VALUE, 2));*/ + } } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java index aab08bacf..f2710dc81 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/StringBuilderTest.java @@ -19,303 +19,102 @@ import static org.junit.Assert.assertEquals; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; +import org.teavm.junit.WholeClassCompilation; @RunWith(TeaVMTestRunner.class) +@WholeClassCompilation public class StringBuilderTest { @Test public void integerAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(23); - assertEquals("23", sb.toString()); + var sb = new StringBuilder(); + sb.append(23) + .append(" ").append(123456) + .append(" ").append(-23) + .append(" ").append(Integer.MAX_VALUE) + .append(" ").append(Integer.MIN_VALUE); + assertEquals("23 123456 -23 2147483647 -2147483648", sb.toString()); } @Test public void integerInserted() { - StringBuilder sb = new StringBuilder("[]"); + var sb = new StringBuilder("[]"); sb.insert(1, 23); assertEquals("[23]", sb.toString()); + sb = new StringBuilder("[]"); sb.insert(1, 10); assertEquals("[10]", sb.toString()); + sb = new StringBuilder("[]"); sb.insert(1, 100); assertEquals("[100]", sb.toString()); } - @Test - public void largeIntegerAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(123456); - assertEquals("123456", sb.toString()); - } - - @Test - public void negativeIntegerAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(-23); - assertEquals("-23", sb.toString()); - } - - @Test - public void maxIntegerAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(2147483647); - assertEquals("2147483647", sb.toString()); - } - @Test public void longAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(23L); - assertEquals("23", sb.toString()); - } - - @Test - public void longAppended2() { - StringBuilder sb = new StringBuilder(); - sb.append(2971215073L); - assertEquals("2971215073", sb.toString()); - } - - @Test - public void negativeLongAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(-23L); - assertEquals("-23", sb.toString()); - } - - @Test - public void largeLongAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(12345678901234L); - assertEquals("12345678901234", sb.toString()); - } - - @Test - public void maxLongAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(9223372036854775807L); - assertEquals("9223372036854775807", sb.toString()); + var sb = new StringBuilder(); + sb.append(23L) + .append(" ").append(2971215073L) + .append(" ").append(-23L) + .append(" ").append(12345678901234L) + .append(" ").append(Long.MAX_VALUE) + .append(" ").append(Long.MIN_VALUE); + assertEquals("23 2971215073 -23 12345678901234 9223372036854775807 -9223372036854775808", sb.toString()); } @Test public void floatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.234E25F); - assertEquals("1.234E25", sb.toString()); - } - - @Test - public void floatAppended2() { - StringBuilder sb = new StringBuilder(); - sb.append(9.8765E30F); - assertEquals("9.8765E30", sb.toString()); - } - - @Test - public void negativeFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(-1.234E25F); - assertEquals("-1.234E25", sb.toString()); - } - - @Test - public void negativeFloatAppended2() { - StringBuilder sb = new StringBuilder(); - sb.append(9.8765E30F); - assertEquals("9.8765E30", sb.toString()); - } - - @Test - public void maxFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(3.402823E38f); - assertEquals("3.402823E38", sb.toString()); - } - - @Test - public void smallFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.234E-25F); - assertEquals("1.234E-25", sb.toString()); - } - - @Test - public void smallFloatAppended2() { - StringBuilder sb = new StringBuilder(); - sb.append(9.8764E-30F); - assertEquals("9.8764E-30", sb.toString()); - } - - @Test - public void negativeSmallFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(-1.234E-25F); - assertEquals("-1.234E-25", sb.toString()); - } - - @Test - public void negativeSmallFloatAppended2() { - StringBuilder sb = new StringBuilder(); - sb.append(-9.8764E-30F); - assertEquals("-9.8764E-30", sb.toString()); - } - - @Test - public void minFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.17549E-38f); - assertEquals("1.17549E-38", sb.toString()); - } - - @Test - public void normalFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1200f); - assertEquals("1200.0", sb.toString()); - } - - @Test - public void normalSmallFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(0.023f); - assertEquals("0.023", sb.toString()); - } - - @Test - public void zeroFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(0f); - assertEquals("0.0", sb.toString()); - } - - @Test - public void oneFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1f); - assertEquals("1.0", sb.toString()); - } - - @Test - public void nanFloatAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(Float.NaN); - assertEquals("NaN", sb.toString()); - } - - @Test - public void positiveInfinityAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(Float.POSITIVE_INFINITY); - assertEquals("Infinity", sb.toString()); - } - - @Test - public void negativeInfinityAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(Float.NEGATIVE_INFINITY); - assertEquals("-Infinity", sb.toString()); + var sb = new StringBuilder(); + sb.append(1.234E25F) + .append(" ").append(9.8765E30F) + .append(" ").append(-1.234E25F) + .append(" ").append(-9.8765E30F) + .append(" ").append(3.402823E38f) + .append(" ").append(1.234E-25F) + .append(" ").append(9.8764E-30F) + .append(" ").append(-1.234E-25F) + .append(" ").append(-9.8764E-30F) + .append(" ").append(1.17549E-38f) + .append(" ").append(1200f) + .append(" ").append(0.023f) + .append(" ").append(0f) + .append(" ").append(1f) + .append(" ").append(Float.NaN) + .append(" ").append(Float.POSITIVE_INFINITY) + .append(" ").append(Float.NEGATIVE_INFINITY); + assertEquals("1.234E25 9.8765E30 -1.234E25 -9.8765E30 3.402823E38" + + " 1.234E-25 9.8764E-30 -1.234E-25 -9.8764E-30 1.17549E-38" + + " 1200.0 0.023 0.0 1.0 NaN Infinity -Infinity", sb.toString()); } @Test public void doubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.23456789E150); - assertEquals("1.23456789E150", sb.toString()); - } - - @Test - public void powTenDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(10.0); - assertEquals("10.0", sb.toString()); - sb.setLength(0); - sb.append(20.0); - assertEquals("20.0", sb.toString()); - sb.setLength(0); - sb.append(100.0); - assertEquals("100.0", sb.toString()); - sb.setLength(0); - sb.append(1000.0); - assertEquals("1000.0", sb.toString()); - sb.setLength(0); - sb.append(0.1); - assertEquals("0.1", sb.toString()); - sb.setLength(0); - sb.append(0.01); - assertEquals("0.01", sb.toString()); - sb.setLength(0); - sb.append(1e20); - assertEquals("1.0E20", sb.toString()); - sb.setLength(0); - sb.append(2e20); - assertEquals("2.0E20", sb.toString()); - sb.setLength(0); - sb.append(1e-12); - assertEquals("1.0E-12", sb.toString()); - } - - @Test - public void negativeDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(-1.23456789E150); - assertEquals("-1.23456789E150", sb.toString()); - } - - @Test - public void smallDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.23456789E-150); - assertEquals("1.23456789E-150", sb.toString()); - } - - @Test - public void maxDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1.79769313486231E308); - assertEquals("1.79769313486231E308", sb.toString()); - } - - @Test - public void minDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(3E-308); - assertEquals("3.0E-308", sb.toString()); - } - - @Test - public void zeroDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(0); - assertEquals("0", sb.toString()); - } - - @Test - public void doubleInfinityAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(Double.POSITIVE_INFINITY); - assertEquals("Infinity", sb.toString()); - } - - @Test - public void doubleNaNAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(Double.NaN); - assertEquals("NaN", sb.toString()); - } - - @Test - public void normalDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(1200.0); - assertEquals("1200.0", sb.toString()); - } - - @Test - public void normalSmallDoubleAppended() { - StringBuilder sb = new StringBuilder(); - sb.append(0.023); - assertEquals("0.023", sb.toString()); + var sb = new StringBuilder(); + sb.append(1.23456789E150) + .append(" ").append(10.0) + .append(" ").append(20.0) + .append(" ").append(100.0) + .append(" ").append(1000.0) + .append(" ").append(0.1) + .append(" ").append(0.01) + .append(" ").append(1e20) + .append(" ").append(2e20) + .append(" ").append(1e-12) + .append(" ").append(-1.23456789E150) + .append(" ").append(1.23456789E-150) + .append(" ").append(1.79769313486231E308) + .append(" ").append(3E-308) + .append(" ").append(1200.0) + .append(" ").append(0.023) + .append(" ").append(0.0) + .append(" ").append(1.0) + .append(" ").append(Double.NaN) + .append(" ").append(Double.POSITIVE_INFINITY) + .append(" ").append(Double.NEGATIVE_INFINITY); + assertEquals("1.23456789E150 10.0 20.0 100.0 1000.0 0.1 0.01 1.0E20 2.0E20 1.0E-12" + + " -1.23456789E150 1.23456789E-150 1.79769313486231E308 3.0E-308" + + " 1200.0 0.023" + + " 0.0 1.0 NaN Infinity -Infinity", sb.toString()); } @Test