// RUN: %target-run-simple-swift // XFAIL: interpret // XFAIL: linux import StdlibUnittest import Foundation extension String { var bufferID: UWord { return unsafeBitCast(_core._owner, UWord.self) } var nativeCapacity: Int { return _core.nativeBuffer!.capacity } var capacity: Int { return _core.nativeBuffer?.capacity ?? 0 } } var StringTests = TestSuite("StringTests") StringTests.test("sizeof") { expectEqual(3 * sizeof(Int.self), sizeof(String.self)) } func checkUnicodeScalarViewIteration( expectedScalars: [UInt32], _ str: String ) { if true { var us = str.unicodeScalars var i = us.startIndex var end = us.endIndex var decoded: [UInt32] = [] while i != end { expectTrue(i < i.successor()) // Check for Comparable conformance decoded.append(us[i].value) i = i.successor() } expectEqual(expectedScalars, decoded) } if true { var us = str.unicodeScalars var start = us.startIndex var i = us.endIndex var decoded: [UInt32] = [] while i != start { i = i.predecessor() decoded.append(us[i].value) } expectEqual(expectedScalars, decoded) } } StringTests.test("unicodeScalars") { checkUnicodeScalarViewIteration([], "") checkUnicodeScalarViewIteration([ 0x0000 ], "\u{0000}") checkUnicodeScalarViewIteration([ 0x0041 ], "A") checkUnicodeScalarViewIteration([ 0x007f ], "\u{007f}") checkUnicodeScalarViewIteration([ 0x0080 ], "\u{0080}") checkUnicodeScalarViewIteration([ 0x07ff ], "\u{07ff}") checkUnicodeScalarViewIteration([ 0x0800 ], "\u{0800}") checkUnicodeScalarViewIteration([ 0xd7ff ], "\u{d7ff}") checkUnicodeScalarViewIteration([ 0x8000 ], "\u{8000}") checkUnicodeScalarViewIteration([ 0xe000 ], "\u{e000}") checkUnicodeScalarViewIteration([ 0xfffd ], "\u{fffd}") checkUnicodeScalarViewIteration([ 0xffff ], "\u{ffff}") checkUnicodeScalarViewIteration([ 0x10000 ], "\u{00010000}") checkUnicodeScalarViewIteration([ 0x10ffff ], "\u{0010ffff}") } StringTests.test("indexComparability") { let empty = "" expectTrue(empty.startIndex == empty.endIndex) expectFalse(empty.startIndex != empty.endIndex) expectTrue(empty.startIndex <= empty.endIndex) expectTrue(empty.startIndex >= empty.endIndex) expectFalse(empty.startIndex > empty.endIndex) expectFalse(empty.startIndex < empty.endIndex) let nonEmpty = "borkus biqualificated" expectFalse(nonEmpty.startIndex == nonEmpty.endIndex) expectTrue(nonEmpty.startIndex != nonEmpty.endIndex) expectTrue(nonEmpty.startIndex <= nonEmpty.endIndex) expectFalse(nonEmpty.startIndex >= nonEmpty.endIndex) expectFalse(nonEmpty.startIndex > nonEmpty.endIndex) expectTrue(nonEmpty.startIndex < nonEmpty.endIndex) } StringTests.test("ForeignIndexes/Valid") { // It is actually unclear what the correct behavior is. This test is just a // change detector. // // Design, document, implement invalidation model // for foreign String indexes if true { let donor = "abcdef" let acceptor = "uvwxyz" expectEqual("u", acceptor[donor.startIndex]) expectEqual("wxy", acceptor[advance(donor.startIndex, 2).. String.Index caches the grapheme " + "cluster size, but it is not always correct to use")) .code { let donor = "\u{1f601}\u{1f602}\u{1f603}" let acceptor = "abcdef" // FIXME: this traps right now when trying to construct Character("ab"). expectEqual("a", acceptor[donor.startIndex]) } StringTests.test("ForeignIndexes/subscript(Index)/OutOfBoundsTrap") { let donor = "abcdef" let acceptor = "uvw" expectEqual("u", acceptor[advance(donor.startIndex, 0)]) expectEqual("v", acceptor[advance(donor.startIndex, 1)]) expectEqual("w", acceptor[advance(donor.startIndex, 2)]) expectCrashLater() acceptor[advance(donor.startIndex, 3)] } StringTests.test("ForeignIndexes/subscript(Range)/OutOfBoundsTrap/1") { let donor = "abcdef" let acceptor = "uvw" expectEqual("uvw", acceptor[donor.startIndex.. initialSize || sliceEnd > initialSize || sliceEnd < sliceStart { continue } var s0 = String(count: initialSize, repeatedValue: UnicodeScalar("x")) let originalIdentity = s0.bufferID s0 = s0[ advance(s0.startIndex, sliceStart)..(content: S) -> String { var s = String() s.extend(content) expectEqual(1, s._core.elementWidth) return s } StringTests.test("stringCoreExtensibility") { let ascii = UTF16.CodeUnit(UnicodeScalar("X").value) let nonAscii = UTF16.CodeUnit(UnicodeScalar("é").value) for k in 0..<3 { for length in 1..<16 { for boundary in 0.. _StringCore { var x = _StringCore() // make sure some - but not all - replacements will have to grow the buffer x.reserveCapacity(base._core.count * 3 / 2) x.extend(base._core) // In case the core was widened and lost its capacity x.reserveCapacity(base._core.count * 3 / 2) return x } StringTests.test("StringCoreReplace") { let narrow = "01234567890" let wide = "ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪ" for s1 in [narrow, wide] { for s2 in [narrow, wide] { checkRangeReplaceable( { makeStringCore(s1) }, { makeStringCore(s2 + s2)[0..<$0] } ) checkRangeReplaceable( { makeStringCore(s1) }, { Array(makeStringCore(s2 + s2)[0..<$0]) } ) } } } StringTests.test("CharacterViewReplace") { let narrow = "01234567890" let wide = "ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪ" for s1 in [narrow, wide] { for s2 in [narrow, wide] { checkRangeReplaceable( { String.CharacterView(makeStringCore(s1)) }, { String.CharacterView(makeStringCore(s2 + s2)[0..<$0]) } ) checkRangeReplaceable( { String.CharacterView(makeStringCore(s1)) }, { Array(String.CharacterView(makeStringCore(s2 + s2)[0..<$0])) } ) } } } StringTests.test("UnicodeScalarViewReplace") { let narrow = "01234567890" let wide = "ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪ" for s1 in [narrow, wide] { for s2 in [narrow, wide] { checkRangeReplaceable( { String(makeStringCore(s1)).unicodeScalars }, { String(makeStringCore(s2 + s2)[0..<$0]).unicodeScalars } ) checkRangeReplaceable( { String(makeStringCore(s1)).unicodeScalars }, { Array(String(makeStringCore(s2 + s2)[0..<$0]).unicodeScalars) } ) } } } StringTests.test("reserveCapacity") { var s = "" let id0 = s.bufferID let oldCap = s.capacity let x: Character = "x" // Help the typechecker - s.splice(Repeat(count: s.capacity + 1, repeatedValue: x), atIndex: s.endIndex) expectNotEqual(id0, s.bufferID) s = "" print("empty capacity \(s.capacity)") s.reserveCapacity(oldCap + 2) print("reserving \(oldCap + 2) -> \(s.capacity), width = \(s._core.elementWidth)") let id1 = s.bufferID s.splice(Repeat(count: oldCap + 2, repeatedValue: x), atIndex: s.endIndex) print("extending by \(oldCap + 2) -> \(s.capacity), width = \(s._core.elementWidth)") expectEqual(id1, s.bufferID) s.splice(Repeat(count: s.capacity + 100, repeatedValue: x), atIndex: s.endIndex) expectNotEqual(id1, s.bufferID) } StringTests.test("toInt") { expectEmpty(Int("")) expectEmpty(Int("+")) expectEmpty(Int("-")) expectOptionalEqual(20, Int("+20")) expectOptionalEqual(0, Int("0")) expectOptionalEqual(-20, Int("-20")) expectEmpty(Int("-cc20")) expectEmpty(Int(" -20")) expectEmpty(Int(" \t 20ddd")) expectOptionalEqual(Int.min, Int("\(Int.min)")) expectOptionalEqual(Int.min + 1, Int("\(Int.min + 1)")) expectOptionalEqual(Int.max, Int("\(Int.max)")) expectOptionalEqual(Int.max - 1, Int("\(Int.max - 1)")) expectEmpty(Int("\(Int.min)0")) expectEmpty(Int("\(Int.max)0")) // Make a String from an Int, mangle the String's characters, // then print if the new String is or is not still an Int. func testConvertabilityOfStringWithModification( initialValue: Int, modification: (inout chars: [UTF8.CodeUnit]) -> () ) { var chars = Array(String(initialValue).utf8) modification(chars: &chars) var str = String._fromWellFormedCodeUnitSequence(UTF8.self, input: chars) expectEmpty(Int(str)) } testConvertabilityOfStringWithModification(Int.min) { $0[2]++; () // underflow by lots } testConvertabilityOfStringWithModification(Int.max) { $0[1]++; () // overflow by lots } // Test values lower than min. if true { let base = UInt(Int.max) expectOptionalEqual(Int.min + 1, Int("-\(base)")) expectOptionalEqual(Int.min, Int("-\(base + 1)")) for i in 2..<20 { expectEmpty(Int("-\(base + UInt(i))")) } } // Test values greater than min. if true { let base = UInt(Int.max) for i in UInt(0)..<20 { expectOptionalEqual(-Int(base - i) , Int("-\(base - i)")) } } // Test values greater than max. if true { let base = UInt(Int.max) expectOptionalEqual(Int.max, Int("\(base)")) for i in 1..<20 { expectEmpty(Int("\(base + UInt(i))")) } } // Test values lower than max. if true { let base = Int.max for i in 0..<20 { expectOptionalEqual(base - i, Int("\(base - i)")) } } } // Make sure strings don't grow unreasonably quickly when appended-to StringTests.test("growth") { var s = "" var s2 = s for i in 0..<20 { s += "x" s2 = s } expectLE(s.nativeCapacity, 34) } StringTests.test("Construction") { expectEqual("abc", String([ "a", "b", "c" ] as [Character])) } StringTests.test("Conversions") { if true { var c: Character = "a" let x = String(c) expectTrue(x._core.isASCII) var s: String = "a" expectEqual(s, x) } if true { var c: Character = "\u{B977}" let x = String(c) expectFalse(x._core.isASCII) var s: String = "\u{B977}" expectEqual(s, x) } } // Check the internal functions are correct for ASCII values StringTests.test( "forall x: Int8, y: Int8 . x < 128 ==> x