| /* |
| * Copyright 2010-2020 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.* |
| |
| class StringNativeTest { |
| |
| @Test |
| fun lowercase() { |
| // Non-ASCII |
| assertEquals("\u214E\uA7B5\u2CEF", "\u2132\uA7B4\u2CEF".lowercase()) |
| |
| // 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 |
| assertEquals("\u0069\u0307", "\u0130".lowercase()) |
| assertEquals("a\u0069\u0307z", "a\u0130Z".lowercase()) |
| |
| // Final_Sigma |
| run { |
| fun caseIgnorable(length: Int): String { |
| return listOf( |
| "\u0483", // COMBINING CYRILLIC TITLO; Mn |
| "\u20DF", // COMBINING ENCLOSING DIAMOND; Me |
| "\uD804\uDCBD", // 110BD; KAITHI NUMBER SIGN; Cf |
| "\u2C7D", // MODIFIER LETTER CAPITAL V; Lm |
| "\uD83C\uDFFD", // 1F3FD; EMOJI MODIFIER FITZPATRICK TYPE-4; Sk |
| "\u003A", // COLON; Po; Word_Break=MidLetter |
| "\uFF0E", // FULLWIDTH FULL STOP; Po; Word_Break=MidNumLet |
| "\u0027" // APOSTROPHE; Po; Word_Break=Single_Quote |
| ).shuffled().take(length).joinToString(separator = "") |
| } |
| |
| fun cased(): String { |
| return listOf( |
| "\u0041", // LATIN CAPITAL LETTER A; Lu |
| "\uD81B\uDE63", // 16E63; MEDEFAIDRIN SMALL LETTER W; Ll |
| "\u01CB", // LATIN CAPITAL LETTER N WITH SMALL LETTER J; Lt |
| "\u217A", // SMALL ROMAN NUMERAL ELEVEN; Nl; Other_Lowercase |
| "\uD83C\uDD50" // 1F150; NEGATIVE CIRCLED LATIN CAPITAL LETTER A; So; Other_Uppercase |
| ).random() |
| } |
| |
| fun other(): String { |
| return listOf( |
| "\u0000", // <control>; Cc |
| "\u0030", // DIGIT ZERO; Nd |
| "\uD838\uDEC6" // 1E2C6; WANCHO LETTER YA; Lo |
| ).random() |
| } |
| |
| fun Char.hex(): String { |
| return code.toString(16).padStart(4, '0') |
| } |
| |
| val sigma = '\u03A3' |
| val lowerSigma = '\u03C3' |
| val specialLowerSigma = '\u03C2' |
| |
| // Build a string of the form: [cased][other](caseIgnorable*)(sigma)(caseIgnorable*)[other][cased] |
| for (precedingCaseIgnorable in 0..5) { |
| for (succeedingCaseIgnorable in 0..5) { |
| val caseIgnorableBefore = caseIgnorable(precedingCaseIgnorable) |
| val caseIgnorableAfter = caseIgnorable(succeedingCaseIgnorable) |
| val sigmaNearby = caseIgnorableBefore + sigma + caseIgnorableAfter |
| val lowerSigmaNearby = caseIgnorableBefore + lowerSigma + caseIgnorableAfter |
| val specialSigmaNearby = caseIgnorableBefore + specialLowerSigma + caseIgnorableAfter |
| |
| for (mask in 0 until (1 shl 4)) { |
| val casedBefore = cased().repeat((mask shr 0) and 1) |
| val casedAfter = cased().repeat((mask shr 1) and 1) |
| val otherBefore = other().repeat((mask shr 2) and 1) |
| val otherAfter = other().repeat((mask shr 3) and 1) |
| |
| val resultSigmaNearby = |
| if (otherBefore.isEmpty() && casedBefore.isNotEmpty() && (otherAfter.isNotEmpty() || casedAfter.isEmpty())) |
| specialSigmaNearby |
| else |
| lowerSigmaNearby |
| |
| val actual = (casedBefore + otherBefore + sigmaNearby + otherAfter + casedAfter).lowercase() |
| val expected = casedBefore.lowercase() + otherBefore + resultSigmaNearby + otherAfter + casedAfter.lowercase() |
| |
| assertEquals( |
| expected, |
| actual, |
| "Expected <$expected>${expected.map { it.hex() }}, Actual <$actual>${actual.map { it.hex() }}" |
| ) |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| 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") |
| } |
| |
| @Test |
| fun subSequence() { |
| assertEquals("ello", "Hello world".subSequence(1, 5).toString()) |
| assertEquals("", "Hello world".subSequence(1, 1).toString()) |
| } |
| } |