/* * 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.random.Random import kotlin.test.* import kotlin.text.* class StringBuilderTest { @Test fun stringBuild() { val s = buildString { append("a") append(true) } assertEquals("atrue", s) } @Test fun appendMany() { assertEquals("a1", StringBuilder().append("a", "1").toString()) assertEquals("a1", StringBuilder().append("a", 1).toString()) assertEquals("a1", StringBuilder().append("a", StringBuilder().append("1")).toString()) } @Test fun append() { // this test is needed for JS implementation assertEquals("em", buildString { appendRange("element", 2, 4) }) } @Test fun asCharSequence() { val original = "Some test string" val sb = StringBuilder(original) val result = sb.toString() val cs = sb as CharSequence assertEquals(result.length, cs.length) assertEquals(result.length, sb.length) for (index in result.indices) { assertEquals(result[index], sb[index]) assertEquals(result[index], cs[index]) } assertEquals(result.substring(2, 6), cs.subSequence(2, 6).toString()) } @Test fun constructors() { StringBuilder().let { sb -> assertEquals(0, sb.length) assertEquals("", sb.toString()) } StringBuilder(16).let { sb -> assertEquals(0, sb.length) assertEquals("", sb.toString()) } StringBuilder("content").let { sb -> assertEquals(7, sb.length) assertEquals("content", sb.toString()) } StringBuilder(StringBuilder("content")).let { sb -> assertEquals(7, sb.length) assertEquals("content", sb.toString()) } } @Test fun clear() { val sb = StringBuilder() sb.append("test") val s = sb.toString() sb.clear() assertTrue(sb.isEmpty()) assertEquals("test", s) } @Test fun get() { val sb = StringBuilder() sb.append("test") assertEquals('t', sb[0]) assertEquals('e', sb[1]) assertEquals('s', sb[2]) assertEquals('t', sb[3]) assertFailsWith { assertEquals('t', sb[-1]) } assertFailsWith { assertEquals('t', sb[4]) } } @Test fun reverse() { StringBuilder("my reverse test").let { sb -> sb.reverse() assertEquals("tset esrever ym", sb.toString()) sb.append('\uD800') sb.append('\uDC00') sb.insert(10, '\uDC01') sb.insert(11, '\uD801') sb.insert(0, "\uD802\uDC02") sb.reverse() assertEquals("\uD800\uDC00my re\uD801\uDC01verse test\uD802\uDC02", sb.toString()) } } @Test fun appendChar() { val times = 100 val expected = "a".repeat(times) val sb = StringBuilder() repeat(times) { sb.append('a') } assertEquals(expected, sb.toString()) sb.append('\uD800') sb.append('\uDC00') assertEquals(expected + "\uD800\uDC00", sb.toString()) } @Test fun appendInt() { val times = 100 val expected = (0 until times).fold("") { res, idx -> res + idx } val sb = StringBuilder() repeat(times) { sb.append(it) } assertEquals(expected, sb.toString()) val cornerCase = listOf(0, -1, Int.MIN_VALUE, Int.MAX_VALUE) val expectedCornerCase = cornerCase.fold("") { res, e -> res + e } for (int in cornerCase) sb.append(int) assertEquals(expected + expectedCornerCase, sb.toString()) } @Test fun appendBoolean() { StringBuilder().append(true).append(false).append(true).append(true).let { sb -> assertEquals("truefalsetruetrue", sb.toString()) } } @Test fun appendString() { val times = 100 val expected = "foo".repeat(times) StringBuilder().let { sb -> repeat(times) { sb.append("foo") } assertEquals(expected, sb.toString()) sb.append(null as String?) assertEquals(expected + "null", sb.toString()) } } @Test fun appendAny() { val myAny = object { override fun toString(): String = "It's My Any!" } StringBuilder().let { sb -> sb.append(null as Any?) sb.append(myAny) assertEquals("nullIt's My Any!", sb.toString()) } } @Test fun appendCharArray() { StringBuilder().let { sb -> val times = 100 val expected = "foo".repeat(times) repeat(times) { sb.append(charArrayOf('f', 'o', 'o')) } assertEquals(expected, sb.toString()) } StringBuilder().let { sb -> val charArray = charArrayOf( 'm', 'y', ' ', 'a', 'p', 'p', 'e', 'n', 'd', ' ', 'c', 'h', 'a', 'r', ' ', 'a', 'r', 'r', 'a', 'y', ' ', 't', 'e', 's', 't' ) sb.appendRange(charArray, 0, charArray.size /*25*/) sb.appendRange(charArray, 0, 9) sb.appendRange(charArray, 15, 25) sb.appendRange(charArray, 9, 15) assertEquals("my append char array testmy appendarray test char ", sb.toString()) assertFails { sb.appendRange(charArrayOf('_', '*', '#'), -1, 0) } assertFails { sb.appendRange(charArrayOf('_', '*', '#'), 0, 4) } assertFails { sb.appendRange(charArrayOf('_', '*', '#'), 2, 1) } assertFails { sb.appendRange(charArrayOf('_', '*', '#'), 2, -1) } } } @Test fun deleteChar() { StringBuilder("my delete test").let { sb -> sb.deleteAt(0) assertEquals("y delete test", sb.toString()) sb.deleteAt(5) assertEquals("y delte test", sb.toString()) sb.deleteAt(11) assertEquals("y delte tes", sb.toString()) assertFailsWith { sb.deleteAt(11) } assertFailsWith { sb.deleteAt(-1) } } } @Test fun deleteSubstring() { StringBuilder("my delete substring test").let { sb -> sb.deleteRange(0, 2) assertEquals(" delete substring test", sb.toString()) sb.deleteRange(7, 17) assertEquals(" delete test", sb.toString()) sb.deleteRange(8, 12) assertEquals(" delete ", sb.toString()) sb.deleteRange(8, 12) assertEquals(" delete ", sb.toString()) assertFails { sb.deleteRange(-1, 1) } assertFails { sb.deleteRange(0, -1) } assertFails { sb.deleteRange(2, 1) } assertFails { sb.deleteRange(sb.length + 1, sb.length + 2) } } } @Test @Suppress("DEPRECATION_ERROR") fun capacityTest() { // assertEquals(100, StringBuilder(100).capacity()) // not implemented in JS StringBuilder("string builder from string capacity test").let { sb -> assertTrue(sb.capacity() >= sb.length) } StringBuilder().let { sb -> assertTrue(sb.capacity() >= sb.length) repeat(Random.nextInt(17, 30)) { sb.append('c') } assertTrue(sb.capacity() >= sb.length) repeat(Random.nextInt(35, 62)) { sb.insert(0, "s") } sb.ensureCapacity(1) assertTrue(sb.capacity() >= sb.length) sb.ensureCapacity(sb.length * 10) // assertTrue(sb.capacity() >= sb.length * 10) // not implemented in JS } } @Test fun indexOf() { StringBuilder("my indexOf test").let { sb -> assertEquals(0, sb.indexOf("")) assertEquals(5, sb.indexOf("", 5)) assertEquals(sb.length, sb.indexOf("", sb.length)) assertEquals(sb.length, sb.indexOf("", 100)) // Java implementation, should be -1 assertEquals(6, sb.indexOf("e")) assertEquals(12, sb.indexOf("e", 7)) assertEquals(-1, sb.indexOf("e", 13)) assertEquals(-1, sb.indexOf("e", 100)) assertEquals(11, sb.indexOf("test")) assertEquals(11, sb.indexOf("test", 11)) assertEquals(-1, sb.indexOf("test", 12)) } } @Test fun lastIndexOf() { StringBuilder("my lastIndexOf test").let { sb -> assertEquals(sb.length, sb.lastIndexOf("")) assertEquals(sb.length, sb.lastIndexOf("", 100)) assertEquals(5, sb.lastIndexOf("", 5)) assertEquals(0, sb.lastIndexOf("", 0)) assertEquals(-1, sb.lastIndexOf("", -100)) assertEquals(16, sb.lastIndexOf("e")) assertEquals(10, sb.lastIndexOf("e", 15)) assertEquals(-1, sb.lastIndexOf("e", 9)) assertEquals(-1, sb.lastIndexOf("e", -100)) assertEquals(15, sb.lastIndexOf("test")) assertEquals(15, sb.lastIndexOf("test", 15)) assertEquals(-1, sb.lastIndexOf("test", 14)) } } @Test fun insertBoolean() { StringBuilder().let { sb -> sb.insert(0, true) assertEquals("true", sb.toString()) sb.insert(0, false) assertEquals("falsetrue", sb.toString()) sb.insert(5, true) assertEquals("falsetruetrue", sb.toString()) assertFailsWith { sb.insert(-1, false) } assertFailsWith { sb.insert(sb.length + 1, false) } } } @Test fun insertChar() { StringBuilder("my insert char test").let { sb -> sb.insert(0, '_') assertEquals("_my insert char test", sb.toString()) sb.insert(10, 'T') assertEquals("_my insertT char test", sb.toString()) sb.insert(21, '_') assertEquals("_my insertT char test_", sb.toString()) assertFailsWith { sb.insert(-1, '_') } assertFailsWith { sb.insert(sb.length + 1, '_') } } } @Test fun insertCharArray() { StringBuilder("my insert CharArray test").let { sb -> sb.insert(0, charArrayOf('_')) assertEquals("_my insert CharArray test", sb.toString()) sb.insert(10, charArrayOf('T')) assertEquals("_my insertT CharArray test", sb.toString()) sb.insertRange(26, charArrayOf('_', '*', '#'), 0, 1) assertEquals("_my insertT CharArray test_", sb.toString()) assertFailsWith { sb.insert(-1, charArrayOf('_')) } assertFailsWith { sb.insert(sb.length + 1, charArrayOf('_')) } assertFails { sb.insertRange(0, charArrayOf('_', '*', '#'), -1, 0) } assertFails { sb.insertRange(0, charArrayOf('_', '*', '#'), 0, 4) } assertFails { sb.insertRange(0, charArrayOf('_', '*', '#'), 2, 1) } assertFails { sb.insertRange(0, charArrayOf('_', '*', '#'), 2, -1) } } } @Test fun insertCharSequence() { StringBuilder("my insert CharSequence test").let { sb -> sb.insert(0, "MMM" as CharSequence) assertEquals("MMMmy insert CharSequence test", sb.toString()) sb.insert(12, StringBuilder("T")) assertEquals("MMMmy insertT CharSequence test", sb.toString()) sb.insertRange(31, "_*#", 0, 1) assertEquals("MMMmy insertT CharSequence test_", sb.toString()) sb.insertRange(0, "null" as CharSequence, 0, 2) assertEquals("nuMMMmy insertT CharSequence test_", sb.toString()) assertFailsWith { sb.insert(-1, "_" as CharSequence) } assertFailsWith { sb.insert(sb.length + 1, StringBuilder("_")) } assertFails { sb.insertRange(0, "null" as CharSequence, -1, 0) } assertFails { sb.insertRange(0, "null" as CharSequence, 0, 5) } assertFails { sb.insertRange(0, "null" as CharSequence, 2, 1) } } } @Test fun insertAny() { val myAny = object { override fun toString(): String = "It's My Any!" } StringBuilder().let { sb -> sb.insert(0, null as Any?) sb.insert(2, myAny) assertEquals("nuIt's My Any!ll", sb.toString()) } } @Test fun insertString() { StringBuilder("my insert string test").let { sb -> sb.insert(0, "_") assertEquals("_my insert string test", sb.toString()) sb.insert(10, "TtT") assertEquals("_my insertTtT string test", sb.toString()) sb.insert(25, "_!_") assertEquals("_my insertTtT string test_!_", sb.toString()) sb.insert(13, null as String?) assertEquals("_my insertTtTnull string test_!_", sb.toString()) } } @Test fun setLength() { StringBuilder("my setLength test").let { sb -> sb.setLength(17) assertEquals("my setLength test", sb.toString()) sb.setLength(0) assertEquals("", sb.toString()) sb.setLength(5) assertEquals("\u0000\u0000\u0000\u0000\u0000", sb.toString()) assertFails { sb.setLength(-1) } } } @Test fun substring() { StringBuilder("my substring test").let { sb -> assertEquals("my ", sb.substring(0, 3)) assertEquals("substring", sb.substring(3, 12)) assertEquals("ing test", sb.substring(9)) assertEquals("ing test", sb.substring(9, 17)) assertFails { sb.substring(-1) } assertFails { sb.substring(0, -1) } assertFails { sb.substring(0, sb.length + 1) } assertFails { sb.substring(2, 1) } } } @Test fun trimToSize() { StringBuilder("my trimToSize test").let { sb -> assertEquals(18, sb.length) // assertTrue(sb.capacity() >= sb.length) sb.append('1') sb.trimToSize() assertEquals(19, sb.length) // assertTrue(sb.capacity() >= sb.length) } } @Test fun set() { StringBuilder("my set test").let { sb -> sb[0] = 'M' assertEquals("My set test", sb.toString()) sb[2] = 'm' assertEquals("Mymset test", sb.toString()) sb[10] = 'T' assertEquals("Mymset tesT", sb.toString()) assertFailsWith { sb[-1] = '_' } assertFailsWith { sb[sb.length] = '_' } } } @Test fun setRange() { StringBuilder("my replace test").let { sb -> sb.setRange(0, 4, "R") assertEquals("Replace test", sb.toString()) sb.setRange(7, 7, " empty string") assertEquals("Replace empty string test", sb.toString()) sb.setRange(20, 25, "") assertEquals("Replace empty string", sb.toString()) sb.setRange(20, 25, "") assertEquals("Replace empty string", sb.toString()) assertFails { sb.setRange(-1, 0, "") } assertFails { sb.setRange(0, -1, "") } assertFails { sb.setRange(2, 1, "") } assertFails { sb.setRange(sb.length + 1, sb.length + 2, "") } } } @Test fun toCharArray() { StringBuilder("my toCharArray test").let { sb -> val chars = CharArray(10) { '_' } sb.toCharArray(chars, 8, 0, 2) assertEquals("________my", chars.concatToString()) sb.toCharArray(chars, 3, 6, 11) assertEquals("___harArmy", chars.concatToString()) sb.toCharArray(chars, 0, 16, 19) assertEquals("estharArmy", chars.concatToString()) sb.setLength(5) assertFails { sb.toCharArray(chars, -1, 0, 1) } assertFails { sb.toCharArray(chars, chars.size, 0, 1) } assertFails { sb.toCharArray(chars, 0, -1, 0) } assertFails { sb.toCharArray(chars, 0, 0, -1) } assertFails { sb.toCharArray(chars, 0, 2, 1) } assertFails { sb.toCharArray(chars, 0, 0, sb.length + 1) } } } @Test fun appendLine() { val stringBuilder = StringBuilder() stringBuilder.appendLine('c') stringBuilder.appendLine("string") stringBuilder.appendLine(true) stringBuilder.appendLine(charArrayOf('a', 'r', 'r', 'a', 'y')) stringBuilder.appendLine() stringBuilder.appendLine("char sequence" as CharSequence) stringBuilder.appendLine(null as Any?) stringBuilder.appendLine("nonnull" as Any?) stringBuilder.appendLine(null as String?) stringBuilder.appendLine(null as CharSequence?) val expected = """ c string true array char sequence null nonnull null null """.trimIndent() assertEquals(expected, stringBuilder.toString()) } }