Skip to content

Commit 0526191

Browse files
committed
Merge branch 'master' of github.com:apple/swift-corelibs-foundation into codable
# Conflicts: # TestFoundation/TestCodable.swift
2 parents 826ed33 + 79322e9 commit 0526191

12 files changed

+184
-62
lines changed

Foundation/ExtraStringAPIs.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,4 @@ extension String.UTF16View.Index : Strideable {
2929
}
3030
}
3131

32-
extension String.UTF16View : RandomAccessCollection {}
33-
extension String.UTF16View.Indices : RandomAccessCollection {}
3432

Foundation/NSGeometry.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ extension CGPoint: NSSpecialValueCoding {
7676
}
7777
}
7878

79+
extension CGPoint : Codable {
80+
public init(from decoder: Decoder) throws {
81+
var container = try decoder.unkeyedContainer()
82+
let x = try container.decode(CGFloat.self)
83+
let y = try container.decode(CGFloat.self)
84+
self.init(x: x, y: y)
85+
}
86+
87+
public func encode(to encoder: Encoder) throws {
88+
var container = encoder.unkeyedContainer()
89+
try container.encode(x)
90+
try container.encode(y)
91+
}
92+
}
93+
7994
public struct CGSize {
8095
public var width: CGFloat
8196
public var height: CGFloat
@@ -139,6 +154,21 @@ extension CGSize: NSSpecialValueCoding {
139154
}
140155
}
141156

157+
extension CGSize : Codable {
158+
public init(from decoder: Decoder) throws {
159+
var container = try decoder.unkeyedContainer()
160+
let width = try container.decode(CGFloat.self)
161+
let height = try container.decode(CGFloat.self)
162+
self.init(width: width, height: height)
163+
}
164+
165+
public func encode(to encoder: Encoder) throws {
166+
var container = encoder.unkeyedContainer()
167+
try container.encode(width)
168+
try container.encode(height)
169+
}
170+
}
171+
142172
public struct CGRect {
143173
public var origin: CGPoint
144174
public var size: CGSize
@@ -157,6 +187,21 @@ extension CGRect: Equatable {
157187
}
158188
}
159189

190+
extension CGRect : Codable {
191+
public init(from decoder: Decoder) throws {
192+
var container = try decoder.unkeyedContainer()
193+
let origin = try container.decode(CGPoint.self)
194+
let size = try container.decode(CGSize.self)
195+
self.init(origin: origin, size: size)
196+
}
197+
198+
public func encode(to encoder: Encoder) throws {
199+
var container = encoder.unkeyedContainer()
200+
try container.encode(origin)
201+
try container.encode(size)
202+
}
203+
}
204+
160205
public typealias NSPoint = CGPoint
161206

162207
public typealias NSPointPointer = UnsafeMutablePointer<NSPoint>

Foundation/NSSortDescriptor.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ open class NSSortDescriptor: NSObject, NSSecureCoding, NSCopying {
3535

3636
open var key: String? { NSUnimplemented() }
3737
open var ascending: Bool { NSUnimplemented() }
38-
var keyPath: AnyKeyPath? { NSUnimplemented() }
38+
public var keyPath: AnyKeyPath? { NSUnimplemented() }
3939

4040
open func allowEvaluation() { NSUnimplemented() } // Force a sort descriptor which was securely decoded to allow evaluation
4141

4242
public init(key: String?, ascending: Bool, comparator cmptr: Comparator) { NSUnimplemented() }
43-
convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool) { NSUnimplemented() }
44-
convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool, comparator cmptr: @escaping Comparator) { NSUnimplemented() }
43+
public convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool) { NSUnimplemented() }
44+
public convenience init<Root, Value>(keyPath: KeyPath<Root, Value>, ascending: Bool, comparator cmptr: @escaping Comparator) { NSUnimplemented() }
4545

4646
open var comparator: Comparator { NSUnimplemented() }
4747

Foundation/NSString.swift

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -346,49 +346,7 @@ extension NSString {
346346
let start = _storage.utf16.startIndex
347347
let min = start.advanced(by: range.location)
348348
let max = start.advanced(by: range.location + range.length)
349-
if let substr = String(_storage.utf16[min..<max]) {
350-
return substr
351-
}
352-
//If we come here, then the range has created unpaired surrogates on either end.
353-
//An unpaired surrogate is replaced by OXFFFD - the Unicode Replacement Character.
354-
//The CRLF ("\r\n") sequence is also treated like a surrogate pair, but its constinuent
355-
//characters "\r" and "\n" can exist outside the pair!
356-
357-
let replacementCharacter = String(describing: UnicodeScalar(0xFFFD)!)
358-
let CR: UInt16 = 13 //carriage return
359-
let LF: UInt16 = 10 //new line
360-
361-
//make sure the range is of non-zero length
362-
guard range.length > 0 else { return "" }
363-
364-
//if the range is pointing to a single unpaired surrogate
365-
if range.length == 1 {
366-
switch _storage.utf16[min] {
367-
case CR: return "\r"
368-
case LF: return "\n"
369-
default: return replacementCharacter
370-
}
371-
}
372-
373-
//set the prefix and suffix characters
374-
let prefix = _storage.utf16[min] == LF ? "\n" : replacementCharacter
375-
let suffix = _storage.utf16[max.advanced(by: -1)] == CR ? "\r" : replacementCharacter
376-
377-
//if the range breaks a surrogate pair at the beginning of the string
378-
if let substrSuffix = String(_storage.utf16[min.advanced(by: 1)..<max]) {
379-
return prefix + substrSuffix
380-
}
381-
382-
//if the range breaks a surrogate pair at the end of the string
383-
if let substrPrefix = String(_storage.utf16[min..<max.advanced(by: -1)]) {
384-
return substrPrefix + suffix
385-
}
386-
387-
//the range probably breaks surrogate pairs at both the ends
388-
guard min.advanced(by: 1) <= max.advanced(by: -1) else { return prefix + suffix }
389-
390-
let substr = String(_storage.utf16[min.advanced(by: 1)..<max.advanced(by: -1)])!
391-
return prefix + substr + suffix
349+
return String(decoding: _storage.utf16[min..<max], as: UTF16.self)
392350
} else {
393351
let buff = UnsafeMutablePointer<unichar>.allocate(capacity: range.length)
394352
getCharacters(buff, range: range)

Foundation/NSURLSession/NSURLSessionTask.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -546,13 +546,12 @@ extension _ProtocolClient : URLProtocolClient {
546546
guard let task = `protocol`.task else { fatalError() }
547547
guard let session = task.session as? URLSession else { fatalError() }
548548
switch session.behaviour(for: task) {
549-
case .taskDelegate(let delegate) where delegate is URLSessionDownloadDelegate:
550-
let downloadDelegate = delegate as! URLSessionDownloadDelegate
551-
let downloadTask = task as! URLSessionDownloadTask
552-
session.delegateQueue.addOperation {
553-
downloadDelegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: `protocol`.properties[URLProtocol._PropertyKey.temporaryFileURL] as! URL)
554-
}
555549
case .taskDelegate(let delegate):
550+
if let downloadDelegate = delegate as? URLSessionDownloadDelegate, let downloadTask = task as? URLSessionDownloadTask {
551+
session.delegateQueue.addOperation {
552+
downloadDelegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: `protocol`.properties[URLProtocol._PropertyKey.temporaryFileURL] as! URL)
553+
}
554+
}
556555
session.delegateQueue.addOperation {
557556
delegate.urlSession(session, task: task, didCompleteWithError: nil)
558557
task.state = .completed

Foundation/NSURLSession/http/HTTPMessage.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ private extension String {
222222
/// Split a request line into its 3 parts: *Method*, *Request-URI*, and *HTTP-Version*.
223223
/// - SeeAlso: https://tools.ietf.org/html/rfc2616#section-5.1
224224
func splitRequestLine() -> (String, String, String)? {
225-
let scalars = self.unicodeScalars
225+
let scalars = self.unicodeScalars[...]
226226
guard let firstSpace = scalars.rangeOfSpace else { return nil }
227227
let remainingRange = firstSpace.upperBound..<scalars.endIndex
228228
let remainder = scalars[remainingRange]
@@ -285,7 +285,7 @@ private extension _HTTPURLProtocol._HTTPMessage._Header {
285285
// recipient MAY replace any linear white space with a single SP before
286286
// interpreting the field value or forwarding the message downstream.
287287
guard let (head, tail) = lines.decompose else { return nil }
288-
let headView = head.unicodeScalars
288+
let headView = head.unicodeScalars[...]
289289
guard let nameRange = headView.rangeOfTokenPrefix else { return nil }
290290
guard headView.index(after: nameRange.upperBound) <= headView.endIndex && headView[nameRange.upperBound] == _HTTPCharacters.Colon else { return nil }
291291
let name = String(headView[nameRange])
@@ -302,10 +302,10 @@ private extension _HTTPURLProtocol._HTTPMessage._Header {
302302
}
303303
do {
304304
var t = tail
305-
while t.first?.unicodeScalars.hasSPHTPrefix ?? false {
305+
while t.first?.unicodeScalars[...].hasSPHTPrefix ?? false {
306306
guard let (h2, t2) = t.decompose else { return nil }
307307
t = t2
308-
guard let v = h2.unicodeScalars.trimSPHTPrefix else { return nil }
308+
guard let v = h2.unicodeScalars[...].trimSPHTPrefix else { return nil }
309309
let valuePart = String(v)
310310
value = value.map { $0 + " " + valuePart } ?? valuePart
311311
}
@@ -321,7 +321,7 @@ private extension Collection {
321321
return (head, tail)
322322
}
323323
}
324-
private extension String.UnicodeScalarView {
324+
private extension String.UnicodeScalarView.SubSequence {
325325
/// The range of *Token* characters as specified by RFC 2616.
326326
var rangeOfTokenPrefix: Range<Index>? {
327327
var end = startIndex
@@ -344,7 +344,7 @@ private extension String.UnicodeScalarView {
344344
}
345345
/// Unicode scalars after removing the leading spaces (SP) and horizontal tabs (HT).
346346
/// Returns `nil` if the unicode scalars do not start with a SP or HT.
347-
var trimSPHTPrefix: String.UnicodeScalarView? {
347+
var trimSPHTPrefix: SubSequence? {
348348
guard !isEmpty else { return nil }
349349
var idx = startIndex
350350
while idx < endIndex {

Foundation/Process.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,30 @@ open class Process: NSObject {
387387
posix(posix_spawn_file_actions_addclose(&fileActions, fd))
388388
}
389389

390+
let fileManager = FileManager()
391+
let previousDirectoryPath = fileManager.currentDirectoryPath
392+
if !fileManager.changeCurrentDirectoryPath(currentDirectoryPath) {
393+
// Foundation throws an NSException when changing the working directory fails,
394+
// and unfortunately launch() is not marked `throws`, so we get away with a
395+
// fatalError.
396+
switch errno {
397+
case ENOENT:
398+
fatalError("Process: The specified working directory does not exist.")
399+
case EACCES:
400+
fatalError("Process: The specified working directory cannot be accessed.")
401+
default:
402+
fatalError("Process: The specified working directory cannot be set.")
403+
}
404+
}
405+
390406
// Launch
391407

392408
var pid = pid_t()
393409
posix(posix_spawn(&pid, launchPath, &fileActions, nil, argv, envp))
394410

411+
// Reset the previous working directory path.
412+
fileManager.changeCurrentDirectoryPath(previousDirectoryPath)
413+
395414
// Close the write end of the input and output pipes.
396415
if let pipe = standardInput as? Pipe {
397416
pipe.fileHandleForReading.closeFile()

TestFoundation/TestCodable.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,54 @@ class TestCodable : XCTestCase {
221221
}
222222
}
223223

224+
// MARK: - CGPoint
225+
lazy var cgpointValues: [CGPoint] = [
226+
CGPoint(),
227+
CGPoint(x: 10, y: 20),
228+
CGPoint(x: -10, y: -20),
229+
// Disabled due to limit on magnitude in JSON. See SR-5346
230+
// CGPoint(x: .greatestFiniteMagnitude, y: .greatestFiniteMagnitude),
231+
]
232+
233+
func test_CGPoint_JSON() {
234+
for point in cgpointValues {
235+
expectRoundTripEqualityThroughJSON(for: point)
236+
}
237+
}
238+
239+
// MARK: - CGSize
240+
lazy var cgsizeValues: [CGSize] = [
241+
CGSize(),
242+
CGSize(width: 30, height: 40),
243+
CGSize(width: -30, height: -40),
244+
// Disabled due to limit on magnitude in JSON. See SR-5346
245+
// CGSize(width: .greatestFiniteMagnitude, height: .greatestFiniteMagnitude),
246+
]
247+
248+
func test_CGSize_JSON() {
249+
for size in cgsizeValues {
250+
expectRoundTripEqualityThroughJSON(for: size)
251+
}
252+
}
253+
254+
// MARK: - CGRect
255+
lazy var cgrectValues: [CGRect] = [
256+
CGRect(),
257+
CGRect(origin: CGPoint(x: 10, y: 20), size: CGSize(width: 30, height: 40)),
258+
CGRect(origin: CGPoint(x: -10, y: -20), size: CGSize(width: -30, height: -40)),
259+
// Disabled due to limit on magnitude in JSON. See SR-5346
260+
// CGRect(origin: CGPoint(x: -.greatestFiniteMagnitude / 2,
261+
// y: -.greatestFiniteMagnitude / 2),
262+
// size: CGSize(width: .greatestFiniteMagnitude,
263+
// height: .greatestFiniteMagnitude)),
264+
]
265+
266+
func test_CGRect_JSON() {
267+
for rect in cgrectValues {
268+
expectRoundTripEqualityThroughJSON(for: rect)
269+
}
270+
}
271+
224272
// MARK: - CharacterSet
225273
lazy var characterSetValues: [CharacterSet] = [
226274
CharacterSet.controlCharacters,
@@ -261,6 +309,9 @@ extension TestCodable {
261309
("test_IndexPath_JSON", test_IndexPath_JSON),
262310
("test_AffineTransform_JSON", test_AffineTransform_JSON),
263311
("test_Decimal_JSON", test_Decimal_JSON),
312+
("test_CGPoint_JSON", test_CGPoint_JSON),
313+
("test_CGSize_JSON", test_CGSize_JSON),
314+
("test_CGRect_JSON", test_CGRect_JSON),
264315
("test_CharacterSet_JSON", test_CharacterSet_JSON),
265316
]
266317
}

TestFoundation/TestNSDecimal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class TestNSDecimal: XCTestCase {
185185
_length: 0xff,
186186
_isNegative: 3,
187187
_isCompact: 4,
188-
_reserved: UInt32(1<<18 + 1<<17 + 1),
188+
_reserved: 1<<18 + 1<<17 + 1,
189189
_mantissa: (6, 7, 8, 9, 10, 11, 12, 13)
190190
)
191191
XCTAssertEqual(0x7f, explicit._exponent)

TestFoundation/TestNSString.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,10 @@ class TestNSString : XCTestCase {
11341134

11351135
let s5 = NSString(string: "\r\ncats😺")
11361136
XCTAssertEqual(s5.substring(with: NSMakeRange(1,6)), "\ncats�")
1137+
1138+
// SR-3363
1139+
let s6 = NSString(string: "Beyonce\u{301} and Tay")
1140+
XCTAssertEqual(s6.substring(with: NSMakeRange(7, 9)), "\u{301} and Tay")
11371141
}
11381142
}
11391143

TestFoundation/TestNSURLSession.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class TestURLSession : LoopbackServerTest {
4141
("test_outOfRangeButCorrectlyFormattedHTTPCode", test_outOfRangeButCorrectlyFormattedHTTPCode),
4242
("test_missingContentLengthButStillABody", test_missingContentLengthButStillABody),
4343
("test_illegalHTTPServerResponses", test_illegalHTTPServerResponses),
44+
("test_dataTaskWithSharedDelegate", test_dataTaskWithSharedDelegate),
4445
]
4546
}
4647

@@ -429,8 +430,37 @@ class TestURLSession : LoopbackServerTest {
429430
waitForExpectations(timeout: 12)
430431
}
431432
}
433+
434+
func test_dataTaskWithSharedDelegate() {
435+
let sharedDelegate = SharedDelegate()
436+
let urlString0 = "http://127.0.0.1:\(TestURLSession.serverPort)/Nepal"
437+
let session = URLSession(configuration: .default, delegate: sharedDelegate, delegateQueue: nil)
438+
439+
let dataRequest = URLRequest(url: URL(string: urlString0)!)
440+
let dataTask = session.dataTask(with: dataRequest)
441+
442+
sharedDelegate.dataCompletionExpectation = expectation(description: "GET \(urlString0)")
443+
dataTask.resume()
444+
waitForExpectations(timeout: 20)
445+
}
432446
}
433447

448+
class SharedDelegate: NSObject {
449+
var dataCompletionExpectation: XCTestExpectation!
450+
}
451+
452+
extension SharedDelegate: URLSessionDataDelegate {
453+
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
454+
dataCompletionExpectation.fulfill()
455+
}
456+
}
457+
458+
extension SharedDelegate: URLSessionDownloadDelegate {
459+
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
460+
}
461+
}
462+
463+
434464
class SessionDelegate: NSObject, URLSessionDelegate {
435465
let invalidateExpectation: XCTestExpectation
436466
init(invalidateExpectation: XCTestExpectation){

0 commit comments

Comments
 (0)