[K/N] Migrate runtime/text tests to new testing infra ^KT-61259

This commit is contained in:
Alexander Shabalin
2023-10-23 16:11:12 +02:00
committed by Space Team
parent e9983a947f
commit 17dc60aac9
22 changed files with 693 additions and 1240 deletions
@@ -2299,49 +2299,9 @@ tasks.register("listof1", KonanLocalTest) {
source = "datagen/literals/listof1.kt"
}
tasks.register("string_builder0", KonanLocalTest) {
tasks.register("print_utf8", KonanLocalTest) {
useGoldenData = true
source = "runtime/text/string_builder0.kt"
}
tasks.register("string_builder1", KonanLocalTest) {
useGoldenData = true
source = "runtime/text/string_builder1.kt"
}
tasks.register("string0", KonanLocalTest) {
useGoldenData = true
source = "runtime/text/string0.kt"
}
tasks.register("parse0", KonanLocalTest) {
source = "runtime/text/parse0.kt"
}
tasks.register("to_string0", KonanLocalTest) {
useGoldenData = true
source = "runtime/text/to_string0.kt"
}
tasks.register("trim", KonanLocalTest) {
useGoldenData = true
source = "runtime/text/trim.kt"
}
tasks.register("chars0", KonanLocalTest) {
disabled = isAggressiveGC // TODO: Investigate why too slow
source = "runtime/text/chars0.kt"
expectedExitStatus = 0
}
tasks.register("indexof", KonanLocalTest) {
source = "runtime/text/indexof.kt"
}
tasks.register("utf8", KonanLocalTest) {
enabled = !isAggressiveGC // TODO: Investigate why too slow
useGoldenData = true
source = "runtime/text/utf8.kt"
source = "runtime/basic/print_utf8.kt"
}
tasks.register("catch1", KonanLocalTest) {
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package runtime.basic.print_utf8
import kotlin.test.*
import kotlinx.cinterop.toKString
fun convertUtf8to16(byteArray: ByteArray, action: (String) -> Unit) {
byteArray.decodeToString().let { action(it) }
byteArray.toKString().let { action(it) }
}
@Test
fun testPrint() {
// Valid strings.
println("Hello")
println("Привет")
println("\uD800\uDC00")
println("")
// Illegal surrogate pair -> default output
println("\uDC00\uD800")
// Lone surrogate -> default output
println("\uD80012")
println("\uDC0012")
println("12\uD800")
// https://github.com/JetBrains/kotlin-native/issues/1091
val array = byteArrayOf(0xF0.toByte(), 0x9F.toByte(), 0x98.toByte(), 0xA5.toByte())
convertUtf8to16(array) { badString ->
assertEquals(2, badString.length)
println(badString)
}
}
@@ -1,109 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
package runtime.text.chars0
import kotlin.test.*
fun testIsSupplementaryCodePoint() {
assertFalse(Char.isSupplementaryCodePoint(-1))
for (c in 0..0xFFFF) {
assertFalse(Char.isSupplementaryCodePoint(c.toInt()))
}
for (c in 0xFFFF + 1..0x10FFFF) {
assertTrue(Char.isSupplementaryCodePoint(c))
}
assertFalse(Char.isSupplementaryCodePoint(0x10FFFF + 1))
}
fun testIsSurrogatePair() {
assertFalse(Char.isSurrogatePair('\u0000', '\u0000'))
assertFalse(Char.isSurrogatePair('\u0000', '\uDC00'))
assertTrue( Char.isSurrogatePair('\uD800', '\uDC00'))
assertTrue( Char.isSurrogatePair('\uD800', '\uDFFF'))
assertTrue( Char.isSurrogatePair('\uDBFF', '\uDFFF'))
assertFalse(Char.isSurrogatePair('\uDBFF', '\uF000'))
}
fun testToChars() {
assertTrue(charArrayOf('\uD800', '\uDC00').contentEquals(Char.toChars(0x010000)))
assertTrue(charArrayOf('\uD800', '\uDC01').contentEquals(Char.toChars(0x010001)))
assertTrue(charArrayOf('\uD801', '\uDC01').contentEquals(Char.toChars(0x010401)))
assertTrue(charArrayOf('\uDBFF', '\uDFFF').contentEquals(Char.toChars(0x10FFFF)))
try {
Char.toChars(Int.MAX_VALUE)
throw AssertionError()
} catch (e: IllegalArgumentException) {}
}
fun testToCodePoint() {
assertEquals(0x010000, Char.toCodePoint('\uD800', '\uDC00'))
assertEquals(0x010001, Char.toCodePoint('\uD800', '\uDC01'))
assertEquals(0x010401, Char.toCodePoint('\uD801', '\uDC01'))
assertEquals(0x10FFFF, Char.toCodePoint('\uDBFF', '\uDFFF'))
}
// TODO: Uncomment when such operations are supported for supplementary codepoints and the API is public.
fun testCase() {
/*
assertEquals('A'.toInt(), Char.toUpperCase('a'.toInt()))
assertEquals('A'.toInt(), Char.toUpperCase('A'.toInt()))
assertEquals('1'.toInt(), Char.toUpperCase('1'.toInt()))
assertEquals('a'.toInt(), Char.toLowerCase('A'.toInt()))
assertEquals('a'.toInt(), Char.toLowerCase('a'.toInt()))
assertEquals('1'.toInt(), Char.toLowerCase('1'.toInt()))
assertEquals(0x010400, Char.toUpperCase(0x010428))
assertEquals(0x010400, Char.toUpperCase(0x010400))
assertEquals(0x10FFFF, Char.toUpperCase(0x10FFFF))
assertEquals(0x110000, Char.toUpperCase(0x110000))
assertEquals(0x010428, Char.toLowerCase(0x010400))
assertEquals(0x010428, Char.toLowerCase(0x010428))
assertEquals(0x10FFFF, Char.toLowerCase(0x10FFFF))
assertEquals(0x110000, Char.toLowerCase(0x110000))
*/
}
fun testCategory() {
assertTrue('\n' in CharCategory.CONTROL)
assertTrue('1' in CharCategory.DECIMAL_DIGIT_NUMBER)
assertTrue(' ' in CharCategory.SPACE_SEPARATOR)
assertTrue('a' in CharCategory.LOWERCASE_LETTER)
assertTrue('A' in CharCategory.UPPERCASE_LETTER)
assertTrue('<' in CharCategory.MATH_SYMBOL)
assertTrue(';' in CharCategory.OTHER_PUNCTUATION)
assertTrue('_' in CharCategory.CONNECTOR_PUNCTUATION)
assertTrue('$' in CharCategory.CURRENCY_SYMBOL)
assertTrue('\u2029' in CharCategory.PARAGRAPH_SEPARATOR)
}
fun testIsHighSurrogate() {
assertTrue('\uD800'.isHighSurrogate())
assertTrue('\uDBFF'.isHighSurrogate())
assertFalse('\uDC00'.isHighSurrogate())
assertFalse('\uDFFF'.isHighSurrogate())
}
fun testIsLowSurrogate() {
assertFalse('\uD800'.isLowSurrogate())
assertFalse('\uDBFF'.isLowSurrogate())
assertTrue('\uDC00'.isLowSurrogate())
assertTrue('\uDFFF'.isLowSurrogate())
}
@Test fun runTest() {
testIsSurrogatePair()
testToChars()
testToCodePoint()
testIsSupplementaryCodePoint()
testCase()
testCategory()
testIsHighSurrogate()
testIsLowSurrogate()
}
@@ -1,38 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.text.indexof
import kotlin.test.*
@Test fun runTest() {
var str = "Hello World!!" // for indexOf String
var ch = 'a' // for indexOf Char
assertEquals(6, str.indexOf("World", 0))
assertEquals(6, str.indexOf("World", -1))
assertEquals(-1, str.indexOf(ch, 0))
str = "Kotlin/Native"
assertEquals(-1, str.indexOf("/", str.length + 1))
assertEquals(-1, str.indexOf("/", Int.MAX_VALUE))
assertEquals(str.length, str.indexOf("", Int.MAX_VALUE))
assertEquals(1, str.indexOf("", 1))
assertEquals(8, str.indexOf(ch, 1))
assertEquals(-1, str.indexOf(ch, str.length - 1))
str = ""
assertEquals(-1, str.indexOf("a", -3))
assertEquals(0, str.indexOf("", 0))
assertEquals(-1, str.indexOf(ch, -3))
assertEquals(-1, str.indexOf(ch, 10))
ch = 0.toChar()
assertEquals(-1, str.indexOf(ch, -3))
assertEquals(-1, str.indexOf(ch, 10))
}
@@ -1,146 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(kotlin.experimental.ExperimentalNativeApi::class)
package runtime.text.parse0
import kotlin.test.*
import kotlin.native.OsFamily
import kotlin.native.Platform
@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")
if (Platform.osFamily != OsFamily.WASM) {
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")
if (Platform.osFamily != OsFamily.WASM) {
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()
}
}
}
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.text.string0
import kotlin.test.*
@Test fun runTest() {
val str = "hello"
println(str.equals("HElLo", true))
val strI18n = "Привет"
println(strI18n.equals("прИВет", true))
println(strI18n.toUpperCase())
println(strI18n.toLowerCase())
println("пока".capitalize())
println("http://jetbrains.com".startsWith("http://"))
}
@@ -1,6 +0,0 @@
true
true
ПРИВЕТ
привет
Пока
true
@@ -1,277 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.text.string_builder0
import kotlin.test.*
// Utils ====================================================================================================
fun assertTrue(cond: Boolean) {
if (!cond)
throw AssertionError("Condition expected to be true")
}
fun assertFalse(cond: Boolean) {
if (cond)
throw AssertionError("Condition expected to be false")
}
fun assertEquals(value1: String, value2: String) {
if (value1 != value2)
throw AssertionError("FAIL: '" + value1 + "' != '" + value2 + "'")
}
fun assertEquals(value1: Int, value2: Int) {
if (value1 != value2)
throw AssertionError("FAIL" + value1.toString() + " != " + value2.toString())
}
fun assertEquals(builder: StringBuilder, content: String) = assertEquals(builder.toString(), content)
// IndexOutOfBoundsException.
fun assertException(body: () -> Unit) {
try {
body()
throw AssertionError ("Test failed: no IndexOutOfBoundsException on wrong indices")
} catch (e: IndexOutOfBoundsException) {
} catch (e: IllegalArgumentException) {}
}
// Insert ===================================================================================================
fun testInsertString(initial: String, index: Int, toInsert: String, expected: String) {
assertEquals(StringBuilder(initial).insert(index, toInsert), expected)
assertEquals(StringBuilder(initial).insert(index, toInsert.toCharArray()), expected)
assertEquals(StringBuilder(initial).insert(index, toInsert as CharSequence), expected)
}
fun testInsertStringException(initial: String, index: Int, toInsert: String) {
assertException { StringBuilder(initial).insert(index, toInsert) }
assertException { StringBuilder(initial).insert(index, toInsert.toCharArray()) }
assertException { StringBuilder(initial).insert(index, toInsert as CharSequence) }
}
fun testInsertSingle(value: Byte) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Short) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Int) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Long) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Float) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Double) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Any?) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsertSingle(value: Char) {
assertEquals(StringBuilder("abcd").insert(0, value), value.toString() + "abcd")
assertEquals(StringBuilder("abcd").insert(4, value), "abcd" + value.toString())
assertEquals(StringBuilder("abcd").insert(2, value), "ab" + value.toString() + "cd")
assertEquals(StringBuilder("").insert(0, value), value.toString())
}
fun testInsert() {
// String/CharSequence/CharArray.
testInsertString("abcd", 0, "12", "12abcd")
testInsertString("abcd", 4, "12", "abcd12")
testInsertString("abcd", 2, "12", "ab12cd")
testInsertString("", 0, "12", "12")
testInsertStringException("a", -1, "1")
testInsertStringException("a", 2, "1")
// Null inserting.
assertEquals(StringBuilder("abcd").insert(0, null as CharSequence?), "nullabcd")
assertEquals(StringBuilder("abcd").insert(4, null as CharSequence?), "abcdnull")
assertEquals(StringBuilder("abcd").insert(2, null as CharSequence?), "abnullcd")
assertEquals(StringBuilder("").insert(0, null as CharSequence?), "null")
// Subsequence of CharSequence.
// Insert in the beginning.
assertEquals(StringBuilder("abcd").insertRange(0, "1234", 0, 0), "abcd") // 0 symbols
assertEquals(StringBuilder("abcd").insertRange(0, "1234", 0, 1), "1abcd") // 1 symbol
assertEquals(StringBuilder("abcd").insertRange(0, "1234", 1, 3), "23abcd") // 2 symbols
// Insert in the end.
assertEquals(StringBuilder("abcd").insertRange(4, "1234", 0, 0), "abcd")
assertEquals(StringBuilder("abcd").insertRange(4, "1234", 0, 1), "abcd1")
assertEquals(StringBuilder("abcd").insertRange(4, "1234", 1, 3), "abcd23")
// Insert in the middle.
assertEquals(StringBuilder("abcd").insertRange(2, "1234", 0, 0), "abcd")
assertEquals(StringBuilder("abcd").insertRange(2, "1234", 0, 1), "ab1cd")
assertEquals(StringBuilder("abcd").insertRange(2, "1234", 1, 3), "ab23cd")
// Incorrect indices.
assertException { StringBuilder("a").insertRange(-1, "1", 0, 0) }
assertException { StringBuilder("a").insertRange(2, "1", 0, 0) }
assertException { StringBuilder("a").insertRange(1, "1", -1, 0) }
assertException { StringBuilder("a").insertRange(1, "1", 0, 2) }
assertException { StringBuilder("a").insertRange(1, "123", 2, 0) }
// Other types.
testInsertSingle(true)
testInsertSingle(42.toByte())
testInsertSingle(42.toShort())
testInsertSingle(42.toInt())
testInsertSingle(42.toLong())
testInsertSingle(42.2.toFloat())
testInsertSingle(42.2.toDouble())
testInsertSingle(object {
override fun toString(): String {
return "Object"
}
})
testInsertSingle('a')
}
// Reverse ==================================================================================================
fun testReverse(original: String, reversed: String, reversedBack: String) {
assertEquals(StringBuilder(original).reverse(), reversed)
assertEquals(StringBuilder(reversed).reverse(), reversedBack)
}
fun testReverse() {
var builder = StringBuilder("123456")
assertTrue(builder === builder.reverse())
assertEquals(builder, "654321")
builder.setLength(1)
assertEquals(builder, "6")
builder.setLength(0)
assertEquals(builder, "")
var str: String = "a"
testReverse(str, str, str)
str = "ab"
testReverse(str, "ba", str)
str = "abcdef"
testReverse(str, "fedcba", str)
str = "abcdefg"
testReverse(str, "gfedcba", str)
str = "\ud800\udc00"
testReverse(str, str, str)
str = "\udc00\ud800"
testReverse(str, "\ud800\udc00", "\ud800\udc00")
str = "a\ud800\udc00"
testReverse(str, "\ud800\udc00a", str)
str = "ab\ud800\udc00"
testReverse(str, "\ud800\udc00ba", str)
str = "abc\ud800\udc00"
testReverse(str, "\ud800\udc00cba", str)
str = "\ud800\udc00\udc01\ud801\ud802\udc02"
testReverse(str, "\ud802\udc02\ud801\udc01\ud800\udc00",
"\ud800\udc00\ud801\udc01\ud802\udc02")
str = "\ud800\udc00\ud801\udc01\ud802\udc02"
testReverse(str, "\ud802\udc02\ud801\udc01\ud800\udc00", str)
str = "\ud800\udc00\udc01\ud801a"
testReverse(str, "a\ud801\udc01\ud800\udc00",
"\ud800\udc00\ud801\udc01a")
str = "a\ud800\udc00\ud801\udc01"
testReverse(str, "\ud801\udc01\ud800\udc00a", str)
str = "\ud800\udc00\udc01\ud801ab"
testReverse(str, "ba\ud801\udc01\ud800\udc00",
"\ud800\udc00\ud801\udc01ab")
str = "ab\ud800\udc00\ud801\udc01"
testReverse(str, "\ud801\udc01\ud800\udc00ba", str)
str = "\ud800\udc00\ud801\udc01"
testReverse(str, "\ud801\udc01\ud800\udc00", str)
str = "a\ud800\udc00z\ud801\udc01"
testReverse(str, "\ud801\udc01z\ud800\udc00a", str)
str = "a\ud800\udc00bz\ud801\udc01"
testReverse(str, "\ud801\udc01zb\ud800\udc00a", str)
str = "abc\ud802\udc02\ud801\udc01\ud800\udc00"
testReverse(str, "\ud800\udc00\ud801\udc01\ud802\udc02cba", str)
str = "abcd\ud802\udc02\ud801\udc01\ud800\udc00"
testReverse(str, "\ud800\udc00\ud801\udc01\ud802\udc02dcba", str)
}
// Basic ====================================================================================================
fun testBasic() {
val sb = StringBuilder()
assertEquals(0, sb.length)
assertEquals("", sb.toString())
sb.append(1)
assertEquals(1, sb.length)
assertEquals("1", sb.toString())
sb.append(", ")
assertEquals(3, sb.length)
assertEquals("1, ", sb.toString())
sb.append(true)
assertEquals(7, sb.length)
assertEquals("1, true", sb.toString())
sb.append(12345678L)
assertEquals(15, sb.length)
assertEquals("1, true12345678", sb.toString())
sb.append(null as CharSequence?)
assertEquals(19, sb.length)
assertEquals("1, true12345678null", sb.toString())
sb.setLength(0)
assertEquals(0, sb.length)
assertEquals("", sb.toString())
}
@Test fun runTest() {
testBasic()
testInsert()
testReverse()
println("OK")
}
@@ -1,14 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.text.string_builder1
import kotlin.test.*
@Test fun runTest() {
val a = StringBuilder()
a.append("Hello").appendLine("Kotlin").appendLine(42).appendLine(0.1).appendLine(true)
println(a.toString())
}
@@ -1,5 +0,0 @@
HelloKotlin
42
0.1
true
@@ -1,50 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package runtime.text.to_string0
import kotlin.test.*
// Based on Apache Harmony tests.
fun assertEquals(actual: String, expected: String, msg: String) {
if (actual != expected) throw AssertionError("$msg. Actual: $actual. Expected: $expected")
}
fun testIntToStringWithRadix() {
assertEquals(2147483647.toString(8), "17777777777", "Octal string")
assertEquals(2147483647.toString(16), "7fffffff", "Hex string")
assertEquals(2147483647.toString(2), "1111111111111111111111111111111", "Binary string")
assertEquals(2147483647.toString(10), "2147483647", "Decimal string")
assertEquals((-2147483647).toString(8), "-17777777777", "Octal string")
assertEquals((-2147483647).toString(16), "-7fffffff", "Hex string")
assertEquals((-2147483647).toString(2), "-1111111111111111111111111111111", "Binary string")
assertEquals((-2147483647).toString(10), "-2147483647", "Decimal string")
assertEquals((-2147483648).toString(8), "-20000000000", "Octal string")
assertEquals((-2147483648).toString(16), "-80000000", "Hex string")
assertEquals((-2147483648).toString(2), "-10000000000000000000000000000000", "Binary string")
assertEquals((-2147483648).toString(10), "-2147483648", "Decimal string")
}
fun testLongToStringWithRadix() {
assertEquals(100000000L.toString(10), "100000000", "Decimal string")
assertEquals(68719476735L.toString(16), "fffffffff", "Hex string")
assertEquals(8589934591L.toString(8), "77777777777", "Octal string")
assertEquals(8796093022207L.toString(2), "1111111111111111111111111111111111111111111", "Binary string")
assertEquals((-0x7fffffffffffffffL - 1).toString(10), "-9223372036854775808", "Min decimal string")
assertEquals(0x7fffffffffffffffL.toString(10), "9223372036854775807", "Max decimal string")
assertEquals((-0x7fffffffffffffffL - 1).toString(16), "-8000000000000000", "Min hex string")
assertEquals(0x7fffffffffffffffL.toString(16), "7fffffffffffffff", "Max hex string")
}
@Test fun runTest() {
testIntToStringWithRadix()
testLongToStringWithRadix()
println("OK")
}
@@ -1 +0,0 @@
OK
@@ -1,54 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
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<NumberFormatException> { "\u202F3.14".toFloat() }
assertFailsWith<NumberFormatException> { "\u20293.14".toDouble() }
assertFailsWith<NumberFormatException> { "3.14\u200B".toDouble() }
assertFailsWith<NumberFormatException> { "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 = "\u00A0 \u1FFFString".trim(),
message = "Trim special whitespace but should left a unicode symbol")
assertEquals(expected = "String\tSTR", actual = " \nString\tSTR ".trim(), message = "Trim newline")
}
@@ -1 +0,0 @@
OK
@@ -1,477 +0,0 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
package runtime.text.utf8
import kotlin.test.*
import kotlin.reflect.KClass
import kotlinx.cinterop.toKString
// -------------------------------------- Utils --------------------------------------
fun assertEquals(expected: ByteArray, actual: ByteArray, message: String) =
assertTrue(expected.contentEquals(actual), message)
fun checkUtf16to8(string: String, expected: IntArray, conversion: String.() -> ByteArray) {
expected.forEach {
assertTrue(it in Byte.MIN_VALUE..Byte.MAX_VALUE, "Expected array contains illegal values")
}
val expectedBytes = ByteArray(expected.size) { i -> expected[i].toByte() }
val actual = string.conversion()
assertEquals(expectedBytes, actual, """
Assert failed for string: $string
Expected: ${expected.joinToString()}
Actual: ${actual.joinToString()}
""".trimIndent())
}
// Utils for checking successful UTF-16 to UTF-8 conversion.
fun checkUtf16to8Replacing(string: String, expected: IntArray) {
checkUtf16to8(string, expected) { encodeToByteArray() }
}
fun checkUtf16to8Throwing(string: String, expected: IntArray) {
checkUtf16to8(string, expected) { encodeToByteArray(throwOnInvalidSequence = true) }
}
fun checkValidUtf16to8(string: String, expected: IntArray) {
checkUtf16to8Replacing(string, expected)
checkUtf16to8Throwing(string, expected)
}
fun checkUtf16to8Replacing(string: String, expected: IntArray, start: Int, size: Int) {
checkUtf16to8(string, expected) { encodeToByteArray(start, start + size) }
}
fun checkUtf16to8Throwing(string: String, expected: IntArray, start: Int, size: Int) {
checkUtf16to8(string, expected) { encodeToByteArray(start, start + size, true) }
}
fun checkValidUtf16to8(string: String, expected: IntArray, start: Int, size: Int) {
checkUtf16to8Replacing(string, expected, start, size)
checkUtf16to8Throwing(string, expected, start, size)
}
// Utils for checking successful UTF-8 to UTF-16 conversion.
fun checkUtf8to16(expected: String, array: IntArray, conversion: ByteArray.() -> String) {
array.forEach {
assertTrue(it in Byte.MIN_VALUE..Byte.MAX_VALUE, "Expected array contains illegal values")
}
val arrayBytes = ByteArray(array.size) { i -> array[i].toByte() }
val actual = arrayBytes.conversion()
assertEquals(expected, actual, """
Assert failed for string: $expected
Expected: $expected
Actual: $actual
""".trimIndent())
}
fun checkZeroTerminatedUtf8to16Replacing(expected: String, array: IntArray) {
checkUtf8to16(expected, array) { toKString() }
checkUtf8to16(expected, array.copyOf(array.size + 1)) { toKString() }
}
fun checkUtf8to16Replacing(expected: String, array: IntArray) {
checkUtf8to16(expected, array) { decodeToString() }
checkZeroTerminatedUtf8to16Replacing(expected, array)
}
fun checkZeroTerminatedUtf8to16Throwing(expected: String, array: IntArray) {
checkUtf8to16(expected, array) { toKString(throwOnInvalidSequence = true) }
checkUtf8to16(expected, array.copyOf(array.size + 1)) { toKString(throwOnInvalidSequence = true) }
}
fun checkUtf8to16Throwing(expected: String, array: IntArray) {
checkUtf8to16(expected, array) { decodeToString(throwOnInvalidSequence = true) }
checkZeroTerminatedUtf8to16Throwing(expected, array)
}
fun checkValidUtf8to16(expected: String, array: IntArray) {
checkUtf8to16Replacing(expected, array)
checkUtf8to16Throwing(expected, array)
}
fun checkValidZeroTerminatedUtf8to16(expected: String, array: IntArray) {
checkZeroTerminatedUtf8to16Replacing(expected, array)
checkZeroTerminatedUtf8to16Throwing(expected, array)
}
fun checkZeroTerminatedUtf8to16Replacing(expected: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16(expected, array) { toKString(start, start + size) }
checkUtf8to16(expected, array.copyOf(array.size + 1)) { toKString(start, start + size) }
}
fun checkUtf8to16Replacing(expected: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16(expected, array) { decodeToString(start, start + size) }
checkZeroTerminatedUtf8to16Replacing(expected, array, start, size)
}
fun checkZeroTerminatedUtf8to16Throwing(expected: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16(expected, array) { toKString(start, start + size, true) }
checkUtf8to16(expected, array.copyOf(array.size + 1)) { toKString(start, start + size, true) }
}
fun checkUtf8to16Throwing(expected: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16(expected, array) { decodeToString(start, start + size, true) }
checkZeroTerminatedUtf8to16Throwing(expected, array, start, size)
}
fun checkValidUtf8to16(expected: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16Replacing(expected, array, start, size)
checkUtf8to16Throwing(expected, array, start, size)
}
fun checkValidZeroTerminatedUtf8to16(expected: String, array: IntArray, start: Int, size: Int) {
checkZeroTerminatedUtf8to16Replacing(expected, array, start, size)
checkZeroTerminatedUtf8to16Throwing(expected, array, start, size)
}
// Utils for checking malformed UTF-16 to UTF-8 conversion.
fun <T: Any> checkThrows(e: KClass<T>, string: String, action: () -> Unit) {
var exception: Throwable? = null
try {
action()
} catch (e: Throwable) {
exception = e
}
assertNotNull(exception, "No exception was thrown for string: $string")
assertTrue(e.isInstance(exception),"""
Wrong exception was thrown for string: $string
Expected: ${e.qualifiedName}
Actual: ${exception::class.qualifiedName}: $exception}
""".trimIndent())
}
fun checkUtf16to8Throws(string: String) {
checkThrows(CharacterCodingException::class, string) { string.encodeToByteArray(throwOnInvalidSequence = true) }
}
fun checkUtf16to8Throws(string: String, start: Int, size: Int) {
checkThrows(CharacterCodingException::class, string) { string.encodeToByteArray(start, start + size, true) }
}
// Utils for checking malformed UTF-8 to UTF-16 conversion.
fun <T: Any> checkUtf8to16Throws(e: KClass<T>, string: String, array: IntArray, conversion: ByteArray.() -> String)
= checkThrows(e, string) {
array.forEach {
assertTrue(it in Byte.MIN_VALUE..Byte.MAX_VALUE, "Expected array contains illegal values")
}
val arrayBytes = ByteArray(array.size) { i -> array[i].toByte() }
arrayBytes.conversion()
}
fun checkZeroTerminatedUtf8to16Throws(string: String, array: IntArray) {
checkUtf8to16Throws(CharacterCodingException::class, string, array) { toKString(throwOnInvalidSequence = true) }
checkUtf8to16Throws(CharacterCodingException::class, string, array.copyOf(array.size + 1)) { toKString(throwOnInvalidSequence = true) }
}
fun checkUtf8to16Throws(string: String, array: IntArray) {
checkUtf8to16Throws(CharacterCodingException::class, string, array) { decodeToString(throwOnInvalidSequence = true) }
checkZeroTerminatedUtf8to16Throws(string, array)
}
fun checkZeroTerminatedUtf8to16Throws(string: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16Throws(CharacterCodingException::class, string, array) { toKString(start, start + size, true) }
checkUtf8to16Throws(CharacterCodingException::class, string, array.copyOf(array.size + 1)) { toKString(start, start + size, true) }
}
fun checkUtf8to16Throws(string: String, array: IntArray, start: Int, size: Int) {
checkUtf8to16Throws(CharacterCodingException::class, string, array) { decodeToString(start, start + size, true) }
checkZeroTerminatedUtf8to16Throws(string, array, start, size)
}
// Utils for checking String to floating-point number conversion.
fun checkDoubleConversionThrows(string: String) = checkThrows(NumberFormatException::class, string) {
string.toDouble()
}
fun checkFloatConversionThrows(string: String) = checkThrows(NumberFormatException::class, string) {
string.toFloat()
}
// Utils for checking invalid-bounds-exception thrown by UTF-16 to UTF-8 conversion.
fun <T: Any> checkOutOfBoundsUtf16to8Replacing(e: KClass<T>, string: String, start: Int, size: Int) {
checkThrows(e, string) { string.encodeToByteArray(start, start + size) }
}
fun <T: Any> checkOutOfBoundsUtf16to8Throwing(e: KClass<T>, string: String, start: Int, size: Int) {
checkThrows(e, string) { string.encodeToByteArray(start, start + size, true) }
}
fun <T: Any> checkOutOfBoundsUtf16to8(e: KClass<T>, string: String, start: Int, size: Int) {
checkOutOfBoundsUtf16to8Replacing(e, string, start, size)
checkOutOfBoundsUtf16to8Throwing(e, string, start, size)
}
// Utils for checking invalid-bounds-exception thrown by UTF-8 to UTF-16 conversion.
fun <T: Any> checkOutOfBoundsZeroTerminatedUtf8to16Replacing(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkThrows(e, string) { byteArray.toKString(start, start + size) }
}
fun <T: Any> checkOutOfBoundsUtf8to16Replacing(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkThrows(e, string) { byteArray.decodeToString(start, start + size) }
checkOutOfBoundsZeroTerminatedUtf8to16Replacing(e, string, byteArray, start, size)
}
fun <T: Any> checkOutOfBoundsZeroTerminatedUtf8to16Throwing(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkThrows(e, string) { byteArray.toKString(start, start + size, true) }
}
fun <T: Any> checkOutOfBoundsUtf8to16Throwing(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkThrows(e, string) { byteArray.decodeToString(start, start + size, true) }
checkOutOfBoundsZeroTerminatedUtf8to16Throwing(e, string, byteArray, start, size)
}
fun <T: Any> checkOutOfBoundsUtf8to16(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkOutOfBoundsUtf8to16Replacing(e, string, byteArray, start, size)
checkOutOfBoundsUtf8to16Throwing(e, string, byteArray, start, size)
}
fun <T: Any> checkOutOfBoundsZeroTerminatedUtf8to16(e: KClass<T>, string: String, byteArray: ByteArray, start: Int, size: Int) {
checkOutOfBoundsZeroTerminatedUtf8to16Replacing(e, string, byteArray, start, size)
checkOutOfBoundsZeroTerminatedUtf8to16Throwing(e, string, byteArray, start, size)
}
// Util for performing action on result of UTF-8 to UTF-16 conversion.
fun convertUtf8to16(byteArray: ByteArray, action: (String) -> Unit) {
byteArray.decodeToString().let { action(it) }
byteArray.toKString().let { action(it) }
}
// ------------------------- Test UTF-16 to UTF-8 conversion -------------------------
fun test16to8() {
// Valid strings.
checkValidUtf16to8("Hello", intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()))
checkValidUtf16to8("Привет", intArrayOf(-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126))
checkValidUtf16to8("\uD800\uDC00", intArrayOf(-16, -112, -128, -128))
checkValidUtf16to8("", intArrayOf())
// Test manual conversion with replacement.
// Illegal surrogate pair -> replace with default
checkUtf16to8Replacing("\uDC00\uD800", intArrayOf(-17, -65, -67, -17, -65, -67))
// Different kinds of input
checkUtf16to8Replacing("\uD800\uDC001\uDC00\uD800",
intArrayOf(-16, -112, -128, -128, '1'.toInt(), -17, -65, -67, -17, -65, -67))
// Lone surrogate - replace with default
checkUtf16to8Replacing("\uD80012", intArrayOf(-17, -65, -67, '1'.toInt(), '2'.toInt()))
checkUtf16to8Replacing("\uDC0012", intArrayOf(-17, -65, -67, '1'.toInt(), '2'.toInt()))
checkUtf16to8Replacing("12\uD800", intArrayOf('1'.toInt(), '2'.toInt(), -17, -65, -67))
// Test manual conversion with an exception if an input is invalid.
// Illegal surrogate pair -> throw
checkUtf16to8Throws("\uDC00\uD800")
// Different kinds of input (including illegal one) -> throw
checkUtf16to8Throws("\uD800\uDC001\uDC00\uD800")
// Lone surrogate - throw
checkUtf16to8Throws("\uD80012")
checkUtf16to8Throws("\uDC0012")
checkUtf16to8Throws("12\uD800")
// Test double parsing.
assertEquals(4.2, "4.2".toDouble())
// Illegal surrogate pair -> throw
checkDoubleConversionThrows("\uDC00\uD800")
// Different kinds of input (including illegal one) -> throw
checkDoubleConversionThrows("\uD800\uDC001\uDC00\uD800")
// Lone surrogate - throw
checkDoubleConversionThrows("\uD80012")
checkDoubleConversionThrows("\uDC0012")
checkDoubleConversionThrows("12\uD800")
// Test float parsing.
assertEquals(4.2F, "4.2".toFloat())
// Illegal surrogate pair -> throw
checkFloatConversionThrows("\uDC00\uD800")
// Different kinds of input (including illegal one) -> throw
checkFloatConversionThrows("\uD800\uDC001\uDC00\uD800")
// Lone surrogate - throw
checkFloatConversionThrows("\uD80012")
checkFloatConversionThrows("\uDC0012")
checkFloatConversionThrows("12\uD800")
}
fun test16to8CustomBorders() {
// Valid strings.
checkValidUtf16to8("Hello!", intArrayOf('H'.toInt(), 'e'.toInt()), 0, 2)
checkValidUtf16to8("Hello!", intArrayOf('e'.toInt(), 'l'.toInt()), 1, 2)
checkValidUtf16to8("Hello!", intArrayOf('o'.toInt(), '!'.toInt()), 4, 2)
checkValidUtf16to8("Hello!", intArrayOf(), 0, 0)
checkValidUtf16to8("Hello!", intArrayOf(), 6, 0)
checkValidUtf16to8("\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128), 0, 4)
checkValidUtf16to8("\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128), 2, 4)
checkValidUtf16to8("\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128), 4, 4)
// Index out of bound
checkOutOfBoundsUtf16to8(IndexOutOfBoundsException::class, "Hello", -1, 4)
checkOutOfBoundsUtf16to8(IndexOutOfBoundsException::class, "Hello", 5, 10)
checkOutOfBoundsUtf16to8(IndexOutOfBoundsException::class, "Hello", 2, 10)
checkOutOfBoundsUtf16to8(IllegalArgumentException::class, "Hello", 3, -2)
// Test manual conversion with replacement and custom borders.
// Illegal surrogate pair -> replace with default
checkUtf16to8Replacing("\uDC00\uD80012",
intArrayOf(-17, -65, -67, -17, -65, -67, '1'.toInt()), 0, 3)
checkUtf16to8Replacing("1\uDC00\uD8002",
intArrayOf(-17, -65, -67, -17, -65, -67, '2'.toInt()), 1, 3)
checkUtf16to8Replacing("12\uDC00\uD800",
intArrayOf('2'.toInt(), -17, -65, -67, -17, -65, -67), 1, 3)
// Lone surrogate - replace with default
checkUtf16to8Replacing("1\uD800\uDC002", intArrayOf('1'.toInt(), -17, -65, -67), 0, 2)
checkUtf16to8Replacing("1\uD800\uDC002", intArrayOf(-17, -65, -67, '2'.toInt()), 2, 2)
// Test manual conversion with an exception if an input is invalid and custom borders.
// Illegal surrogate pair -> throw
checkUtf16to8Throws("\uDC00\uD80012", 0, 3)
checkUtf16to8Throws("1\uDC00\uD8002", 1, 3)
checkUtf16to8Throws("12\uDC00\uD800", 1, 3)
// Lone surrogate -> throw
checkUtf16to8Throws("1\uD800\uDC002", 0, 2)
checkUtf16to8Throws("1\uD800\uDC002", 2, 2)
}
fun testPrint() {
// Valid strings.
println("Hello")
println("Привет")
println("\uD800\uDC00")
println("")
// Illegal surrogate pair -> default output
println("\uDC00\uD800")
// Lone surrogate -> default output
println("\uD80012")
println("\uDC0012")
println("12\uD800")
// https://github.com/JetBrains/kotlin-native/issues/1091
val array = byteArrayOf(0xF0.toByte(), 0x9F.toByte(), 0x98.toByte(), 0xA5.toByte())
convertUtf8to16(array) { badString ->
assertEquals(2, badString.length)
println(badString)
}
}
// ------------------------- Test UTF-8 to UTF-16 conversion -------------------------
fun test8to16() {
// Valid strings.
checkValidUtf8to16("Hello", intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()))
checkValidUtf8to16("Привет", intArrayOf(-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126))
checkValidUtf8to16("\uD800\uDC00", intArrayOf(-16, -112, -128, -128))
checkValidUtf8to16("", intArrayOf())
// Test manual conversion with replacement.
// Incorrect UTF-8 lead character.
checkUtf8to16Replacing("\uFFFD1", intArrayOf(-1, '1'.toInt()))
// Incomplete codepoint.
checkUtf8to16Replacing("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt()))
checkUtf8to16Replacing("\uFFFD1\uFFFD", intArrayOf(-16, -97, -104, '1'.toInt(), -16, -97, -104))
// Test manual conversion with exception throwing
// Incorrect UTF-8 lead character -> throw.
checkUtf8to16Throws("\uFFFD1", intArrayOf(-1, '1'.toInt()))
// Incomplete codepoint -> throw.
checkUtf8to16Throws("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt()))
checkUtf8to16Throws("\uFFFD1\uFFFD", intArrayOf(-16, -97, -104, '1'.toInt(), -16, -97, -104))
}
fun test8to16CustomBorders() {
// Valid strings.
checkValidUtf8to16("He",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()),0, 2)
checkValidUtf8to16("ll",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 2, 2)
checkValidUtf8to16("lo",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 2)
checkValidUtf8to16("",
intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
checkValidUtf8to16("\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
0, 8)
checkValidUtf8to16("\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
4, 8)
checkValidUtf8to16("\uD800\uDC00\uD800\uDC00",
intArrayOf(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128),
8, 8)
// Index out of bound
val helloArray = byteArrayOf('H'.toByte(), 'e'.toByte(), 'l'.toByte(), 'l'.toByte(), 'o'.toByte())
checkOutOfBoundsUtf8to16(IndexOutOfBoundsException::class, "Hello", helloArray, -1, 4)
checkOutOfBoundsUtf8to16(IndexOutOfBoundsException::class, "Hello", helloArray, 5, 10)
checkOutOfBoundsUtf8to16(IndexOutOfBoundsException::class, "Hello", helloArray, 2, 10)
checkOutOfBoundsUtf8to16(IndexOutOfBoundsException::class, "Hello", helloArray, 10, 0)
checkOutOfBoundsUtf8to16(IllegalArgumentException::class, "Hello", helloArray, 3, -2)
// Test manual conversion with replacement and custom borders.
// Incorrect UTF-8 lead character.
checkUtf8to16Replacing("\uFFFD1", intArrayOf(-1, '1'.toInt(), '2'.toInt()), 0, 2)
checkUtf8to16Replacing("\uFFFD2", intArrayOf('1'.toInt(), -1, '2'.toInt(), '3'.toInt()), 1, 2)
checkUtf8to16Replacing("2\uFFFD", intArrayOf('1'.toInt(), '2'.toInt(), -1), 1, 2)
// Incomplete codepoint.
checkUtf8to16Replacing("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt(), '2'.toInt()), 0, 4)
checkUtf8to16Replacing("\uFFFD2", intArrayOf('1'.toInt(), -16, -97, -104, '2'.toInt(), '3'.toInt()), 1, 4)
checkUtf8to16Replacing("2\uFFFD", intArrayOf('1'.toInt(), '2'.toInt(), -16, -97, -104), 1, 4)
// Test manual conversion with an exception if an input is invalid and custom borders.
// Incorrect UTF-8 lead character.
checkUtf8to16Throws("\uFFFD1", intArrayOf(-1, '1'.toInt(), '2'.toInt()), 0, 2)
checkUtf8to16Throws("\uFFFD2", intArrayOf('1'.toInt(), -1, '2'.toInt(), '3'.toInt()), 1, 2)
checkUtf8to16Throws("2\uFFFD", intArrayOf('1'.toInt(), '2'.toInt(), -1), 1, 2)
// Incomplete codepoint.
checkUtf8to16Throws("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt(), '2'.toInt()), 0, 4)
checkUtf8to16Throws("\uFFFD2", intArrayOf('1'.toInt(), -16, -97, -104, '2'.toInt(), '3'.toInt()), 1, 4)
checkUtf8to16Throws("2\uFFFD", intArrayOf('1'.toInt(), '2'.toInt(), -16, -97, -104), 1, 4)
}
// ----------------- Test zero-terminated UTF-8 to UTF-16 conversion -----------------
fun testZeroTerminated8To16() {
// Valid strings.
checkValidZeroTerminatedUtf8to16("Hell", intArrayOf('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 0, 'o'.toInt()))
checkValidZeroTerminatedUtf8to16("При", intArrayOf(-48, -97, -47, -128, -48, -72, 0, -48, -78, 0, -48, -75, -47, -126))
checkValidZeroTerminatedUtf8to16("\uD800\uDC00", intArrayOf(-16, -112, -128, -128, 0, -16, -112, -128, -128))
checkValidZeroTerminatedUtf8to16("", intArrayOf(0, 'H'.toInt()))
// Test manual conversion with replacement.
// Incorrect UTF-8 lead character.
checkZeroTerminatedUtf8to16Replacing("\uFFFD", intArrayOf(-1, 0, '1'.toInt()))
// Incomplete codepoint.
checkZeroTerminatedUtf8to16Replacing("\uFFFD", intArrayOf(-16, -97, -104, 0, '1'.toInt()))
checkZeroTerminatedUtf8to16Replacing("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt(), 0, -16, -97, -104))
// Test manual conversion with exception throwing
// Incorrect UTF-8 lead character -> throw.
checkZeroTerminatedUtf8to16Throws("\uFFFD", intArrayOf(-1, 0, '1'.toInt()))
// Incomplete codepoint -> throw.
checkZeroTerminatedUtf8to16Throws("\uFFFD", intArrayOf(-16, -97, -104, 0, '1'.toInt()))
checkZeroTerminatedUtf8to16Throws("\uFFFD1", intArrayOf(-16, -97, -104, '1'.toInt(), 0, -16, -97, -104))
}
fun testZeroTerminated8To16CustomBorders() {
val array = intArrayOf('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0)
checkValidZeroTerminatedUtf8to16("aaa", array, 0, 5)
checkValidZeroTerminatedUtf8to16("a", array, 2, 2)
checkValidZeroTerminatedUtf8to16("", array, 3, 2)
checkValidZeroTerminatedUtf8to16("bb", array, 4, 2)
checkValidZeroTerminatedUtf8to16("bbb", array, 4, 3)
checkValidZeroTerminatedUtf8to16("bbb", array, 4, 4)
checkValidZeroTerminatedUtf8to16("bb", array, 5, 3)
checkValidZeroTerminatedUtf8to16("b", array, 6, 2)
checkValidZeroTerminatedUtf8to16("", array, 7, 1)
checkValidZeroTerminatedUtf8to16("", array, 8, 0)
val byteArray = ByteArray(array.size) { array[it].toByte() }
checkOutOfBoundsZeroTerminatedUtf8to16(IndexOutOfBoundsException::class, "aaa0bbb0", byteArray, -1, 4)
checkOutOfBoundsZeroTerminatedUtf8to16(IndexOutOfBoundsException::class, "aaa0bbb0", byteArray, 8, 10)
checkOutOfBoundsZeroTerminatedUtf8to16(IndexOutOfBoundsException::class, "aaa0bbb0", byteArray, 2, 10)
checkOutOfBoundsZeroTerminatedUtf8to16(IndexOutOfBoundsException::class, "aaa0bbb0", byteArray, 10, 0)
checkOutOfBoundsZeroTerminatedUtf8to16(IllegalArgumentException::class, "aaa0bbb0", byteArray, 3, -2)
}
// ------------------------------------ Run tests ------------------------------------
@Test fun runTest() {
test16to8()
test16to8CustomBorders()
test8to16()
test8to16CustomBorders()
testZeroTerminated8To16()
testZeroTerminated8To16CustomBorders()
testPrint()
}
@@ -63,10 +63,59 @@ class CharNativeTest {
assertEquals("\u0069\u0307", '\u0130'.lowercase())
}
@Test
fun titlecase() {
// titlecase = titlecaseChar = char != uppercaseChar
assertEquals('\u10F0'.titlecaseChar().toString(), '\u10F0'.titlecase())
assertEquals('\u10F0', '\u10F0'.titlecaseChar())
assertNotEquals('\u10F0', '\u10F0'.uppercaseChar())
}
@Test
fun testIsSupplementaryCodePoint() {
assertFalse(Char.isSupplementaryCodePoint(-1))
for (c in 0..0xFFFF) {
assertFalse(Char.isSupplementaryCodePoint(c.toInt()))
}
for (c in 0xFFFF + 1..0x10FFFF) {
assertTrue(Char.isSupplementaryCodePoint(c))
}
assertFalse(Char.isSupplementaryCodePoint(0x10FFFF + 1))
}
@Test
fun isSurrogatePair() {
assertFalse(Char.isSurrogatePair('\u0000', '\u0000'))
assertFalse(Char.isSurrogatePair('\u0000', '\uDC00'))
assertTrue( Char.isSurrogatePair('\uD800', '\uDC00'))
assertTrue( Char.isSurrogatePair('\uD800', '\uDFFF'))
assertTrue( Char.isSurrogatePair('\uDBFF', '\uDFFF'))
assertFalse(Char.isSurrogatePair('\uDBFF', '\uF000'))
}
@Test
fun toChars() {
assertContentEquals(Char.toChars(0x010000), charArrayOf('\uD800', '\uDC00'))
assertContentEquals(Char.toChars(0x010001), charArrayOf('\uD800', '\uDC01'))
assertContentEquals(Char.toChars(0x010401), charArrayOf('\uD801', '\uDC01'))
assertContentEquals(Char.toChars(0x10FFFF), charArrayOf('\uDBFF', '\uDFFF'))
assertFailsWith<IllegalArgumentException> { Char.toChars(Int.MAX_VALUE) }
}
@Test
fun toCodePoint() {
assertEquals(0x010000, Char.toCodePoint('\uD800', '\uDC00'))
assertEquals(0x010001, Char.toCodePoint('\uD800', '\uDC01'))
assertEquals(0x010401, Char.toCodePoint('\uD801', '\uDC01'))
assertEquals(0x10FFFF, Char.toCodePoint('\uDBFF', '\uDFFF'))
}
@Test
fun category() {
assertTrue('<' in CharCategory.MATH_SYMBOL)
assertTrue(';' in CharCategory.OTHER_PUNCTUATION)
assertTrue('_' in CharCategory.CONNECTOR_PUNCTUATION)
assertTrue('$' in CharCategory.CURRENCY_SYMBOL)
}
}
@@ -0,0 +1,218 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test.text
import kotlin.test.*
// Native-specific part of stdlib/test/text/StringBuilderTest.kt
class StringBuilderNativeTest {
@Test
fun insertCharSequence() {
StringBuilder("my insert CharSequence test").let { sb ->
sb.insert(0, null as CharSequence?)
assertEquals("nullmy insert CharSequence test", sb.toString())
sb.insert(2, null as CharSequence?)
assertEquals("nunullllmy insert CharSequence test", sb.toString())
sb.insert(sb.length, null as CharSequence?)
assertEquals("nunullllmy insert CharSequence testnull", sb.toString())
sb.insert(2, "12" as CharSequence)
assertEquals("nu12nullllmy insert CharSequence testnull", sb.toString())
sb.insert(sb.length, "12" as CharSequence)
assertEquals("nu12nullllmy insert CharSequence testnull12", sb.toString())
}
}
@Test
fun insertString() {
StringBuilder("my insert String test").let { sb ->
sb.insertRange(0, "1234", 0, 0)
assertEquals("my insert String test", sb.toString())
sb.insertRange(0, "1234", 0, 1)
assertEquals("1my insert String test", sb.toString())
sb.insertRange(0, "1234", 1, 3)
assertEquals("231my insert String test", sb.toString())
sb.insertRange(2, "1234", 0, 0)
assertEquals("231my insert String test", sb.toString())
sb.insertRange(2, "1234", 0, 1)
assertEquals("2311my insert String test", sb.toString())
sb.insertRange(2, "1234", 1, 3)
assertEquals("232311my insert String test", sb.toString())
sb.insertRange(sb.length, "1234", 0, 0)
assertEquals("232311my insert String test", sb.toString())
sb.insertRange(sb.length, "1234", 0, 1)
assertEquals("232311my insert String test1", sb.toString())
sb.insertRange(sb.length, "1234", 1, 3)
assertEquals("232311my insert String test123", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, "_") }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, "_") }
assertFails { sb.insertRange(0, "null", -1, 0) }
assertFails { sb.insertRange(0, "null", 0, 5) }
assertFails { sb.insertRange(0, "null", 2, 1) }
}
}
@Test
fun insertByte() {
StringBuilder().let { sb ->
sb.insert(0, 42.toByte())
assertEquals("42", sb.toString())
sb.insert(0, 13.toByte())
assertEquals("1342", sb.toString())
sb.insert(3, -1.toByte())
assertEquals("134-12", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.toByte()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.toByte()) }
}
}
@Test
fun insertShort() {
StringBuilder().let { sb ->
sb.insert(0, 42.toShort())
assertEquals("42", sb.toString())
sb.insert(0, 13.toShort())
assertEquals("1342", sb.toString())
sb.insert(3, -1.toShort())
assertEquals("134-12", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.toShort()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.toShort()) }
}
}
@Test
fun insertInt() {
StringBuilder().let { sb ->
sb.insert(0, 42.toInt())
assertEquals("42", sb.toString())
sb.insert(0, 13.toInt())
assertEquals("1342", sb.toString())
sb.insert(3, -1.toInt())
assertEquals("134-12", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.toInt()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.toInt()) }
}
}
@Test
fun insertLong() {
StringBuilder().let { sb ->
sb.insert(0, 42.toLong())
assertEquals("42", sb.toString())
sb.insert(0, 13.toLong())
assertEquals("1342", sb.toString())
sb.insert(3, -1.toLong())
assertEquals("134-12", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.toLong()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.toLong()) }
}
}
@Test
fun insertFloat() {
StringBuilder().let { sb ->
sb.insert(0, 42.2.toFloat())
assertEquals("42.2", sb.toString())
sb.insert(0, 13.1.toFloat())
assertEquals("13.142.2", sb.toString())
sb.insert(3, -1.toFloat())
assertEquals("13.-1.0142.2", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.2.toFloat()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.2.toFloat()) }
}
}
@Test
fun insertDouble() {
StringBuilder().let { sb ->
sb.insert(0, 42.2.toDouble())
assertEquals("42.2", sb.toString())
sb.insert(0, 13.1.toDouble())
assertEquals("13.142.2", sb.toString())
sb.insert(3, -1.toDouble())
assertEquals("13.-1.0142.2", sb.toString())
assertFailsWith<IndexOutOfBoundsException> { sb.insert(-1, 42.2.toDouble()) }
assertFailsWith<IndexOutOfBoundsException> { sb.insert(sb.length + 1, 42.2.toDouble()) }
}
}
@Test
fun testReverse() {
val sb = StringBuilder("123456")
assertTrue(sb === sb.reverse())
assertEquals("654321", sb.toString())
sb.setLength(1)
assertEquals("6", sb.toString())
sb.setLength(0)
assertEquals("", sb.toString())
}
@Test
fun testDoubleReverse() {
fun assertReversed(original: String, reversed: String, reversedBack: String = original) {
assertEquals(reversed, StringBuilder(original).reverse().toString())
assertEquals(reversedBack, StringBuilder(reversed).reverse().toString())
}
assertReversed("a", "a")
assertReversed("ab", "ba")
assertReversed("abcdef", "fedcba")
assertReversed("abcdefg", "gfedcba")
assertReversed("\ud800\udc00", "\ud800\udc00")
assertReversed("\udc00\ud800", "\ud800\udc00", "\ud800\udc00")
assertReversed("a\ud800\udc00", "\ud800\udc00a")
assertReversed("ab\ud800\udc00", "\ud800\udc00ba")
assertReversed("abc\ud800\udc00", "\ud800\udc00cba")
assertReversed("\ud800\udc00\udc01\ud801\ud802\udc02", "\ud802\udc02\ud801\udc01\ud800\udc00", "\ud800\udc00\ud801\udc01\ud802\udc02")
assertReversed("\ud800\udc00\ud801\udc01\ud802\udc02", "\ud802\udc02\ud801\udc01\ud800\udc00")
assertReversed("\ud800\udc00\udc01\ud801a", "a\ud801\udc01\ud800\udc00", "\ud800\udc00\ud801\udc01a")
assertReversed("a\ud800\udc00\ud801\udc01", "\ud801\udc01\ud800\udc00a")
assertReversed("\ud800\udc00\udc01\ud801ab", "ba\ud801\udc01\ud800\udc00", "\ud800\udc00\ud801\udc01ab")
assertReversed("ab\ud800\udc00\ud801\udc01", "\ud801\udc01\ud800\udc00ba")
assertReversed("\ud800\udc00\ud801\udc01", "\ud801\udc01\ud800\udc00")
assertReversed("a\ud800\udc00z\ud801\udc01", "\ud801\udc01z\ud800\udc00a")
assertReversed("a\ud800\udc00bz\ud801\udc01", "\ud801\udc01zb\ud800\udc00a")
assertReversed("abc\ud802\udc02\ud801\udc01\ud800\udc00", "\ud800\udc00\ud801\udc01\ud802\udc02cba")
assertReversed("abcd\ud802\udc02\ud801\udc01\ud800\udc00", "\ud800\udc00\ud801\udc01\ud802\udc02dcba")
}
@Test
fun appendLong() {
val times = 100
val expected = (12345678L until (12345678L + times)).fold("") { res, idx -> res + idx }
val sb = StringBuilder()
repeat(times) { sb.append(12345678L + it) }
assertEquals(expected, sb.toString())
val cornerCase = listOf(0L, -1L, Long.MIN_VALUE, Long.MAX_VALUE)
val expectedCornerCase = cornerCase.fold("") { res, e -> res + e }
for (v in cornerCase) sb.append(v)
assertEquals(expected + expectedCornerCase, sb.toString())
}
@Test
fun appendNullCharSequence() {
val sb = StringBuilder()
sb.append(null as CharSequence?)
assertEquals("null", sb.toString())
}
@Test
fun appendLine() {
val sb = StringBuilder()
sb.appendLine("abc").appendLine(42).appendLine(0.1)
assertEquals("abc\n42\n0.1\n", sb.toString())
}
}
@@ -6,7 +6,216 @@
package test.text
import kotlin.reflect.KClass
import kotlin.test.*
import kotlinx.cinterop.toKString
import test.assertArrayContentEquals
internal actual val surrogateCodePointDecoding: String = "\uFFFD".repeat(3)
internal actual val surrogateCharEncoding: ByteArray = byteArrayOf(0xEF.toByte(), 0xBF.toByte(), 0xBD.toByte())
// Native-specific part of stdlib/test/text/StringEncodingTest.kt
class StringEncodingTestNative {
private fun bytes(vararg elements: Int) = ByteArray(elements.size) {
val v = elements[it]
require(v in Byte.MIN_VALUE..Byte.MAX_VALUE)
v.toByte()
}
private fun testEncoding(isWellFormed: Boolean, expected: ByteArray, string: String) {
assertArrayContentEquals(expected, string.encodeToByteArray())
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { string.encodeToByteArray(throwOnInvalidSequence = true) }
} else {
assertArrayContentEquals(expected, string.encodeToByteArray(throwOnInvalidSequence = true))
assertEquals(string, string.encodeToByteArray(throwOnInvalidSequence = true).decodeToString())
}
}
private fun testEncoding(isWellFormed: Boolean, expected: ByteArray, string: String, startIndex: Int, endIndex: Int) {
assertArrayContentEquals(expected, string.encodeToByteArray(startIndex, endIndex))
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { string.encodeToByteArray(startIndex, endIndex, true) }
} else {
assertArrayContentEquals(expected, string.encodeToByteArray(startIndex, endIndex, true))
string.encodeToByteArray(startIndex, endIndex, true).decodeToString()
}
}
@Test
fun encodeToByteArray() {
// Valid strings.
testEncoding(true, bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), "Hello")
testEncoding(true, bytes(-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126), "Привет")
// Different kinds of input
testEncoding(false, bytes(-16, -112, -128, -128, '1'.toInt(), -17, -65, -67, -17, -65, -67), "\uD800\uDC001\uDC00\uD800")
// Lone surrogate
testEncoding(false, bytes(-17, -65, -67, '1'.toInt(), '2'.toInt()), "\uD80012", )
testEncoding(false, bytes(-17, -65, -67, '1'.toInt(), '2'.toInt()), "\uDC0012")
testEncoding(false, bytes('1'.toInt(), '2'.toInt(), -17, -65, -67), "12\uD800")
}
@Test
fun encodeToByteArraySlice() {
// Valid strings.
testEncoding(true, bytes(-16, -112, -128, -128, -16, -112, -128, -128), "\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00", 0, 4)
testEncoding(true, bytes(-16, -112, -128, -128, -16, -112, -128, -128), "\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00", 2, 6)
testEncoding(true, bytes(-16, -112, -128, -128, -16, -112, -128, -128), "\uD800\uDC00\uD800\uDC00\uD800\uDC00\uD800\uDC00", 4, 8)
// Illegal surrogate pair
testEncoding(false, bytes(-17, -65, -67, -17, -65, -67, '1'.toInt()), "\uDC00\uD80012", 0, 3)
testEncoding(false, bytes(-17, -65, -67, -17, -65, -67, '2'.toInt()), "1\uDC00\uD8002", 1, 4)
testEncoding(false, bytes('2'.toInt(), -17, -65, -67, -17, -65, -67), "12\uDC00\uD800", 1, 4)
// Lone surrogate
testEncoding(false, bytes('1'.toInt(), -17, -65, -67), "1\uD800\uDC002", 0, 2)
testEncoding(false, bytes(-17, -65, -67, '2'.toInt()), "1\uD800\uDC002", 2, 4)
}
private fun testDecoding(isWellFormed: Boolean, expected: String, bytes: ByteArray) {
assertEquals(expected, bytes.decodeToString())
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { bytes.decodeToString(throwOnInvalidSequence = true) }
} else {
assertEquals(expected, bytes.decodeToString(throwOnInvalidSequence = true))
assertArrayContentEquals(bytes, bytes.decodeToString(throwOnInvalidSequence = true).encodeToByteArray())
}
}
private fun testDecoding(isWellFormed: Boolean, expected: String, bytes: ByteArray, startIndex: Int, endIndex: Int) {
assertEquals(expected, bytes.decodeToString(startIndex, endIndex))
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { bytes.decodeToString(startIndex, endIndex, true) }
} else {
assertEquals(expected, bytes.decodeToString(startIndex, endIndex, true))
assertArrayContentEquals(
bytes.sliceArray(startIndex until endIndex),
bytes.decodeToString(startIndex, endIndex, true).encodeToByteArray()
)
}
}
@Test
fun decodeToString() {
// Valid strings.
testDecoding(true, "Hello", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()))
testDecoding(true, "Привет", bytes(-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126))
testDecoding(true, "\uD800\uDC00", bytes(-16, -112, -128, -128))
// Incorrect UTF-8 lead character.
testDecoding(false, "\uFFFD1", bytes(-1, '1'.toInt()))
// Incomplete codepoint.
testDecoding(false, "\uFFFD1", bytes(-16, -97, -104, '1'.toInt()))
testDecoding(false, "\uFFFD1\uFFFD", bytes(-16, -97, -104, '1'.toInt(), -16, -97, -104))
}
@Test
fun decodeToStringSlice() {
// Valid strings.
testDecoding(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 0, 8)
testDecoding(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 4, 12)
testDecoding(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 8, 16)
// Incorrect UTF-8 lead character.
testDecoding(false, "\uFFFD1", bytes(-1, '1'.toInt(), '2'.toInt()), 0, 2)
testDecoding(false, "\uFFFD2", bytes('1'.toInt(), -1, '2'.toInt(), '3'.toInt()), 1, 3)
testDecoding(false, "2\uFFFD", bytes('1'.toInt(), '2'.toInt(), -1), 1, 3)
// Incomplete codepoint.
testDecoding(false, "\uFFFD1", bytes(-16, -97, -104, '1'.toInt(), '2'.toInt()), 0, 4)
testDecoding(false, "\uFFFD2", bytes('1'.toInt(), -16, -97, -104, '2'.toInt(), '3'.toInt()), 1, 5)
testDecoding(false, "2\uFFFD", bytes('1'.toInt(), '2'.toInt(), -16, -97, -104), 1, 5)
}
private fun testToKString(isWellFormed: Boolean, expected: String, bytes: ByteArray) {
assertEquals(expected, bytes.toKString())
assertEquals(expected, bytes.copyOf(bytes.size + 1).toKString())
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { bytes.toKString(throwOnInvalidSequence = true) }
assertFailsWith<CharacterCodingException> { bytes.copyOf(bytes.size + 1).toKString(throwOnInvalidSequence = true) }
} else {
assertEquals(expected, bytes.toKString(throwOnInvalidSequence = true))
assertEquals(expected, bytes.copyOf(bytes.size + 1).toKString(throwOnInvalidSequence = true))
}
}
private fun testToKString(isWellFormed: Boolean, expected: String, bytes: ByteArray, startIndex: Int, endIndex: Int) {
assertEquals(expected, bytes.toKString(startIndex, endIndex))
assertEquals(expected, bytes.copyOf(bytes.size + 1).toKString(startIndex, endIndex))
if (!isWellFormed) {
assertFailsWith<CharacterCodingException> { bytes.toKString(startIndex, endIndex, true) }
assertFailsWith<CharacterCodingException> { bytes.copyOf(bytes.size + 1).toKString(startIndex, endIndex, true) }
} else {
assertEquals(expected, bytes.toKString(startIndex, endIndex, true))
assertEquals(expected, bytes.copyOf(bytes.size + 1).toKString(startIndex, endIndex, true))
}
}
@Test
fun toKString() {
// Valid strings.
testToKString(true, "Hello", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()))
testToKString(true, "Hell", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 0, 'o'.toInt()))
testToKString(true, "Привет", bytes(-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126))
testToKString(true, "При", bytes(-48, -97, -47, -128, -48, -72, 0, -48, -78, 0, -48, -75, -47, -126))
testToKString(true, "\uD800\uDC00", bytes(-16, -112, -128, -128))
testToKString(true, "\uD800\uDC00", bytes(-16, -112, -128, -128, 0, -16, -112, -128, -128))
testToKString(true, "", bytes())
testToKString(true, "", bytes(0, 'H'.toInt()))
// Incorrect UTF-8 lead character.
testToKString(false, "\uFFFD1", bytes(-1, '1'.toInt()))
testToKString(false, "\uFFFD", bytes(-1, 0, '1'.toInt()))
// Incomplete codepoint.
testToKString(false, "\uFFFD1", bytes(-16, -97, -104, '1'.toInt()))
testToKString(false, "\uFFFD", bytes(-16, -97, -104, 0, '1'.toInt()))
testToKString(false, "\uFFFD1\uFFFD", bytes(-16, -97, -104, '1'.toInt(), -16, -97, -104))
testToKString(false, "\uFFFD1", bytes(-16, -97, -104, '1'.toInt(), 0, -16, -97, -104))
}
@Test
fun toKStringSlice() {
assertFailsWith<IndexOutOfBoundsException> { bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()).toKString(-1, 3) }
assertFailsWith<IndexOutOfBoundsException> { bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()).toKString(5, 15) }
assertFailsWith<IndexOutOfBoundsException> { bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()).toKString(2, 12) }
assertFailsWith<IndexOutOfBoundsException> { bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()).toKString(10, 10) }
assertFailsWith<IllegalArgumentException> { bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()).toKString(3, 1) }
assertFailsWith<IndexOutOfBoundsException> { bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0).toKString(-1, 3) }
assertFailsWith<IndexOutOfBoundsException> { bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0).toKString(8, 18) }
assertFailsWith<IndexOutOfBoundsException> { bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0).toKString(2, 12) }
assertFailsWith<IndexOutOfBoundsException> { bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0).toKString(10, 10) }
assertFailsWith<IllegalArgumentException> { bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0).toKString(3, 1) }
// Valid strings.
testToKString(true, "He", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 2)
testToKString(true, "ll", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 2, 4)
testToKString(true, "lo", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 3, 5)
testToKString(true, "", bytes('H'.toInt(), 'e'.toInt(), 'l'.toInt(), 'l'.toInt(), 'o'.toInt()), 0, 0)
testToKString(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 0, 8)
testToKString(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 4, 12)
testToKString(true, "\uD800\uDC00\uD800\uDC00", bytes(-16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128, -16, -112, -128, -128), 8, 16)
testToKString(true, "aaa", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 0, 5)
testToKString(true, "a", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 2, 4)
testToKString(true, "", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 3, 5)
testToKString(true, "bb", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 4, 6)
testToKString(true, "bbb", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 4, 7)
testToKString(true, "bbb", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 4, 8)
testToKString(true, "bb", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 5, 8)
testToKString(true, "b", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 6, 8)
testToKString(true, "", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 7, 8)
testToKString(true, "", bytes('a'.toInt(), 'a'.toInt(), 'a'.toInt(), 0, 'b'.toInt(), 'b'.toInt(), 'b'.toInt(), 0), 8, 8)
// Incorrect UTF-8 lead character.
testToKString(false, "\uFFFD1", bytes(-1, '1'.toInt(), '2'.toInt()), 0, 2)
testToKString(false, "\uFFFD2", bytes('1'.toInt(), -1, '2'.toInt(), '3'.toInt()), 1, 3)
testToKString(false, "2\uFFFD", bytes('1'.toInt(), '2'.toInt(), -1), 1, 3)
// Incomplete codepoint.
testToKString(false, "\uFFFD1", bytes(-16, -97, -104, '1'.toInt(), '2'.toInt()), 0, 4)
testToKString(false, "\uFFFD2", bytes('1'.toInt(), -16, -97, -104, '2'.toInt(), '3'.toInt()), 1, 5)
testToKString(false, "2\uFFFD", bytes('1'.toInt(), '2'.toInt(), -16, -97, -104), 1, 5)
}
}
@@ -16,6 +16,8 @@ class StringNativeTest {
// Surrogate pairs
assertEquals("\uD801\uDC4F\uD806\uDCD0\uD81B\uDE7F", "\uD801\uDC27\uD806\uDCB0\uD81B\uDE5F".lowercase())
assertEquals("\ud801\udc28", "\ud801\udc28".lowercase())
assertEquals("\ud801\udc28", "\ud801\udc00".lowercase())
// Special Casing
// LATIN CAPITAL LETTER I WITH DOT ABOVE
@@ -102,5 +104,51 @@ class StringNativeTest {
fun uppercase() {
// Non-ASCII
assertEquals("\u00DE\u03A9\u0403\uA779", "\u00FE\u03A9\u0453\uA77A".uppercase())
// Surrogate pairs
assertEquals("\ud801\udc00", "\ud801\udc28".uppercase())
assertEquals("\ud801\udc00", "\ud801\udc00".uppercase())
}
@Test
fun capitalize() {
// Non-ASCII
assertEquals("\u00DE\u03A9\u0453\uA77A", "\u00FE\u03A9\u0453\uA77A".capitalize())
}
@Test fun indexOfString() {
assertEquals(1, "bceded".indexOf("ced", -1))
assertEquals(-1, "bceded".indexOf("e", 7))
assertEquals(-1, "bceded".indexOf("e", Int.MAX_VALUE))
assertEquals(6, "bceded".indexOf("", Int.MAX_VALUE))
assertEquals(-1, "".indexOf("a", -3))
assertEquals(0, "".indexOf("", 0))
}
@Test
fun indexOfChar() {
assertEquals(-1, "bcedef".indexOf('e', 5))
assertEquals(-1, "".indexOf('a', -3))
assertEquals(-1, "".indexOf('a', 10))
assertEquals(-1, "".indexOf(0.toChar(), -3))
assertEquals(-1, "".indexOf(0.toChar(), 10))
}
@Test
fun equalsIgnoreCase() {
assertTrue("hello".equals("HElLo", true))
assertTrue("Привет".equals("прИВет", true))
}
@Test
fun trim() {
assertEquals(expected = "String", actual = "\u0020 \u202FString\u2028\u2029".trim(),
message = "Trim special whitespaces")
assertEquals(expected = "\u1FFFString", actual = "\u00A0 \u1FFFString".trim(),
message = "Trim special whitespace but should left a unicode symbol")
}
}
@@ -0,0 +1,130 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test.text
import kotlin.test.*
// Native-specific part of stdlib/test/text/StringNumberConversionTest.kt
class StringNumberConversionNativeTest {
@Test
fun toDouble() {
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(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(2.71, "\u0009 \u000A 2.71 \u000D".toDouble())
assertEquals(42.3, "\n 42.3 ".toDouble())
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()
}
assertFailsWith<NumberFormatException> { "\u20293.14".toDouble() }
assertFailsWith<NumberFormatException> { "3.14\u200B".toDouble() }
assertFailsWith<NumberFormatException> { "3.14\u200B ABC".toDouble() }
// Illegal surrogate pair
assertFailsWith<NumberFormatException> { "\uDC00\uD800".toDouble() }
// Different kinds of input (including illegal one)
assertFailsWith<NumberFormatException> { "\uD800\uDC001\uDC00\uD800".toDouble() }
// Lone surrogate
assertFailsWith<NumberFormatException> { "\uD80012".toDouble() }
assertFailsWith<NumberFormatException> { "\uDC0012".toDouble() }
assertFailsWith<NumberFormatException> { "12\uD800".toDouble() }
}
@Test
fun toFloat() {
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(Float.POSITIVE_INFINITY, "+5.234e+123f".toFloat())
assertEquals(7.15f, "\u0019 7.15 ".toFloat())
assertEquals(2.71f, "\u0009 \u000A 2.71 \u000D".toFloat())
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()
}
assertFailsWith<NumberFormatException> { "\u202F3.14".toFloat() }
// Illegal surrogate pair
assertFailsWith<NumberFormatException> { "\uDC00\uD800".toFloat() }
// Different kinds of input (including illegal one)
assertFailsWith<NumberFormatException> { "\uD800\uDC001\uDC00\uD800".toFloat() }
// Lone surrogate
assertFailsWith<NumberFormatException> { "\uD80012".toFloat() }
assertFailsWith<NumberFormatException> { "\uDC0012".toFloat() }
assertFailsWith<NumberFormatException> { "12\uD800".toFloat() }
}
}