From 902519a26bd0546157f0d03afbe77eaff477a658 Mon Sep 17 00:00:00 2001 From: Pavel Punegov <32519625+PavelPunegov@users.noreply.github.com> Date: Wed, 10 Jan 2018 14:57:04 +0300 Subject: [PATCH] Check all whitespace characters according to Unicode standard --- backend.native/tests/build.gradle | 5 +++ backend.native/tests/runtime/text/trim.kt | 49 +++++++++++++++++++++++ runtime/src/main/cpp/KString.cpp | 25 +++--------- 3 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 backend.native/tests/runtime/text/trim.kt diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index c87f0721f54..7ffd3dd2ca4 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1512,6 +1512,11 @@ task to_string0(type: RunKonanTest) { source = "runtime/text/to_string0.kt" } +task trim(type: RunKonanTest) { + goldValue = "OK\n" + source = "runtime/text/trim.kt" +} + task chars0(type: RunKonanTest) { expectedFail = (project.testTarget == 'wasm32') // Uses exceptions. source = "runtime/text/chars0.kt" diff --git a/backend.native/tests/runtime/text/trim.kt b/backend.native/tests/runtime/text/trim.kt new file mode 100644 index 00000000000..be6251d3ffd --- /dev/null +++ b/backend.native/tests/runtime/text/trim.kt @@ -0,0 +1,49 @@ +package runtime.text.trim + +import kotlin.test.* + +/** + * Tests correct conversions of floats/doubles along with trimming of leading/trailing whitespaces. + * String.trim() trims all whitespaces (see kotlin/text/Strings.kt) while String.toFloat() uses + * the same approach as java.lang.Float.parseFloat() + */ +@Test fun runTest() { + convertToFloatingPoint() + convertWithWhitespaces() + trimWhitespaces() + + println("OK") +} + +private fun convertToFloatingPoint() { + assertEquals(expected = 3.14F, actual = " 3.14 ".toFloat(), message = "String float should be trimmed") + assertEquals(expected = 3.14, actual = " 3.14 ".toDouble(), message = "String double should be trimmed") + assertEquals(expected = 7.15F, actual = "\u0019 7.15 ".toFloat(), message = "String float should be trimmed") + assertEquals(expected = 42.3, actual = "\n 42.3 ".toDouble(), message = "String double should be trimmed") +} + +private fun convertWithWhitespaces() { + val s = "\u0009 \u000A 2.71 \u000D" + assertEquals(expected = 2.71F, actual = s.toFloat(), + message = "String should be cleared of LF, CR, TAB and converted to Float") + assertEquals(expected = 2.71, actual = s.toDouble(), + message = "String should be cleared of LF, CR, TAB and converted to Double") + + // Special symbols should not be trimmed during String to Float/Double conversion + assertFailsWith { "\u202F3.14".toFloat() } + assertFailsWith { "\u20293.14".toDouble() } + assertFailsWith { "3.14\u200B".toDouble() } + assertFailsWith { "3.14\u200B ABC".toDouble() } +} + +private fun trimWhitespaces() { + assertEquals(expected = "String", actual = " String".trim(), message = "Trim leading spaces") + assertEquals(expected = "String ", actual = " String ".trimStart(), message = "Trim start") + assertEquals(expected = " String", actual = " String \t ".trimEnd(), message = "Trim end") + + assertEquals(expected = "String", actual = "\u0020 \u202FString\u2028\u2029".trim(), + message = "Trim special whitespaces") + assertEquals(expected = "\u1FFFString", actual = "\u0085 \u1FFFString".trim(), + message = "Trim special whitespace but should left a unicode symbol") + assertEquals(expected = "String\tSTR", actual = " \nString\tSTR ".trim(), message = "Trim newline") +} diff --git a/runtime/src/main/cpp/KString.cpp b/runtime/src/main/cpp/KString.cpp index 5dcd9be4920..e00e690798a 100644 --- a/runtime/src/main/cpp/KString.cpp +++ b/runtime/src/main/cpp/KString.cpp @@ -671,17 +671,17 @@ int iswalnum_Konan(KChar ch) { } int iswspace_Konan(KChar ch) { - // Optimized case for ASCII. + // FILE, GROUP, RECORD, UNIT separators, # Zs SPACE or # Cc CONTROLs if ((ch >= 0x1c && ch <= 0x20) || (ch >= 0x9 && ch <= 0xd)) { return true; } - if (ch == 0x1680) { - return true; - } - if (ch < 0x2000 || ch == 0x2007) { + // not (# Zs OGHAM SPACE MARK or # Cc or # Zs NO-BREAK SPACE) + if (ch < 0x2000 && !(ch == 0x1680 || ch == 0x85 || ch == 0xA0)) { return false; } - return ch <= 0x200b || ch == 0x2028 || ch == 0x2029 || ch == 0x3000; + // if # Zl LINE SEPARATOR or # Zp PARAGRAPH SEPARATOR or # Zs NARROW NO-BREAK SPACE + // or # Zs MEDIUM MATHEMATICAL SPACE or # Zs IDEOGRAPHIC SPACE + return ch < 0x200b || ch == 0x2028 || ch == 0x2029 || ch == 0x202F || ch == 0x205F || ch == 0x3000; } int iswupper_Konan(KChar ch) { @@ -708,19 +708,6 @@ int iswlower_Konan(KChar ch) { return getType(ch) == LOWERCASE_LETTER; } -void checkParsingErrors(const char* c_str, const char* end, KStdString::size_type c_str_size) { - if (end == c_str) { - ThrowNumberFormatException(); - } - // According to http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#valueOf-java.lang.String- - // trailing whitespace characters must be ignored so we need to do an additional check. - for (const char* p = end; p < c_str + c_str_size; p++) { - if (!iswspace_Konan(*p)) { - ThrowNumberFormatException(); - } - } -} - } // namespace extern "C" {