From d88d2cb05805782aec8629e2d636fb6415bb6270 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Tue, 25 Feb 2020 21:29:56 +0300 Subject: [PATCH] Test new Double/Float constants Split test expectations based on actual support of enforced Float range KT-29182, KT-13887 --- libraries/stdlib/common/test/testUtils.kt | 4 +- .../js-v1/test/core/BuiltinCompanionJsTest.kt | 2 - libraries/stdlib/js/test/core/testUtils.kt | 5 +- libraries/stdlib/jvm/test/testUtilsJVM.kt | 4 +- libraries/stdlib/test/numbers/NumbersTest.kt | 50 +++++++++++++++++-- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/libraries/stdlib/common/test/testUtils.kt b/libraries/stdlib/common/test/testUtils.kt index ee11d89a8dc..0a24e2d119a 100644 --- a/libraries/stdlib/common/test/testUtils.kt +++ b/libraries/stdlib/common/test/testUtils.kt @@ -12,4 +12,6 @@ internal expect fun String.removeLeadingPlusOnJava6(): String internal expect inline fun testOnNonJvm6And7(f: () -> Unit) public expect fun testOnJvm(action: () -> Unit) -public expect fun testOnJs(action: () -> Unit) \ No newline at end of file +public expect fun testOnJs(action: () -> Unit) + +public expect val isFloat32RangeEnforced: Boolean \ No newline at end of file diff --git a/libraries/stdlib/js-v1/test/core/BuiltinCompanionJsTest.kt b/libraries/stdlib/js-v1/test/core/BuiltinCompanionJsTest.kt index 8077b17e70a..f2f5095cc40 100644 --- a/libraries/stdlib/js-v1/test/core/BuiltinCompanionJsTest.kt +++ b/libraries/stdlib/js-v1/test/core/BuiltinCompanionJsTest.kt @@ -22,8 +22,6 @@ class BuiltinCompanionJsTest { } @Test fun floatMinMaxValues() { - assertEquals(js("Number.MIN_VALUE"), Float.MIN_VALUE) - assertEquals(js("Number.MAX_VALUE"), Float.MAX_VALUE) assertEquals(js("Number.POSITIVE_INFINITY"), Float.POSITIVE_INFINITY) assertEquals(js("Number.NEGATIVE_INFINITY"), Float.NEGATIVE_INFINITY) } diff --git a/libraries/stdlib/js/test/core/testUtils.kt b/libraries/stdlib/js/test/core/testUtils.kt index fdbd9bac25d..a54215597e9 100644 --- a/libraries/stdlib/js/test/core/testUtils.kt +++ b/libraries/stdlib/js/test/core/testUtils.kt @@ -20,4 +20,7 @@ internal actual inline fun testOnNonJvm6And7(f: () -> Unit) { public actual fun testOnJvm(action: () -> Unit) { } -public actual fun testOnJs(action: () -> Unit) = action() \ No newline at end of file +public actual fun testOnJs(action: () -> Unit) = action() + +// TODO: should be true at least in JS IR after implementing KT-24975 +public actual val isFloat32RangeEnforced: Boolean = false \ No newline at end of file diff --git a/libraries/stdlib/jvm/test/testUtilsJVM.kt b/libraries/stdlib/jvm/test/testUtilsJVM.kt index 6fe3b763d57..42d783866f2 100644 --- a/libraries/stdlib/jvm/test/testUtilsJVM.kt +++ b/libraries/stdlib/jvm/test/testUtilsJVM.kt @@ -30,4 +30,6 @@ public actual fun testOnJvm(action: () -> Unit) = action() public actual fun testOnJs(action: () -> Unit) {} @Suppress("HasPlatformType", "UNCHECKED_CAST") -public fun platformNull() = Collections.singletonList(null as T).first() \ No newline at end of file +public fun platformNull() = Collections.singletonList(null as T).first() + +public actual val isFloat32RangeEnforced: Boolean = true \ No newline at end of file diff --git a/libraries/stdlib/test/numbers/NumbersTest.kt b/libraries/stdlib/test/numbers/NumbersTest.kt index 5a5f862629b..3dcb4b376bb 100644 --- a/libraries/stdlib/test/numbers/NumbersTest.kt +++ b/libraries/stdlib/test/numbers/NumbersTest.kt @@ -5,6 +5,7 @@ package test.numbers +import test.isFloat32RangeEnforced import kotlin.random.Random import kotlin.test.* @@ -20,6 +21,13 @@ object NumbersTestConstants { public const val longMinSucc: Long = Long.MIN_VALUE + 1L public const val longMaxPred: Long = Long.MAX_VALUE - 1L + + public const val doubleMaxHalf: Double = Double.MAX_VALUE / 2 + public const val doubleMinTwice: Double = Double.MIN_VALUE * 2 + + public const val floatMaxHalf: Float = Float.MAX_VALUE / 2 + public const val floatMinTwice: Float = Float.MIN_VALUE * 2 + } class NumbersTest { @@ -28,6 +36,8 @@ class NumbersTest { var oneS: Short = 1 var oneB: Byte = 1 + var two: Int = 2 + @Test fun intMinMaxValues() { assertTrue(Int.MIN_VALUE < 0) assertTrue(Int.MAX_VALUE > 0) @@ -80,6 +90,9 @@ class NumbersTest { assertTrue(Double.MIN_VALUE > 0) assertTrue(Double.MAX_VALUE > 0) + assertEquals(NumbersTestConstants.doubleMaxHalf, Double.MAX_VALUE / two) + assertEquals(NumbersTestConstants.doubleMinTwice, Double.MIN_VALUE * two) + // overflow behavior expect(Double.POSITIVE_INFINITY) { Double.MAX_VALUE * 2 } expect(Double.NEGATIVE_INFINITY) {-Double.MAX_VALUE * 2 } @@ -90,10 +103,20 @@ class NumbersTest { assertTrue(Float.MIN_VALUE > 0) assertTrue(Float.MAX_VALUE > 0) + if (isFloat32RangeEnforced) { + assertEquals(NumbersTestConstants.floatMaxHalf, Float.MAX_VALUE / two) + assertEquals(NumbersTestConstants.floatMinTwice, Float.MIN_VALUE * two) + } else { + assertAlmostEquals(NumbersTestConstants.floatMaxHalf, Float.MAX_VALUE / two, 0.0000001 * NumbersTestConstants.floatMaxHalf) + assertAlmostEquals(NumbersTestConstants.floatMinTwice, Float.MIN_VALUE * two, 0.0000001 * NumbersTestConstants.floatMinTwice) + } + // overflow behavior - expect(Float.POSITIVE_INFINITY) { Float.MAX_VALUE * 2 } - expect(Float.NEGATIVE_INFINITY) { -Float.MAX_VALUE * 2 } - expect(0.0F) { Float.MIN_VALUE / 2.0F } + if (isFloat32RangeEnforced) { + expect(Float.POSITIVE_INFINITY) { Float.MAX_VALUE * 2 } + expect(Float.NEGATIVE_INFINITY) { -Float.MAX_VALUE * 2 } + expect(0.0F) { Float.MIN_VALUE / 2.0F } + } } @Test fun charMinMaxValues() { @@ -162,13 +185,27 @@ class NumbersTest { @Test fun floatToBits() { val PI_F = kotlin.math.PI.toFloat() assertEquals(0x40490fdb, PI_F.toBits()) - assertAlmostEquals(PI_F, Float.fromBits(0x40490fdb)) // PI_F is actually Double in JS - // -Float.MAX_VALUE, Float.MAX_VALUE, -Float.MIN_VALUE, Float.MIN_VALUE: overflow or underflow + if (isFloat32RangeEnforced) { + assertEquals(PI_F, Float.fromBits(0x40490fdb)) + } else { + assertAlmostEquals(PI_F, Float.fromBits(0x40490fdb)) // PI_F is actually Double in JS + } for (value in listOf(Float.NEGATIVE_INFINITY, -1.0F, -0.0F, 0.0F, Float.POSITIVE_INFINITY, 1.0F)) { assertEquals(value, Float.fromBits(value.toBits())) assertEquals(value, Float.fromBits(value.toRawBits())) } + for (value in listOf(-Float.MAX_VALUE, Float.MAX_VALUE, -Float.MIN_VALUE, Float.MIN_VALUE)) { + if (isFloat32RangeEnforced) { + assertEquals(value, Float.fromBits(value.toBits())) + assertEquals(value, Float.fromBits(value.toRawBits())) + } else { + val tolerance = if (kotlin.math.abs(value) == Float.MIN_VALUE) 0.001 * value else 0.0000001 * value + assertAlmostEquals(value, Float.fromBits(value.toBits()), tolerance) + assertAlmostEquals(value, Float.fromBits(value.toRawBits()), tolerance) + } + } + assertTrue(Float.NaN.toBits().let(Float.Companion::fromBits).isNaN()) assertTrue(Float.NaN.toRawBits().let { Float.fromBits(it) }.isNaN()) @@ -195,6 +232,9 @@ class NumbersTest { testSizes(Short, Short.SIZE_BYTES, Short.SIZE_BITS, 2) testSizes(Int, Int.SIZE_BYTES, Int.SIZE_BITS, 4) testSizes(Long, Long.SIZE_BYTES, Long.SIZE_BITS, 8) + + testSizes(Float, Float.SIZE_BYTES, Float.SIZE_BITS, 4) + testSizes(Double, Double.SIZE_BYTES, Double.SIZE_BITS, 8) testSizes(UByte, UByte.SIZE_BYTES, UByte.SIZE_BITS, 1) testSizes(UShort, UShort.SIZE_BYTES, UShort.SIZE_BITS, 2)