[Native, All platforms] HotFix of the incorrect parsing of long strings to Float and Double (#4492)

### What's done:
- Fixed incorrect logic of String.toFloat() and String.toDouble().
  Long string without any digits were treated as Float or Double:
  "this string does not look as float isn't it?".toFloat() == "Infinity".

- Fixed incorrect parsing of floating point constants "NaN" and "Infinity":
  String values like "NaNPICEZy" or "InfinityN" were treated as valid numbers.

- Merged parsing logic for Double and Float:
  Removed the code duplication, unified methods, made the code more Kotlin-like, not C++-like.

- Updated tests:
  Removed useless tests that checked nothing, updated tests with regression scenarios.
This commit is contained in:
Andrey Kuleshov
2021-07-15 10:47:55 +03:00
committed by GitHub
parent 118889add5
commit 26a71af6b3
3 changed files with 270 additions and 191 deletions
@@ -7,19 +7,133 @@ package runtime.text.parse0
import kotlin.test.*
@Test fun runTest() {
println("false".toBoolean())
println("true".toBoolean())
println("-1".toByte())
println("a".toByte(16))
println("aa".toShort(16))
println("11110".toInt(2))
println("ffffffff".toLong(16))
try {
val x = "ffffffff".toLong(10)
} catch (ne: NumberFormatException) {
println("bad format")
@Test
fun runTest() {
assertEquals(false, "false".toBoolean())
assertEquals(true, "true".toBoolean())
assertEquals(-1, "-1".toByte())
assertEquals(10, "a".toByte(16))
assertEquals(170, "aa".toShort(16))
assertEquals(30, "11110".toInt(2))
assertEquals(4294967295, "ffffffff".toLong(16))
assertFailsWith<NumberFormatException> {
"ffffffff".toLong(10)
}
}
@Test
fun checkDouble() {
// ===== toDouble() parsing =======
assertEquals(0.5, "0.5".toDouble())
assertEquals(-5000000000.0, "-00000000000000000000.5e10".toDouble())
assertEquals(-0.005, "-00000000000000000000.5e-2".toDouble())
assertEquals(50000000000.0, "+5e10".toDouble())
assertEquals(50000000000.0, " +5e10 ".toDouble())
assertEquals(0.052, "+5.2e-2".toDouble())
assertEquals(520.0, "+5.2e2d".toDouble())
assertEquals(0.052, "+5.2e-2d".toDouble())
assertEquals(52340000000.0, "+5.234e+10d".toDouble())
assertEquals(5.234E123, "+5.234e+123d".toDouble())
assertEquals(5.234E123, "+5.234e+123f".toDouble())
assertEquals(5.234E123, "+5.234e+123".toDouble())
assertEquals(5.5, "5.5f".toDouble())
assertEquals(1.0 / 0.0, "+Infinity".toDouble())
assertEquals(1.0 / 0.0, "Infinity".toDouble())
assertEquals(-1.0 / 0.0, "-Infinity".toDouble())
assertTrue("Infinity".toDouble().isInfinite(), "Infinity is expected for parsing Infinity")
assertTrue("+NaN".toDouble().isNaN(), "NaN is expected for parsing +NaN")
assertTrue("NaN".toDouble().isNaN(), "NaN is expected for parsing NaN")
assertTrue("-NaN".toDouble().isNaN(), "NaN is expected for parsing -NaN")
assertFailsWith<NumberFormatException> {
"+-5.0".toDouble()
}
assertFailsWith<NumberFormatException> {
"d".toDouble()
}
assertFailsWith<NumberFormatException> {
"5.5.3e123d".toDouble()
}
// regression of incorrect processing of long lines - such values returned Infinity
assertFailsWith<NumberFormatException> {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".toDouble()
}
assertFailsWith<NumberFormatException> {
"+-my free text with different letters $3213#. e ".toDouble()
}
assertFailsWith<NumberFormatException> {
"eeeeeEEEEEeeeeeee".toDouble()
}
assertFailsWith<NumberFormatException> {
"InfinityN".toDouble()
}
assertFailsWith<NumberFormatException> {
"NaNPICEZy".toDouble()
}
}
@Test
fun checkFloat() {
// ===== toFloat() parsing =======
assertEquals(0.5f, "0.5".toFloat())
assertEquals(-5000000000f, "-00000000000000000000.5e10f".toFloat())
assertEquals(-0.005f, "-00000000000000000000.5e-2f".toFloat())
assertEquals(50000000000f, "+5e10".toFloat())
assertEquals(50000000000f, " +5e10 ".toFloat())
assertEquals(0.052f, "+5.2e-2f".toFloat())
assertEquals(520f, "+5.2e2f".toFloat())
assertEquals(0.052f, "+5.2e-2f".toFloat())
assertEquals(52340000000f, "+5.234e+10f".toFloat())
assertEquals(1.0F / 0.0F, "+5.234e+123f".toFloat())
assertEquals(1.0F / 0.0F, "+Infinity".toFloat())
assertEquals(1.0F / 0.0F, "Infinity".toFloat())
assertEquals(-1.0F / 0.0F, "-Infinity".toFloat())
assertTrue("Infinity".toFloat().isInfinite(), "Infinity is expected for parsing Infinity")
assertTrue("+NaN".toFloat().isNaN(), "NaN is expected for parsing +NaN")
assertTrue("NaN".toFloat().isNaN(), "NaN is expected for parsing NaN")
assertTrue("-NaN".toFloat().isNaN(), "NaN is expected for parsing -NaN")
assertFailsWith<NumberFormatException> {
"+-5.0f".toFloat()
}
assertFailsWith<NumberFormatException> {
"f".toFloat()
}
assertFailsWith<NumberFormatException> {
"5.5.3e123f".toFloat()
}
// regression of incorrect processing of long lines - such values returned Infinity
assertFailsWith<NumberFormatException> {
// should be more than 38 symbols
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".toFloat()
}
assertFailsWith<NumberFormatException> {
// should be more than 38 symbols
"this string is not a numb3r, am I right?????????????".toFloat()
}
assertFailsWith<NumberFormatException> {
// should be more than 38 symbols
"+-my free text with different letters $3213#. e ".toFloat()
}
assertFailsWith<NumberFormatException> {
// should be more than 38 symbols
"eeeeeEEEEEeeeeeee".toFloat()
}
assertFailsWith<NumberFormatException> {
"InfinityN".toFloat()
}
assertFailsWith<NumberFormatException> {
"NaNPICEZy".toFloat()
}
println("0.5".toFloat())
println("2.39".toDouble())
}