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