// RUN: rm -rf %t // RUN: mkdir -p %t // RUN: %target-build-swift %s -o %t/a.out // RUN: %target-run %t/a.out // REQUIRES: executable_test // REQUIRES: objc_interop // // Tests for the NSString APIs as exposed by String // import StdlibUnittest import Foundation import StdlibUnittestFoundationExtras // The most simple subclass of NSString that CoreFoundation does not know // about. class NonContiguousNSString : NSString { required init(coder aDecoder: NSCoder) { fatalError("don't call this initializer") } override init() { _value = [] super.init() } init(_ value: [UInt16]) { _value = value super.init() } @objc override func copyWithZone(zone: NSZone) -> AnyObject { // Ensure that copying this string produces a class that CoreFoundation // does not know about. return self } @objc override var length: Int { return _value.count } @objc override func characterAtIndex(index: Int) -> unichar { return _value[index] } var _value: [UInt16] } let temporaryFileContents = "Lorem ipsum dolor sit amet, consectetur adipisicing elit,\n" + "sed do eiusmod tempor incididunt ut labore et dolore magna\n" + "aliqua.\n" func createNSStringTemporaryFile() -> (existingPath: String, nonExistentPath: String) { let existingPath = createTemporaryFile("NSStringAPIs.", ".txt", temporaryFileContents) let nonExistentPath = existingPath + "-NoNeXiStEnT" return (existingPath, nonExistentPath) } var NSStringAPIs = TestSuite("NSStringAPIs") NSStringAPIs.test("Encodings") { let availableEncodings: [NSStringEncoding] = String.availableStringEncodings() expectNotEqual(0, availableEncodings.count) let defaultCStringEncoding = String.defaultCStringEncoding() expectTrue(availableEncodings.contains(defaultCStringEncoding)) expectNotEqual("", String.localizedNameOfStringEncoding(NSUTF8StringEncoding)) } NSStringAPIs.test("NSStringEncoding") { // Make sure NSStringEncoding and its values are type-compatible. var enc: NSStringEncoding enc = NSWindowsCP1250StringEncoding enc = NSUTF32LittleEndianStringEncoding enc = NSUTF32BigEndianStringEncoding enc = NSASCIIStringEncoding enc = NSUTF8StringEncoding } NSStringAPIs.test("localizedStringWithFormat(_:...)") { var world: NSString = "world" expectEqual("Hello, world!%42", String.localizedStringWithFormat( "Hello, %@!%%%ld", world, 42)) withOverriddenNSLocaleCurrentLocale("en_US") { expectEqual("0.5", String.localizedStringWithFormat("%g", 0.5)) } withOverriddenNSLocaleCurrentLocale("uk") { expectEqual("0,5", String.localizedStringWithFormat("%g", 0.5)) } } NSStringAPIs.test("init(contentsOfFile:encoding:error:)") { let (existingPath, nonExistentPath) = createNSStringTemporaryFile() do { let content = try String( contentsOfFile: existingPath, encoding: NSASCIIStringEncoding) expectEqual( "Lorem ipsum dolor sit amet, consectetur adipisicing elit,", content._lines[0]) } catch { expectUnreachableCatch(error) } do { let content = try String( contentsOfFile: nonExistentPath, encoding: NSASCIIStringEncoding) expectUnreachable() } catch { } } NSStringAPIs.test("init(contentsOfFile:usedEncoding:error:)") { let (existingPath, nonExistentPath) = createNSStringTemporaryFile() do { var usedEncoding: NSStringEncoding = 0 let content = try String( contentsOfFile: existingPath, usedEncoding: &usedEncoding) expectNotEqual(0, usedEncoding) expectEqual( "Lorem ipsum dolor sit amet, consectetur adipisicing elit,", content._lines[0]) } catch { expectUnreachableCatch(error) } var usedEncoding: NSStringEncoding = 0 do { try String(contentsOfFile: nonExistentPath) expectUnreachable() } catch { expectEqual(0, usedEncoding) } } NSStringAPIs.test("init(contentsOfURL:encoding:error:)") { let (existingPath, nonExistentPath) = createNSStringTemporaryFile() let existingURL = NSURL(string: "file://" + existingPath)! let nonExistentURL = NSURL(string: "file://" + nonExistentPath)! do { let content = try String( contentsOfURL: existingURL, encoding: NSASCIIStringEncoding) expectEqual( "Lorem ipsum dolor sit amet, consectetur adipisicing elit,", content._lines[0]) } catch { expectUnreachableCatch(error) } do { try String(contentsOfURL: nonExistentURL, encoding: NSASCIIStringEncoding) expectUnreachable() } catch { } } NSStringAPIs.test("init(contentsOfURL:usedEncoding:error:)") { let (existingPath, nonExistentPath) = createNSStringTemporaryFile() let existingURL = NSURL(string: "file://" + existingPath)! let nonExistentURL = NSURL(string: "file://" + nonExistentPath)! do { var usedEncoding: NSStringEncoding = 0 let content = try String( contentsOfURL: existingURL, usedEncoding: &usedEncoding) expectNotEqual(0, usedEncoding) expectEqual( "Lorem ipsum dolor sit amet, consectetur adipisicing elit,", content._lines[0]) } catch { expectUnreachableCatch(error) } var usedEncoding: NSStringEncoding = 0 do { try String(contentsOfURL: nonExistentURL, usedEncoding: &usedEncoding) expectUnreachable() } catch { expectEqual(0, usedEncoding) } } NSStringAPIs.test("init(withCString_:encoding:)") { expectOptionalEqual("foo, a basmati bar!", String(CString: "foo, a basmati bar!", encoding: String.defaultCStringEncoding())) } NSStringAPIs.test("init(UTF8String:)") { var s = "foo あいう" var up = UnsafeMutablePointer.alloc(100) var i = 0 for b in s.utf8 { up[i] = b i++ } up[i] = 0 expectOptionalEqual(s, String(UTF8String: UnsafePointer(up))) up.dealloc(100) } NSStringAPIs.test("canBeConvertedToEncoding(_:)") { expectTrue("foo".canBeConvertedToEncoding(NSASCIIStringEncoding)) expectFalse("あいう".canBeConvertedToEncoding(NSASCIIStringEncoding)) } NSStringAPIs.test("capitalizedString") { expectEqual("Foo Foo Foo Foo", "foo Foo fOO FOO".capitalizedString) expectEqual("Жжж", "жжж".capitalizedString) } NSStringAPIs.test("localizedCapitalizedString") { if #available(OSX 10.11, iOS 9.0, *) { withOverriddenNSLocaleCurrentLocale("en") { () -> () in expectEqual( "Foo Foo Foo Foo", "foo Foo fOO FOO".localizedCapitalizedString) expectEqual("Жжж", "жжж".localizedCapitalizedString) return () } // // Special casing. // // U+0069 LATIN SMALL LETTER I // to upper case: // U+0049 LATIN CAPITAL LETTER I withOverriddenNSLocaleCurrentLocale("en") { expectEqual("Iii Iii", "iii III".localizedCapitalizedString) } // U+0069 LATIN SMALL LETTER I // to upper case in Turkish locale: // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE withOverriddenNSLocaleCurrentLocale("tr") { expectEqual("\u{0130}ii Iıı", "iii III".localizedCapitalizedString) } } } NSStringAPIs.test("capitalizedStringWithLocale(_:)") { expectEqual( "Foo Foo Foo Foo", "foo Foo fOO FOO".capitalizedStringWithLocale(NSLocale.currentLocale())) expectEqual( "Жжж", "жжж".capitalizedStringWithLocale(NSLocale.currentLocale())) expectEqual( "Foo Foo Foo Foo", "foo Foo fOO FOO".capitalizedStringWithLocale(nil)) expectEqual("Жжж", "жжж".capitalizedStringWithLocale(nil)) // // Special casing. // // U+0069 LATIN SMALL LETTER I // to upper case: // U+0049 LATIN CAPITAL LETTER I expectEqual( "Iii Iii", "iii III".capitalizedStringWithLocale( NSLocale(localeIdentifier: "en"))) // U+0069 LATIN SMALL LETTER I // to upper case in Turkish locale: // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE expectEqual( "İii Iıı", "iii III".capitalizedStringWithLocale( NSLocale(localeIdentifier: "tr"))) } NSStringAPIs.test("caseInsensitiveCompare(_:)") { expectEqual(NSComparisonResult.OrderedSame, "abCD".caseInsensitiveCompare("AbCd")) expectEqual(NSComparisonResult.OrderedAscending, "abCD".caseInsensitiveCompare("AbCdE")) expectEqual(NSComparisonResult.OrderedSame, "абвг".caseInsensitiveCompare("АбВг")) expectEqual(NSComparisonResult.OrderedAscending, "абВГ".caseInsensitiveCompare("АбВгД")) } NSStringAPIs.test("commonPrefixWithString(_:options:)") { expectEqual("ab", "abcd".commonPrefixWithString("abdc", options: [])) expectEqual("abC", "abCd".commonPrefixWithString("abce", options: .CaseInsensitiveSearch)) expectEqual("аб", "абвг".commonPrefixWithString("абгв", options: [])) expectEqual("абВ", "абВг".commonPrefixWithString("абвд", options: .CaseInsensitiveSearch)) } NSStringAPIs.test("compare(_:options:range:locale:)") { expectEqual(NSComparisonResult.OrderedSame, "abc".compare("abc")) expectEqual(NSComparisonResult.OrderedAscending, "абв".compare("где")) expectEqual(NSComparisonResult.OrderedSame, "abc".compare("abC", options: .CaseInsensitiveSearch)) expectEqual(NSComparisonResult.OrderedSame, "абв".compare("абВ", options: .CaseInsensitiveSearch)) if true { let s = "abcd" let r = s.startIndex.successor()..(data!.bytes), count: data!.length)) let expectedBytes: [UInt8] = [ 0xe3, 0x81, 0x82, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0x86 ] expectEqualSequence(expectedBytes, bytes) } } NSStringAPIs.test("decomposedStringWithCanonicalMapping") { expectEqual("abc", "abc".decomposedStringWithCanonicalMapping) expectEqual("\u{305f}\u{3099}くてん", "だくてん".decomposedStringWithCanonicalMapping) expectEqual("\u{ff80}\u{ff9e}クテン", "ダクテン".decomposedStringWithCanonicalMapping) } NSStringAPIs.test("decomposedStringWithCompatibilityMapping") { expectEqual("abc", "abc".decomposedStringWithCompatibilityMapping) expectEqual("\u{30bf}\u{3099}クテン", "ダクテン".decomposedStringWithCompatibilityMapping) } NSStringAPIs.test("enumerateLines(_:)") { var lines: [String] = [] "abc\n\ndefghi\njklm".enumerateLines { (line: String, inout stop: Bool) in lines.append(line) if lines.count == 3 { stop = true } } expectEqual([ "abc", "", "defghi" ], lines) } NSStringAPIs.test("enumerateLinguisticTagsInRange(_:scheme:options:orthography:_:") { let s = "Абв. Глокая куздра штеко будланула бокра и кудрячит бокрёнка. Абв." let startIndex = advance(s.startIndex, 5) let endIndex = advance(s.startIndex, 62) var tags: [String] = [] var tokens: [String] = [] var sentences: [String] = [] s.enumerateLinguisticTagsInRange(startIndex.., sentenceRange: Range, inout stop: Bool) in tags.append(tag) tokens.append(s[tokenRange]) sentences.append(s[sentenceRange]) if tags.count == 3 { stop = true } } expectEqual( [ NSLinguisticTagWord, NSLinguisticTagWhitespace, NSLinguisticTagWord ], tags) expectEqual([ "Глокая", " ", "куздра" ], tokens) let sentence = s[startIndex.., enclosingRange: Range, inout stop: Bool) in substrings.append(substring!) expectEqual(substring, s[substringRange]) expectEqual(substring, s[enclosingRange]) } expectEqual([ "\u{304b}\u{3099}", "お", "☺️", "😀" ], substrings) } if true { var substrings: [String] = [] s.enumerateSubstringsInRange(startIndex.., enclosingRange: Range, inout stop: Bool) in expectEmpty(substring_) let substring = s[substringRange] substrings.append(substring) expectEqual(substring, s[enclosingRange]) } expectEqual([ "\u{304b}\u{3099}", "お", "☺️", "😀" ], substrings) } } NSStringAPIs.test("fastestEncoding") { let availableEncodings: [NSStringEncoding] = String.availableStringEncodings() expectTrue(availableEncodings.contains("abc".fastestEncoding)) } NSStringAPIs.test("getBytes(_:maxLength:usedLength:encoding:options:range:remainingRange:)") { let s = "abc абв def где gh жз zzz" let startIndex = advance(s.startIndex, 8) let endIndex = advance(s.startIndex, 22) if true { // 'maxLength' is limiting. let bufferLength = 100 var expectedStr: [UInt8] = Array("def где ".utf8) while (expectedStr.count != bufferLength) { expectedStr.append(0xff) } var buffer = [UInt8](count: bufferLength, repeatedValue: 0xff) var usedLength = 0 var remainingRange = startIndex..] = [] var tags = s.linguisticTagsInRange(startIndex.. NFKD normalization as implemented by 'precomposedStringWithCompatibilityMapping:' is not idempotent expectEqual("\u{30c0}クテン", "\u{ff80}\u{ff9e}クテン".precomposedStringWithCompatibilityMapping) */ expectEqual("ffi", "\u{fb03}".precomposedStringWithCompatibilityMapping) } NSStringAPIs.test("propertyList()") { expectEqual([ "foo", "bar" ], "(\"foo\", \"bar\")".propertyList() as! [String]) } NSStringAPIs.test("propertyListFromStringsFileFormat()") { expectEqual([ "foo": "bar", "baz": "baz" ], "/* comment */\n\"foo\" = \"bar\";\n\"baz\";" .propertyListFromStringsFileFormat() as Dictionary) } NSStringAPIs.test("rangeOfCharacterFromSet(_:options:range:)") { if true { let charset = NSCharacterSet(charactersInString: "абв") if true { let s = "Глокая куздра" let r = s.rangeOfCharacterFromSet(charset)! expectEqual(advance(s.startIndex, 4), r.startIndex) expectEqual(advance(s.startIndex, 5), r.endIndex) } if true { expectEmpty("клмн".rangeOfCharacterFromSet(charset)) } if true { let s = "абвклмнабвклмн" let r = s.rangeOfCharacterFromSet(charset, options: .BackwardsSearch)! expectEqual(advance(s.startIndex, 9), r.startIndex) expectEqual(advance(s.startIndex, 10), r.endIndex) } if true { let s = "абвклмнабв" let r = s.rangeOfCharacterFromSet(charset, range: advance(s.startIndex, 3)..? ) -> Range? { guard let range = maybeRange else { return nil } return distance(string.startIndex, range.startIndex) ..< distance(string.startIndex, range.endIndex) } NSStringAPIs.test("rangeOfString(_:options:range:locale:)") { if true { let s = "" expectEmpty(s.rangeOfString("")) expectEmpty(s.rangeOfString("abc")) } if true { let s = "abc" expectEmpty(s.rangeOfString("")) expectEmpty(s.rangeOfString("def")) expectOptionalEqual(0..<3, toIntRange(s, s.rangeOfString("abc"))) } if true { let s = "さ\u{3099}し\u{3099}す\u{3099}せ\u{3099}そ\u{3099}" expectOptionalEqual(2..<3, toIntRange(s, s.rangeOfString("す\u{3099}"))) expectOptionalEqual(2..<3, toIntRange(s, s.rangeOfString("\u{305a}"))) expectEmpty(s.rangeOfString("\u{3099}す")) expectEmpty(s.rangeOfString("す")) // Note: here `rangeOfString` API produces indexes that don't point between // grapheme cluster boundaries -- these can not be created with public // String interface. // // FIXME: why does this seach succeed and the above queries fail? There is // no apparent pattern. expectEqual("\u{3099}", s[s.rangeOfString("\u{3099}")!]) } if true { let s = "а\u{0301}б\u{0301}в\u{0301}г\u{0301}" expectOptionalEqual(0..<1, toIntRange(s, s.rangeOfString("а\u{0301}"))) expectOptionalEqual(1..<2, toIntRange(s, s.rangeOfString("б\u{0301}"))) expectEmpty(s.rangeOfString("б")) expectEmpty(s.rangeOfString("\u{0301}б")) // FIXME: Again, indexes that don't correspond to grapheme // cluster boundaries. expectEqual("\u{0301}", s[s.rangeOfString("\u{0301}")!]) } } NSStringAPIs.test("localizedStandardContainsString(_:)") { if #available(OSX 10.11, iOS 9.0, *) { withOverriddenNSLocaleCurrentLocale("en") { () -> () in expectFalse("".localizedStandardContainsString("")) expectFalse("".localizedStandardContainsString("a")) expectFalse("a".localizedStandardContainsString("")) expectFalse("a".localizedStandardContainsString("b")) expectTrue("a".localizedStandardContainsString("a")) expectTrue("a".localizedStandardContainsString("A")) expectTrue("A".localizedStandardContainsString("a")) expectTrue("a".localizedStandardContainsString("a\u{0301}")) expectTrue("a\u{0301}".localizedStandardContainsString("a\u{0301}")) expectTrue("a\u{0301}".localizedStandardContainsString("a")) expectTrue("a\u{0301}".localizedStandardContainsString("\u{0301}")) expectFalse("a".localizedStandardContainsString("\u{0301}")) expectTrue("i".localizedStandardContainsString("I")) expectTrue("I".localizedStandardContainsString("i")) expectTrue("\u{0130}".localizedStandardContainsString("i")) expectTrue("i".localizedStandardContainsString("\u{0130}")) return () } withOverriddenNSLocaleCurrentLocale("tr") { expectTrue("\u{0130}".localizedStandardContainsString("ı")) } } } NSStringAPIs.test("localizedStandardRangeOfString(_:)") { if #available(OSX 10.11, iOS 9.0, *) { func rangeOfString(string: String, _ substring: String) -> Range? { return toIntRange( string, string.localizedStandardRangeOfString(substring)) } withOverriddenNSLocaleCurrentLocale("en") { () -> () in expectEmpty(rangeOfString("", "")) expectEmpty(rangeOfString("", "a")) expectEmpty(rangeOfString("a", "")) expectEmpty(rangeOfString("a", "b")) expectEqual(0..<1, rangeOfString("a", "a")) expectEqual(0..<1, rangeOfString("a", "A")) expectEqual(0..<1, rangeOfString("A", "a")) expectEqual(0..<1, rangeOfString("a", "a\u{0301}")) expectEqual(0..<1, rangeOfString("a\u{0301}", "a\u{0301}")) expectEqual(0..<1, rangeOfString("a\u{0301}", "a")) if true { // FIXME: Indices that don't correspond to grapheme cluster boundaries. let s = "a\u{0301}" expectEqual( "\u{0301}", s[s.localizedStandardRangeOfString("\u{0301}")!]) } expectEmpty(rangeOfString("a", "\u{0301}")) expectEqual(0..<1, rangeOfString("i", "I")) expectEqual(0..<1, rangeOfString("I", "i")) expectEqual(0..<1, rangeOfString("\u{0130}", "i")) expectEqual(0..<1, rangeOfString("i", "\u{0130}")) return () } withOverriddenNSLocaleCurrentLocale("tr") { expectEqual(0..<1, rangeOfString("\u{0130}", "ı")) } } } NSStringAPIs.test("smallestEncoding") { let availableEncodings: [NSStringEncoding] = String.availableStringEncodings() expectTrue(availableEncodings.contains("abc".smallestEncoding)) } func getHomeDir() -> String { #if os(OSX) return String.fromCString(getpwuid(getuid()).memory.pw_dir)! #elseif os(iOS) || os(tvOS) || os(watchOS) // getpwuid() returns null in sandboxed apps under iOS simulator. return NSHomeDirectory() #else preconditionFailed("implement") #endif } NSStringAPIs.test("stringByAddingPercentEscapesUsingEncoding(_:)") { expectEmpty( "abcd абвг".stringByAddingPercentEscapesUsingEncoding( NSASCIIStringEncoding)) expectOptionalEqual("abcd%20%D0%B0%D0%B1%D0%B2%D0%B3", "abcd абвг".stringByAddingPercentEscapesUsingEncoding( NSUTF8StringEncoding)) } NSStringAPIs.test("stringByAppendingFormat(_:_:...)") { expectEqual("", "".stringByAppendingFormat("")) expectEqual("a", "a".stringByAppendingFormat("")) expectEqual( "abc абв \u{0001F60A}", "abc абв \u{0001F60A}".stringByAppendingFormat("")) let formatArg: NSString = "привет мир \u{0001F60A}" expectEqual( "abc абв \u{0001F60A}def привет мир \u{0001F60A} 42", "abc абв \u{0001F60A}" .stringByAppendingFormat("def %@ %ld", formatArg, 42)) } NSStringAPIs.test("stringByAppendingPathComponent(_:)") { expectEqual("", "".stringByAppendingPathComponent("")) expectEqual("a.txt", "".stringByAppendingPathComponent("a.txt")) expectEqual("/tmp/a.txt", "/tmp".stringByAppendingPathComponent("a.txt")) } NSStringAPIs.test("stringByAppendingString(_:)") { expectEqual("", "".stringByAppendingString("")) expectEqual("a", "a".stringByAppendingString("")) expectEqual("a", "".stringByAppendingString("a")) expectEqual("さ\u{3099}", "さ".stringByAppendingString("\u{3099}")) } NSStringAPIs.test("stringByDeletingLastPathComponent") { expectEqual("", "".stringByDeletingLastPathComponent) expectEqual("/", "/".stringByDeletingLastPathComponent) expectEqual("/", "/tmp".stringByDeletingLastPathComponent) expectEqual("/tmp", "/tmp/a.txt".stringByDeletingLastPathComponent) } NSStringAPIs.test("stringByFoldingWithOptions(_:locale:)") { expectEqual("abcd", "abCD".stringByFoldingWithOptions( .CaseInsensitiveSearch, locale: NSLocale(localeIdentifier: "en"))) // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE // to lower case: // U+0069 LATIN SMALL LETTER I // U+0307 COMBINING DOT ABOVE expectEqual("\u{0069}\u{0307}", "\u{0130}".stringByFoldingWithOptions( .CaseInsensitiveSearch, locale: NSLocale(localeIdentifier: "en"))) // U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE // to lower case in Turkish locale: // U+0069 LATIN SMALL LETTER I expectEqual("\u{0069}", "\u{0130}".stringByFoldingWithOptions( .CaseInsensitiveSearch, locale: NSLocale(localeIdentifier: "tr"))) expectEqual( "example123", "example123".stringByFoldingWithOptions( .WidthInsensitiveSearch, locale: NSLocale(localeIdentifier: "en"))) } NSStringAPIs.test("stringByPaddingToLength(_:withString:startingAtIndex:)") { expectEqual( "abc абв \u{0001F60A}", "abc абв \u{0001F60A}".stringByPaddingToLength( 10, withString: "XYZ", startingAtIndex: 0)) expectEqual( "abc абв \u{0001F60A}XYZXY", "abc абв \u{0001F60A}".stringByPaddingToLength( 15, withString: "XYZ", startingAtIndex: 0)) expectEqual( "abc абв \u{0001F60A}YZXYZ", "abc абв \u{0001F60A}".stringByPaddingToLength( 15, withString: "XYZ", startingAtIndex: 1)) } NSStringAPIs.test("stringByRemovingPercentEncoding/OSX 10.9") .xfail(.OSXMinor(10, 9, reason: "looks like a bug in Foundation in OS X 10.9")) .xfail(.iOSMajor(7, reason: "same bug in Foundation in iOS 7.*")) .skip(.iOSSimulatorAny("same bug in Foundation in iOS Simulator 7.*")) .code { expectOptionalEqual("", "".stringByRemovingPercentEncoding) } NSStringAPIs.test("stringByRemovingPercentEncoding") { expectEmpty("%".stringByRemovingPercentEncoding) expectOptionalEqual( "abcd абвг", "ab%63d %D0%B0%D0%B1%D0%B2%D0%B3".stringByRemovingPercentEncoding) } NSStringAPIs.test("stringByReplacingCharactersInRange(_:withString:)") { if true { let empty = "" expectEqual("", empty.stringByReplacingCharactersInRange( empty.startIndex.. NSString " + "stringByReplacingPercentEscapesUsingEncoding: does not return nil " + "when a byte sequence is not legal in ASCII")) .code { expectEmpty( "abcd%FF".stringByReplacingPercentEscapesUsingEncoding( NSASCIIStringEncoding)) } NSStringAPIs.test("stringByResolvingSymlinksInPath") { // Difference between // stringByResolvingSymlinksInPath and stringByStandardizingPath is unclear expectEqual("", "".stringByResolvingSymlinksInPath) expectEqual( "/var", "/private/var/tmp////..//".stringByResolvingSymlinksInPath) } NSStringAPIs.test("stringByStandardizingPath") { // Difference between // stringByResolvingSymlinksInPath and stringByStandardizingPath is unclear expectEqual("", "".stringByStandardizingPath) expectEqual( "/var", "/private/var/tmp////..//".stringByStandardizingPath) } NSStringAPIs.test("stringByTrimmingCharactersInSet(_:)") { expectEqual("", "".stringByTrimmingCharactersInSet( NSCharacterSet.decimalDigitCharacterSet())) expectEqual("abc", "abc".stringByTrimmingCharactersInSet( NSCharacterSet.decimalDigitCharacterSet())) expectEqual("", "123".stringByTrimmingCharactersInSet( NSCharacterSet.decimalDigitCharacterSet())) expectEqual("abc", "123abc789".stringByTrimmingCharactersInSet( NSCharacterSet.decimalDigitCharacterSet())) // Performs Unicode scalar comparison. expectEqual( "し\u{3099}abc", "し\u{3099}abc".stringByTrimmingCharactersInSet( NSCharacterSet(charactersInString: "\u{3058}"))) } NSStringAPIs.test("stringsByAppendingPaths(_:)") { expectEqual([], "".stringsByAppendingPaths([])) expectEqual( [ "/tmp/foo", "/tmp/bar" ], "/tmp".stringsByAppendingPaths([ "foo", "bar" ])) } NSStringAPIs.test("substringFromIndex(_:)") { let s = "\u{1F601}abc さ\u{3099}し\u{3099}す\u{3099}せ\u{3099}そ\u{3099}" expectEqual(s, s.substringFromIndex(s.startIndex)) expectEqual("せ\u{3099}そ\u{3099}", s.substringFromIndex(advance(s.startIndex, 8))) expectEqual("", s.substringFromIndex(advance(s.startIndex, 10))) } NSStringAPIs.test("substringToIndex(_:)") { let s = "\u{1F601}abc さ\u{3099}し\u{3099}す\u{3099}せ\u{3099}そ\u{3099}" expectEqual("", s.substringToIndex(s.startIndex)) expectEqual("\u{1F601}abc さ\u{3099}し\u{3099}す\u{3099}", s.substringToIndex(advance(s.startIndex, 8))) expectEqual(s, s.substringToIndex(advance(s.startIndex, 10))) } NSStringAPIs.test("substringWithRange(_:)") { let s = "\u{1F601}abc さ\u{3099}し\u{3099}す\u{3099}せ\u{3099}そ\u{3099}" expectEqual("", s.substringWithRange(s.startIndex..= rhs, stackTrace: stackTrace) expectEqual(expected.isGT(), lhs > rhs, stackTrace: stackTrace) checkComparable(expected, lhs, rhs, stackTrace: stackTrace.withCurrentLoc()) // NSString / NSString let lhsNSString = lhs as NSString let rhsNSString = rhs as NSString let expectedEqualUnicodeScalars = Array(lhs.unicodeScalars) == Array(rhs.unicodeScalars) // FIXME: Swift String and NSString comparison may not be equal. expectEqual( expectedEqualUnicodeScalars, lhsNSString == rhsNSString, stackTrace: stackTrace) expectEqual( !expectedEqualUnicodeScalars, lhsNSString != rhsNSString, stackTrace: stackTrace) checkHashable( expectedEqualUnicodeScalars, lhsNSString, rhsNSString, stackTrace: stackTrace.withCurrentLoc()) } NSStringAPIs.test("String.{Equatable,Hashable,Comparable}") { for test in comparisonTests { checkStringComparison( test.expectedUnicodeCollation, test.lhs, test.rhs, test.loc.withCurrentLoc()) checkStringComparison( test.expectedUnicodeCollation.flip(), test.rhs, test.lhs, test.loc.withCurrentLoc()) } } func checkCharacterComparison( expected: ExpectedComparisonResult, _ lhs: Character, _ rhs: Character, _ stackTrace: SourceLocStack ) { // Character / Character expectEqual(expected.isEQ(), lhs == rhs, stackTrace: stackTrace) expectEqual(expected.isNE(), lhs != rhs, stackTrace: stackTrace) checkHashable( expected.isEQ(), lhs, rhs, stackTrace: stackTrace.withCurrentLoc()) expectEqual(expected.isLT(), lhs < rhs, stackTrace: stackTrace) expectEqual(expected.isLE(), lhs <= rhs, stackTrace: stackTrace) expectEqual(expected.isGE(), lhs >= rhs, stackTrace: stackTrace) expectEqual(expected.isGT(), lhs > rhs, stackTrace: stackTrace) checkComparable(expected, lhs, rhs, stackTrace: stackTrace.withCurrentLoc()) } NSStringAPIs.test("Character.{Equatable,Hashable,Comparable}") { for test in comparisonTests { if test.lhs.characters.count == 1 && test.rhs.characters.count == 1 { let lhsCharacter = Character(test.lhs) let rhsCharacter = Character(test.rhs) checkCharacterComparison( test.expectedUnicodeCollation, lhsCharacter, rhsCharacter, test.loc.withCurrentLoc()) checkCharacterComparison( test.expectedUnicodeCollation.flip(), rhsCharacter, lhsCharacter, test.loc.withCurrentLoc()) } } } func checkHasPrefixHasSuffix( lhs: String, _ rhs: String, _ stackTrace: SourceLocStack ) { if lhs == "" { return } if rhs == "" { expectFalse(lhs.hasPrefix(rhs), stackTrace: stackTrace) expectFalse(lhs.hasSuffix(rhs), stackTrace: stackTrace) return } // To determine the expected results, compare grapheme clusters, // scalar-to-scalar, of the NFD form of the strings. let lhsNFDGraphemeClusters = lhs.decomposedStringWithCanonicalMapping.characters.map { Array(String($0).unicodeScalars) } let rhsNFDGraphemeClusters = rhs.decomposedStringWithCanonicalMapping.characters.map { Array(String($0).unicodeScalars) } let expectHasPrefix = lhsNFDGraphemeClusters.startsWith( rhsNFDGraphemeClusters, isEquivalent: (==)) let expectHasSuffix = lazy(lhsNFDGraphemeClusters).reverse().startsWith( lazy(rhsNFDGraphemeClusters).reverse(), isEquivalent: (==)) expectEqual(expectHasPrefix, lhs.hasPrefix(rhs), stackTrace: stackTrace) expectEqual( expectHasPrefix, (lhs + "abc").hasPrefix(rhs), stackTrace: stackTrace) expectEqual(expectHasSuffix, lhs.hasSuffix(rhs), stackTrace: stackTrace) expectEqual( expectHasSuffix, ("abc" + lhs).hasSuffix(rhs), stackTrace: stackTrace) } NSStringAPIs.test("hasPrefix,hasSuffix") { for test in comparisonTests { checkHasPrefixHasSuffix(test.lhs, test.rhs, test.loc.withCurrentLoc()) checkHasPrefixHasSuffix(test.rhs, test.lhs, test.loc.withCurrentLoc()) } } NSStringAPIs.test("Failures{hasPrefix,hasSuffix}-CF") .xfail(.Custom({ true }, reason: "rdar://problem/19034601")).code { let test = ComparisonTest(.LT, "\u{0}", "\u{0}\u{0}") checkHasPrefixHasSuffix(test.lhs, test.rhs, test.loc.withCurrentLoc()) } NSStringAPIs.test("Failures{hasPrefix,hasSuffix}") .xfail(.Custom({ true }, reason: "blocked on rdar://problem/19036555")).code { let tests = [ComparisonTest(.LT, "\r\n", "t"), ComparisonTest(.GT, "\r\n", "\n")] tests.map { checkHasPrefixHasSuffix($0.lhs, $0.rhs, $0.loc.withCurrentLoc()) } } NSStringAPIs.test("SameTypeComparisons") { // U+0323 COMBINING DOT BELOW // U+0307 COMBINING DOT ABOVE // U+1E63 LATIN SMALL LETTER S WITH DOT BELOW let xs = "\u{1e69}" expectTrue(xs == "s\u{323}\u{307}") expectFalse(xs != "s\u{323}\u{307}") expectTrue("s\u{323}\u{307}" == xs) expectFalse("s\u{323}\u{307}" != xs) expectTrue("\u{1e69}" == "s\u{323}\u{307}") expectFalse("\u{1e69}" != "s\u{323}\u{307}") expectTrue(xs == xs) expectFalse(xs != xs) } NSStringAPIs.test("MixedTypeComparisons") { // U+0323 COMBINING DOT BELOW // U+0307 COMBINING DOT ABOVE // U+1E63 LATIN SMALL LETTER S WITH DOT BELOW // NSString does not decompose characters, so the two strings will be (==) in // swift but not in Foundation. let xs = "\u{1e69}" let ys: NSString = "s\u{323}\u{307}" expectFalse(ys == "\u{1e69}") expectTrue(ys != "\u{1e69}") expectFalse("\u{1e69}" == ys) expectTrue("\u{1e69}" != ys) expectFalse(xs == ys) expectTrue(xs != ys) expectTrue(ys == ys) expectFalse(ys != ys) } NSStringAPIs.test("CompareStringsWithUnpairedSurrogates") .xfail( .Custom({ true }, reason: " Strings referring to underlying " + "storage with unpaired surrogates compare unequal")) .code { let donor = "abcdef" let acceptor = "\u{1f601}\u{1f602}\u{1f603}" expectEqual("\u{fffd}\u{1f602}\u{fffd}", acceptor[advance(donor.startIndex, 1).. UnsafeMutablePointer { return nil } func getASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x61 up[1] = 0x62 up[2] = 0 return (up, { up.dealloc(100) }) } func getNonASCIICString() -> (UnsafeMutablePointer, dealloc: ()->()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0xd0 up[1] = 0xb0 up[2] = 0xd0 up[3] = 0xb1 up[4] = 0 return (UnsafeMutablePointer(up), { up.dealloc(100) }) } func getIllFormedUTF8String1( ) -> (UnsafeMutablePointer, dealloc: ()->()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x41 up[1] = 0xed up[2] = 0xa0 up[3] = 0x80 up[4] = 0x41 up[5] = 0 return (UnsafeMutablePointer(up), { up.dealloc(100) }) } func getIllFormedUTF8String2( ) -> (UnsafeMutablePointer, dealloc: ()->()) { let up = UnsafeMutablePointer.alloc(100) up[0] = 0x41 up[1] = 0xed up[2] = 0xa0 up[3] = 0x81 up[4] = 0x41 up[5] = 0 return (UnsafeMutablePointer(up), { up.dealloc(100) }) } func asCCharArray(a: [UInt8]) -> [CChar] { return a.map { CChar(bitPattern: $0) } } CStringTests.test("String.fromCString") { if true { let s = getNullCString() expectEmpty(String.fromCString(s)) } if true { let (s, dealloc) = getASCIICString() expectOptionalEqual("ab", String.fromCString(s)) dealloc() } if true { let (s, dealloc) = getNonASCIICString() expectOptionalEqual("аб", String.fromCString(s)) dealloc() } if true { let (s, dealloc) = getIllFormedUTF8String1() expectEmpty(String.fromCString(s)) dealloc() } } CStringTests.test("String.fromCStringRepairingIllFormedUTF8") { if true { let s = getNullCString() let (result, hadError) = String.fromCStringRepairingIllFormedUTF8(s) expectEmpty(result) expectFalse(hadError) } if true { let (s, dealloc) = getASCIICString() let (result, hadError) = String.fromCStringRepairingIllFormedUTF8(s) expectOptionalEqual("ab", result) expectFalse(hadError) dealloc() } if true { let (s, dealloc) = getNonASCIICString() let (result, hadError) = String.fromCStringRepairingIllFormedUTF8(s) expectOptionalEqual("аб", result) expectFalse(hadError) dealloc() } if true { let (s, dealloc) = getIllFormedUTF8String1() let (result, hadError) = String.fromCStringRepairingIllFormedUTF8(s) expectOptionalEqual("\u{41}\u{fffd}\u{fffd}\u{fffd}\u{41}", result) expectTrue(hadError) dealloc() } } runAllTests()