[K/N] Migrate runtime/text tests to new testing infra ^KT-61259
This commit is contained in:
committed by
Space Team
parent
e9983a947f
commit
17dc60aac9
@@ -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 +0,0 @@
|
||||
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() }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user