Merge pull request #1279 from spevans/pr_thread_name

diff --git a/Foundation/Data.swift b/Foundation/Data.swift
index 99bb93f..0102662 100644
--- a/Foundation/Data.swift
+++ b/Foundation/Data.swift
@@ -38,6 +38,22 @@
 import _SwiftFoundationOverlayShims
 import _SwiftCoreFoundationOverlayShims
     
+internal func __NSDataIsCompact(_ data: NSData) -> Bool {
+    if #available(OSX 10.10, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
+        return data._isCompact()
+    } else {
+        var compact = true
+        let len = data.length
+        data.enumerateBytes { (_, byteRange, stop) in
+            if byteRange.length != len {
+                compact = false
+            }
+            stop.pointee = true
+        }
+        return compact
+    }
+}
+
 @_silgen_name("__NSDataWriteToURL")
 internal func __NSDataWriteToURL(_ data: NSData, _ url: NSURL, _ options: UInt, _ error: NSErrorPointer) -> Bool
     
@@ -130,7 +146,7 @@
         case .mutable:
             return try apply(UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.count, _length)))
         case .customReference(let d):
-            if d._isCompact() {
+            if __NSDataIsCompact(d) {
                 let len = d.length
                 guard len > 0 else {
                     return try apply(UnsafeRawBufferPointer(start: nil, count: 0))
@@ -161,7 +177,7 @@
                 return try apply(UnsafeRawBufferPointer(buffer))
             }
         case .customMutableReference(let d):
-            if d._isCompact() {
+            if __NSDataIsCompact(d) {
                 let len = d.length
                 guard len > 0 else {
                     return try apply(UnsafeRawBufferPointer(start: nil, count: 0))
@@ -505,7 +521,7 @@
         case .mutable:
             return _bytes!.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
         case .customReference(let d):
-            if d._isCompact() {
+            if __NSDataIsCompact(d) {
                 return d.bytes.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
             } else {
                 var byte: UInt8 = 0
@@ -519,7 +535,7 @@
                 return byte
             }
         case .customMutableReference(let d):
-            if d._isCompact() {
+            if __NSDataIsCompact(d) {
                 return d.bytes.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
             } else {
                 var byte: UInt8 = 0
@@ -1626,9 +1642,11 @@
     public var hashValue: Int {
         var hashValue = 0
         let hashRange: Range<Int> = _sliceRange.lowerBound..<Swift.min(_sliceRange.lowerBound + 80, _sliceRange.upperBound)
-        _withStackOrHeapBuffer(hashRange.count) { buffer in
-            _backing.withUnsafeBytes(in: hashRange) {
-                memcpy(buffer.pointee.memory, $0.baseAddress!, hashRange.count)
+        _withStackOrHeapBuffer(hashRange.count + 1) { buffer in
+            if hashRange.count > 0 {
+                _backing.withUnsafeBytes(in: hashRange) {
+                    memcpy(buffer.pointee.memory, $0.baseAddress!, hashRange.count)
+                }
             }
             hashValue = Int(bitPattern: CFHashBytes(buffer.pointee.memory.assumingMemoryBound(to: UInt8.self), hashRange.count))
         }
diff --git a/Foundation/DateInterval.swift b/Foundation/DateInterval.swift
index 3a5d36a..0d22b7a 100644
--- a/Foundation/DateInterval.swift
+++ b/Foundation/DateInterval.swift
@@ -52,10 +52,7 @@
     ///
     /// - precondition: `end >= start`
     public init(start: Date, end: Date) {
-        if end < start {
-            fatalError("Reverse intervals are not allowed")
-        }
-        
+        precondition(end >= start, "Reverse intervals are not allowed")
         self.start = start
         duration = end.timeIntervalSince(start)
     }
diff --git a/Foundation/NSAttributedString.swift b/Foundation/NSAttributedString.swift
index 3877813..de1464b 100644
--- a/Foundation/NSAttributedString.swift
+++ b/Foundation/NSAttributedString.swift
@@ -9,6 +9,22 @@
 
 import CoreFoundation
 
+public struct NSAttributedStringKey : RawRepresentable, Equatable, Hashable {
+    public let rawValue: String
+
+    public init(_ rawValue: String) {
+        self.rawValue = rawValue
+    }
+
+    public init(rawValue: String) {
+        self.rawValue = rawValue
+    }
+
+    public var hashValue: Int {
+        return rawValue.hashValue
+    }
+}
+
 open class NSAttributedString: NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
     
     private let _cfinfo = _CFInfo(typeID: CFAttributedStringGetTypeID())
@@ -42,12 +58,14 @@
     open func mutableCopy(with zone: NSZone? = nil) -> Any {
         NSUnimplemented()
     }
-    
+
+    /// The character contents of the receiver as an NSString object.
     open var string: String {
         return _string._swiftObject
     }
-    
-    open func attributes(at location: Int, effectiveRange range: NSRangePointer) -> [String : Any] {
+
+    /// Returns the attributes for the character at a given index.
+    open func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedStringKey : Any] {
         let rangeInfo = RangeInfo(
             rangePointer: range,
             shouldFetchLongestEffectiveRange: false,
@@ -55,60 +73,72 @@
         return _attributes(at: location, rangeInfo: rangeInfo)
     }
 
+    /// The length of the receiver’s string object.
     open var length: Int {
         return CFAttributedStringGetLength(_cfObject)
     }
-    
-    open func attribute(_ attrName: String, at location: Int, effectiveRange range: NSRangePointer?) -> Any? {
+
+    /// Returns the value for an attribute with a given name of the character at a given index, and by reference the range over which the attribute applies.
+    open func attribute(_ attrName: NSAttributedStringKey, at location: Int, effectiveRange range: NSRangePointer?) -> Any? {
         let rangeInfo = RangeInfo(
             rangePointer: range,
             shouldFetchLongestEffectiveRange: false,
             longestEffectiveRangeSearchRange: nil)
         return _attribute(attrName, atIndex: location, rangeInfo: rangeInfo)
     }
-    
+
+    /// Returns an NSAttributedString object consisting of the characters and attributes within a given range in the receiver.
     open func attributedSubstring(from range: NSRange) -> NSAttributedString { NSUnimplemented() }
-    
-    open func attributes(at location: Int, longestEffectiveRange range: NSRangePointer?, in rangeLimit: NSRange) -> [String : Any] {
+
+    /// Returns the attributes for the character at a given index, and by reference the range over which the attributes apply.
+    open func attributes(at location: Int, longestEffectiveRange range: NSRangePointer?, in rangeLimit: NSRange) -> [NSAttributedStringKey : Any] {
         let rangeInfo = RangeInfo(
             rangePointer: range,
             shouldFetchLongestEffectiveRange: true,
             longestEffectiveRangeSearchRange: rangeLimit)
         return _attributes(at: location, rangeInfo: rangeInfo)
     }
-    
-    open func attribute(_ attrName: String, at location: Int, longestEffectiveRange range: NSRangePointer?, in rangeLimit: NSRange) -> Any? {
+
+    /// Returns the value for the attribute with a given name of the character at a given index, and by reference the range over which the attribute applies.
+    open func attribute(_ attrName: NSAttributedStringKey, at location: Int, longestEffectiveRange range: NSRangePointer?, in rangeLimit: NSRange) -> Any? {
         let rangeInfo = RangeInfo(
             rangePointer: range,
             shouldFetchLongestEffectiveRange: true,
             longestEffectiveRangeSearchRange: rangeLimit)
         return _attribute(attrName, atIndex: location, rangeInfo: rangeInfo)
     }
-    
+
+    /// Returns a Boolean value that indicates whether the receiver is equal to another given attributed string.
     open func isEqual(to other: NSAttributedString) -> Bool { NSUnimplemented() }
-    
-    public init(string str: String) {
-        _string = str._nsObject
+
+    /// Returns an NSAttributedString object initialized with the characters of a given string and no attribute information.
+    public init(string: String) {
+        _string = string._nsObject
         _attributeArray = CFRunArrayCreate(kCFAllocatorDefault)
         
         super.init()
         addAttributesToAttributeArray(attrs: nil)
     }
-    
-    public init(string str: String, attributes attrs: [String : Any]?) {
-        _string = str._nsObject
+
+    /// Returns an NSAttributedString object initialized with a given string and attributes.
+    public init(string: String, attributes attrs: [NSAttributedStringKey : Any]? = nil) {
+        _string = string._nsObject
         _attributeArray = CFRunArrayCreate(kCFAllocatorDefault)
-        
+
         super.init()
         addAttributesToAttributeArray(attrs: attrs)
     }
-    
-    public init(NSAttributedString attrStr: NSAttributedString) { NSUnimplemented() }
 
-    open func enumerateAttributes(in enumerationRange: NSRange, options opts: NSAttributedString.EnumerationOptions = [], using block: ([String : Any], NSRange, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
+    /// Returns an NSAttributedString object initialized with the characters and attributes of another given attributed string.
+    public init(attributedString: NSAttributedString) {
+        NSUnimplemented()
+    }
+
+    /// Executes the block for each attribute in the range.
+    open func enumerateAttributes(in enumerationRange: NSRange, options opts: NSAttributedString.EnumerationOptions = [], using block: ([NSAttributedStringKey : Any], NSRange, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
         _enumerate(in: enumerationRange, reversed: opts.contains(.reverse)) { currentIndex, stop in
             var attributesEffectiveRange = NSRange(location: NSNotFound, length: 0)
-            let attributesInRange: [String : Any]
+            let attributesInRange: [NSAttributedStringKey : Any]
             if opts.contains(.longestEffectiveRangeNotRequired) {
                 attributesInRange = attributes(at: currentIndex, effectiveRange: &attributesEffectiveRange)
             } else {
@@ -122,8 +152,9 @@
             return attributesEffectiveRange
         }
     }
-    
-    open func enumerateAttribute(_ attrName: String, in enumerationRange: NSRange, options opts: NSAttributedString.EnumerationOptions = [], using block: (Any?, NSRange, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
+
+    /// Executes the block for the specified attribute run in the specified range.
+    open func enumerateAttribute(_ attrName: NSAttributedStringKey, in enumerationRange: NSRange, options opts: NSAttributedString.EnumerationOptions = [], using block: (Any?, NSRange, UnsafeMutablePointer<ObjCBool>) -> Swift.Void) {
         _enumerate(in: enumerationRange, reversed: opts.contains(.reverse)) { currentIndex, stop in
             var attributeEffectiveRange = NSRange(location: NSNotFound, length: 0)
             let attributeInRange: Any?
@@ -183,9 +214,9 @@
         let longestEffectiveRangeSearchRange: NSRange?
     }
     
-    func _attributes(at location: Int, rangeInfo: RangeInfo) -> [String : Any] {
+    func _attributes(at location: Int, rangeInfo: RangeInfo) -> [NSAttributedStringKey : Any] {
         var cfRange = CFRange()
-        return withUnsafeMutablePointer(to: &cfRange) { (cfRangePointer: UnsafeMutablePointer<CFRange>) -> [String : Any] in
+        return withUnsafeMutablePointer(to: &cfRange) { (cfRangePointer: UnsafeMutablePointer<CFRange>) -> [NSAttributedStringKey : Any] in
             // Get attributes value using CoreFoundation function
             let value: CFDictionary
             if rangeInfo.shouldFetchLongestEffectiveRange, let searchRange = rangeInfo.longestEffectiveRangeSearchRange {
@@ -196,12 +227,12 @@
             
             // Convert the value to [String : AnyObject]
             let dictionary = unsafeBitCast(value, to: NSDictionary.self)
-            var results = [String : Any]()
+            var results = [NSAttributedStringKey : Any]()
             for (key, value) in dictionary {
                 guard let stringKey = (key as? NSString)?._swiftObject else {
                     continue
                 }
-                results[stringKey] = value
+                results[NSAttributedStringKey(stringKey)] = value
             }
             
             // Update effective range and return the results
@@ -211,15 +242,15 @@
         }
     }
     
-    func _attribute(_ attrName: String, atIndex location: Int, rangeInfo: RangeInfo) -> Any? {
+    func _attribute(_ attrName: NSAttributedStringKey, atIndex location: Int, rangeInfo: RangeInfo) -> Any? {
         var cfRange = CFRange()
         return withUnsafeMutablePointer(to: &cfRange) { (cfRangePointer: UnsafeMutablePointer<CFRange>) -> AnyObject? in
             // Get attribute value using CoreFoundation function
             let attribute: AnyObject?
             if rangeInfo.shouldFetchLongestEffectiveRange, let searchRange = rangeInfo.longestEffectiveRangeSearchRange {
-                attribute = CFAttributedStringGetAttributeAndLongestEffectiveRange(_cfObject, location, attrName._cfObject, CFRange(searchRange), cfRangePointer)
+                attribute = CFAttributedStringGetAttributeAndLongestEffectiveRange(_cfObject, location, attrName.rawValue._cfObject, CFRange(searchRange), cfRangePointer)
             } else {
-                attribute = CFAttributedStringGetAttribute(_cfObject, location, attrName._cfObject, cfRangePointer)
+                attribute = CFAttributedStringGetAttribute(_cfObject, location, attrName.rawValue._cfObject, cfRangePointer)
             }
             
             // Update effective range and return the result
@@ -241,18 +272,17 @@
         }
     }
     
-    func addAttributesToAttributeArray(attrs: [String : Any]?) {
+    func addAttributesToAttributeArray(attrs: [NSAttributedStringKey : Any]?) {
         guard _string.length > 0 else {
             return
         }
         
         let range = CFRange(location: 0, length: _string.length)
+        var attributes: [String : Any] = [:]
         if let attrs = attrs {
-            CFRunArrayInsert(_attributeArray, range, attrs._cfObject)
-        } else {
-            let emptyAttrs = [String : AnyObject]()
-            CFRunArrayInsert(_attributeArray, range, emptyAttrs._cfObject)
+            attrs.forEach { attributes[$0.rawValue] = $1 }
         }
+        CFRunArrayInsert(_attributeArray, range, attributes._cfObject)
     }
 }
 
@@ -277,19 +307,19 @@
 open class NSMutableAttributedString : NSAttributedString {
     
     open func replaceCharacters(in range: NSRange, with str: String) { NSUnimplemented() }
-    open func setAttributes(_ attrs: [String : Any]?, range: NSRange) { NSUnimplemented() }
+    open func setAttributes(_ attrs: [NSAttributedStringKey : Any]?, range: NSRange) { NSUnimplemented() }
     
     open var mutableString: NSMutableString {
         return _string as! NSMutableString
     }
-    
-    open func addAttribute(_ name: String, value: Any, range: NSRange) {
-        CFAttributedStringSetAttribute(_cfMutableObject, CFRange(range), name._cfObject, _SwiftValue.store(value))
+
+    open func addAttribute(_ name: NSAttributedStringKey, value: Any, range: NSRange) {
+        CFAttributedStringSetAttribute(_cfMutableObject, CFRange(range), name.rawValue._cfObject, _SwiftValue.store(value))
     }
+
+    open func addAttributes(_ attrs: [NSAttributedStringKey : Any], range: NSRange) { NSUnimplemented() }
     
-    open func addAttributes(_ attrs: [String : Any], range: NSRange) { NSUnimplemented() }
-    
-    open func removeAttribute(_ name: String, range: NSRange) { NSUnimplemented() }
+    open func removeAttribute(_ name: NSAttributedStringKey, range: NSRange) { NSUnimplemented() }
     
     open func replaceCharacters(in range: NSRange, with attrString: NSAttributedString) { NSUnimplemented() }
     open func insert(_ attrString: NSAttributedString, at loc: Int) { NSUnimplemented() }
diff --git a/Foundation/NSGeometry.swift b/Foundation/NSGeometry.swift
index 80c8d25..3420df6 100644
--- a/Foundation/NSGeometry.swift
+++ b/Foundation/NSGeometry.swift
@@ -237,11 +237,173 @@
                                         y: -CGFloat.greatestFiniteMagnitude / 2,
                                         width: CGFloat.greatestFiniteMagnitude,
                                         height: CGFloat.greatestFiniteMagnitude)
+
+    public var width: CGFloat { return abs(self.size.width) }
+    public var height: CGFloat { return abs(self.size.height) }
+
+    public var minX: CGFloat { return self.origin.x + min(self.size.width, 0) }
+    public var midX: CGFloat { return (self.minX + self.maxX) * 0.5 }
+    public var maxX: CGFloat { return self.origin.x + max(self.size.width, 0) }
+
+    public var minY: CGFloat { return self.origin.y + min(self.size.height, 0) }
+    public var midY: CGFloat { return (self.minY + self.maxY) * 0.5 }
+    public var maxY: CGFloat { return self.origin.y + max(self.size.height, 0) }
+
+    public var isEmpty: Bool { return self.isNull || self.size.width == 0 || self.size.height == 0 }
+    public var isInfinite: Bool { return self == .infinite }
+    public var isNull: Bool { return self.origin.x == .infinity || self.origin.y == .infinity }
+
+    public func contains(_ point: CGPoint) -> Bool {
+        if self.isNull || self.isEmpty { return false }
+
+        return (self.minX..<self.maxX).contains(point.x) && (self.minY..<self.maxY).contains(point.y)
+    }
+
+    public func contains(_ rect2: CGRect) -> Bool {
+        return self.union(rect2) == self
+    }
+
+    public var standardized: CGRect {
+        if self.isNull { return .null }
+
+        return CGRect(x: self.minX,
+                      y: self.minY,
+                      width: self.width,
+                      height: self.height)
+    }
+
+    public var integral: CGRect {
+        if self.isNull { return self }
+
+        let standardized = self.standardized
+        let x = standardized.origin.x.rounded(.down)
+        let y = standardized.origin.y.rounded(.down)
+        let width = (standardized.origin.x + standardized.size.width).rounded(.up) - x
+        let height = (standardized.origin.y + standardized.size.height).rounded(.up) - y
+        return CGRect(x: x, y: y, width: width, height: height)
+    }
+
+    public func insetBy(dx: CGFloat, dy: CGFloat) -> CGRect {
+        if self.isNull { return self }
+
+        var rect = self.standardized
+
+        rect.origin.x += dx
+        rect.origin.y += dy
+        rect.size.width -= 2 * dx
+        rect.size.height -= 2 * dy
+
+        if rect.size.width < 0 || rect.size.height < 0 {
+            return .null
+        }
+
+        return rect
+    }
+
+    public func union(_ r2: CGRect) -> CGRect {
+        if self.isNull {
+            return r2
+        }
+        else if r2.isNull {
+            return self
+        }
+
+        let rect1 = self.standardized
+        let rect2 = r2.standardized
+
+        let minX = min(rect1.minX, rect2.minX)
+        let minY = min(rect1.minY, rect2.minY)
+        let maxX = max(rect1.maxX, rect2.maxX)
+        let maxY = max(rect1.maxY, rect2.maxY)
+
+        return CGRect(x: minX,
+                      y: minY,
+                      width: maxX - minX,
+                      height: maxY - minY)
+    }
+
+    public func intersection(_ r2: CGRect) -> CGRect {
+        if self.isNull || r2.isNull { return .null }
+
+        let rect1 = self.standardized
+        let rect2 = r2.standardized
+
+        let rect1SpanH = rect1.minX...rect1.maxX
+        let rect1SpanV = rect1.minY...rect1.maxY
+
+        let rect2SpanH = rect2.minX...rect2.maxX
+        let rect2SpanV = rect2.minY...rect2.maxY
+
+        if !rect1SpanH.overlaps(rect2SpanH) || !rect1SpanV.overlaps(rect2SpanV) {
+            return .null
+        }
+
+        let overlapH = rect1SpanH.clamped(to: rect2SpanH)
+        let overlapV = rect1SpanV.clamped(to: rect2SpanV)
+
+        return CGRect(x: overlapH.lowerBound,
+                      y: overlapV.lowerBound,
+                      width: overlapH.upperBound - overlapH.lowerBound,
+                      height: overlapV.upperBound - overlapV.lowerBound)
+    }
+
+    public func intersects(_ r2: CGRect) -> Bool {
+        return !self.intersection(r2).isNull
+    }
+
+    public func offsetBy(dx: CGFloat, dy: CGFloat) -> CGRect {
+        if self.isNull { return self }
+
+        var rect = self.standardized
+        rect.origin.x += dx
+        rect.origin.y += dy
+        return rect
+    }
+
+    public func divided(atDistance: CGFloat, from fromEdge: CGRectEdge) -> (slice: CGRect, remainder: CGRect) {
+        if self.isNull { return (.null, .null) }
+
+        let splitLocation: CGFloat
+        switch fromEdge {
+        case .minXEdge: splitLocation = min(max(atDistance, 0), self.width)
+        case .maxXEdge: splitLocation = min(max(self.width - atDistance, 0), self.width)
+        case .minYEdge: splitLocation = min(max(atDistance, 0), self.height)
+        case .maxYEdge: splitLocation = min(max(self.height - atDistance, 0), self.height)
+        }
+
+        let rect = self.standardized
+        var rect1 = rect
+        var rect2 = rect
+
+        switch fromEdge {
+        case .minXEdge: fallthrough
+        case .maxXEdge:
+            rect1.size.width = splitLocation
+            rect2.origin.x = rect1.maxX
+            rect2.size.width = rect.width - splitLocation
+        case .minYEdge: fallthrough
+        case .maxYEdge:
+            rect1.size.height = splitLocation
+            rect2.origin.y = rect1.maxY
+            rect2.size.height = rect.height - splitLocation
+        }
+
+        switch fromEdge {
+        case .minXEdge: fallthrough
+        case .minYEdge: return (rect1, rect2)
+        case .maxXEdge: fallthrough
+        case .maxYEdge: return (rect2, rect1)
+        }
+    }
 }
 
 extension CGRect: Equatable {
     public static func ==(lhs: CGRect, rhs: CGRect) -> Bool {
-        return lhs.origin == rhs.origin && lhs.size == rhs.size
+        if lhs.isNull && rhs.isNull { return true }
+
+        let r1 = lhs.standardized
+        let r2 = rhs.standardized
+        return r1.origin == r2.origin && r1.size == r2.size
     }
 }
 
diff --git a/Foundation/NSLocale.swift b/Foundation/NSLocale.swift
index 4b1b44f..f6ba25a 100644
--- a/Foundation/NSLocale.swift
+++ b/Foundation/NSLocale.swift
@@ -50,6 +50,10 @@
         self.init(localeIdentifier: String._unconditionallyBridgeFromObjectiveC(identifier))
     }
     
+    deinit {
+        _CFDeinit(self)
+    }
+    
     open override func copy() -> Any {
         return copy(with: nil)
     }
diff --git a/Foundation/Unit.swift b/Foundation/Unit.swift
index f43e5ff..b27409c 100644
--- a/Foundation/Unit.swift
+++ b/Foundation/Unit.swift
@@ -1632,8 +1632,8 @@
         static let milliwatts = "mW"
         static let microwatts = "µW"
         static let nanowatts  = "nW"
-        static let picowatts  = "nW"
-        static let femtowatts = "nHz"
+        static let picowatts  = "pW"
+        static let femtowatts = "fW"
         static let horsepower = "hp"
     }
     
diff --git a/Foundation/UserDefaults.swift b/Foundation/UserDefaults.swift
index 42cbd0d..a1eba75 100644
--- a/Foundation/UserDefaults.swift
+++ b/Foundation/UserDefaults.swift
@@ -247,7 +247,7 @@
         set(NSNumber(value: value), forKey: defaultName)
     }
     open func set(_ url: URL?, forKey defaultName: String) {
-		if let url = url {
+        if let url = url {
             //FIXME: CFURLIsFileReferenceURL is limited to OS X/iOS
             #if os(OSX) || os(iOS)
                 //FIXME: no SwiftFoundation version of CFURLIsFileReferenceURL at time of writing!
diff --git a/TestFoundation/TestNSAttributedString.swift b/TestFoundation/TestNSAttributedString.swift
index a1f2a35..5b08922 100644
--- a/TestFoundation/TestNSAttributedString.swift
+++ b/TestFoundation/TestNSAttributedString.swift
@@ -18,7 +18,6 @@
 #endif
 
 
-
 class TestNSAttributedString : XCTestCase {
     
     static var allTests: [(String, (TestNSAttributedString) -> () throws -> Void)] {
@@ -30,7 +29,7 @@
             ("test_enumerateAttributes", test_enumerateAttributes),
         ]
     }
-    
+
     func test_initWithString() {
         let string = "Lorem 😀 ipsum dolor sit amet, consectetur adipiscing elit. ⌘ Phasellus consectetur et sem vitae consectetur. Nam venenatis lectus a laoreet blandit. ಠ_ರೃ"
         let attrString = NSAttributedString(string: string)
@@ -43,7 +42,7 @@
         XCTAssertEqual(range.length, string.utf16.count)
         XCTAssertEqual(attrs.count, 0)
 
-        let attribute = attrString.attribute("invalid", at: 0, effectiveRange: &range)
+        let attribute = attrString.attribute(NSAttributedStringKey("invalid"), at: 0, effectiveRange: &range)
         XCTAssertNil(attribute)
         XCTAssertEqual(range.location, 0)
         XCTAssertEqual(range.length, string.utf16.count)
@@ -51,7 +50,7 @@
     
     func test_initWithStringAndAttributes() {
         let string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur et sem vitae consectetur. Nam venenatis lectus a laoreet blandit."
-        let attributes: [String : AnyObject] = ["attribute.placeholder.key" : "attribute.placeholder.value" as NSString]
+        let attributes: [NSAttributedStringKey : AnyObject] = [NSAttributedStringKey("attribute.placeholder.key") : "attribute.placeholder.value" as NSString]
         
         let attrString = NSAttributedString(string: string, attributes: attributes)
         XCTAssertEqual(attrString.string, string)
@@ -59,7 +58,7 @@
         
         var range = NSRange()
         let attrs = attrString.attributes(at: 0, effectiveRange: &range)
-        guard let value = attrs["attribute.placeholder.key"] as? String else {
+        guard let value = attrs[NSAttributedStringKey("attribute.placeholder.key")] as? String else {
             XCTAssert(false, "attribute value not found")
             return
         }
@@ -67,16 +66,16 @@
         XCTAssertEqual(range.length, attrString.length)
         XCTAssertEqual(value, "attribute.placeholder.value")
 
-        let invalidAttribute = attrString.attribute("invalid", at: 0, effectiveRange: &range)
+        let invalidAttribute = attrString.attribute(NSAttributedStringKey("invalid"), at: 0, effectiveRange: &range)
         XCTAssertNil(invalidAttribute)
         XCTAssertEqual(range.location, 0)
         XCTAssertEqual(range.length, string.utf16.count)
 
-        let attribute = attrString.attribute("attribute.placeholder.key", at: 0, effectiveRange: &range)
+        let attribute = attrString.attribute(NSAttributedStringKey("attribute.placeholder.key"), at: 0, effectiveRange: &range)
         XCTAssertEqual(range.location, 0)
         XCTAssertEqual(range.length, attrString.length)
         guard let validAttribute = attribute as? NSString else {
-            XCTAssert(false, "attribuet not found")
+            XCTAssert(false, "attribute not found")
             return
         }
         XCTAssertEqual(validAttribute, "attribute.placeholder.value")
@@ -85,7 +84,7 @@
     func test_longestEffectiveRange() {
         let string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur et sem vitae consectetur. Nam venenatis lectus a laoreet blandit."
         
-        let attrKey = "attribute.placeholder.key"
+        let attrKey = NSAttributedStringKey("attribute.placeholder.key")
         let attrValue = "attribute.placeholder.value" as NSString
         
         let attrRange1 = NSRange(location: 0, length: 20)
@@ -110,12 +109,12 @@
     func test_enumerateAttributeWithName() {
         let string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur et sem vitae consectetur. Nam venenatis lectus a laoreet blandit."
         
-        let attrKey1 = "attribute.placeholder.key1"
+        let attrKey1 = NSAttributedStringKey("attribute.placeholder.key1")
         let attrValue1 = "attribute.placeholder.value1"
         let attrRange1 = NSRange(location: 0, length: 20)
         let attrRange2 = NSRange(location: 18, length: 10)
         
-        let attrKey3 = "attribute.placeholder.key3"
+        let attrKey3 = NSAttributedStringKey("attribute.placeholder.key3")
         let attrValue3 = "attribute.placeholder.value3"
         let attrRange3 = NSRange(location: 40, length: 5)
         
@@ -161,15 +160,15 @@
 #else
         let string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur et sem vitae consectetur. Nam venenatis lectus a laoreet blandit."
         
-        let attrKey1 = "attribute.placeholder.key1"
+        let attrKey1 = NSAttributedStringKey("attribute.placeholder.key1")
         let attrValue1 = "attribute.placeholder.value1"
         let attrRange1 = NSRange(location: 0, length: 20)
         
-        let attrKey2 = "attribute.placeholder.key2"
+        let attrKey2 = NSAttributedStringKey("attribute.placeholder.key2")
         let attrValue2 = "attribute.placeholder.value2"
         let attrRange2 = NSRange(location: 18, length: 10)
         
-        let attrKey3 = "attribute.placeholder.key3"
+        let attrKey3 = NSAttributedStringKey("attribute.placeholder.key3")
         let attrValue3 = "attribute.placeholder.value3"
         let attrRange3 = NSRange(location: 40, length: 5)
         
@@ -235,9 +234,9 @@
         }
     }
     
-    fileprivate func describe(attrs: [String : Any]) -> String {
+    fileprivate func describe(attrs: [NSAttributedStringKey : Any]) -> String {
         if attrs.count > 0 {
-            return "[" + attrs.map({ "\($0):\($1)" }).sorted(by: { $0 < $1 }).joined(separator: ",") + "]"
+            return "[" + attrs.map({ "\($0.rawValue):\($1)" }).sorted(by: { $0 < $1 }).joined(separator: ",") + "]"
         } else {
             return "[:]"
         }
diff --git a/TestFoundation/TestNSGeometry.swift b/TestFoundation/TestNSGeometry.swift
index 953bdd8..3c662f9 100644
--- a/TestFoundation/TestNSGeometry.swift
+++ b/TestFoundation/TestNSGeometry.swift
@@ -16,6 +16,28 @@
     import SwiftXCTest
 #endif
 
+private func assertEqual(_ rect: CGRect,
+                         x: CGFloat,
+                         y: CGFloat,
+                         width: CGFloat,
+                         height: CGFloat,
+                         accuracy: CGFloat? = nil,
+                         _ message: @autoclosure () -> String = "",
+                         file: StaticString = #file,
+                         line: UInt = #line) {
+
+    if let accuracy = accuracy {
+        XCTAssertEqual(rect.origin.x, x, accuracy: accuracy, message, file: file, line: line)
+        XCTAssertEqual(rect.origin.y, y, accuracy: accuracy, message, file: file, line: line)
+        XCTAssertEqual(rect.size.width, width, accuracy: accuracy, message, file: file, line: line)
+        XCTAssertEqual(rect.size.height, height, accuracy: accuracy, message, file: file, line: line)
+    } else {
+        XCTAssertEqual(rect.origin.x, x, message, file: file, line: line)
+        XCTAssertEqual(rect.origin.y, y, message, file: file, line: line)
+        XCTAssertEqual(rect.size.width, width, message, file: file, line: line)
+        XCTAssertEqual(rect.size.height, height, message, file: file, line: line)
+    }
+}
 
 class TestNSGeometry : XCTestCase {
 
@@ -32,6 +54,21 @@
             ("test_CGRect_BasicConstruction", test_CGRect_BasicConstruction),
             ("test_CGRect_ExtendedConstruction", test_CGRect_ExtendedConstruction),
             ("test_CGRect_SpecialValues", test_CGRect_SpecialValues),
+            ("test_CGRect_IsNull", test_CGRect_IsNull),
+            ("test_CGRect_IsInfinite", test_CGRect_IsInfinite),
+            ("test_CGRect_IsEmpty", test_CGRect_IsEmpty),
+            ("test_CGRect_Equatable", test_CGRect_Equatable),
+            ("test_CGRect_CalculatedGeometricProperties", test_CGRect_CalculatedGeometricProperties),
+            ("test_CGRect_Standardized", test_CGRect_Standardized),
+            ("test_CGRect_Integral", test_CGRect_Integral),
+            ("test_CGRect_ContainsPoint", test_CGRect_ContainsPoint),
+            ("test_CGRect_ContainsRect", test_CGRect_ContainsRect),
+            ("test_CGRect_Union", test_CGRect_Union),
+            ("test_CGRect_Intersection", test_CGRect_Intersection),
+            ("test_CGRect_Intersects", test_CGRect_Intersects),
+            ("test_CGRect_OffsetBy", test_CGRect_OffsetBy),
+            ("test_CGRect_Divide", test_CGRect_Divide),
+            ("test_CGRect_InsetBy", test_CGRect_InsetBy),
             ("test_NSEdgeInsets_BasicConstruction", test_NSEdgeInsets_BasicConstruction),
             ("test_NSEdgeInsetsEqual", test_NSEdgeInsetsEqual),
             ("test_NSMakePoint", test_NSMakePoint),
@@ -195,6 +232,674 @@
         XCTAssertEqual(r4.size.width, CGFloat(3))
         XCTAssertEqual(r4.size.height, CGFloat(4))
     }
+
+    func test_CGRect_IsNull() {
+        XCTAssertTrue(CGRect.null.isNull)
+        XCTAssertTrue(CGRect(x: CGFloat.infinity, y: CGFloat.infinity, width: 0, height: 0).isNull)
+        XCTAssertTrue(CGRect(x: CGFloat.infinity, y: CGFloat.infinity, width: 10, height: 10).isNull)
+        XCTAssertTrue(CGRect(x: CGFloat.infinity, y: CGFloat.infinity, width: -10, height: -10).isNull)
+        XCTAssertTrue(CGRect(x: CGFloat.infinity, y: 0, width: 0, height: 0).isNull)
+        XCTAssertTrue(CGRect(x: 0, y: CGFloat.infinity, width: 0, height: 0).isNull)
+        XCTAssertFalse(CGRect(x: 0, y: 0, width: 0, height: 0).isNull)
+    }
+
+    func test_CGRect_IsInfinite() {
+        XCTAssertTrue(CGRect.infinite.isInfinite)
+
+        XCTAssertFalse(CGRect(x: 0,
+                              y: CGRect.infinite.origin.y,
+                              width: CGRect.infinite.size.width,
+                              height: CGRect.infinite.size.height).isInfinite)
+
+        XCTAssertFalse(CGRect(x: CGRect.infinite.origin.x,
+                              y: 0,
+                              width: CGRect.infinite.size.width,
+                              height: CGRect.infinite.size.height).isInfinite)
+
+        XCTAssertFalse(CGRect(x: CGRect.infinite.origin.x,
+                              y: CGRect.infinite.origin.y,
+                              width: 0,
+                              height: CGRect.infinite.size.height).isInfinite)
+
+        XCTAssertFalse(CGRect(x: CGRect.infinite.origin.x,
+                              y: CGRect.infinite.origin.y,
+                              width: CGRect.infinite.size.width,
+                              height: 0).isInfinite)
+
+        XCTAssertFalse(CGRect(x: CGFloat.infinity,
+                              y: CGFloat.infinity,
+                              width: CGFloat.infinity,
+                              height: CGFloat.infinity).isInfinite)
+
+        XCTAssertFalse(CGRect.null.isInfinite)
+    }
+
+    func test_CGRect_IsEmpty() {
+        XCTAssertTrue(CGRect.zero.isEmpty)
+        XCTAssertTrue(CGRect.null.isEmpty)
+        XCTAssertTrue(CGRect(x: 10, y: 20, width: 30, height: 0).isEmpty)
+        XCTAssertTrue(CGRect(x: 10, y: 20, width: 0, height: 30).isEmpty)
+        XCTAssertTrue(CGRect(x: 10, y: 20, width: -30, height: 0).isEmpty)
+        XCTAssertTrue(CGRect(x: 10, y: 20, width: 0, height: -30).isEmpty)
+
+        var r1 = CGRect.null
+        r1.origin.x = 0
+        XCTAssertTrue(r1.isEmpty)
+
+        var r2 = CGRect.null
+        r2.origin.y = 0
+        XCTAssertTrue(r2.isEmpty)
+
+        var r3 = CGRect.null
+        r3.size.width = 20
+        XCTAssertTrue(r3.isEmpty)
+
+        var r4 = CGRect.null
+        r4.size.height = 20
+        XCTAssertTrue(r4.isEmpty)
+
+        var r5 = CGRect.null
+        r5.size.width = 20
+        r5.size.height = 20
+        XCTAssertTrue(r5.isEmpty)
+
+        XCTAssertFalse(CGRect.infinite.isEmpty)
+        XCTAssertFalse(CGRect.infinite.isEmpty)
+    }
+
+    func test_CGRect_Equatable() {
+        XCTAssertEqual(CGRect(x: 10, y: 20, width: 30, height: 40), CGRect(x: 10, y: 20, width: 30, height: 40))
+        XCTAssertEqual(CGRect(x: -10, y: -20, width: -30, height: -40), CGRect(x: -10, y: -20, width: -30, height: -40))
+        XCTAssertEqual(CGRect(x: -10, y: -20, width: 30, height: 40), CGRect(x: 20, y: 20, width: -30, height: -40))
+
+        XCTAssertNotEqual(CGRect(x: 10, y: 20, width: 30, height: 40), CGRect(x: 10, y: 20, width: 30, height: -40))
+        XCTAssertNotEqual(CGRect(x: 10, y: 20, width: 30, height: 40), CGRect(x: 10, y: 20, width: -30, height: 40))
+        XCTAssertNotEqual(CGRect(x: 10, y: 20, width: 30, height: 40), CGRect(x: 10, y: -20, width: 30, height: 40))
+        XCTAssertNotEqual(CGRect(x: 10, y: 20, width: 30, height: 40), CGRect(x: -10, y: 20, width: 30, height: 40))
+
+        XCTAssertEqual(CGRect.infinite, CGRect.infinite)
+        XCTAssertEqual(CGRect.null, CGRect.null)
+        XCTAssertNotEqual(CGRect.infinite, CGRect.null)
+
+        var r1 = CGRect.null
+        r1.size = CGSize(width: 20, height: 20)
+        XCTAssertEqual(r1, CGRect.null)
+
+        var r2 = CGRect.null
+        r2.origin.x = 20
+        XCTAssertEqual(r2, CGRect.null)
+
+        var r3 = CGRect.null
+        r3.origin.y = 20
+        XCTAssertEqual(r3, CGRect.null)
+
+        var r4 = CGRect.null
+        r4.origin = CGPoint(x: 10, y: 20)
+        XCTAssertNotEqual(r4, CGRect.null)
+    }
+
+    func test_CGRect_CalculatedGeometricProperties() {
+        let ε = CGFloat(0.00001)
+
+        let r1 = CGRect(x: 1.2, y: 3.4, width: 5.6, height: 7.8)
+        XCTAssertEqual(r1.width, 5.6, accuracy: ε)
+        XCTAssertEqual(r1.height, 7.8, accuracy: ε)
+
+        XCTAssertEqual(r1.minX, 1.2, accuracy: ε)
+        XCTAssertEqual(r1.midX, 4, accuracy: ε)
+        XCTAssertEqual(r1.maxX, 6.8, accuracy: ε)
+
+        XCTAssertEqual(r1.minY, 3.4, accuracy: ε)
+        XCTAssertEqual(r1.midY, 7.3, accuracy: ε)
+        XCTAssertEqual(r1.maxY, 11.2, accuracy: ε)
+
+        let r2 = CGRect(x: -1.2, y: -3.4, width: 5.6, height: 7.8)
+        XCTAssertEqual(r2.width, 5.6, accuracy: ε)
+        XCTAssertEqual(r2.height, 7.8, accuracy: ε)
+
+        XCTAssertEqual(r2.minX, -1.2, accuracy: ε)
+        XCTAssertEqual(r2.midX, 1.6, accuracy: ε)
+        XCTAssertEqual(r2.maxX, 4.4, accuracy: ε)
+
+        XCTAssertEqual(r2.minY, -3.4, accuracy: ε)
+        XCTAssertEqual(r2.midY, 0.5, accuracy: ε)
+        XCTAssertEqual(r2.maxY, 4.4, accuracy: ε)
+
+        let r3 = CGRect(x: 1.2, y: 3.4, width: -5.6, height: -7.8)
+        XCTAssertEqual(r3.width, 5.6, accuracy: ε)
+        XCTAssertEqual(r3.height, 7.8, accuracy: ε)
+
+        XCTAssertEqual(r3.minX, -4.4, accuracy: ε)
+        XCTAssertEqual(r3.midX, -1.6, accuracy: ε)
+        XCTAssertEqual(r3.maxX, 1.2, accuracy: ε)
+
+        XCTAssertEqual(r3.minY, -4.4, accuracy: ε)
+        XCTAssertEqual(r3.midY, -0.5, accuracy: ε)
+        XCTAssertEqual(r3.maxY, 3.4, accuracy: ε)
+
+        let r4 = CGRect(x: -1.2, y: -3.4, width: -5.6, height: -7.8)
+        XCTAssertEqual(r4.width, 5.6, accuracy: ε)
+        XCTAssertEqual(r4.height, 7.8, accuracy: ε)
+
+        XCTAssertEqual(r4.minX, -6.8, accuracy: ε)
+        XCTAssertEqual(r4.midX, -4.0, accuracy: ε)
+        XCTAssertEqual(r4.maxX, -1.2, accuracy: ε)
+
+        XCTAssertEqual(r4.minY, -11.2, accuracy: ε)
+        XCTAssertEqual(r4.midY, -7.3, accuracy: ε)
+        XCTAssertEqual(r4.maxY, -3.4, accuracy: ε)
+    }
+
+    func test_CGRect_Standardized() {
+        let ε = CGFloat(0.00001)
+        let nullX = CGRect.null.origin.x
+        let nullY = CGRect.null.origin.y
+        let nullWidth = CGRect.null.size.width
+        let nullHeight = CGRect.null.size.height
+
+        let r1 = CGRect(x: 1.9, y: 1.9, width: 10.1, height: 10.2).standardized
+        assertEqual(r1, x: 1.9, y: 1.9, width: 10.1, height: 10.2, accuracy: ε)
+
+        let r2 = CGRect(x: 1.9, y: 1.9, width: -10.1, height: -10.2).standardized
+        assertEqual(r2, x: -8.2, y: -8.3, width: 10.1, height: 10.2, accuracy: ε)
+
+        let r3 = CGRect(x: -1.9, y: -1.9, width: 10.1, height: 10.2).standardized
+        assertEqual(r3, x: -1.9, y: -1.9, width: 10.1, height: 10.2, accuracy: ε)
+
+        let r4 = CGRect(x: -1.9, y: -1.9, width: -10.1, height: -10.2).standardized
+        assertEqual(r4, x: -12, y: -12.1, width: 10.1, height: 10.2, accuracy: ε)
+
+        let r5 = CGRect.null.standardized
+        assertEqual(r5, x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+
+        var r6 = CGRect.null
+        r6.size = CGSize(width: 10, height: 20)
+        r6 = r6.standardized
+        assertEqual(r6, x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+
+        var r7 = CGRect.null
+        r7.size = CGSize(width: -10, height: -20)
+        r7 = r7.standardized
+        assertEqual(r7, x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+
+        var r8 = CGRect.null
+        r8.origin.x = 20
+        r8 = r8.standardized
+        assertEqual(r8, x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+
+        var r9 = CGRect.null
+        r9.origin.y = 20
+        r9 = r9.standardized
+        assertEqual(r9, x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+
+        var r10 = CGRect.null
+        r10.origin = CGPoint(x: 10, y: 20)
+        r10 = r10.standardized
+        assertEqual(r10, x: 10, y: 20, width: 0, height: 0)
+    }
+
+    func test_CGRect_Integral() {
+        let ε = CGFloat(0.00001)
+
+        let r1 = CGRect(x: 1.9, y: 1.9, width: 10.1, height: 10.2).integral
+        XCTAssertEqual(r1.origin.x, 1, accuracy: ε)
+        XCTAssertEqual(r1.origin.y, 1, accuracy: ε)
+        XCTAssertEqual(r1.size.width, 11, accuracy: ε)
+        XCTAssertEqual(r1.size.height, 12, accuracy: ε)
+
+        let r2 = CGRect(x: 1.9, y: 1.9, width: -10.1, height: -10.2).integral
+        XCTAssertEqual(r2.origin.x, -9, accuracy: ε)
+        XCTAssertEqual(r2.origin.y, -9, accuracy: ε)
+        XCTAssertEqual(r2.size.width, 11, accuracy: ε)
+        XCTAssertEqual(r2.size.height, 11, accuracy: ε)
+
+        let r3 = CGRect(x: -1.9, y: -1.9, width: 10.1, height: 10.2).integral
+        XCTAssertEqual(r3.origin.x, -2, accuracy: ε)
+        XCTAssertEqual(r3.origin.y, -2, accuracy: ε)
+        XCTAssertEqual(r3.size.width, 11, accuracy: ε)
+        XCTAssertEqual(r3.size.height, 11, accuracy: ε)
+
+        let r4 = CGRect(x: -1.9, y: -1.9, width: -10.1, height: -10.2).integral
+        XCTAssertEqual(r4.origin.x, -12, accuracy: ε)
+        XCTAssertEqual(r4.origin.y, -13, accuracy: ε)
+        XCTAssertEqual(r4.size.width, 11, accuracy: ε)
+        XCTAssertEqual(r4.size.height, 12, accuracy: ε)
+
+        let r5 = CGRect.null.integral
+        XCTAssertEqual(r5.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(r5.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(r5.size.width, CGRect.null.size.width)
+        XCTAssertEqual(r5.size.height, CGRect.null.size.height)
+
+        var r6 = CGRect.null
+        r6.origin.x = 10
+        r6.size = CGSize(width: -20, height: -30)
+        r6 = r6.integral
+        XCTAssertEqual(r6.origin.x, 10)
+        XCTAssertEqual(r6.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(r6.size.width, -20)
+        XCTAssertEqual(r6.size.height, -30)
+
+        var r7 = CGRect.null
+        r7.origin.y = 10
+        r7.size = CGSize(width: -20, height: -30)
+        r7 = r7.integral
+        XCTAssertEqual(r7.origin.x, CGRect.null.origin.y)
+        XCTAssertEqual(r7.origin.y, 10)
+        XCTAssertEqual(r7.size.width, -20)
+        XCTAssertEqual(r7.size.height, -30)
+
+        var r8 = CGRect.null
+        r8.origin = CGPoint(x: 10, y: 20)
+        r8.size = CGSize(width: -30, height: -40)
+        r8 = r8.integral
+        XCTAssertEqual(r8.origin.x, -20)
+        XCTAssertEqual(r8.origin.y, -20)
+        XCTAssertEqual(r8.size.width, 30)
+        XCTAssertEqual(r8.size.height, 40)
+    }
+
+    func test_CGRect_ContainsPoint() {
+        XCTAssertFalse(CGRect.null.contains(CGPoint()))
+        XCTAssertFalse(CGRect.zero.contains(CGPoint()))
+
+        let r1 = CGRect(x: 5, y: 5, width: 10, height: 10)
+        XCTAssertFalse(r1.contains(CGPoint(x: 1, y: 2)))
+        XCTAssertFalse(r1.contains(CGPoint(x: 7, y: 2)))
+        XCTAssertFalse(r1.contains(CGPoint(x: 2, y: 7)))
+        XCTAssertFalse(r1.contains(CGPoint(x: -7, y: -7)))
+        XCTAssertFalse(r1.contains(CGPoint(x: 15, y: 15)))
+        XCTAssertTrue(r1.contains(CGPoint(x: 7, y: 7)))
+        XCTAssertTrue(r1.contains(CGPoint(x: 10, y: 10)))
+        XCTAssertTrue(r1.contains(CGPoint(x: 5, y: 5)))
+
+        let r2 = CGRect(x: -5, y: -5, width: -10, height: -10)
+        XCTAssertFalse(r2.contains(CGPoint(x: -1, y: -2)))
+        XCTAssertFalse(r2.contains(CGPoint(x: -7, y: -2)))
+        XCTAssertFalse(r2.contains(CGPoint(x: -2, y: -7)))
+        XCTAssertFalse(r2.contains(CGPoint(x: 7, y: 7)))
+        XCTAssertFalse(r2.contains(CGPoint(x: -5, y: -5)))
+        XCTAssertTrue(r2.contains(CGPoint(x: -7, y: -7)))
+        XCTAssertTrue(r2.contains(CGPoint(x: -10, y: -10)))
+        XCTAssertTrue(r2.contains(CGPoint(x: -15, y: -15)))
+
+        XCTAssertTrue(CGRect.infinite.contains(CGPoint()))
+    }
+
+    func test_CGRect_ContainsRect() {
+        XCTAssertFalse(CGRect.zero.contains(.infinite))
+        XCTAssertTrue(CGRect.zero.contains(.null))
+        XCTAssertTrue(CGRect.zero.contains(CGRect.zero))
+        XCTAssertFalse(CGRect.zero.contains(CGRect(x: -1.2, y: -3.4, width: 5.6, height: 7.8)))
+
+        XCTAssertFalse(CGRect.null.contains(.infinite))
+        XCTAssertTrue(CGRect.null.contains(.null))
+        XCTAssertFalse(CGRect.null.contains(CGRect.zero))
+        XCTAssertFalse(CGRect.null.contains(CGRect(x: -1.2, y: -3.4, width: 5.6, height: 7.8)))
+
+        XCTAssertTrue(CGRect.infinite.contains(.infinite))
+        XCTAssertTrue(CGRect.infinite.contains(.null))
+        XCTAssertTrue(CGRect.infinite.contains(CGRect.zero))
+        XCTAssertTrue(CGRect.infinite.contains(CGRect(x: -1.2, y: -3.4, width: 5.6, height: 7.8)))
+
+        let r1 = CGRect(x: 10, y: 20, width: 30, height: 40)
+        XCTAssertTrue(r1.contains(r1))
+
+        let r2 = CGRect(x: -10, y: -20, width: -30, height: -40)
+        XCTAssertTrue(r2.contains(r2))
+
+        let r3 = CGRect(x: -10, y: -20, width: 30, height: 40)
+        let r4 = CGRect(x: 20, y: 20, width: -30, height: -40)
+        XCTAssertTrue(r3.contains(r4))
+
+        let r5 = CGRect(x: -10, y: -10, width: 20, height: 20)
+        let r6 = CGRect(x: -5, y: -5, width: 10, height: 10)
+        XCTAssertTrue(r5.contains(r6))
+        XCTAssertFalse(r6.contains(r5))
+    }
+
+    func test_CGRect_Union() {
+        let r1 = CGRect.null
+        let r2 = CGRect.null
+        let u1 = r1.union(r2)
+        XCTAssertEqual(u1.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(u1.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(u1.size.width, CGRect.null.size.width)
+        XCTAssertEqual(u1.size.height, CGRect.null.size.height)
+
+        let r3 = CGRect.null
+        var r4 = CGRect.null
+        r4.size = CGSize(width: 10, height: 20)
+        let u2 = r3.union(r4)
+        XCTAssertEqual(u2.origin.x, r4.origin.x)
+        XCTAssertEqual(u2.origin.y, r4.origin.y)
+        XCTAssertEqual(u2.size.width, r4.size.width)
+        XCTAssertEqual(u2.size.height, r4.size.height)
+
+        let u3 = r4.union(r3)
+        XCTAssertEqual(u3.origin.x, r3.origin.x)
+        XCTAssertEqual(u3.origin.y, r3.origin.y)
+        XCTAssertEqual(u3.size.width, r3.size.width)
+        XCTAssertEqual(u3.size.height, r3.size.height)
+
+        let r5 = CGRect(x: -1.2, y: -3.4, width: -5.6, height: -7.8)
+        let r6 = CGRect(x: 1.2, y: 3.4, width: 5.6, height: 7.8)
+        let u4 = r5.union(r6)
+        XCTAssertEqual(u4.origin.x, -6.8)
+        XCTAssertEqual(u4.origin.y, -11.2)
+        XCTAssertEqual(u4.size.width, 13.6)
+        XCTAssertEqual(u4.size.height, 22.4)
+
+        let r7 = CGRect(x: 1, y: 2, width: 3, height: 4)
+        let r8 = CGRect.infinite
+        let u5 = r7.union(r8)
+        XCTAssertEqual(u5.origin.x, r8.origin.x)
+        XCTAssertEqual(u5.origin.y, r8.origin.y)
+        XCTAssertEqual(u5.size.width, r8.size.width)
+        XCTAssertEqual(u5.size.height, r8.size.height)
+    }
+
+    func test_CGRect_Intersection() {
+        let r1 = CGRect(x: 10, y: 10, width: 50, height: 60)
+        let r2 = CGRect(x: 25, y: 25, width: 60, height: 70)
+        let i1 = r1.intersection(r2)
+        XCTAssertEqual(i1.origin.x, 25)
+        XCTAssertEqual(i1.origin.y, 25)
+        XCTAssertEqual(i1.size.width, 35)
+        XCTAssertEqual(i1.size.height, 45)
+
+        let r3 = CGRect(x: 85, y: 95, width: -60, height: -70)
+        let i2 = r1.intersection(r3)
+        XCTAssertEqual(i2.origin.x, 25)
+        XCTAssertEqual(i2.origin.y, 25)
+        XCTAssertEqual(i2.size.width, 35)
+        XCTAssertEqual(i2.size.height, 45)
+
+        let r4 = CGRect(x: -10, y: -10, width: -30, height: -30)
+        let i3 = r1.intersection(r4)
+        XCTAssertEqual(i3.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(i3.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(i3.size.width, CGRect.null.size.width)
+        XCTAssertEqual(i3.size.height, CGRect.null.size.height)
+
+        let r5 = CGRect.null
+        let i4 = r1.intersection(r5)
+        XCTAssertEqual(i4.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(i4.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(i4.size.width, CGRect.null.size.width)
+        XCTAssertEqual(i4.size.height, CGRect.null.size.height)
+
+        let i5 = r5.intersection(r1)
+        XCTAssertEqual(i5.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(i5.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(i5.size.width, CGRect.null.size.width)
+        XCTAssertEqual(i5.size.height, CGRect.null.size.height)
+
+        var r6 = CGRect.null
+        r6.size = CGSize(width: 10, height: 20)
+        r6.origin.x = 30
+        let i6 = r5.intersection(r6)
+        XCTAssertEqual(i6.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(i6.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(i6.size.width, CGRect.null.size.width)
+        XCTAssertEqual(i6.size.height, CGRect.null.size.height)
+
+        let i7 = r1.intersection(.infinite)
+        XCTAssertEqual(i7.origin.x, r1.origin.x)
+        XCTAssertEqual(i7.origin.y, r1.origin.y)
+        XCTAssertEqual(i7.size.width, r1.size.width)
+        XCTAssertEqual(i7.size.height, r1.size.height)
+
+        let i8 = CGRect.infinite.intersection(.infinite)
+        XCTAssertEqual(i8.origin.x, CGRect.infinite.origin.x)
+        XCTAssertEqual(i8.origin.y, CGRect.infinite.origin.y)
+        XCTAssertEqual(i8.size.width, CGRect.infinite.size.width)
+        XCTAssertEqual(i8.size.height, CGRect.infinite.size.height)
+
+        let r7 = CGRect(x: -10, y: -10, width: 20, height: 20)
+        let i9 = r7.intersection(.zero)
+        XCTAssertEqual(i9.origin.x, 0)
+        XCTAssertEqual(i9.origin.y, 0)
+        XCTAssertEqual(i9.size.width, 0)
+        XCTAssertEqual(i9.size.height, 0)
+    }
+
+    func test_CGRect_Intersects() {
+        let r1 = CGRect(x: 10, y: 10, width: 50, height: 60)
+        let r2 = CGRect(x: 25, y: 25, width: 60, height: 70)
+        XCTAssertTrue(r1.intersects(r2))
+
+        let r3 = CGRect(x: 85, y: 95, width: -60, height: -70)
+        XCTAssertTrue(r1.intersects(r3))
+
+        let r4 = CGRect(x: -10, y: -10, width: -30, height: -30)
+        XCTAssertFalse(r1.intersects(r4))
+
+        let r5 = CGRect.null
+        XCTAssertFalse(r1.intersects(r5))
+        XCTAssertFalse(r5.intersects(r1))
+
+        var r6 = CGRect.null
+        r6.size = CGSize(width: 10, height: 20)
+        r6.origin.x = 30
+        XCTAssertFalse(r5.intersects(r6))
+
+        XCTAssertTrue(r1.intersects(.infinite))
+
+        XCTAssertTrue(CGRect.infinite.intersects(.infinite))
+
+        let r7 = CGRect(x: -10, y: -10, width: 20, height: 20)
+        XCTAssertTrue(r7.intersects(.zero))
+    }
+
+    func test_CGRect_OffsetBy() {
+        var r1 = CGRect.null
+        r1.size = CGSize(width: 10, height: 20)
+        r1.origin.x = 30
+        let o1 = r1.offsetBy(dx: 40, dy: 50)
+        XCTAssertEqual(o1.origin.x, r1.origin.x)
+        XCTAssertEqual(o1.origin.y, r1.origin.y)
+        XCTAssertEqual(o1.size.width, r1.size.width)
+        XCTAssertEqual(o1.size.height, r1.size.height)
+
+        var r2 = CGRect.null
+        r2.size = CGSize(width: 10, height: 20)
+        r2.origin.y = 30
+        let o2 = r2.offsetBy(dx: 40, dy: 50)
+        XCTAssertEqual(o2.origin.x, r2.origin.x)
+        XCTAssertEqual(o2.origin.y, r2.origin.y)
+        XCTAssertEqual(o2.size.width, r2.size.width)
+        XCTAssertEqual(o2.size.height, r2.size.height)
+
+        let o3 = CGRect(x: 1.2, y: 3.4, width: 5.6, height: 7.8).offsetBy(dx: 10.5, dy: 20.5)
+        XCTAssertEqual(o3.origin.x, 11.7)
+        XCTAssertEqual(o3.origin.y, 23.9)
+        XCTAssertEqual(o3.size.width, 5.6)
+        XCTAssertEqual(o3.size.height, 7.8)
+
+        let o4 = CGRect(x: -1.2, y: -3.4, width: -5.6, height: -7.8).offsetBy(dx: -10.5, dy: -20.5)
+        XCTAssertEqual(o4.origin.x, -17.3)
+        XCTAssertEqual(o4.origin.y, -31.7)
+        XCTAssertEqual(o4.size.width, 5.6)
+        XCTAssertEqual(o4.size.height, 7.8)
+    }
+
+    func test_CGRect_Divide() {
+        let r1 = CGRect(x: 10, y: 20, width: 30, height: 40)
+        let d1 = r1.divided(atDistance: 10, from: .minXEdge)
+        XCTAssertEqual(d1.slice.origin.x, 10)
+        XCTAssertEqual(d1.slice.origin.y, 20)
+        XCTAssertEqual(d1.slice.size.width, 10)
+        XCTAssertEqual(d1.slice.size.height, 40)
+        XCTAssertEqual(d1.remainder.origin.x, 20)
+        XCTAssertEqual(d1.remainder.origin.y, 20)
+        XCTAssertEqual(d1.remainder.size.width, 20)
+        XCTAssertEqual(d1.remainder.size.height, 40)
+
+        let d2 = r1.divided(atDistance: 10, from: .maxXEdge)
+        XCTAssertEqual(d2.slice.origin.x, 30)
+        XCTAssertEqual(d2.slice.origin.y, 20)
+        XCTAssertEqual(d2.slice.size.width, 10)
+        XCTAssertEqual(d2.slice.size.height, 40)
+        XCTAssertEqual(d2.remainder.origin.x, 10)
+        XCTAssertEqual(d2.remainder.origin.y, 20)
+        XCTAssertEqual(d2.remainder.size.width, 20)
+        XCTAssertEqual(d2.remainder.size.height, 40)
+
+        let d3 = r1.divided(atDistance: 10, from: .minYEdge)
+        XCTAssertEqual(d3.slice.origin.x, 10)
+        XCTAssertEqual(d3.slice.origin.y, 20)
+        XCTAssertEqual(d3.slice.size.width, 30)
+        XCTAssertEqual(d3.slice.size.height, 10)
+        XCTAssertEqual(d3.remainder.origin.x, 10)
+        XCTAssertEqual(d3.remainder.origin.y, 30)
+        XCTAssertEqual(d3.remainder.size.width, 30)
+        XCTAssertEqual(d3.remainder.size.height, 30)
+
+        let d4 = r1.divided(atDistance: 10, from: .maxYEdge)
+        XCTAssertEqual(d4.slice.origin.x, 10)
+        XCTAssertEqual(d4.slice.origin.y, 50)
+        XCTAssertEqual(d4.slice.size.width, 30)
+        XCTAssertEqual(d4.slice.size.height, 10)
+        XCTAssertEqual(d4.remainder.origin.x, 10)
+        XCTAssertEqual(d4.remainder.origin.y, 20)
+        XCTAssertEqual(d4.remainder.size.width, 30)
+        XCTAssertEqual(d4.remainder.size.height, 30)
+
+        let d5 = r1.divided(atDistance: 31, from: .minXEdge)
+        XCTAssertEqual(d5.slice.origin.x, 10)
+        XCTAssertEqual(d5.slice.origin.y, 20)
+        XCTAssertEqual(d5.slice.size.width, 30)
+        XCTAssertEqual(d5.slice.size.height, 40)
+        XCTAssertEqual(d5.remainder.origin.x, 40)
+        XCTAssertEqual(d5.remainder.origin.y, 20)
+        XCTAssertEqual(d5.remainder.size.width, 0)
+        XCTAssertEqual(d5.remainder.size.height, 40)
+
+        let d6 = r1.divided(atDistance: 31, from: .maxXEdge)
+        XCTAssertEqual(d6.slice.origin.x, 10)
+        XCTAssertEqual(d6.slice.origin.y, 20)
+        XCTAssertEqual(d6.slice.size.width, 30)
+        XCTAssertEqual(d6.slice.size.height, 40)
+        XCTAssertEqual(d6.remainder.origin.x, 10)
+        XCTAssertEqual(d6.remainder.origin.y, 20)
+        XCTAssertEqual(d6.remainder.size.width, 0)
+        XCTAssertEqual(d6.remainder.size.height, 40)
+
+        let d7 = r1.divided(atDistance: 41, from: .minYEdge)
+        XCTAssertEqual(d7.slice.origin.x, 10)
+        XCTAssertEqual(d7.slice.origin.y, 20)
+        XCTAssertEqual(d7.slice.size.width, 30)
+        XCTAssertEqual(d7.slice.size.height, 40)
+        XCTAssertEqual(d7.remainder.origin.x, 10)
+        XCTAssertEqual(d7.remainder.origin.y, 60)
+        XCTAssertEqual(d7.remainder.size.width, 30)
+        XCTAssertEqual(d7.remainder.size.height, 0)
+
+        let d8 = r1.divided(atDistance: 41, from: .maxYEdge)
+        XCTAssertEqual(d8.slice.origin.x, 10)
+        XCTAssertEqual(d8.slice.origin.y, 20)
+        XCTAssertEqual(d8.slice.size.width, 30)
+        XCTAssertEqual(d8.slice.size.height, 40)
+        XCTAssertEqual(d8.remainder.origin.x, 10)
+        XCTAssertEqual(d8.remainder.origin.y, 20)
+        XCTAssertEqual(d8.remainder.size.width, 30)
+        XCTAssertEqual(d8.remainder.size.height, 0)
+
+        let d9 = CGRect(x: -10, y: -20, width: -30, height: -40).divided(atDistance: 10, from: .minXEdge)
+        XCTAssertEqual(d9.slice.origin.x, -40)
+        XCTAssertEqual(d9.slice.origin.y, -60)
+        XCTAssertEqual(d9.slice.size.width, 10)
+        XCTAssertEqual(d9.slice.size.height, 40)
+        XCTAssertEqual(d9.remainder.origin.x, -30)
+        XCTAssertEqual(d9.remainder.origin.y, -60)
+        XCTAssertEqual(d9.remainder.size.width, 20)
+        XCTAssertEqual(d9.remainder.size.height, 40)
+
+        var r2 = CGRect.null
+        r2.size = CGSize(width: 10, height: 20)
+        r2.origin.x = 30
+        let d10 = r2.divided(atDistance: 10, from: .minXEdge)
+        XCTAssertEqual(d10.slice.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(d10.slice.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(d10.slice.size.width, CGRect.null.size.width)
+        XCTAssertEqual(d10.slice.size.height, CGRect.null.size.height)
+        XCTAssertEqual(d10.remainder.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(d10.remainder.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(d10.remainder.size.width, CGRect.null.size.width)
+        XCTAssertEqual(d10.remainder.size.height, CGRect.null.size.height)
+
+        var r3 = CGRect.null
+        r3.size = CGSize(width: 10, height: 20)
+        r3.origin.y = 30
+        let d11 = r3.divided(atDistance: 10, from: .minXEdge)
+        XCTAssertEqual(d11.slice.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(d11.slice.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(d11.slice.size.width, CGRect.null.size.width)
+        XCTAssertEqual(d11.slice.size.height, CGRect.null.size.height)
+        XCTAssertEqual(d11.remainder.origin.x, CGRect.null.origin.x)
+        XCTAssertEqual(d11.remainder.origin.y, CGRect.null.origin.y)
+        XCTAssertEqual(d11.remainder.size.width, CGRect.null.size.width)
+        XCTAssertEqual(d11.remainder.size.height, CGRect.null.size.height)
+    }
+
+    func test_CGRect_InsetBy() {
+        let ε = CGFloat(0.00001)
+        let nullX = CGRect.null.origin.x
+        let nullY = CGRect.null.origin.y
+        let nullWidth = CGRect.null.size.width
+        let nullHeight = CGRect.null.size.height
+
+        let r1 = CGRect(x: 1.2, y: 3.4, width: 5.6, height: 7.8)
+        assertEqual(r1.insetBy(dx: 2.8, dy: 0), x: 4, y: 3.4, width: 0, height: 7.8, accuracy: ε)
+        assertEqual(r1.insetBy(dx: 0, dy: 3.9), x: 1.2, y: 7.3, width: 5.6, height: 0, accuracy: ε)
+        assertEqual(r1.insetBy(dx: 10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r1.insetBy(dx: 10, dy: -10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r1.insetBy(dx: -10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r1.insetBy(dx: -10, dy: -10), x: -8.8, y: -6.6, width: 25.6, height: 27.8, accuracy: ε)
+
+        let r2 = CGRect(x: 1.2, y: 3.4, width: -5.6, height: -7.8)
+        assertEqual(r2.insetBy(dx: 2.8, dy: 0), x: -1.6, y: -4.4, width: 0, height: 7.8, accuracy: ε)
+        assertEqual(r2.insetBy(dx: 0, dy: 3.9), x: -4.4, y: -0.5, width: 5.6, height: 0, accuracy: ε)
+        assertEqual(r2.insetBy(dx: 10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r2.insetBy(dx: 10, dy: -10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r2.insetBy(dx: -10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r2.insetBy(dx: -10, dy: -10), x: -14.4, y: -14.4, width: 25.6, height: 27.8, accuracy: ε)
+
+        let r3 = CGRect(x: -1.2, y: -3.4, width: 5.6, height: 7.8)
+        assertEqual(r3.insetBy(dx: 2.8, dy: 0), x: 1.6, y: -3.4, width: 0, height: 7.8, accuracy: ε)
+        assertEqual(r3.insetBy(dx: 0, dy: 3.9), x: -1.2, y: 0.5, width: 5.6, height: 0, accuracy: ε)
+        assertEqual(r3.insetBy(dx: 10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r3.insetBy(dx: 10, dy: -10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r3.insetBy(dx: -10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r3.insetBy(dx: -10, dy: -10), x: -11.2, y: -13.4, width: 25.6, height: 27.8, accuracy: ε)
+
+        let r4 = CGRect(x: -1.2, y: -3.4, width: -5.6, height: -7.8)
+        assertEqual(r4.insetBy(dx: 2.8, dy: 0), x: -4, y: -11.2, width: 0, height: 7.8, accuracy: ε)
+        assertEqual(r4.insetBy(dx: 0, dy: 3.9), x: -6.8, y: -7.3, width: 5.6, height: 0, accuracy: ε)
+        assertEqual(r4.insetBy(dx: 10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r4.insetBy(dx: 10, dy: -10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r4.insetBy(dx: -10, dy: 10), x: nullX, y: nullY, width: nullWidth, height: nullHeight)
+        assertEqual(r4.insetBy(dx: -10, dy: -10), x: -16.8, y: -21.2, width: 25.6, height: 27.8, accuracy: ε)
+
+        var r5 = CGRect.null
+        r5.size = CGSize(width: 10, height: 20)
+        r5.origin.x = 30
+        let i1 = r5.insetBy(dx: 50, dy: 60)
+        XCTAssertEqual(i1.origin.x, 30)
+        XCTAssertEqual(i1.origin.y, r5.origin.y)
+        XCTAssertEqual(i1.size.width, 10)
+        XCTAssertEqual(i1.size.height, 20)
+
+        var r6 = CGRect.null
+        r6.size = CGSize(width: 10, height: 20)
+        r6.origin.y = 30
+        let i2 = r6.insetBy(dx: 50, dy: 60)
+        XCTAssertEqual(i2.origin.x, r6.origin.x)
+        XCTAssertEqual(i2.origin.y, 30)
+        XCTAssertEqual(i2.size.width, 10)
+        XCTAssertEqual(i2.size.height, 20)
+    }
     
     func test_CGRect_SpecialValues() {
         let r1 = CGRect.null