Merge pull request #1195 from johnno1962e/master

diff --git a/Foundation/HTTPCookieStorage.swift b/Foundation/HTTPCookieStorage.swift
index 2e9e080..045b69d 100644
--- a/Foundation/HTTPCookieStorage.swift
+++ b/Foundation/HTTPCookieStorage.swift
@@ -49,7 +49,7 @@
         let bundlePath = Bundle.main.bundlePath
         var bundleName = bundlePath.components(separatedBy: "/").last!
         if let range = bundleName.range(of: ".", options: String.CompareOptions.backwards, range: nil, locale: nil) {
-            bundleName = bundleName.substring(to: range.lowerBound)
+            bundleName = String(bundleName[..<range.lowerBound])
         }
         let cookieFolderPath = _CFXDGCreateDataHomePath()._swiftObject + "/" + bundleName
         cookieFilePath = filePath(path: cookieFolderPath, fileName: "/.cookies." + cookieStorageName, bundleName: bundleName)
diff --git a/Foundation/JSONSerialization.swift b/Foundation/JSONSerialization.swift
index a7b011f..f74932d 100644
--- a/Foundation/JSONSerialization.swift
+++ b/Foundation/JSONSerialization.swift
@@ -62,8 +62,9 @@
                 return true
             }
             
-            // object is Swift.String, NSNull, Int, Bool, or UInt
-            if obj is String || obj is NSNull || obj is Int || obj is Bool || obj is UInt {
+            if obj is String || obj is NSNull || obj is Int || obj is Bool || obj is UInt ||
+                obj is Int8 || obj is Int16 || obj is Int32 || obj is Int64 ||
+                obj is UInt8 || obj is UInt16 || obj is UInt32 || obj is UInt64 {
                 return true
             }
 
@@ -76,6 +77,10 @@
                 return number.isFinite
             }
 
+            if let number = obj as? Decimal {
+                return number.isFinite
+            }
+
             // object is Swift.Array
             if let array = obj as? [Any?] {
                 for element in array {
@@ -99,8 +104,13 @@
             // object is NSNumber and is not NaN or infinity
             // For better performance, this (most expensive) test should be last.
             if let number = _SwiftValue.store(obj) as? NSNumber {
-                let invalid = number.doubleValue.isInfinite || number.doubleValue.isNaN
-                return !invalid
+                if CFNumberIsFloatType(number._cfObject) {
+                    let dv = number.doubleValue
+                    let invalid = dv.isInfinite || dv.isNaN
+                    return !invalid
+                } else {
+                    return true
+                }
             }
 
             // invalid object
@@ -285,9 +295,7 @@
 
 //MARK: - JSONSerializer
 private struct JSONWriter {
-    
-    private let maxUIntLength = String(describing: UInt.max).count
-    private let maxIntLength = String(describing: Int.max).count
+
     var indent = 0
     let pretty: Bool
     let sortedKeys: Bool
@@ -320,13 +328,37 @@
         case let boolValue as Bool:
             serializeBool(boolValue)
         case let num as Int:
-            try serializeInt(value: num)
+            serializeInteger(value: num)
+        case let num as Int8:
+            serializeInteger(value: num)
+        case let num as Int16:
+            serializeInteger(value: num)
+        case let num as Int32:
+            serializeInteger(value: num)
+        case let num as Int64:
+            serializeInteger(value: num)
         case let num as UInt:
-            try serializeUInt(value: num)
+            serializeInteger(value: num)
+        case let num as UInt8:
+            serializeInteger(value: num)
+        case let num as UInt16:
+            serializeInteger(value: num)
+        case let num as UInt32:
+            serializeInteger(value: num)
+        case let num as UInt64:
+            serializeInteger(value: num)
         case let array as Array<Any?>:
             try serializeArray(array)
         case let dict as Dictionary<AnyHashable, Any?>:
             try serializeDictionary(dict)
+        case let num as Float:
+            try serializeNumber(NSNumber(value: num))
+        case let num as Double:
+            try serializeNumber(NSNumber(value: num))
+        case let num as Decimal:
+            writer(num.description)
+        case let num as NSDecimalNumber:
+            writer(num.description)
         case is NSNull:
             try serializeNull()
         case _ where _SwiftValue.store(obj) is NSNumber:
@@ -336,92 +368,33 @@
         }
     }
 
-    private func serializeUInt(value: UInt) throws {
-        if value == 0 {
-            writer("0")
-            return
-        }
-        var array: [UInt] = []
-        var stringResult = ""
-        //Maximum length of an UInt
-        array.reserveCapacity(maxUIntLength)
-        stringResult.reserveCapacity(maxUIntLength)
-        var number = value
-        
-        while number != 0 {
-            array.append(number % 10)
+    private func serializeInteger<T: UnsignedInteger>(value: T, isNegative: Bool = false) {
+        let maxIntLength = 22   // 20 digits in UInt64 + optional sign + trailing '\0'
+        let asciiZero: CChar = 0x30  // ASCII '0' == 0x30
+        let asciiMinus: CChar = 0x2d // ASCII '-' == 0x2d
+
+        var number = UInt64(value)
+        var buffer = Array<CChar>(repeating: 0, count: maxIntLength)
+        var pos = maxIntLength - 1
+
+        repeat {
+            pos -= 1
+            buffer[pos] = asciiZero + CChar(number % 10)
             number /= 10
+        } while number != 0
+
+        if isNegative {
+            pos -= 1
+            buffer[pos] = asciiMinus
         }
-        
-        /*
-         Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
-         */
-        var counter = array.count
-        while counter > 0 {
-            counter -= 1
-            let digit: UInt = array[counter]
-            switch digit {
-            case 0: stringResult.append("0")
-            case 1: stringResult.append("1")
-            case 2: stringResult.append("2")
-            case 3: stringResult.append("3")
-            case 4: stringResult.append("4")
-            case 5: stringResult.append("5")
-            case 6: stringResult.append("6")
-            case 7: stringResult.append("7")
-            case 8: stringResult.append("8")
-            case 9: stringResult.append("9")
-            default: fatalError()
-            }
-        }
-        
-        writer(stringResult)
+        let output = String(cString: Array(buffer.suffix(from: pos)))
+        writer(output)
     }
-    
-    private func serializeInt(value: Int) throws {
-        if value == 0 {
-            writer("0")
-            return
-        }
-        var array: [Int] = []
-        var stringResult = ""
-        array.reserveCapacity(maxIntLength)
-        //Account for a negative sign
-        stringResult.reserveCapacity(maxIntLength + 1)
-        var number = value
-        
-        while number != 0 {
-            array.append(number % 10)
-            number /= 10
-        }
-        //If negative add minus sign before adding any values
-        if value < 0 {
-            stringResult.append("-")
-        }
-        /*
-         Step backwards through the array and append the values to the string. This way the values are appended in the correct order.
-         */
-        var counter = array.count
-        while counter > 0 {
-            counter -= 1
-            let digit = array[counter]
-            switch digit {
-            case 0: stringResult.append("0")
-            case 1, -1: stringResult.append("1")
-            case 2, -2: stringResult.append("2")
-            case 3, -3: stringResult.append("3")
-            case 4, -4: stringResult.append("4")
-            case 5, -5: stringResult.append("5")
-            case 6, -6: stringResult.append("6")
-            case 7, -7: stringResult.append("7")
-            case 8, -8: stringResult.append("8")
-            case 9, -9: stringResult.append("9")
-            default: fatalError()
-            }
-        }
-        writer(stringResult)
+
+    private func serializeInteger<T: SignedInteger>(value: T) {
+        serializeInteger(value: UInt64(value.magnitude), isNegative: value < 0)
     }
-    
+
     func serializeString(_ str: String) throws {
         writer("\"")
         for scalar in str.unicodeScalars {
@@ -462,15 +435,30 @@
     }
 
     mutating func serializeNumber(_ num: NSNumber) throws {
-        if num.doubleValue.isInfinite || num.doubleValue.isNaN {
-            throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Number cannot be infinity or NaN"])
-        }
-        
-        switch num._cfTypeID {
-        case CFBooleanGetTypeID():
-            serializeBool(num.boolValue)
-        default:
-            writer(_serializationString(for: num))
+        if CFNumberIsFloatType(num._cfObject) {
+            let dv = num.doubleValue
+            if !dv.isFinite {
+                let value: String
+                if dv.isNaN {
+                    value = "NaN"
+                } else if dv.isInfinite {
+                    value = "infinite"
+                } else {
+                    value = String(dv)
+                }
+
+                throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Invalid number value (\(value)) in JSON write"])
+            }
+
+            let string = CFNumberFormatterCreateStringWithNumber(nil, _numberformatter, num._cfObject)._swiftObject
+            writer(string)
+        } else {
+            switch num._cfTypeID {
+            case CFBooleanGetTypeID():
+                serializeBool(num.boolValue)
+            default:
+                writer(num.stringValue)
+            }
         }
     }
 
@@ -578,13 +566,6 @@
         }
     }
 
-    //[SR-2151] https://bugs.swift.org/browse/SR-2151
-    private mutating func _serializationString(for number: NSNumber) -> String {
-        if !CFNumberIsFloatType(number._cfObject) {
-            return number.stringValue
-        }
-        return CFNumberFormatterCreateStringWithNumber(nil, _numberformatter, number._cfObject)._swiftObject
-    }
 }
 
 //MARK: - JSONDeserializer
diff --git a/TestFoundation/HTTPServer.swift b/TestFoundation/HTTPServer.swift
index 14823d5..f52b771 100644
--- a/TestFoundation/HTTPServer.swift
+++ b/TestFoundation/HTTPServer.swift
@@ -37,6 +37,12 @@
     static let EMPTY = ""
 }
 
+extension UInt16 {
+    public init(networkByteOrder input: UInt16) {
+        self.init(bigEndian: input)
+    }
+}
+
 class _TCPSocket {
   
     private var listenSocket: Int32!
@@ -57,12 +63,15 @@
         return r
     }
 
-    init(port: UInt16) throws {
+    public private(set) var port: UInt16
+
+    init(port: UInt16?) throws {
         #if os(Linux)
             let SOCKSTREAM = Int32(SOCK_STREAM.rawValue)
         #else
             let SOCKSTREAM = SOCK_STREAM
         #endif
+        self.port = port ?? 0
         listenSocket = try attempt("socket", valid: isNotNegative, socket(AF_INET, SOCKSTREAM, Int32(IPPROTO_TCP)))
         var on: Int = 1
         _ = try attempt("setsockopt", valid: isZero, setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &on, socklen_t(MemoryLayout<Int>.size)))
@@ -72,16 +81,26 @@
             let addr = UnsafePointer<sockaddr>($0)
             _ = try attempt("bind", valid: isZero, bind(listenSocket, addr, socklen_t(MemoryLayout<sockaddr>.size)))
         })
+
+        var actualSA = sockaddr_in()
+        withUnsafeMutablePointer(to: &actualSA) { ptr in
+            ptr.withMemoryRebound(to: sockaddr.self, capacity: 1) { (ptr: UnsafeMutablePointer<sockaddr>) in
+                var len = socklen_t(MemoryLayout<sockaddr>.size)
+                getsockname(listenSocket, ptr, &len)
+            }
+        }
+
+        self.port = UInt16(networkByteOrder: actualSA.sin_port)
     }
 
-    private func createSockaddr(_ port: UInt16) -> sockaddr_in {
+    private func createSockaddr(_ port: UInt16?) -> sockaddr_in {
         // Listen on the loopback address so that OSX doesnt pop up a dialog
         // asking to accept incoming connections if the firewall is enabled.
         let addr = UInt32(INADDR_LOOPBACK).bigEndian
         #if os(Linux)
-            return sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: htons(port), sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
+            return sockaddr_in(sin_family: sa_family_t(AF_INET), sin_port: htons(port ?? 0), sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
         #else
-            return sockaddr_in(sin_len: 0, sin_family: sa_family_t(AF_INET), sin_port: CFSwapInt16HostToBig(port), sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
+            return sockaddr_in(sin_len: 0, sin_family: sa_family_t(AF_INET), sin_port: CFSwapInt16HostToBig(port ?? 0), sin_addr: in_addr(s_addr: addr), sin_zero: (0,0,0,0,0,0,0,0))
         #endif
     }
 
@@ -135,20 +154,27 @@
     }
 
     func shutdown() {
-        close(connectionSocket)
+        if let connectionSocket = self.connectionSocket {
+            close(connectionSocket)
+        }
         close(listenSocket)
     }
 }
 
 class _HTTPServer {
 
-    let socket: _TCPSocket 
+    let socket: _TCPSocket
+    var port: UInt16 {
+        get {
+            return self.socket.port
+        }
+    }
     
-    init(port: UInt16) throws {
+    init(port: UInt16?) throws {
         socket = try _TCPSocket(port: port)
     }
 
-    public class func create(port: UInt16) throws -> _HTTPServer {
+    public class func create(port: UInt16?) throws -> _HTTPServer {
         return try _HTTPServer(port: port)
     }
 
@@ -161,7 +187,7 @@
     }
    
     public func request() throws -> _HTTPRequest {
-       return _HTTPRequest(request: try socket.readData()) 
+       return try _HTTPRequest(request: socket.readData())
     }
 
     public func respond(with response: _HTTPResponse, startDelay: TimeInterval? = nil, sendDelay: TimeInterval? = nil, bodyChunks: Int? = nil) throws {
@@ -309,8 +335,13 @@
     let startDelay: TimeInterval?
     let sendDelay: TimeInterval?
     let bodyChunks: Int?
+    var port: UInt16 {
+        get {
+            return self.httpServer.port
+        }
+    }
     
-    public init (port: UInt16, startDelay: TimeInterval? = nil, sendDelay: TimeInterval? = nil, bodyChunks: Int? = nil) throws {
+    public init (port: UInt16?, startDelay: TimeInterval? = nil, sendDelay: TimeInterval? = nil, bodyChunks: Int? = nil) throws {
         httpServer = try _HTTPServer.create(port: port)
         self.startDelay = startDelay
         self.sendDelay = sendDelay
@@ -406,23 +437,28 @@
 }
 
 class LoopbackServerTest : XCTestCase {
-    static var serverPort: Int = -1
+    private static let staticSyncQ = DispatchQueue(label: "org.swift.TestFoundation.HTTPServer.StaticSyncQ")
+
+    private static var _serverPort: Int = -1
+    static var serverPort: Int {
+        get {
+            return staticSyncQ.sync { _serverPort }
+        }
+        set {
+            staticSyncQ.sync { _serverPort = newValue }
+        }
+    }
 
     override class func setUp() {
         super.setUp()
         func runServer(with condition: ServerSemaphore, startDelay: TimeInterval? = nil, sendDelay: TimeInterval? = nil, bodyChunks: Int? = nil) throws {
-            let start = 21961
-            for port in start...(start+100) { //we must find at least one port to bind
-                do {
-                    serverPort = port
-                    let test = try TestURLSessionServer(port: UInt16(port), startDelay: startDelay, sendDelay: sendDelay, bodyChunks: bodyChunks)
-                    try test.start(started: condition)
-                    try test.readAndRespond()
-                    test.stop()
-                } catch let e as ServerError {
-                    if e.operation == "bind" { continue }
-                    throw e
-                }
+            while true {
+                let test = try TestURLSessionServer(port: nil, startDelay: startDelay, sendDelay: sendDelay, bodyChunks: bodyChunks)
+                serverPort = Int(test.port)
+                try test.start(started: condition)
+                try test.readAndRespond()
+                serverPort = -2
+                test.stop()
             }
         }
 
diff --git a/TestFoundation/TestHTTPCookieStorage.swift b/TestFoundation/TestHTTPCookieStorage.swift
index bea3391..472e34a 100644
--- a/TestFoundation/TestHTTPCookieStorage.swift
+++ b/TestFoundation/TestHTTPCookieStorage.swift
@@ -230,7 +230,7 @@
         let bundlePath = Bundle.main.bundlePath
         var bundleName = "/" + bundlePath.components(separatedBy: "/").last!
         if let range = bundleName.range(of: ".", options: String.CompareOptions.backwards, range: nil, locale: nil) {
-            bundleName = bundleName.substring(to: range.lowerBound)
+            bundleName = String(bundleName[..<range.lowerBound])
         }
         if let xdg_data_home = getenv("XDG_DATA_HOME") {
             destPath = String(utf8String: xdg_data_home)! + bundleName + "/.cookies.shared"
@@ -251,7 +251,7 @@
         let exeName = "/xdgTestHelper/xdgTestHelper"
         #endif
 
-        task.launchPath = bundlePath.substring(to: pathIndex!) + exeName
+        task.launchPath = bundlePath[..<pathIndex!] + exeName
         var environment = ProcessInfo.processInfo.environment
         let testPath = NSHomeDirectory() + "/TestXDG"
         environment["XDG_DATA_HOME"] = testPath
diff --git a/TestFoundation/TestJSONEncoder.swift b/TestFoundation/TestJSONEncoder.swift
index 6444296..842eb52 100644
--- a/TestFoundation/TestJSONEncoder.swift
+++ b/TestFoundation/TestJSONEncoder.swift
@@ -405,23 +405,13 @@
     // UInt and Int
     func test_codingOfUIntMinMax() {
 
-        let encoder = JSONEncoder()
-
         struct MyValue: Codable {
-            let intMin:Int = Int.min
-            let intMax:Int = Int.max
-            let uintMin:UInt = UInt.min
-            let uintMax:UInt = UInt.max
+            let int64Min = Int64.min
+            let int64Max = Int64.max
+            let uint64Min = UInt64.min
+            let uint64Max = UInt64.max
         }
 
-        let myValue = MyValue()
-        let myDictI: [String:Any] = ["intMin": myValue.intMin, "intMax": myValue.intMax]
-        let myDictU: [String:Any] = ["uintMin": myValue.uintMin, "uintMax": myValue.uintMax]
-        let myDict1: [String:Any] = ["intMin": myValue.intMin]
-        let myDict2: [String:Any] = ["intMax": myValue.intMax]
-        let myDict3: [String:Any] = ["uintMin": myValue.uintMin]
-        let myDict4: [String:Any] = ["uintMax": myValue.uintMax]
-
         func compareJSON(_ s1: String, _ s2: String) {
             let ss1 = s1.trimmingCharacters(in: CharacterSet(charactersIn: "{}")).split(separator: Character(",")).sorted()
             let ss2 = s2.trimmingCharacters(in: CharacterSet(charactersIn: "{}")).split(separator: Character(",")).sorted()
@@ -429,40 +419,16 @@
         }
 
         do {
+            let encoder = JSONEncoder()
+            let myValue = MyValue()
             let result = try encoder.encode(myValue)
             let r = String(data: result, encoding: .utf8) ?? "nil"
-            compareJSON(r, "{\"uintMin\":0,\"uintMax\":18446744073709551615,\"intMin\":-9223372036854775808,\"intMax\":9223372036854775807}")
-
-            let resultI = try JSONSerialization.data(withJSONObject: myDictI)
-            let rI = String(data: resultI, encoding: .utf8) ?? "nil"
-            compareJSON(rI, "{\"intMin\":-9223372036854775808,\"intMax\":9223372036854775807}")
-
-            let resultU = try JSONSerialization.data(withJSONObject: myDictU)
-            let rU = String(data: resultU, encoding: .utf8) ?? "nil"
-            compareJSON(rU, "{\"uintMax\":18446744073709551615,\"uintMin\":0}")
-
-            let result1 = try JSONSerialization.data(withJSONObject: myDict1)
-            let r1 = String(data: result1, encoding: .utf8) ?? "nil"
-            XCTAssertEqual(r1, "{\"intMin\":-9223372036854775808}")
-
-            let result2 = try JSONSerialization.data(withJSONObject: myDict2)
-            let r2 = String(data: result2, encoding: .utf8) ?? "nil"
-            XCTAssertEqual(r2, "{\"intMax\":9223372036854775807}")
-
-            let result3 = try JSONSerialization.data(withJSONObject: myDict3)
-            let r3 = String(data: result3, encoding: .utf8) ?? "nil"
-            XCTAssertEqual(r3, "{\"uintMin\":0}")
-
-            let result4 = try JSONSerialization.data(withJSONObject: myDict4)
-            let r4 = String(data: result4, encoding: .utf8) ?? "nil"
-            XCTAssertEqual(r4, "{\"uintMax\":18446744073709551615}")
+            compareJSON(r, "{\"uint64Min\":0,\"uint64Max\":18446744073709551615,\"int64Min\":-9223372036854775808,\"int64Max\":9223372036854775807}")
         } catch {
             XCTFail(String(describing: error))
         }
     }
 
-
-
     // MARK: - Helper Functions
     private var _jsonEmptyDictionary: Data {
         return "{}".data(using: .utf8)!
diff --git a/TestFoundation/TestJSONSerialization.swift b/TestFoundation/TestJSONSerialization.swift
index 61e23c1..a07eba4 100644
--- a/TestFoundation/TestJSONSerialization.swift
+++ b/TestFoundation/TestJSONSerialization.swift
@@ -829,6 +829,7 @@
         return [
             ("test_isValidJSONObjectTrue", test_isValidJSONObjectTrue),
             ("test_isValidJSONObjectFalse", test_isValidJSONObjectFalse),
+            ("test_validNumericJSONObjects", test_validNumericJSONObjects)
         ]
     }
 
@@ -924,6 +925,36 @@
         }
     }
 
+    func test_validNumericJSONObjects() {
+        // All of the numeric types supported by JSONSerialization
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([nil, NSNull()]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([true, false]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([Int.min, Int8.min, Int16.min, Int32.min, Int64.min]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([UInt.min, UInt8.min, UInt16.min, UInt32.min, UInt64.min]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([Float.leastNonzeroMagnitude, Double.leastNonzeroMagnitude]))
+
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([NSNumber(value: true), NSNumber(value: Float.greatestFiniteMagnitude), NSNumber(value: Double.greatestFiniteMagnitude)]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([NSNumber(value: Int.max), NSNumber(value: Int8.max), NSNumber(value: Int16.max), NSNumber(value: Int32.max), NSNumber(value: Int64.max)]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([NSNumber(value: UInt.max), NSNumber(value: UInt8.max), NSNumber(value: UInt16.max), NSNumber(value: UInt32.max), NSNumber(value: UInt64.max)]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([NSDecimalNumber(booleanLiteral: true), NSDecimalNumber(decimal: Decimal.greatestFiniteMagnitude), NSDecimalNumber(floatLiteral: Double.greatestFiniteMagnitude), NSDecimalNumber(integerLiteral: Int.min)]))
+        XCTAssertTrue(JSONSerialization.isValidJSONObject([Decimal(123), Decimal(Double.leastNonzeroMagnitude)]))
+
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(Float.nan))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(Float.infinity))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(-Float.infinity))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: Float.nan)))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: Float.infinity)))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: -Float.infinity)))
+
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(Double.nan))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(Double.infinity))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(-Double.infinity))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: Double.nan)))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: Double.infinity)))
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSNumber(value: -Double.infinity)))
+
+        XCTAssertFalse(JSONSerialization.isValidJSONObject(NSDecimalNumber(decimal: Decimal(floatLiteral: Double.nan))))
+    }
 }
 
 // MARK: - serializationTests
@@ -941,6 +972,14 @@
             ("test_serialize_IntMin", test_serialize_IntMin),
             ("test_serialize_UIntMax", test_serialize_UIntMax),
             ("test_serialize_UIntMin", test_serialize_UIntMin),
+            ("test_serialize_8BitSizes", test_serialize_8BitSizes),
+            ("test_serialize_16BitSizes", test_serialize_16BitSizes),
+            ("test_serialize_32BitSizes", test_serialize_32BitSizes),
+            ("test_serialize_64BitSizes", test_serialize_64BitSizes),
+            ("test_serialize_Float", test_serialize_Float),
+            ("test_serialize_Double", test_serialize_Double),
+            ("test_serialize_Decimal", test_serialize_Decimal),
+            ("test_serialize_NSDecimalNumber", test_serialize_NSDecimalNumber),
             ("test_serialize_stringEscaping", test_serialize_stringEscaping),
             ("test_jsonReadingOffTheEndOfBuffers", test_jsonReadingOffTheEndOfBuffers),
             ("test_jsonObjectToOutputStreamBuffer", test_jsonObjectToOutputStreamBuffer),
@@ -1172,7 +1211,80 @@
         let json: [Any] = [UInt.min]
         XCTAssertEqual(try trySerialize(json), "[\(UInt.min)]")
     }
-    
+
+    func test_serialize_8BitSizes() {
+        let json1 = [Int8.min, Int8(-1), Int8(0), Int8(1), Int8.max]
+        XCTAssertEqual(try trySerialize(json1), "[-128,-1,0,1,127]")
+        let json2 = [UInt8.min, UInt8(0), UInt8(1), UInt8.max]
+        XCTAssertEqual(try trySerialize(json2), "[0,0,1,255]")
+    }
+
+    func test_serialize_16BitSizes() {
+        let json1 = [Int16.min, Int16(-1), Int16(0), Int16(1), Int16.max]
+        XCTAssertEqual(try trySerialize(json1), "[-32768,-1,0,1,32767]")
+        let json2 = [UInt16.min, UInt16(0), UInt16(1), UInt16.max]
+        XCTAssertEqual(try trySerialize(json2), "[0,0,1,65535]")
+    }
+
+    func test_serialize_32BitSizes() {
+        let json1 = [Int32.min, Int32(-1), Int32(0), Int32(1), Int32.max]
+        XCTAssertEqual(try trySerialize(json1), "[-2147483648,-1,0,1,2147483647]")
+        let json2 = [UInt32.min, UInt32(0), UInt32(1), UInt32.max]
+        XCTAssertEqual(try trySerialize(json2), "[0,0,1,4294967295]")
+    }
+
+    func test_serialize_64BitSizes() {
+        let json1 = [Int64.min, Int64(-1), Int64(0), Int64(1), Int64.max]
+        XCTAssertEqual(try trySerialize(json1), "[-9223372036854775808,-1,0,1,9223372036854775807]")
+        let json2 = [UInt64.min, UInt64(0), UInt64(1), UInt64.max]
+        XCTAssertEqual(try trySerialize(json2), "[0,0,1,18446744073709551615]")
+    }
+
+    func test_serialize_Float() {
+        XCTAssertEqual(try trySerialize([-Float.leastNonzeroMagnitude, Float.leastNonzeroMagnitude]), "[-0,0]")
+        XCTAssertEqual(try trySerialize([-Float.greatestFiniteMagnitude]), "[-340282346638529000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Float.greatestFiniteMagnitude]), "[340282346638529000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Float(-1), Float.leastNonzeroMagnitude, Float(1)]), "[-1,0,1]")
+    }
+
+    func test_serialize_Double() {
+        XCTAssertEqual(try trySerialize([-Double.leastNonzeroMagnitude, Double.leastNonzeroMagnitude]), "[-0,0]")
+        XCTAssertEqual(try trySerialize([-Double.leastNormalMagnitude, Double.leastNormalMagnitude]), "[-0,0]")
+        XCTAssertEqual(try trySerialize([-Double.greatestFiniteMagnitude]), "[-179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Double.greatestFiniteMagnitude]), "[179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Double(-1.0),  Double(1.0)]), "[-1,1]")
+    }
+
+    func test_serialize_Decimal() {
+        XCTAssertEqual(try trySerialize([-Decimal.leastFiniteMagnitude]), "[3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Decimal.leastFiniteMagnitude]), "[-3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([-Decimal.leastNonzeroMagnitude]), "[-0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]")
+        XCTAssertEqual(try trySerialize([Decimal.leastNonzeroMagnitude]), "[0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001]")
+        XCTAssertEqual(try trySerialize([-Decimal.greatestFiniteMagnitude]), "[-3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Decimal.greatestFiniteMagnitude]), "[3402823669209384634633746074317682114550000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([Decimal(Int8.min), Decimal(Int8(0)), Decimal(Int8.max)]), "[-128,0,127]")
+        XCTAssertEqual(try trySerialize([Decimal(string: "-0.0"), Decimal(string: "0.000"), Decimal(string: "1.0000")]), "[0,0,1]")
+    }
+
+    func test_serialize_NSDecimalNumber() {
+        let dn0: [Any] = [NSDecimalNumber(floatLiteral: -Double.leastNonzeroMagnitude)]
+        let dn1: [Any] = [NSDecimalNumber(floatLiteral: Double.leastNonzeroMagnitude)]
+        let dn2: [Any] = [NSDecimalNumber(floatLiteral: -Double.leastNormalMagnitude)]
+        let dn3: [Any] = [NSDecimalNumber(floatLiteral: Double.leastNormalMagnitude)]
+        let dn4: [Any] = [NSDecimalNumber(floatLiteral: -Double.greatestFiniteMagnitude)]
+        let dn5: [Any] = [NSDecimalNumber(floatLiteral: Double.greatestFiniteMagnitude)]
+
+        XCTAssertEqual(try trySerialize(dn0), "[-0.00000000000000000000000000000000000000000000000000000000000000000004940656458412464128]")
+        XCTAssertEqual(try trySerialize(dn1), "[0.00000000000000000000000000000000000000000000000000000000000000000004940656458412464128]")
+        XCTAssertEqual(try trySerialize(dn2), "[-0.0000000000000000000000000000000000000000000000000002225073858507201792]")
+        XCTAssertEqual(try trySerialize(dn3), "[0.0000000000000000000000000000000000000000000000000002225073858507201792]")
+        XCTAssertEqual(try trySerialize(dn4), "[-17976931348623167488000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize(dn5), "[17976931348623167488000000000000000000000000000000000]")
+        XCTAssertEqual(try trySerialize([NSDecimalNumber(string: "0.0001"), NSDecimalNumber(string: "0.00"), NSDecimalNumber(string: "-0.0")]), "[0.0001,0,0]")
+        XCTAssertEqual(try trySerialize([NSDecimalNumber(integerLiteral: Int(Int16.min)), NSDecimalNumber(integerLiteral: 0), NSDecimalNumber(integerLiteral: Int(Int16.max))]), "[-32768,0,32767]")
+        XCTAssertEqual(try trySerialize([NSDecimalNumber(booleanLiteral: true), NSDecimalNumber(booleanLiteral: false)]), "[1,0]")
+    }
+
     func test_serialize_stringEscaping() {
         var json = ["foo"]
         XCTAssertEqual(try trySerialize(json), "[\"foo\"]")
diff --git a/TestFoundation/TestOperationQueue.swift b/TestFoundation/TestOperationQueue.swift
index f60f17b..02f95c4 100644
--- a/TestFoundation/TestOperationQueue.swift
+++ b/TestFoundation/TestOperationQueue.swift
@@ -175,12 +175,17 @@
 
     override internal(set) var isExecuting: Bool {
         get {
-            return _executing
+            lock.lock()
+            let wasExecuting = _executing
+            lock.unlock()
+            return wasExecuting
         }
         set {
-            if _executing != newValue {
+            if isExecuting != newValue {
                 willChangeValue(forKey: "isExecuting")
+                lock.lock()
                 _executing = newValue
+                lock.unlock()
                 didChangeValue(forKey: "isExecuting")
             }
         }
@@ -188,12 +193,17 @@
 
     override internal(set) var isFinished: Bool {
         get {
-            return _finished
+            lock.lock()
+            let wasFinished = _finished
+            lock.unlock()
+            return wasFinished
         }
         set {
-            if _finished != newValue {
+            if isFinished != newValue {
                 willChangeValue(forKey: "isFinished")
+                lock.lock()
                 _finished = newValue
+                lock.unlock()
                 didChangeValue(forKey: "isFinished")
             }
         }
@@ -213,10 +223,8 @@
 
         queue.async {
             sleep(1)
-            self.lock.lock()
             self.isExecuting = false
             self.isFinished = true
-            self.lock.unlock()
         }
     }
 
diff --git a/TestFoundation/TestProcess.swift b/TestFoundation/TestProcess.swift
index 163dc31..922c607 100644
--- a/TestFoundation/TestProcess.swift
+++ b/TestFoundation/TestProcess.swift
@@ -334,7 +334,7 @@
         guard let range = line.range(of: "=") else {
             throw Error.InvalidEnvironmentVariable(line)
         }
-        result[line.substring(to: range.lowerBound)] = line.substring(from: range.upperBound)
+        result[String(line[..<range.lowerBound])] = String(line[range.upperBound...])
     }
     return result
 }
diff --git a/TestFoundation/TestURLSession.swift b/TestFoundation/TestURLSession.swift
index 68339fc..c941f1c 100644
--- a/TestFoundation/TestURLSession.swift
+++ b/TestFoundation/TestURLSession.swift
@@ -36,7 +36,7 @@
             ("test_verifyHttpAdditionalHeaders", test_verifyHttpAdditionalHeaders),
             ("test_timeoutInterval", test_timeoutInterval),
             ("test_httpRedirection", test_httpRedirection),
-            ("test_httpRedirectionTimeout", test_httpRedirectionTimeout),
+            //("test_httpRedirectionTimeout", test_httpRedirectionTimeout), /* temporarily disabled (https://bugs.swift.org/browse/SR-5751) */
             ("test_http0_9SimpleResponses", test_http0_9SimpleResponses),
             ("test_outOfRangeButCorrectlyFormattedHTTPCode", test_outOfRangeButCorrectlyFormattedHTTPCode),
             ("test_missingContentLengthButStillABody", test_missingContentLengthButStillABody),
@@ -313,6 +313,8 @@
         waitForExpectations(timeout: 12)
     }
 
+    /*
+     // temporarily disabled (https://bugs.swift.org/browse/SR-5751)
     func test_httpRedirectionTimeout() {
         let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/UnitedStates"
         var req = URLRequest(url: URL(string: urlString)!)
@@ -325,11 +327,14 @@
             if let e = error as? URLError {
                 XCTAssertEqual(e.code, .timedOut, "Unexpected error code")
                 return
+            } else {
+                XCTFail("test unexpectedly succeeded (response=\(response.debugDescription))")
             }
         }
         task.resume()
         waitForExpectations(timeout: 12)
     }
+    */
 
     func test_http0_9SimpleResponses() {
         for brokenCity in ["Pompeii", "Sodom"] {
diff --git a/TestFoundation/TestXMLParser.swift b/TestFoundation/TestXMLParser.swift
index 84e5782..b08f0b3 100644
--- a/TestFoundation/TestXMLParser.swift
+++ b/TestFoundation/TestXMLParser.swift
@@ -86,10 +86,10 @@
             return xmlUnderTest
         }
         if let open = encoding.range(of: "(") {
-            encoding = encoding.substring(from: open.upperBound)
+            encoding = String(encoding[open.upperBound...])
         }
         if let close = encoding.range(of: ")") {
-            encoding = encoding.substring(to: close.lowerBound)
+            encoding = String(encoding[..<close.lowerBound])
         }
         return "<?xml version='1.0' encoding='\(encoding.uppercased())' standalone='no'?>\n\(xmlUnderTest)\n"
     }