From 5c24026ffc756e7948a11c6e4943df5126d1342f Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 15:19:20 -0500 Subject: [PATCH 1/6] Implement NSRangeFromString. An initial implementation of NSRangeFromString that attempts to replicate the behavior of standard Foundation. --- Foundation/NSRange.swift | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index 2cbdee73c6..199c2b246b 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -99,5 +99,26 @@ public func NSStringFromRange(range: NSRange) -> String { } public func NSRangeFromString(aString: String) -> NSRange { - NSUnimplemented() -} \ No newline at end of file + // just by playing around in the REPL, it looks like + // NSRangeFromString just walks through the string finding + // all integers in order, defaulting to 0 if they're not found. + return NSRangeParser.parseRange(aString) +} + +struct NSRangeParser { + static let decimalDigitsAndCommas: NSCharacterSet = { + let mutable = NSCharacterSet.decimalDigitCharacterSet().mutableCopy() as! NSMutableCharacterSet + mutable.addCharactersInString(",") + return mutable.invertedSet + }() + static func parseRange(string: String) -> NSRange { + var final = NSRange(location: 0, length: 0) + let components = (string as NSString).componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas) + let ints = components.flatMap { Int($0) } + guard let location = ints.first else { return final } + final.location = location + guard let length = ints.dropFirst().first else { return final } + final.length = length + return final + } +} From c8a23202e92f690391c4c8b3832dccc3235ee0d3 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 15:28:32 -0500 Subject: [PATCH 2/6] Fixed implementation (verified using playground) --- Foundation/NSRange.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index 199c2b246b..db14f8b0a3 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -105,7 +105,15 @@ public func NSRangeFromString(aString: String) -> NSRange { return NSRangeParser.parseRange(aString) } +public func _NSRangeFromString(aString: String) -> NSRange { + // just by playing around in the REPL, it looks like + // NSRangeFromString just walks through the string finding + // all integers in order, defaulting to 0 if they're not found. + return NSRangeParser.parseRange(aString) +} + struct NSRangeParser { + // removes all characters that are not decimal digits and commas. static let decimalDigitsAndCommas: NSCharacterSet = { let mutable = NSCharacterSet.decimalDigitCharacterSet().mutableCopy() as! NSMutableCharacterSet mutable.addCharactersInString(",") @@ -113,8 +121,8 @@ struct NSRangeParser { }() static func parseRange(string: String) -> NSRange { var final = NSRange(location: 0, length: 0) - let components = (string as NSString).componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas) - let ints = components.flatMap { Int($0) } + let removeNonDigits = (string as NSString).componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas).joinWithSeparator("") + let ints = removeNonDigits.componentsSeparatedByString(",").flatMap { Int($0) } guard let location = ints.first else { return final } final.location = location guard let length = ints.dropFirst().first else { return final } From 7884230265403c5e56bdc3ed04e1308e5101645c Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 15:29:54 -0500 Subject: [PATCH 3/6] Removed duplicate function definition. --- Foundation/NSRange.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index db14f8b0a3..b5b217939d 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -105,13 +105,6 @@ public func NSRangeFromString(aString: String) -> NSRange { return NSRangeParser.parseRange(aString) } -public func _NSRangeFromString(aString: String) -> NSRange { - // just by playing around in the REPL, it looks like - // NSRangeFromString just walks through the string finding - // all integers in order, defaulting to 0 if they're not found. - return NSRangeParser.parseRange(aString) -} - struct NSRangeParser { // removes all characters that are not decimal digits and commas. static let decimalDigitsAndCommas: NSCharacterSet = { From a8b0f558faef113ba9059c776c485967ee9424a0 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 15:47:07 -0500 Subject: [PATCH 4/6] Added NSRange tests and cleaned up parsing a little --- Foundation.xcodeproj/project.pbxproj | 4 +++ Foundation/NSRange.swift | 4 ++- TestFoundation/TestNSRange.swift | 51 ++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 TestFoundation/TestNSRange.swift diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index afce7cd277..3fb3fc8b05 100644 --- a/Foundation.xcodeproj/project.pbxproj +++ b/Foundation.xcodeproj/project.pbxproj @@ -189,6 +189,7 @@ 5BF7AEBF1BCD51F9008F214A /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4A1BCC5DCB00ED97BB /* NSURL.swift */; }; 5BF7AEC01BCD51F9008F214A /* NSUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4B1BCC5DCB00ED97BB /* NSUUID.swift */; }; 5BF7AEC11BCD51F9008F214A /* NSValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BDC3F4C1BCC5DCB00ED97BB /* NSValue.swift */; }; + DCC7AF291C10DE57000417E3 /* TestNSRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC7AF271C10DE57000417E3 /* TestNSRange.swift */; }; EA66F6361BEED03E00136161 /* TargetConditionals.h in Headers */ = {isa = PBXBuildFile; fileRef = EA66F6351BEED03E00136161 /* TargetConditionals.h */; settings = {ATTRIBUTES = (Public, ); }; }; EA66F6441BF1619600136161 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA66F6381BF1619600136161 /* main.swift */; }; EA66F6481BF1619600136161 /* NSURLTestData.plist in Resources */ = {isa = PBXBuildFile; fileRef = EA66F63B1BF1619600136161 /* NSURLTestData.plist */; }; @@ -503,6 +504,7 @@ 5BDC3FCF1BCF17E600ED97BB /* NSCFSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSCFSet.swift; sourceTree = ""; }; 5BDC405C1BD6D83B00ED97BB /* TestFoundation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestFoundation.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5BF7AEC21BCD568D008F214A /* ForSwiftFoundationOnly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ForSwiftFoundationOnly.h; sourceTree = ""; }; + DCC7AF271C10DE57000417E3 /* TestNSRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSRange.swift; sourceTree = ""; }; EA313DFC1BE7F2E90060A403 /* CFURLComponents_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFURLComponents_Internal.h; sourceTree = ""; }; EA313DFD1BE7F2E90060A403 /* CFURLComponents_URIParser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFURLComponents_URIParser.c; sourceTree = ""; }; EA313DFE1BE7F2E90060A403 /* CFURLComponents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CFURLComponents.c; sourceTree = ""; }; @@ -986,6 +988,7 @@ EA66F65A1BF1976100136161 /* Tests */ = { isa = PBXGroup; children = ( + DCC7AF271C10DE57000417E3 /* TestNSRange.swift */, EA66F63C1BF1619600136161 /* TestNSArray.swift */, EA66F63D1BF1619600136161 /* TestNSDictionary.swift */, EA66F63E1BF1619600136161 /* TestNSIndexSet.swift */, @@ -1678,6 +1681,7 @@ files = ( 525AECED1BF2C9C500D15BB0 /* TestNSFileManager.swift in Sources */, EA66F6501BF1619600136161 /* TestNSNumber.swift in Sources */, + DCC7AF291C10DE57000417E3 /* TestNSRange.swift in Sources */, EA66F6521BF1619600136161 /* TestNSPropertyList.swift in Sources */, EA66F64E1BF1619600136161 /* TestNSIndexSet.swift in Sources */, EA66F6541BF1619600136161 /* TestNSSet.swift in Sources */, diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index b5b217939d..2a3cfd2530 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -114,7 +114,9 @@ struct NSRangeParser { }() static func parseRange(string: String) -> NSRange { var final = NSRange(location: 0, length: 0) - let removeNonDigits = (string as NSString).componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas).joinWithSeparator("") + let removeNonDigits = (string as NSString) + .componentsSeparatedByCharactersInSet(NSRangeParser.decimalDigitsAndCommas) + .joinWithSeparator("") let ints = removeNonDigits.componentsSeparatedByString(",").flatMap { Int($0) } guard let location = ints.first else { return final } final.location = location diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift new file mode 100644 index 0000000000..89bcbd22b8 --- /dev/null +++ b/TestFoundation/TestNSRange.swift @@ -0,0 +1,51 @@ +// +// TestNSRange.swift +// Foundation +// +// Created by Harlan Haskins on 12/3/15. +// Copyright © 2015 Apple. All rights reserved. +// + +#if DEPLOYMENT_RUNTIME_OBJC || os(Linux) + import Foundation + import XCTest +#else + import SwiftFoundation + import SwiftXCTest +#endif + +class TestNSRange: XCTestCase { + + override func setUp() { + super.setUp() + } + + override func tearDown() { + super.tearDown() + } + + func testRangeWithValidInput() { + XCTAssertEqual(NSRangeFromString("{4,5}"), NSRange(location: 4, length: 5)) + } + + func testRangesWithInvalidInput() { + XCTAssertEqual(NSRangeFromString("4,5}"), NSRange(location: 4, length: 5)) + XCTAssertEqual(NSRangeFromString("{4,5"), NSRange(location: 4, length: 5)) + XCTAssertEqual(NSRangeFromString("{4,}"), NSRange(location: 4, length: 0)) + XCTAssertEqual(NSRangeFromString(",4}"), NSRange(location: 4, length: 0)) + XCTAssertEqual(NSRangeFromString("4,5"), NSRange(location: 4, length: 5)) + } + + func testRoundTrip() { + let initial = NSRange(location: 4, length: 5) + NSRangeFromString(NSStringFromRange(initial)) == initial + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measureBlock { + // Put the code you want to measure the time of here. + } + } + +} From 31dc40f6aea07a5fbc3ea7f4f330e26771d227b6 Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 15:47:52 -0500 Subject: [PATCH 5/6] Fixed test to actually use XCTAssertEqual --- TestFoundation/TestNSRange.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift index 89bcbd22b8..9751a9d5cc 100644 --- a/TestFoundation/TestNSRange.swift +++ b/TestFoundation/TestNSRange.swift @@ -38,7 +38,7 @@ class TestNSRange: XCTestCase { func testRoundTrip() { let initial = NSRange(location: 4, length: 5) - NSRangeFromString(NSStringFromRange(initial)) == initial + XCTAssertEqual(NSRangeFromString(NSStringFromRange(initial)), initial) } func testPerformanceExample() { From 24afb9ba0e35ef595eb49e445c0bee1e2bfa583c Mon Sep 17 00:00:00 2001 From: Harlan Haskins Date: Thu, 3 Dec 2015 17:52:59 -0500 Subject: [PATCH 6/6] =?UTF-8?q?Added=20(incredibly)=20nai=CC=88ve=20implem?= =?UTF-8?q?entations=20of=20NSString=20methods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented NSString.componentsSeparatedByString and NSString.componentsSeparatedByCharactersInSet --- Foundation/NSRange.swift | 6 +++--- Foundation/NSString.swift | 32 ++++++++++++++++++++++++++++-- TestFoundation/TestNSRange.swift | 34 ++++++++++++++++---------------- TestFoundation/main.swift | 2 +- 4 files changed, 51 insertions(+), 23 deletions(-) diff --git a/Foundation/NSRange.swift b/Foundation/NSRange.swift index 2a3cfd2530..3467218f95 100644 --- a/Foundation/NSRange.swift +++ b/Foundation/NSRange.swift @@ -108,9 +108,9 @@ public func NSRangeFromString(aString: String) -> NSRange { struct NSRangeParser { // removes all characters that are not decimal digits and commas. static let decimalDigitsAndCommas: NSCharacterSet = { - let mutable = NSCharacterSet.decimalDigitCharacterSet().mutableCopy() as! NSMutableCharacterSet - mutable.addCharactersInString(",") - return mutable.invertedSet + let characterSet = NSMutableCharacterSet(bitmapRepresentation: NSCharacterSet.decimalDigitCharacterSet().bitmapRepresentation) + characterSet.addCharactersInString(",") + return characterSet.invertedSet }() static func parseRange(string: String) -> NSRange { var final = NSRange(location: 0, length: 0) diff --git a/Foundation/NSString.swift b/Foundation/NSString.swift index 1521ca0f85..6d1a8f8a6b 100644 --- a/Foundation/NSString.swift +++ b/Foundation/NSString.swift @@ -630,11 +630,39 @@ extension NSString { } public func componentsSeparatedByString(separator: String) -> [String] { - NSUnimplemented() + let sepLength = separator.characters.count + var previousSplit = 0 + var components = [String]() + for i in (0.. [String] { - NSUnimplemented() + let worker = self as String + var components = [String]() + var current = "" + for scalar in worker.unicodeScalars { + if separator.characterIsMember(unichar(unicodeScalarLiteral: scalar)) { + components.append(current) + current = "" + } else { + current.append(scalar) + } + } + components.append(current) + return components } public func stringByTrimmingCharactersInSet(set: NSCharacterSet) -> String { diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift index 9751a9d5cc..0af3cafd3d 100644 --- a/TestFoundation/TestNSRange.swift +++ b/TestFoundation/TestNSRange.swift @@ -14,21 +14,28 @@ import SwiftXCTest #endif +extension NSRange: Equatable {} + +public func ==(lhs: NSRange, rhs: NSRange) -> Bool { + return lhs.location == rhs.location && lhs.length == rhs.length +} + class TestNSRange: XCTestCase { - override func setUp() { - super.setUp() + var allTests: [(String, () -> ())] { + return [ + ("test_rangeWithValidInput", test_rangeWithValidInput), + ("test_rangesWithInvalidInput", test_rangesWithInvalidInput), + ("test_roundTrip", test_roundTrip) + ] } - override func tearDown() { - super.tearDown() + func test_rangeWithValidInput() { + let practice = NSRangeFromString("{4,5}") + XCTAssertEqual(practice, NSRange(location: 4, length: 5)) } - func testRangeWithValidInput() { - XCTAssertEqual(NSRangeFromString("{4,5}"), NSRange(location: 4, length: 5)) - } - - func testRangesWithInvalidInput() { + func test_rangesWithInvalidInput() { XCTAssertEqual(NSRangeFromString("4,5}"), NSRange(location: 4, length: 5)) XCTAssertEqual(NSRangeFromString("{4,5"), NSRange(location: 4, length: 5)) XCTAssertEqual(NSRangeFromString("{4,}"), NSRange(location: 4, length: 0)) @@ -36,16 +43,9 @@ class TestNSRange: XCTestCase { XCTAssertEqual(NSRangeFromString("4,5"), NSRange(location: 4, length: 5)) } - func testRoundTrip() { + func test_roundTrip() { let initial = NSRange(location: 4, length: 5) XCTAssertEqual(NSRangeFromString(NSStringFromRange(initial)), initial) } - func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock { - // Put the code you want to measure the time of here. - } - } - } diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift index 9bbf59448d..20b4197138 100644 --- a/TestFoundation/main.swift +++ b/TestFoundation/main.swift @@ -20,4 +20,4 @@ internal func testBundle() -> NSBundle { } // For the Swift version of the Foundation tests, we must manually list all test cases here. -XCTMain([TestNSString(), TestNSArray(), TestNSDictionary(), TestNSSet(), TestNSNumber(), TestNSPropertyList(), TestNSURL(), TestNSIndexSet(), TestNSCharacterSet(), TestNSFileManger()]) +XCTMain([TestNSString(), TestNSArray(), TestNSDictionary(), TestNSSet(), TestNSNumber(), TestNSPropertyList(), TestNSURL(), TestNSIndexSet(), TestNSCharacterSet(), TestNSFileManger(), TestNSRange()])