Merge pull request #690 from kareman/implement-FileHandle.nullDevice
diff --git a/Docs/Status.md b/Docs/Status.md
index de77b21..6c0eb68 100644
--- a/Docs/Status.md
+++ b/Docs/Status.md
@@ -47,7 +47,7 @@
|------------------------------|-----------------|---------------|--------------------------------------------------------------------------------------------------------------------|
| `URLAuthenticationChallenge` | Unimplemented | None | |
| `URLCache` | Unimplemented | None | |
- | `URLCredential` | Mostly Complete | Incomplete | `NSCoding` and `NSCopying` remain unimplemented |
+ | `URLCredential` | Mostly Complete | Incomplete | `NSCopying` remains unimplemented |
| `URLCredentialStorage` | Unimplemented | None | |
| `NSURLError*` | Complete | N/A | |
| `URLProtectionSpace` | Unimplemented | None | |
diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj
index 45e43e4..2af4035 100755
--- a/Foundation.xcodeproj/project.pbxproj
+++ b/Foundation.xcodeproj/project.pbxproj
@@ -308,6 +308,7 @@
7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */; };
7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */; };
AE35A1861CBAC85E0042DB84 /* SwiftFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ BF8E65311DC3B3CB005AB5C3 /* TestNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */; };
CC5249C01D341D23007CB54D /* TestUnitConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC5249BF1D341D23007CB54D /* TestUnitConverter.swift */; };
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */ = {isa = PBXBuildFile; fileRef = CE19A88B1C23AA2300B4CB6A /* NSStringTestData.txt */; };
D31302011C30CEA900295652 /* NSConcreteValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31302001C30CEA900295652 /* NSConcreteValue.swift */; };
@@ -744,6 +745,7 @@
88D28DE61C13AE9000494606 /* TestNSGeometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSGeometry.swift; sourceTree = "<group>"; };
A5A34B551C18C85D00FD972B /* TestNSByteCountFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSByteCountFormatter.swift; sourceTree = "<group>"; };
AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftFoundation.h; sourceTree = "<group>"; };
+ BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNotification.swift; sourceTree = "<group>"; };
C2A9D75B1C15C08B00993803 /* TestNSUUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSUUID.swift; sourceTree = "<group>"; };
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAffineTransform.swift; sourceTree = "<group>"; };
CC5249BF1D341D23007CB54D /* TestUnitConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUnitConverter.swift; sourceTree = "<group>"; };
@@ -1378,6 +1380,7 @@
0383A1741D2E558A0052E5D1 /* TestNSStream.swift */,
5B1FD9E21D6D17B80080E83C /* TestNSURLSession.swift */,
EA54A6FA1DB16D53009E0809 /* TestObjCRuntime.swift */,
+ BF8E65301DC3B3CB005AB5C3 /* TestNotification.swift */,
);
name = Tests;
sourceTree = "<group>";
@@ -2215,6 +2218,7 @@
5B13B34D1C582D4C00651CE2 /* TestNSUUID.swift in Sources */,
5B13B3281C582D4C00651CE2 /* TestNSBundle.swift in Sources */,
5B13B32A1C582D4C00651CE2 /* TestNSCharacterSet.swift in Sources */,
+ BF8E65311DC3B3CB005AB5C3 /* TestNotification.swift in Sources */,
EA01AAEC1DA839C4008F4E07 /* TestProgress.swift in Sources */,
5B13B3411C582D4C00651CE2 /* TestNSRegularExpression.swift in Sources */,
5B13B3491C582D4C00651CE2 /* TestNSTimeZone.swift in Sources */,
diff --git a/Foundation/CGFloat.swift b/Foundation/CGFloat.swift
index bba73b4..3462d8d 100644
--- a/Foundation/CGFloat.swift
+++ b/Foundation/CGFloat.swift
@@ -145,15 +145,17 @@
public var native: NativeType
}
-@_transparent extension CGFloat : BinaryFloatingPoint {
+extension CGFloat : BinaryFloatingPoint {
public typealias RawSignificand = UInt
public typealias Exponent = Int
-
+
+ @_transparent
public static var exponentBitCount: Int {
return NativeType.exponentBitCount
}
+ @_transparent
public static var significandBitCount: Int {
return NativeType.significandBitCount
}
@@ -161,10 +163,12 @@
// Conversions to/from integer encoding. These are not part of the
// BinaryFloatingPoint prototype because there's no guarantee that an
// integer type of the same size actually exists (e.g. Float80).
+ @_transparent
public var bitPattern: UInt {
return UInt(native.bitPattern)
}
-
+
+ @_transparent
public init(bitPattern: UInt) {
#if arch(i386) || arch(arm)
native = NativeType(bitPattern: UInt32(bitPattern))
@@ -172,19 +176,23 @@
native = NativeType(bitPattern: UInt64(bitPattern))
#endif
}
-
+
+ @_transparent
public var sign: FloatingPointSign {
return native.sign
}
-
+
+ @_transparent
public var exponentBitPattern: UInt {
return native.exponentBitPattern
}
-
+
+ @_transparent
public var significandBitPattern: UInt {
return UInt(native.significandBitPattern)
}
-
+
+ @_transparent
public init(sign: FloatingPointSign,
exponentBitPattern: UInt,
significandBitPattern: UInt) {
@@ -192,177 +200,217 @@
exponentBitPattern: exponentBitPattern,
significandBitPattern: NativeType.RawSignificand(significandBitPattern))
}
-
+
+ @_transparent
public init(nan payload: RawSignificand, signaling: Bool) {
native = NativeType(nan: NativeType.RawSignificand(payload),
signaling: signaling)
}
-
+
+ @_transparent
public static var infinity: CGFloat {
return CGFloat(NativeType.infinity)
}
-
+
+ @_transparent
public static var nan: CGFloat {
return CGFloat(NativeType.nan)
}
-
+
+ @_transparent
public static var signalingNaN: CGFloat {
return CGFloat(NativeType.signalingNaN)
}
-
+
@available(*, unavailable, renamed: "nan")
public static var quietNaN: CGFloat {
fatalError("unavailable")
}
-
+
+ @_transparent
public static var greatestFiniteMagnitude: CGFloat {
return CGFloat(NativeType.greatestFiniteMagnitude)
}
-
+
+ @_transparent
public static var pi: CGFloat {
return CGFloat(NativeType.pi)
}
-
+
+ @_transparent
public var ulp: CGFloat {
return CGFloat(native.ulp)
}
-
+
+ @_transparent
public static var leastNormalMagnitude: CGFloat {
return CGFloat(NativeType.leastNormalMagnitude)
}
-
+
+ @_transparent
public static var leastNonzeroMagnitude: CGFloat {
return CGFloat(NativeType.leastNonzeroMagnitude)
}
-
+
+ @_transparent
public var exponent: Int {
return native.exponent
}
-
+
+ @_transparent
public var significand: CGFloat {
return CGFloat(native.significand)
}
-
+
+ @_transparent
public init(sign: FloatingPointSign, exponent: Int, significand: CGFloat) {
native = NativeType(sign: sign,
exponent: exponent, significand: significand.native)
}
-
+
+ @_transparent
public mutating func round(_ rule: FloatingPointRoundingRule) {
native.round(rule)
}
-
+
+ @_transparent
public var nextUp: CGFloat {
return CGFloat(native.nextUp)
}
-
+
+ @_transparent
public var magnitude: CGFloat {
return CGFloat(Swift.abs(native))
}
-
+
+ @_transparent
public mutating func negate() {
native.negate()
}
-
+
+ @_transparent
public mutating func add(_ other: CGFloat) {
native.add(other.native)
}
-
+
+ @_transparent
public mutating func subtract(_ other: CGFloat) {
native.subtract(other.native)
}
-
+
+ @_transparent
public mutating func multiply(by other: CGFloat) {
native.multiply(by: other.native)
}
-
+
+ @_transparent
public mutating func divide(by other: CGFloat) {
native.divide(by: other.native)
}
-
+
+ @_transparent
public mutating func formTruncatingRemainder(dividingBy other: CGFloat) {
native.formTruncatingRemainder(dividingBy: other.native)
}
-
+
+ @_transparent
public mutating func formRemainder(dividingBy other: CGFloat) {
native.formRemainder(dividingBy: other.native)
}
-
+
+ @_transparent
public mutating func formSquareRoot( ) {
native.formSquareRoot( )
}
-
+
+ @_transparent
public mutating func addProduct(_ lhs: CGFloat, _ rhs: CGFloat) {
native.addProduct(lhs.native, rhs.native)
}
-
+
+ @_transparent
public func isEqual(to other: CGFloat) -> Bool {
return self.native.isEqual(to: other.native)
}
-
+
+ @_transparent
public func isLess(than other: CGFloat) -> Bool {
return self.native.isLess(than: other.native)
}
-
+
+ @_transparent
public func isLessThanOrEqualTo(_ other: CGFloat) -> Bool {
return self.native.isLessThanOrEqualTo(other.native)
}
-
+
+ @_transparent
public var isNormal: Bool {
return native.isNormal
}
-
+
+ @_transparent
public var isFinite: Bool {
return native.isFinite
}
-
+
+ @_transparent
public var isZero: Bool {
return native.isZero
}
-
+
+ @_transparent
public var isSubnormal: Bool {
return native.isSubnormal
}
-
+
+ @_transparent
public var isInfinite: Bool {
return native.isInfinite
}
-
+
+ @_transparent
public var isNaN: Bool {
return native.isNaN
}
-
+
+ @_transparent
public var isSignalingNaN: Bool {
return native.isSignalingNaN
}
-
+
@available(*, unavailable, renamed: "isSignalingNaN")
public var isSignaling: Bool {
fatalError("unavailable")
}
-
+
+ @_transparent
public var isCanonical: Bool {
return true
}
-
+
+ @_transparent
public var floatingPointClass: FloatingPointClassification {
return native.floatingPointClass
}
-
+
+ @_transparent
public var binade: CGFloat {
return CGFloat(native.binade)
}
-
+
+ @_transparent
public var significandWidth: Int {
return native.significandWidth
}
-
+
/// Create an instance initialized to `value`.
+ @_transparent
public init(floatLiteral value: NativeType) {
native = value
}
-
+
/// Create an instance initialized to `value`.
+ @_transparent
public init(integerLiteral value: Int) {
native = NativeType(value)
}
@@ -402,14 +450,14 @@
}
}
-@_transparent extension CGFloat : CustomStringConvertible {
+extension CGFloat : CustomStringConvertible {
/// A textual representation of `self`.
public var description: String {
return native.description
}
}
-@_transparent extension CGFloat : Hashable {
+extension CGFloat : Hashable {
/// The hash value.
///
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
@@ -417,78 +465,91 @@
/// - Note: the hash value is not guaranteed to be stable across
/// different invocations of the same program. Do not persist the
/// hash value across program runs.
+ @_transparent
public var hashValue: Int {
return native.hashValue
}
}
-@_transparent extension UInt8 {
+extension UInt8 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt8(value.native)
}
}
-@_transparent extension Int8 {
+extension Int8 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int8(value.native)
}
}
-@_transparent extension UInt16 {
+extension UInt16 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt16(value.native)
}
}
-@_transparent extension Int16 {
+extension Int16 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int16(value.native)
}
}
-@_transparent extension UInt32 {
+extension UInt32 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt32(value.native)
}
}
-@_transparent extension Int32 {
+extension Int32 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int32(value.native)
}
}
-@_transparent extension UInt64 {
+extension UInt64 {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt64(value.native)
}
}
-@_transparent extension Int64 {
+extension Int64 {
+ @_transparent
public init(_ value: CGFloat) {
self = Int64(value.native)
}
}
-@_transparent extension UInt {
+extension UInt {
+ @_transparent
public init(_ value: CGFloat) {
self = UInt(value.native)
}
}
-@_transparent extension Int {
+extension Int {
+ @_transparent
public init(_ value: CGFloat) {
self = Int(value.native)
}
}
-@_transparent extension Double {
+extension Double {
+ @_transparent
public init(_ value: CGFloat) {
self = Double(value.native)
}
}
-@_transparent extension Float {
+extension Float {
+ @_transparent
public init(_ value: CGFloat) {
self = Float(value.native)
}
@@ -547,7 +608,7 @@
// Strideable Conformance
//===----------------------------------------------------------------------===//
-@_transparent extension CGFloat : Strideable {
+extension CGFloat : Strideable {
/// Returns a stride `x` such that `self.advanced(by: x)` approximates
/// `other`.
///
@@ -571,41 +632,35 @@
// Deprecated operators
//===----------------------------------------------------------------------===//
-@_transparent
@available(*, unavailable, message: "use += 1")
@discardableResult
public prefix func ++(rhs: inout CGFloat) -> CGFloat {
fatalError("++ is not available")
}
-@_transparent
@available(*, unavailable, message: "use -= 1")
@discardableResult
public prefix func --(rhs: inout CGFloat) -> CGFloat {
fatalError("-- is not available")
}
-@_transparent
@available(*, unavailable, message: "use += 1")
@discardableResult
public postfix func ++(lhs: inout CGFloat) -> CGFloat {
fatalError("++ is not available")
}
-@_transparent
@available(*, unavailable, message: "use -= 1")
@discardableResult
public postfix func --(lhs: inout CGFloat) -> CGFloat {
fatalError("-- is not available")
}
-@_transparent
@available(*, unavailable, message: "Use truncatingRemainder instead")
public func %(lhs: CGFloat, rhs: CGFloat) -> CGFloat {
fatalError("% is not available.")
}
-@_transparent
@available(*, unavailable, message: "Use formTruncatingRemainder instead")
public func %=(lhs: inout CGFloat, rhs: CGFloat) {
fatalError("%= is not available.")
@@ -880,16 +935,17 @@
return CGFloat(yn(n, Double(x.native)))
}
-@_transparent
extension CGFloat : _CVarArgPassedAsDouble, _CVarArgAligned {
/// Transform `self` into a series of machine words that can be
/// appropriately interpreted by C varargs
+ @_transparent
public var _cVarArgEncoding: [Int] {
return native._cVarArgEncoding
}
/// Return the required alignment in bytes of
/// the value returned by `_cVarArgEncoding`.
+ @_transparent
public var _cVarArgAlignment: Int {
return native._cVarArgAlignment
}
diff --git a/Foundation/CharacterSet.swift b/Foundation/CharacterSet.swift
index 4babf01..35fbe72 100644
--- a/Foundation/CharacterSet.swift
+++ b/Foundation/CharacterSet.swift
@@ -13,6 +13,10 @@
private func _utfRangeToNSRange(_ inRange : Range<UnicodeScalar>) -> NSRange {
return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value))
}
+
+private func _utfRangeToNSRange(_ inRange : ClosedRange<UnicodeScalar>) -> NSRange {
+ return NSMakeRange(Int(inRange.lowerBound.value), Int(inRange.upperBound.value - inRange.lowerBound.value + 1))
+}
internal final class _SwiftNSCharacterSet : NSCharacterSet, _SwiftNativeFoundationType {
internal typealias ImmutableType = NSCharacterSet
@@ -129,8 +133,7 @@
///
/// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
public init(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(halfOpenRange)))
+ _wrapped = _SwiftNSCharacterSet(immutableObject: NSCharacterSet(range: _utfRangeToNSRange(range)))
}
/// Initialize with the characters in the given string.
@@ -320,8 +323,7 @@
///
/// It is the caller's responsibility to ensure that the values represent valid `UnicodeScalar` values, if that is what is desired.
public mutating func insert(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- let nsRange = _utfRangeToNSRange(halfOpenRange)
+ let nsRange = _utfRangeToNSRange(range)
_applyUnmanagedMutation {
$0.addCharacters(in: nsRange)
}
@@ -337,8 +339,7 @@
/// Remove a closed range of integer values from the `CharacterSet`.
public mutating func remove(charactersIn range: ClosedRange<UnicodeScalar>) {
- let halfOpenRange = range.lowerBound..<UnicodeScalar(range.upperBound.value + 1)!
- let nsRange = _utfRangeToNSRange(halfOpenRange)
+ let nsRange = _utfRangeToNSRange(range)
_applyUnmanagedMutation {
$0.removeCharacters(in: nsRange)
}
diff --git a/Foundation/Locale.swift b/Foundation/Locale.swift
index ffe584a..46642ac 100644
--- a/Foundation/Locale.swift
+++ b/Foundation/Locale.swift
@@ -69,7 +69,7 @@
/// Returns a localized string for a specified identifier.
///
- /// For example, in the "en" locale, the result for `"en"` is `"Spanish"`.
+ /// For example, in the "en" locale, the result for `"es"` is `"Spanish"`.
public func localizedString(forIdentifier identifier: String) -> String? {
return _wrapped.displayName(forKey: .identifier, value: identifier)
}
@@ -83,7 +83,7 @@
/// Returns a localized string for a specified region code.
///
- /// For example, in the "en" locale, the result for `"fr"` is `"French"`.
+ /// For example, in the "en" locale, the result for `"fr"` is `"France"`.
public func localizedString(forRegionCode regionCode: String) -> String? {
return _wrapped.displayName(forKey: .countryCode, value: regionCode)
}
diff --git a/Foundation/NSCFString.swift b/Foundation/NSCFString.swift
index e12e0fa..4558549 100644
--- a/Foundation/NSCFString.swift
+++ b/Foundation/NSCFString.swift
@@ -140,19 +140,18 @@
}
internal func _CFSwiftStringGetBytes(_ str: AnyObject, encoding: CFStringEncoding, range: CFRange, buffer: UnsafeMutablePointer<UInt8>?, maxBufLen: CFIndex, usedBufLen: UnsafeMutablePointer<CFIndex>?) -> CFIndex {
+ let convertedLength: CFIndex
switch encoding {
// TODO: Don't treat many encodings like they are UTF8
case CFStringEncoding(kCFStringEncodingUTF8), CFStringEncoding(kCFStringEncodingISOLatin1), CFStringEncoding(kCFStringEncodingMacRoman), CFStringEncoding(kCFStringEncodingASCII), CFStringEncoding(kCFStringEncodingNonLossyASCII):
- let encodingView = (str as! NSString)._swiftObject.utf8
- let start = encodingView.startIndex
+ let encodingView = (str as! NSString).substring(with: NSRange(range)).utf8
if let buffer = buffer {
- for idx in 0..<range.length {
- let characterIndex = encodingView.index(start, offsetBy: idx + range.location)
- let character = encodingView[characterIndex]
+ for (idx, character) in encodingView.enumerated() {
buffer.advanced(by: idx).initialize(to: character)
}
}
- usedBufLen?.pointee = range.length
+ usedBufLen?.pointee = encodingView.count
+ convertedLength = encodingView.count
case CFStringEncoding(kCFStringEncodingUTF16):
let encodingView = (str as! NSString)._swiftObject.utf16
@@ -169,13 +168,13 @@
}
// Every character was 2 bytes
usedBufLen?.pointee = range.length * 2
-
+ convertedLength = range.length
default:
fatalError("Attempted to get bytes of a Swift string using an unsupported encoding")
}
- return range.length
+ return convertedLength
}
internal func _CFSwiftStringCreateWithSubstring(_ str: AnyObject, range: CFRange) -> Unmanaged<AnyObject> {
diff --git a/Foundation/NSDecimal.swift b/Foundation/NSDecimal.swift
index c5a999f..dcba6f4 100644
--- a/Foundation/NSDecimal.swift
+++ b/Foundation/NSDecimal.swift
@@ -33,6 +33,9 @@
return UInt32((__lengthAndFlags & 0b0000_1111))
}
set {
+ guard newValue <= maxMantissaLength else {
+ fatalError("Attempt to set a length greater than capacity \(newValue) > \(maxMantissaLength)")
+ }
__lengthAndFlags =
(__lengthAndFlags & 0b1111_0000) |
UInt8(newValue & 0b0000_1111)
@@ -88,9 +91,8 @@
public init(_exponent: Int32, _length: UInt32, _isNegative: UInt32, _isCompact: UInt32, _reserved: UInt32, _mantissa: (UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16)){
self._mantissa = _mantissa
self.__exponent = Int8(truncatingBitPattern: _exponent)
- self.__lengthAndFlags = 0
+ self.__lengthAndFlags = UInt8(_length & 0b1111)
self.__reserved = 0
- self._length = _length
self._isNegative = _isNegative
self._isCompact = _isCompact
self._reserved = _reserved
@@ -564,9 +566,7 @@
d[i] = UInt16(accumulator / UInt32(divisor))
carry = accumulator % UInt32(divisor)
}
- while d._length != 0 && d[d._length - 1] == 0 {
- d._length -= 1
- }
+ d.trimTrailingZeros()
return (UInt16(carry),.noError)
}
@@ -674,7 +674,7 @@
var previousRemainder: Bool = false
// Divide by 10 as much as possible
- while big._length >= Decimal.maxSize {
+ while big._length > Decimal.maxSize + 1 {
if remainder != 0 {
previousRemainder = true
}
@@ -727,21 +727,19 @@
return .lossOfPrecision;
}
-fileprivate func integerMultiply(_ big: inout WideDecimal,
- _ left: WideDecimal,
- _ right: WideDecimal) -> NSDecimalNumber.CalculationError {
+fileprivate func integerMultiply<T:VariableLengthNumber>(_ big: inout T,
+ _ left: T,
+ _ right: Decimal) -> NSDecimalNumber.CalculationError {
if left._length == 0 || right._length == 0 {
big._length = 0
return .noError
}
- if big._length > left._length + right._length {
- big._length = left._length + right._length
+ if big._length == 0 || big._length > left._length + right._length {
+ big._length = min(big.maxMantissaLength,left._length + right._length)
}
- for i in 0..<big._length {
- big[i] = 0
- }
+ big.zeroMantissa()
var carry: UInt16 = 0
@@ -769,16 +767,14 @@
}
}
- while big._length != 0 && big[big._length - 1] == 0 {
- big._length -= 1
- }
+ big.trimTrailingZeros()
return .noError
}
-fileprivate func integerDivide(_ r: inout WideDecimal,
- _ cu: WideDecimal,
- _ cv: WideDecimal) -> NSDecimalNumber.CalculationError {
+fileprivate func integerDivide<T:VariableLengthNumber>(_ r: inout T,
+ _ cu: T,
+ _ cv: Decimal) -> NSDecimalNumber.CalculationError {
// Calculate result = a / b.
// Result could NOT be a pointer to same space as a or b.
// resultLen must be >= aLen - bLen.
@@ -792,17 +788,19 @@
var u = WideDecimal(true)
var v = WideDecimal(true) // divisor
- var v1:UInt16, v2:UInt16
-
// Simple case
if cv.isZero {
return .divideByZero;
}
// If u < v, the result is approximately 0...
- if cu < cv {
- r._length = 0
- return .noError;
+ if cu._length < cv._length {
+ for i in 0..<cv._length {
+ if cu[i] < cv[i] {
+ r._length = 0
+ return .noError;
+ }
+ }
}
// Fast algorithm
@@ -812,6 +810,9 @@
return error
}
+ u.copyMantissa(from: cu)
+ v.copyMantissa(from: cv)
+
u._length = cu._length + 1
v._length = cv._length + 1
@@ -826,9 +827,12 @@
_ = multiplyByShort(&u, UInt16(d))
_ = multiplyByShort(&v, UInt16(d))
+ u.trimTrailingZeros()
+ v.trimTrailingZeros()
+
// Set a zero at the leftmost u position if the multiplication
- // do not have a carry.
- if(u._length == cu._length) {
+ // does not have a carry.
+ if u._length == cu._length {
u[u._length] = 0
u._length += 1
}
@@ -845,22 +849,20 @@
// It's used to determine the quotient digit as fast as possible
// The test vl > 1 is probably useless, since optimizations
// up there are taking over this case. I'll keep it, just in case.
- v1 = v[v._length-1]
- v2 = v._length > 1 ? v[v._length-2] : 0
+ let v1:UInt16 = v[v._length-1]
+ let v2:UInt16 = v._length > 1 ? v[v._length-2] : 0
// D2: initialize j
// On each pass, build a single value for the quotient.
for j in 0..<ql {
- var q: UInt32 // Quotient digit. could be a short.
// D3: calculate q^
// This formula and test for q gives at most q+1; See Knuth for proof.
let ul = u._length
- let uu = u // work around compiler bug
- let tmp: UInt32 = UInt32(uu[ul - UInt32(j) - UInt32(1)] << 16 + uu[ul - UInt32(j) - UInt32(2)])
- q = tmp / UInt32(v1)
- var rtmp: UInt32 = tmp % UInt32(v1)
+ let tmp:UInt32 = UInt32(u[ul - UInt32(j) - UInt32(1)]) << 16 + UInt32(u[ul - UInt32(j) - UInt32(2)])
+ var q:UInt32 = tmp / UInt32(v1) // Quotient digit. could be a short.
+ var rtmp:UInt32 = tmp % UInt32(v1)
// This test catches all cases where q is really q+2 and
// most where it is q+1
@@ -888,8 +890,7 @@
acc = q * UInt32(v[i]) + mk // multiply
mk = acc >> 16 // multiplication carry
acc = acc & 0xffff;
- let uu = u // work around compiler bug
- acc = 0xffff + UInt32(uu[ul - vl + i - UInt32(j) - UInt32(1)]) - acc + sk; // subtract
+ acc = 0xffff + UInt32(u[ul - vl + i - UInt32(j) - UInt32(1)]) - acc + sk; // subtract
sk = acc >> 16;
u[ul - vl + i - UInt32(j) - UInt32(1)] = UInt16(truncatingBitPattern:acc)
}
@@ -905,9 +906,7 @@
for i in 0...v._length {
let ul = u._length
let vl = v._length
- let vv = v // work around compiler bug
- let uu = u // work around compiler bug
- acc = UInt32(vv[i]) + UInt32(uu[UInt32(ul) - UInt32(vl) + UInt32(i) - UInt32(j) - UInt32(1)]) + k
+ acc = UInt32(v[i]) + UInt32(u[UInt32(ul) - UInt32(vl) + UInt32(i) - UInt32(j) - UInt32(1)]) + k
k = acc >> 16;
u[UInt32(ul) - UInt32(vl) + UInt32(i) - UInt32(j) - UInt32(1)] = UInt16(truncatingBitPattern:acc)
}
@@ -920,14 +919,12 @@
r._length = UInt32(ql);
- while r._length != 0 && r[r._length - 1] == 0 {
- r._length -= 1
- }
+ r.trimTrailingZeros()
return .noError;
}
-fileprivate func integerMultiplyByPowerOf10(_ result: inout WideDecimal, _ left: WideDecimal, _ p: Int) -> NSDecimalNumber.CalculationError {
+fileprivate func integerMultiplyByPowerOf10<T:VariableLengthNumber>(_ result: inout T, _ left: T, _ p: Int) -> NSDecimalNumber.CalculationError {
var power = p
if power == 0 {
result = left
@@ -943,10 +940,10 @@
var error:NSDecimalNumber.CalculationError = .noError
while power > maxpow10 {
- var big = WideDecimal()
+ var big = T()
power -= maxpow10
- let p10 = WideDecimal(pow10[maxpow10])
+ let p10 = pow10[maxpow10]
if !isNegative {
error = integerMultiply(&big,result,p10)
@@ -965,9 +962,10 @@
result._length = big._length
}
- var big = WideDecimal()
+ var big = T()
+
// Handle the rest of the power (<= maxpow10)
- let p10 = WideDecimal(pow10[Int(power)])
+ let p10 = pow10[Int(power)]
if !isNegative {
error = integerMultiply(&big, result, p10)
@@ -994,7 +992,7 @@
public func NSDecimalNormalize(_ a: UnsafeMutablePointer<Decimal>, _ b: UnsafeMutablePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
var diffexp = a.pointee.__exponent - b.pointee.__exponent
- var result = WideDecimal()
+ var result = Decimal()
//
// If the two numbers share the same exponents,
@@ -1030,19 +1028,49 @@
// Try to multiply aa to reach the same exponent level than bb
//
- if integerMultiplyByPowerOf10(&result, WideDecimal(aa.pointee), Int(diffexp)) == .noError {
+ if integerMultiplyByPowerOf10(&result, aa.pointee, Int(diffexp)) == .noError {
// Succeed. Adjust the length/exponent info
// and return no errorNSDecimalNormalize
- aa.pointee._length = result._length
- for i in 0..<result._length {
- aa.pointee[i] = result[i]
- }
- aa.pointee._isCompact = 0
+ aa.pointee.copyMantissa(from: result)
aa.pointee._exponent = bb.pointee._exponent
return .noError;
}
- NSUnimplemented() // work in progress
+ //
+ // Failed, restart from scratch
+ //
+ NSDecimalCopy(aa, &backup);
+
+ //
+ // What is the maximum pow10 we can apply to aa ?
+ //
+ let logBase10of2to16 = 4.81647993
+ let aaLength = aa.pointee._length
+ let maxpow10 = Int8(floor(Double(Decimal.maxSize - aaLength) * logBase10of2to16))
+
+ //
+ // Divide bb by this value
+ //
+ _ = integerMultiplyByPowerOf10(&result, bb.pointee, maxpow10 - diffexp)
+
+ bb.pointee.copyMantissa(from: result)
+ bb.pointee._exponent -= maxpow10 - diffexp;
+
+ //
+ // If bb > 0 multiply aa by the same value
+ //
+ if !bb.pointee.isZero {
+ _ = integerMultiplyByPowerOf10(&result, aa.pointee, Int(maxpow10))
+ aa.pointee.copyMantissa(from: result)
+ aa.pointee._exponent -= Int32(maxpow10)
+ } else {
+ bb.pointee._exponent = aa.pointee._exponent;
+ }
+
+ //
+ // the two exponents are now identical, but we've lost some digits in the operation.
+ //
+ return .lossOfPrecision;
}
public func NSDecimalAdd(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand: UnsafePointer<Decimal>, _ rightOperand: UnsafePointer<Decimal>, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError {
@@ -1233,9 +1261,7 @@
}
result._length = i;
- while result._length != 0 && result[result._length - 1] == 0 {
- result._length -= 1
- }
+ result.trimTrailingZeros()
return .noError;
}
@@ -1265,7 +1291,7 @@
var big = WideDecimal()
var calculationError:NSDecimalNumber.CalculationError = .noError
- calculationError = integerMultiply(&big,WideDecimal(leftOperand.pointee),WideDecimal(rightOperand.pointee))
+ calculationError = integerMultiply(&big,WideDecimal(leftOperand.pointee),rightOperand.pointee)
result.pointee._isNegative = (leftOperand.pointee._isNegative + rightOperand.pointee._isNegative) % 2
@@ -1340,7 +1366,7 @@
}
_ = integerMultiplyByPowerOf10(&big, WideDecimal(a), 38) // Trust me, it's 38 !
- _ = integerDivide(&big, big, WideDecimal(b))
+ _ = integerDivide(&big, big, b)
_ = fitMantissa(&big, &exponent, .down)
let length = min(big._length,Decimal.maxSize)
@@ -1386,23 +1412,84 @@
public func NSDecimalString(_ dcm: UnsafePointer<Decimal>, _ locale: AnyObject?) -> String {
guard locale == nil else {
- fatalError("Locale not supported: \(locale)")
+ fatalError("Locale not supported: \(locale!)")
}
return dcm.pointee.description
}
fileprivate protocol VariableLengthNumber {
var _length: UInt32 { get set }
+ init()
subscript(index:UInt32) -> UInt16 { get set }
var isZero:Bool { get }
+ mutating func copyMantissa<T:VariableLengthNumber>(from other:T)
+ mutating func zeroMantissa()
+ mutating func trimTrailingZeros()
+ var maxMantissaLength: UInt32 { get }
}
extension Decimal: VariableLengthNumber {
-
+ var maxMantissaLength:UInt32 {
+ return Decimal.maxSize
+ }
+ fileprivate mutating func zeroMantissa() {
+ for i in 0..<Decimal.maxSize {
+ self[i] = 0
+ }
+ }
+ internal mutating func trimTrailingZeros() {
+ if _length > Decimal.maxSize {
+ _length = Decimal.maxSize
+ }
+ while _length != 0 && self[_length - 1] == 0 {
+ _length -= 1
+ }
+ }
+ fileprivate mutating func copyMantissa<T : VariableLengthNumber>(from other: T) {
+ if other._length > maxMantissaLength {
+ for i in maxMantissaLength..<other._length {
+ guard other[i] == 0 else {
+ fatalError("Loss of precision during copy other[\(i)] \(other[i]) != 0")
+ }
+ }
+ }
+ let length = min(other._length, maxMantissaLength)
+ for i in 0..<length {
+ self[i] = other[i]
+ }
+ self._length = length
+ self._isCompact = 0
+ }
}
// Provides a way with dealing with extra-length decimals, used for calculations
fileprivate struct WideDecimal : VariableLengthNumber {
+ var maxMantissaLength:UInt32 {
+ return _extraWide ? 17 : 16
+ }
+
+ fileprivate mutating func zeroMantissa() {
+ for i in 0..<maxMantissaLength {
+ self[i] = 0
+ }
+ }
+ fileprivate mutating func trimTrailingZeros() {
+ while _length != 0 && self[_length - 1] == 0 {
+ _length -= 1
+ }
+ }
+ init() {
+ self.init(false)
+ }
+
+ fileprivate mutating func copyMantissa<T : VariableLengthNumber>(from other: T) {
+ let length = other is Decimal ? min(other._length,Decimal.maxSize) : other._length
+ for i in 0..<length {
+ self[i] = other[i]
+ }
+ self._length = length
+ }
+
var isZero: Bool {
return _length == 0
}
@@ -1417,14 +1504,14 @@
return UInt32(__length)
}
set {
- guard newValue <= Decimal.maxSize * 2 + 1 else {
- fatalError("Cannot set size to \(newValue)")
+ guard newValue <= maxMantissaLength else {
+ fatalError("Attempt to set a length greater than capacity \(newValue) > \(maxMantissaLength)")
}
__length = UInt16(newValue)
}
}
init(_ extraWide:Bool = false) {
- __length = UInt16(Decimal.maxSize * 2)
+ __length = 0
_mantissa = (UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0),UInt16(0))
_extraWide = extraWide
}
@@ -1479,26 +1566,6 @@
}
}
}
- public func compare(to rhs: WideDecimal) -> ComparisonResult {
- if self._length > rhs._length {
- return .orderedDescending
- }
- if self._length < rhs._length {
- return .orderedAscending
- }
- for i in (0..<self._length).reversed() {
- if self[i] > rhs[i] {
- return .orderedDescending
- }
- if self[i] < rhs[i] {
- return .orderedAscending
- }
- }
- return .orderedSame
- }
- public static func <(lhs: WideDecimal, rhs: WideDecimal) -> Bool {
- return lhs.compare(to:rhs) == .orderedAscending
- }
func toDecimal() -> Decimal {
var result = Decimal()
result._length = self._length
@@ -1630,7 +1697,7 @@
_exponent = newExponent;
self.compact();
}
- fileprivate func compare(to other:Decimal) -> ComparisonResult {
+ internal func compare(to other:Decimal) -> ComparisonResult {
// NaN is a special case and is arbitrary ordered before everything else
// Conceptually comparing with NaN is bogus anyway but raising or
// always returning the same answer will confuse the sorting algorithms
diff --git a/Foundation/NSDecimalNumber.swift b/Foundation/NSDecimalNumber.swift
index 759dc28..46b9b20 100644
--- a/Foundation/NSDecimalNumber.swift
+++ b/Foundation/NSDecimalNumber.swift
@@ -75,29 +75,86 @@
// Receiver can raise, return a new value, or return nil to ignore the exception.
+fileprivate func handle(_ error: NSDecimalNumber.CalculationError, _ handler: NSDecimalNumberBehaviors) {
+ // handle the error condition, such as throwing an error for over/underflow
+}
/*************** NSDecimalNumber: the class ***********/
open class NSDecimalNumber : NSNumber {
-
- public convenience init(mantissa: UInt64, exponent: Int16, isNegative flag: Bool) { NSUnimplemented() }
- public init(decimal dcm: Decimal) { NSUnimplemented() }
- public convenience init(string numberValue: String?) { NSUnimplemented() }
- public convenience init(string numberValue: String?, locale: AnyObject?) { NSUnimplemented() }
- public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ fileprivate let decimal: Decimal
+ public convenience init(mantissa: UInt64, exponent: Int16, isNegative: Bool) {
+ var d = Decimal()
+ d._exponent = Int32(exponent)
+ d._isNegative = isNegative ? 1 : 0
+ var man = mantissa
+ d._mantissa.0 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.1 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.2 = UInt16(man & 0xffff)
+ man >>= 4
+ d._mantissa.3 = UInt16(man & 0xffff)
+ d._length = 4
+ d.trimTrailingZeros()
+ // TODO more parts of the mantissa...
+ self.init(decimal: d)
+ }
+ public init(decimal dcm: Decimal) {
+ self.decimal = dcm
+ super.init()
+ }
+ public convenience init(string numberValue: String?) {
+ self.init(decimal: Decimal(string: numberValue ?? "") ?? Decimal.nan)
+ }
+ public convenience init(string numberValue: String?, locale: AnyObject?) {
+ self.init(decimal: Decimal(string: numberValue ?? "", locale: locale as? Locale) ?? Decimal.nan)
+ }
+
+ public required init?(coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ let exponent:Int32 = coder.decodeInt32(forKey: "NS.exponent")
+ let length:UInt32 = UInt32(coder.decodeInt32(forKey: "NS.length"))
+ let isNegative:UInt32 = UInt32(coder.decodeBool(forKey: "NS.negative") ? 1 : 0)
+ let isCompact:UInt32 = UInt32(coder.decodeBool(forKey: "NS.compact") ? 1 : 0)
+ // let byteOrder:UInt32 = UInt32(coder.decodeInt32(forKey: "NS.bo"))
+ guard let mantissaData: Data = coder.decodeObject(forKey: "NS.mantissa") as? Data else {
+ return nil // raise "Critical NSDecimalNumber archived data is missing"
+ }
+ guard mantissaData.count == Int(NSDecimalMaxSize * 2) else {
+ return nil // raise "Critical NSDecimalNumber archived data is wrong size"
+ }
+ // Byte order?
+ let mantissa:(UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16, UInt16) = (
+ UInt16(mantissaData[0]) << 8 & UInt16(mantissaData[1]),
+ UInt16(mantissaData[2]) << 8 & UInt16(mantissaData[3]),
+ UInt16(mantissaData[4]) << 8 & UInt16(mantissaData[5]),
+ UInt16(mantissaData[6]) << 8 & UInt16(mantissaData[7]),
+ UInt16(mantissaData[8]) << 8 & UInt16(mantissaData[9]),
+ UInt16(mantissaData[10]) << 8 & UInt16(mantissaData[11]),
+ UInt16(mantissaData[12]) << 8 & UInt16(mantissaData[13]),
+ UInt16(mantissaData[14]) << 8 & UInt16(mantissaData[15])
+ )
+ self.decimal = Decimal(_exponent: exponent, _length: length, _isNegative: isNegative, _isCompact: isCompact, _reserved: 0, _mantissa: mantissa)
+ super.init()
}
public required convenience init(floatLiteral value: Double) {
- NSUnimplemented()
+ self.init(decimal:Decimal(value))
}
public required convenience init(booleanLiteral value: Bool) {
- NSUnimplemented()
+ if value {
+ self.init(integerLiteral: 1)
+ } else {
+ self.init(integerLiteral: 0)
+ }
}
public required convenience init(integerLiteral value: Int) {
- NSUnimplemented()
+ self.init(decimal:Decimal(value))
}
public required convenience init(bytes buffer: UnsafeRawPointer, objCType type: UnsafePointer<Int8>) {
@@ -105,52 +162,180 @@
}
open override func description(withLocale locale: Locale?) -> String { NSUnimplemented() }
+
+ open class var zero: NSDecimalNumber {
+ return NSDecimalNumber(integerLiteral: 0)
+ }
+ open class var one: NSDecimalNumber {
+ return NSDecimalNumber(integerLiteral: 1)
+ }
+ open class var minimum: NSDecimalNumber {
+ return NSDecimalNumber(decimal:Decimal.leastFiniteMagnitude)
+ }
+ open class var maximum: NSDecimalNumber {
+ return NSDecimalNumber(decimal:Decimal.greatestFiniteMagnitude)
+
+ }
+ open class var notANumber: NSDecimalNumber {
+ return NSDecimalNumber(decimal: Decimal.nan)
+ }
- // TODO: "declarations from extensions cannot be overridden yet"
- // Although it's not clear we actually need to redeclare this here when the extension adds it to the superclass of this class
- // open var decimalValue: Decimal { NSUnimplemented() }
+ open func adding(_ other: NSDecimalNumber) -> NSDecimalNumber {
+ return adding(other, withBehavior: nil)
+ }
+ open func adding(_ other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalAdd(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+
+ open func subtracting(_ other: NSDecimalNumber) -> NSDecimalNumber {
+ return subtracting(other, withBehavior: nil)
+ }
+ open func subtracting(_ other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalSubtract(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+ open func multiplying(by other: NSDecimalNumber) -> NSDecimalNumber {
+ return multiplying(by: other, withBehavior: nil)
+ }
+ open func multiplying(by other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalMultiply(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
- open class var zero: NSDecimalNumber { NSUnimplemented() }
- open class var one: NSDecimalNumber { NSUnimplemented() }
- open class var minimum: NSDecimalNumber { NSUnimplemented() }
- open class var maximum: NSDecimalNumber { NSUnimplemented() }
- open class var notANumber: NSDecimalNumber { NSUnimplemented() }
+ open func dividing(by other: NSDecimalNumber) -> NSDecimalNumber {
+ return dividing(by: other, withBehavior: nil)
+ }
+ open func dividing(by other: NSDecimalNumber, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var left = self.decimal
+ var right = other.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalDivide(&result, &left, &right, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
- open func adding(_ decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func adding(_ decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func subtracting(_ decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func subtracting(_ decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func multiplying(by decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func multiplying(by decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func dividing(by decimalNumber: NSDecimalNumber) -> NSDecimalNumber { NSUnimplemented() }
- open func dividing(by decimalNumber: NSDecimalNumber, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func raising(toPower power: Int) -> NSDecimalNumber { NSUnimplemented() }
- open func raising(toPower power: Int, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
-
- open func multiplying(byPowerOf10 power: Int16) -> NSDecimalNumber { NSUnimplemented() }
- open func multiplying(byPowerOf10 power: Int16, withBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
+ open func raising(toPower power: Int) -> NSDecimalNumber {
+ return raising(toPower:power, withBehavior: nil)
+ }
+ open func raising(toPower power: Int, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var input = self.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalPower(&result, &input, power, roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
+
+ open func multiplying(byPowerOf10 power: Int16) -> NSDecimalNumber {
+ return multiplying(byPowerOf10: power, withBehavior: nil)
+ }
+ open func multiplying(byPowerOf10 power: Int16, withBehavior b: NSDecimalNumberBehaviors?) -> NSDecimalNumber {
+ var result = Decimal()
+ var input = self.decimal
+ let behavior = b ?? NSDecimalNumber.defaultBehavior
+ let roundingMode = behavior.roundingMode()
+ let error = NSDecimalPower(&result, &input, Int(power), roundingMode)
+ handle(error,behavior)
+ return NSDecimalNumber(decimal: result)
+ }
open func rounding(accordingToBehavior behavior: NSDecimalNumberBehaviors?) -> NSDecimalNumber { NSUnimplemented() }
// Round to the scale of the behavior.
- open override func compare(_ decimalNumber: NSNumber) -> ComparisonResult { NSUnimplemented() }
// compare two NSDecimalNumbers
-
- open class var defaultBehavior: NSDecimalNumberBehaviors { NSUnimplemented() }
+ open override func compare(_ decimalNumber: NSNumber) -> ComparisonResult {
+ if let num = decimalNumber as? NSDecimalNumber {
+ return decimal.compare(to:num.decimal)
+ } else {
+ return decimal.compare(to:Decimal(decimalNumber.doubleValue))
+ }
+ }
+
+ open class var defaultBehavior: NSDecimalNumberBehaviors {
+ return NSDecimalNumberHandler.defaultBehavior
+ }
// One behavior per thread - The default behavior is
// rounding mode: NSRoundPlain
// scale: No defined scale (full precision)
// ignore exactnessException
// raise on overflow, underflow and divide by zero.
-
- open override var objCType: UnsafePointer<Int8> { NSUnimplemented() }
+ static let OBJC_TYPE = "d".utf8CString
+
+ open override var objCType: UnsafePointer<Int8> {
+ return NSDecimalNumber.OBJC_TYPE.withUnsafeBufferPointer{ $0.baseAddress! }
+ }
// return 'd' for double
- open override var doubleValue: Double { NSUnimplemented() }
+ open override var int8Value: Int8 {
+ return Int8(decimal.doubleValue)
+ }
+ open override var uint8Value: UInt8 {
+ return UInt8(decimal.doubleValue)
+ }
+ open override var int16Value: Int16 {
+ return Int16(decimal.doubleValue)
+ }
+ open override var uint16Value: UInt16 {
+ return UInt16(decimal.doubleValue)
+ }
+ open override var int32Value: Int32 {
+ return Int32(decimal.doubleValue)
+ }
+ open override var uint32Value: UInt32 {
+ return UInt32(decimal.doubleValue)
+ }
+ open override var int64Value: Int64 {
+ return Int64(decimal.doubleValue)
+ }
+ open override var uint64Value: UInt64 {
+ return UInt64(decimal.doubleValue)
+ }
+ open override var floatValue: Float {
+ return Float(decimal.doubleValue)
+ }
+ open override var doubleValue: Double {
+ return decimal.doubleValue
+ }
+ open override var boolValue: Bool {
+ return !decimal.isZero
+ }
+ open override var intValue: Int {
+ return Int(decimal.doubleValue)
+ }
+ open override var uintValue: UInt {
+ return UInt(decimal.doubleValue)
+ }
+
+ open override func isEqual(_ value: Any?) -> Bool {
+ if let number = value as? NSDecimalNumber {
+ return self.decimal == number.decimal
+ } else {
+ return false
+ }
+ }
+
}
// return an approximate double value
@@ -158,33 +343,103 @@
/*********** A class for defining common behaviors *******/
open class NSDecimalNumberHandler : NSObject, NSDecimalNumberBehaviors, NSCoding {
-
- public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+
+ static let defaultBehavior = NSDecimalNumberHandler()
+
+ let _roundingMode: NSDecimalNumber.RoundingMode
+ let _scale:Int16
+
+ let _raiseOnExactness: Bool
+ let _raiseOnOverflow: Bool
+ let _raiseOnUnderflow: Bool
+ let _raiseOnDivideByZero: Bool
+
+ public override init() {
+ _roundingMode = .plain
+ _scale = Int16(NSDecimalNoScale)
+
+ _raiseOnExactness = false
+ _raiseOnOverflow = true
+ _raiseOnUnderflow = true
+ _raiseOnDivideByZero = true
+ }
+ public required init?(coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ _roundingMode = NSDecimalNumber.RoundingMode(rawValue: UInt(coder.decodeInteger(forKey: "NS.roundingMode")))!
+ if coder.containsValue(forKey: "NS.scale") {
+ _scale = Int16(coder.decodeInteger(forKey: "NS.scale"))
+ } else {
+ _scale = Int16(NSDecimalNoScale)
+ }
+ _raiseOnExactness = coder.decodeBool(forKey: "NS.raise.exactness")
+ _raiseOnOverflow = coder.decodeBool(forKey: "NS.raise.overflow")
+ _raiseOnUnderflow = coder.decodeBool(forKey: "NS.raise.underflow")
+ _raiseOnDivideByZero = coder.decodeBool(forKey: "NS.raise.dividebyzero")
}
- open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ open func encode(with coder: NSCoder) {
+ guard coder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+ if _roundingMode != .plain {
+ coder.encode(Int(_roundingMode.rawValue), forKey: "NS.roundingmode")
+ }
+ if _scale != Int16(NSDecimalNoScale) {
+ coder.encode(_scale, forKey:"NS.scale")
+ }
+ if _raiseOnExactness {
+ coder.encode(_raiseOnExactness, forKey:"NS.raise.exactness")
+ }
+ if _raiseOnOverflow {
+ coder.encode(_raiseOnOverflow, forKey:"NS.raise.overflow")
+ }
+ if _raiseOnUnderflow {
+ coder.encode(_raiseOnUnderflow, forKey:"NS.raise.underflow")
+ }
+ if _raiseOnDivideByZero {
+ coder.encode(_raiseOnDivideByZero, forKey:"NS.raise.dividebyzero")
+ }
}
- open class func `default`() -> NSDecimalNumberHandler { NSUnimplemented() }
+ open class func `default`() -> NSDecimalNumberHandler {
+ return defaultBehavior
+ }
// rounding mode: NSRoundPlain
// scale: No defined scale (full precision)
// ignore exactnessException (return nil)
// raise on overflow, underflow and divide by zero.
- public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool) { NSUnimplemented() }
+ public init(roundingMode: NSDecimalNumber.RoundingMode, scale: Int16, raiseOnExactness exact: Bool, raiseOnOverflow overflow: Bool, raiseOnUnderflow underflow: Bool, raiseOnDivideByZero divideByZero: Bool) {
+ _roundingMode = roundingMode
+ _scale = scale
+ _raiseOnExactness = exact
+ _raiseOnOverflow = overflow
+ _raiseOnUnderflow = underflow
+ _raiseOnDivideByZero = divideByZero
+ }
- open func roundingMode() -> NSDecimalNumber.RoundingMode { NSUnimplemented() }
+ open func roundingMode() -> NSDecimalNumber.RoundingMode {
+ return _roundingMode
+ }
- open func scale() -> Int16 { NSUnimplemented() }
- // The scale could return NO_SCALE for no defined scale.
+ // The scale could return NoScale for no defined scale.
+ open func scale() -> Int16 {
+ return _scale
+ }
}
extension NSNumber {
- public var decimalValue: Decimal { NSUnimplemented() }
+ public var decimalValue: Decimal {
+ if let d = self as? NSDecimalNumber {
+ return d.decimal
+ } else {
+ return Decimal(self.doubleValue)
+ }
+ }
}
// Could be silently inexact for float and double.
diff --git a/Foundation/NSKeyedArchiver.swift b/Foundation/NSKeyedArchiver.swift
index 003dc15..f9b473b 100644
--- a/Foundation/NSKeyedArchiver.swift
+++ b/Foundation/NSKeyedArchiver.swift
@@ -270,7 +270,9 @@
return NSKeyedArchiveNullObjectReference
}
- uid = self._objRefMap[objv as! AnyHashable]
+ let value = _SwiftValue.store(objv)!
+
+ uid = self._objRefMap[value]
if uid == nil {
if conditional {
return nil // object has not been unconditionally encoded
@@ -278,7 +280,7 @@
uid = UInt32(self._objects.count)
- self._objRefMap[objv as! AnyHashable] = uid
+ self._objRefMap[value] = uid
self._objects.insert(NSKeyedArchiveNullObjectReferenceName, at: Int(uid!))
}
@@ -292,7 +294,7 @@
if objv == nil {
return true // always have a null reference
} else {
- return self._objRefMap[objv as! AnyHashable] != nil
+ return self._objRefMap[_SwiftValue.store(objv)] != nil
}
}
@@ -361,10 +363,10 @@
*/
private func replaceObject(_ object: Any, withObject replacement: Any?) {
if let unwrappedDelegate = self.delegate {
- unwrappedDelegate.archiver(self, willReplace: object as! AnyHashable, with: replacement)
+ unwrappedDelegate.archiver(self, willReplace: object, with: replacement)
}
- self._replacementMap[object as! AnyHashable] = replacement
+ self._replacementMap[_SwiftValue.store(object)] = replacement
}
/**
@@ -476,9 +478,8 @@
// object replaced by NSObject.replacementObjectForKeyedArchiver
// if it is replaced with nil, it cannot be further replaced
- if objectToEncode == nil {
- let ns = object as? NSObject
- objectToEncode = ns?.replacementObjectForKeyedArchiver(self)
+ if let ns = objectToEncode as? NSObject {
+ objectToEncode = ns.replacementObjectForKeyedArchiver(self)
if objectToEncode == nil {
replaceObject(object!, withObject: nil)
return nil
@@ -510,7 +511,12 @@
haveVisited = _haveVisited(objv)
object = _replacementObject(objv)
-
+
+ // bridge value types
+ if let bridgedObject = object as? _ObjectBridgeable {
+ object = bridgedObject._bridgeToAnyObject()
+ }
+
objectRef = _referenceObject(object, conditional: conditional)
guard let unwrappedObjectRef = objectRef else {
// we can return nil if the object is being conditionally encoded
@@ -531,12 +537,9 @@
_pushEncodingContext(innerEncodingContext)
codable.encode(with: self)
- guard let ns = object as? NSObject else {
- fatalError("Attempt to encode non-NSObject");
- }
-
- let cls : AnyClass = ns.classForKeyedArchiver ?? type(of: object) as! AnyClass
-
+ let ns = object as? NSObject
+ let cls : AnyClass = ns?.classForKeyedArchiver ?? type(of: object!) as! AnyClass
+
_setObjectInCurrentEncodingContext(_classReference(cls), forKey: "$class", escape: false)
_popEncodingContext()
encodedObject = innerEncodingContext.dict
diff --git a/Foundation/NSKeyedUnarchiver.swift b/Foundation/NSKeyedUnarchiver.swift
index d9c691e..b3dfc8e 100644
--- a/Foundation/NSKeyedUnarchiver.swift
+++ b/Foundation/NSKeyedUnarchiver.swift
@@ -375,7 +375,7 @@
unwrappedDelegate.unarchiver(self, willReplace: object, with: replacement)
}
- self._replacementMap[object as! AnyHashable] = replacement
+ self._replacementMap[_SwiftValue.store(object)] = replacement
}
private func _decodingError(_ code: CocoaError.Code, withDescription description: String) -> NSError {
@@ -392,7 +392,7 @@
}
// check replacement cache
- object = self._replacementMap[decodedObject as! AnyHashable]
+ object = self._replacementMap[_SwiftValue.store(decodedObject)]
if object != nil {
return object
}
@@ -489,9 +489,8 @@
}
} else {
// reference to a non-container object
- // FIXME remove these special cases
- if let str = dereferencedObject as? String {
- object = str._bridgeToObjectiveC()
+ if let bridgedObject = dereferencedObject as? _ObjectBridgeable {
+ object = bridgedObject._bridgeToAnyObject()
} else {
object = dereferencedObject
}
diff --git a/Foundation/NSLock.swift b/Foundation/NSLock.swift
index c4a9f68..e166b80 100644
--- a/Foundation/NSLock.swift
+++ b/Foundation/NSLock.swift
@@ -115,7 +115,7 @@
open func lock(before limit: Date) -> Bool {
_cond.lock()
- while _thread == nil {
+ while _thread != nil {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
diff --git a/Foundation/NSNumber.swift b/Foundation/NSNumber.swift
index 724cc02..14bec84 100644
--- a/Foundation/NSNumber.swift
+++ b/Foundation/NSNumber.swift
@@ -290,7 +290,11 @@
super.init()
_CFNumberInitBool(_cfObject, value)
}
-
+
+ override internal init() {
+ super.init()
+ }
+
public required convenience init(bytes buffer: UnsafeRawPointer, objCType: UnsafePointer<Int8>) {
guard let type = _NSSimpleObjCType(UInt8(objCType.pointee)) else {
fatalError("NSNumber.init: unsupported type encoding spec '\(String(cString: objCType))'")
diff --git a/Foundation/NSString.swift b/Foundation/NSString.swift
index 32455e9..95f5e6c 100644
--- a/Foundation/NSString.swift
+++ b/Foundation/NSString.swift
@@ -817,7 +817,7 @@
return data
}
- return nil
+ return Data()
}
public func data(using encoding: UInt) -> Data? {
@@ -1008,8 +1008,10 @@
open func trimmingCharacters(in set: CharacterSet) -> String {
let len = length
var buf = _NSStringBuffer(string: self, start: 0, end: len)
- while !buf.isAtEnd && set.contains(UnicodeScalar(buf.currentCharacter)!) {
- buf.advance()
+ while !buf.isAtEnd,
+ let character = UnicodeScalar(buf.currentCharacter),
+ set.contains(character) {
+ buf.advance()
}
let startOfNonTrimmedRange = buf.location // This points at the first char not in the set
@@ -1018,8 +1020,10 @@
return ""
} else if startOfNonTrimmedRange < len - 1 {
buf.location = len - 1
- while set.contains(UnicodeScalar(buf.currentCharacter)!) && buf.location >= startOfNonTrimmedRange {
- buf.rewind()
+ while let character = UnicodeScalar(buf.currentCharacter),
+ set.contains(character),
+ buf.location >= startOfNonTrimmedRange {
+ buf.rewind()
}
let endOfNonTrimmedRange = buf.location
return substring(with: NSMakeRange(startOfNonTrimmedRange, endOfNonTrimmedRange + 1 - startOfNonTrimmedRange))
diff --git a/Foundation/NSURLCredential.swift b/Foundation/NSURLCredential.swift
index 300126a..32cd075 100644
--- a/Foundation/NSURLCredential.swift
+++ b/Foundation/NSURLCredential.swift
@@ -65,11 +65,32 @@
*/
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ func bridgeString(_ value: NSString) -> String? {
+ return String._unconditionallyBridgeFromObjectiveC(value)
+ }
+
+ let encodedUser = aDecoder.decodeObject(forKey: "NS._user") as! NSString
+ self._user = bridgeString(encodedUser)!
+
+ let encodedPassword = aDecoder.decodeObject(forKey: "NS._password") as! NSString
+ self._password = bridgeString(encodedPassword)!
+
+ let encodedPersistence = aDecoder.decodeObject(forKey: "NS._persistence") as! NSNumber
+ self._persistence = Persistence(rawValue: encodedPersistence.uintValue)!
}
open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ guard aCoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ aCoder.encode(self._user._bridgeToObjectiveC(), forKey: "NS._user")
+ aCoder.encode(self._password._bridgeToObjectiveC(), forKey: "NS._password")
+ aCoder.encode(self._persistence.rawValue._bridgeToObjectiveC(), forKey: "NS._persistence")
}
static public var supportsSecureCoding: Bool {
@@ -84,6 +105,17 @@
return self
}
+ open override func isEqual(_ object: Any?) -> Bool {
+ if let other = object as? URLCredential {
+ return other === self
+ || (other._user == self._user
+ && other._password == self._password
+ && other._persistence == self._persistence)
+ }
+
+ return false
+ }
+
/*!
@method persistence
@abstract Determine whether this credential is or should be stored persistently
diff --git a/Foundation/NSURLSession/HTTPMessage.swift b/Foundation/NSURLSession/HTTPMessage.swift
index 4f41eef..6598d06 100644
--- a/Foundation/NSURLSession/HTTPMessage.swift
+++ b/Foundation/NSURLSession/HTTPMessage.swift
@@ -143,7 +143,12 @@
var headersAsDictionary: [String: String] {
var result: [String: String] = [:]
headers.forEach {
- result[$0.name] = $0.value
+ if result[$0.name] == nil {
+ result[$0.name] = $0.value
+ }
+ else {
+ result[$0.name]! += (", " + $0.value)
+ }
}
return result
}
@@ -287,8 +292,13 @@
var value: String?
let line = headView[headView.index(after: nameRange.upperBound)..<headView.endIndex]
if !line.isEmpty {
- guard let v = line.trimSPHTPrefix else { return nil }
- value = String(v)
+ if line.hasSPHTPrefix && line.count == 1 {
+ // to handle empty headers i.e header without value
+ value = String("")
+ } else {
+ guard let v = line.trimSPHTPrefix else { return nil }
+ value = String(v)
+ }
}
do {
var t = tail
diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift
index f8b9569..27ad59f 100644
--- a/Foundation/NSURLSession/NSURLSessionTask.swift
+++ b/Foundation/NSURLSession/NSURLSessionTask.swift
@@ -88,7 +88,7 @@
originalRequest = nil
body = .none
workQueue = DispatchQueue(label: "URLSessionTask.notused.0")
- taskAttributesIsolation = DispatchQueue(label: "URLSessionTask.notused.1")
+ taskAttributesIsolation = DispatchQueue(label: "URLSessionTask.notused.1", attributes: DispatchQueue.Attributes.concurrent)
let fileName = NSTemporaryDirectory() + NSUUID().uuidString + ".tmp"
_ = FileManager.default.createFile(atPath: fileName, contents: nil)
self.tempFileURL = URL(fileURLWithPath: fileName)
@@ -145,7 +145,7 @@
return r
}
//TODO: dispatch_barrier_async
- set { taskAttributesIsolation.async { self._currentRequest = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._currentRequest = newValue } }
}
fileprivate var _currentRequest: URLRequest? = nil
/*@NSCopying*/ open fileprivate(set) var response: URLResponse? {
@@ -154,7 +154,7 @@
taskAttributesIsolation.sync { r = self._response }
return r
}
- set { taskAttributesIsolation.async { self._response = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._response = newValue } }
}
fileprivate var _response: URLResponse? = nil
@@ -170,7 +170,7 @@
taskAttributesIsolation.sync { r = self._countOfBytesReceived }
return r
}
- set { taskAttributesIsolation.async { self._countOfBytesReceived = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._countOfBytesReceived = newValue } }
}
fileprivate var _countOfBytesReceived: Int64 = 0
@@ -181,7 +181,7 @@
taskAttributesIsolation.sync { r = self._countOfBytesSent }
return r
}
- set { taskAttributesIsolation.async { self._countOfBytesSent = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._countOfBytesSent = newValue } }
}
fileprivate var _countOfBytesSent: Int64 = 0
@@ -213,7 +213,7 @@
taskAttributesIsolation.sync { r = self._state }
return r
}
- set { taskAttributesIsolation.async { self._state = newValue } }
+ set { taskAttributesIsolation.async(flags: .barrier) { self._state = newValue } }
}
fileprivate var _state: URLSessionTask.State = .suspended
@@ -298,7 +298,7 @@
return r
}
set {
- taskAttributesIsolation.async { self._priority = newValue }
+ taskAttributesIsolation.async(flags: .barrier) { self._priority = newValue }
}
}
fileprivate var _priority: Float = URLSessionTaskPriorityDefault
@@ -791,7 +791,7 @@
// to the delegate. But in case of redirects etc. we might send another
// request.
guard case .transferInProgress(let ts) = internalState else { fatalError("Transfer completed, but it wasn't in progress.") }
- guard let request = currentRequest else { fatalError("Transfer completed, but there's no currect request.") }
+ guard let request = currentRequest else { fatalError("Transfer completed, but there's no current request.") }
guard errorCode == nil else {
internalState = .transferFailed
failWith(errorCode: errorCode!, request: request)
diff --git a/Foundation/Notification.swift b/Foundation/Notification.swift
index 2ed74d0..d929dbe 100644
--- a/Foundation/Notification.swift
+++ b/Foundation/Notification.swift
@@ -76,7 +76,17 @@
extension Notification : CustomReflectable {
public var customMirror: Mirror {
- NSUnimplemented()
+ var children: [(label: String?, value: Any)] = [(label: "name", self.name.rawValue)]
+
+ if let object = self.object {
+ children.append((label: "object", object))
+ }
+
+ if let info = self.userInfo {
+ children.append((label: "userInfo", info))
+ }
+
+ return Mirror(self, children: children, displayStyle: .class)
}
}
diff --git a/TestFoundation/TestNSCharacterSet.swift b/TestFoundation/TestNSCharacterSet.swift
index 71ff177..7bd9d62 100644
--- a/TestFoundation/TestNSCharacterSet.swift
+++ b/TestFoundation/TestNSCharacterSet.swift
@@ -28,7 +28,7 @@
("testRanges", testRanges),
("testInsertAndRemove", testInsertAndRemove),
("testBasics", testBasics),
-
+ ("testClosedRanges_SR_2988", testClosedRanges_SR_2988),
("test_Predefines", test_Predefines),
("test_Range", test_Range),
("test_String", test_String),
@@ -223,6 +223,18 @@
}
}
+ func testClosedRanges_SR_2988() {
+ // "CharacterSet.insert(charactersIn: ClosedRange) crashes on a closed ClosedRange<UnicodeScalar> containing U+D7FF"
+ let problematicChar = UnicodeScalar(0xD7FF)!
+ let range = capitalA...problematicChar
+ var characters = CharacterSet(charactersIn: range) // this should not crash
+ XCTAssertTrue(characters.contains(problematicChar))
+ characters.remove(charactersIn: range) // this should not crash
+ XCTAssertTrue(!characters.contains(problematicChar))
+ characters.insert(charactersIn: range) // this should not crash
+ XCTAssertTrue(characters.contains(problematicChar))
+ }
+
func test_Bitmap() {
}
diff --git a/TestFoundation/TestNSData.swift b/TestFoundation/TestNSData.swift
index 9705c15..44daab7 100644
--- a/TestFoundation/TestNSData.swift
+++ b/TestFoundation/TestNSData.swift
@@ -89,6 +89,7 @@
("test_replaceBytes", test_replaceBytes),
("test_initDataWithCapacity", test_initDataWithCapacity),
("test_initDataWithCount", test_initDataWithCount),
+ ("test_emptyStringToData", test_emptyStringToData),
]
}
@@ -438,6 +439,11 @@
return
}
}
+
+ func test_emptyStringToData() {
+ let data = "".data(using: .utf8)!
+ XCTAssertEqual(0, data.count, "data from empty string is empty")
+ }
}
// Tests from Swift SDK Overlay
diff --git a/TestFoundation/TestNSDecimal.swift b/TestFoundation/TestNSDecimal.swift
index 72f33f4..ffddd40 100644
--- a/TestFoundation/TestNSDecimal.swift
+++ b/TestFoundation/TestNSDecimal.swift
@@ -19,18 +19,92 @@
static var allTests : [(String, (TestNSDecimal) -> () throws -> Void)] {
return [
+ ("test_AdditionWithNormalization", test_AdditionWithNormalization),
("test_BasicConstruction", test_BasicConstruction),
("test_Constants", test_Constants),
("test_Description", test_Description),
("test_ExplicitConstruction", test_ExplicitConstruction),
("test_Maths", test_Maths),
("test_Misc", test_Misc),
+ ("test_MultiplicationOverflow", test_MultiplicationOverflow),
+ ("test_NaNInput", test_NaNInput),
+ ("test_NegativeAndZeroMultiplication", test_NegativeAndZeroMultiplication),
("test_Normalise", test_Normalise),
- ("test_Round", test_Round),
("test_NSDecimal", test_NSDecimal),
+ ("test_PositivePowers", test_PositivePowers),
+ ("test_RepeatingDivision", test_RepeatingDivision),
+ ("test_Round", test_Round),
+ ("test_SimpleMultiplication", test_SimpleMultiplication),
+ ("test_SmallerNumbers", test_SmallerNumbers),
+ ("test_ZeroPower", test_ZeroPower),
]
}
+ func test_AdditionWithNormalization() {
+
+ let biggie = Decimal(65536)
+ let smallee = Decimal(65536)
+ let answer = biggie/smallee
+ XCTAssertEqual(Decimal(1),answer)
+
+ var one = Decimal(1)
+ var addend = Decimal(1)
+ var expected = Decimal()
+ var result = Decimal()
+
+ expected._isNegative = 0;
+ expected._isCompact = 0;
+
+ // 2 digits -- certain to work
+ addend._exponent = -1;
+ XCTAssertEqual(.noError, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 0.1")
+ expected._exponent = -1;
+ expected._length = 1;
+ expected._mantissa.0 = 11;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1.1 == 1 + 0.1")
+
+ // 38 digits -- guaranteed by NSDecimal to work
+ addend._exponent = -37;
+ XCTAssertEqual(.noError, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 1e-37")
+ expected._exponent = -37;
+ expected._length = 8;
+ expected._mantissa.0 = 0x0001;
+ expected._mantissa.1 = 0x0000;
+ expected._mantissa.2 = 0x36a0;
+ expected._mantissa.3 = 0x00f4;
+ expected._mantissa.4 = 0x46d9;
+ expected._mantissa.5 = 0xd5da;
+ expected._mantissa.6 = 0xee10;
+ expected._mantissa.7 = 0x0785;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1 + 1e-37")
+
+ // 39 digits -- not guaranteed to work but it happens to, so we make the test work either way
+ addend._exponent = -38;
+ let error = NSDecimalAdd(&result, &one, &addend, .plain)
+ XCTAssertTrue(error == .noError || error == .lossOfPrecision, "1 + 1e-38")
+ if error == .noError {
+ expected._exponent = -38;
+ expected._length = 8;
+ expected._mantissa.0 = 0x0001;
+ expected._mantissa.1 = 0x0000;
+ expected._mantissa.2 = 0x2240;
+ expected._mantissa.3 = 0x098a;
+ expected._mantissa.4 = 0xc47a;
+ expected._mantissa.5 = 0x5a86;
+ expected._mantissa.6 = 0x4ca8;
+ expected._mantissa.7 = 0x4b3b;
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "1 + 1e-38")
+ } else {
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 + 1e-38")
+ }
+
+ // 40 digits -- doesn't work; need to make sure it's rounding for us
+ addend._exponent = -39;
+ XCTAssertEqual(.lossOfPrecision, NSDecimalAdd(&result, &one, &addend, .plain), "1 + 1e-39")
+ XCTAssertEqual("1", result.description)
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 + 1e-39")
+ }
+
func test_BasicConstruction() {
let zero = Decimal()
XCTAssertEqual(20, MemoryLayout<Decimal>.size)
@@ -39,7 +113,7 @@
XCTAssertEqual(0, zero._isNegative)
XCTAssertEqual(0, zero._isCompact)
XCTAssertEqual(0, zero._reserved)
- let (m0,m1,m2,m3,m4,m5,m6,m7) = zero._mantissa
+ let (m0, m1, m2, m3, m4, m5, m6, m7) = zero._mantissa
XCTAssertEqual(0, m0)
XCTAssertEqual(0, m1)
XCTAssertEqual(0, m2)
@@ -59,47 +133,47 @@
XCTAssertFalse(zero.isSignaling)
}
func test_Constants() {
- XCTAssertEqual(8,NSDecimalMaxSize)
- XCTAssertEqual(32767,NSDecimalNoScale)
+ XCTAssertEqual(8, NSDecimalMaxSize)
+ XCTAssertEqual(32767, NSDecimalNoScale)
let smallest = Decimal(_exponent: 127, _length: 8, _isNegative: 1, _isCompact: 1, _reserved: 0, _mantissa: (UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max))
XCTAssertEqual(smallest, Decimal.leastFiniteMagnitude)
let biggest = Decimal(_exponent: 127, _length: 8, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max, UInt16.max))
XCTAssertEqual(biggest, Decimal.greatestFiniteMagnitude)
- let leastNormal = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1,0,0,0,0,0,0,0))
+ let leastNormal = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0))
XCTAssertEqual(leastNormal, Decimal.leastNormalMagnitude)
- let leastNonzero = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1,0,0,0,0,0,0,0))
+ let leastNonzero = Decimal(_exponent: -127, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0))
XCTAssertEqual(leastNonzero, Decimal.leastNonzeroMagnitude)
let pi = Decimal(_exponent: -38, _length: 8, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (0x6623, 0x7d57, 0x16e7, 0xad0d, 0xaf52, 0x4641, 0xdfa7, 0xec58))
- XCTAssertEqual(pi,Decimal.pi)
- XCTAssertEqual(10,Decimal.radix)
+ XCTAssertEqual(pi, Decimal.pi)
+ XCTAssertEqual(10, Decimal.radix)
XCTAssertTrue(Decimal().isCanonical)
XCTAssertFalse(Decimal().isSignalingNaN)
XCTAssertFalse(Decimal.nan.isSignalingNaN)
XCTAssertTrue(Decimal.nan.isNaN)
- XCTAssertEqual(.quietNaN,Decimal.nan.floatingPointClass)
- XCTAssertEqual(.positiveZero,Decimal().floatingPointClass)
- XCTAssertEqual(.negativeNormal,smallest.floatingPointClass)
- XCTAssertEqual(.positiveNormal,biggest.floatingPointClass)
+ XCTAssertEqual(.quietNaN, Decimal.nan.floatingPointClass)
+ XCTAssertEqual(.positiveZero, Decimal().floatingPointClass)
+ XCTAssertEqual(.negativeNormal, smallest.floatingPointClass)
+ XCTAssertEqual(.positiveNormal, biggest.floatingPointClass)
XCTAssertFalse(Double.nan.isFinite)
XCTAssertFalse(Double.nan.isInfinite)
}
func test_Description() {
- XCTAssertEqual("0",Decimal().description)
- XCTAssertEqual("0",Decimal(0).description)
- XCTAssertEqual("10",Decimal(_exponent: 1, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1,0,0,0,0,0,0,0)).description)
- XCTAssertEqual("10",Decimal(10).description)
- XCTAssertEqual("123.458",Decimal(_exponent: -3, _length: 2, _isNegative: 0, _isCompact:1, _reserved: 0, _mantissa: (57922,1,0,0,0,0,0,0)).description)
- XCTAssertEqual("123.458",Decimal(123.458).description)
- XCTAssertEqual("123",Decimal(UInt8(123)).description)
- XCTAssertEqual("45",Decimal(Int8(45)).description)
- XCTAssertEqual("3.14159265358979323846264338327950288419",Decimal.pi.description)
- XCTAssertEqual("-30000000000",Decimal(sign: .minus, exponent: 10, significand: Decimal(3)).description)
- XCTAssertEqual("300000",Decimal(sign: .plus, exponent: 5, significand: Decimal(3)).description)
- XCTAssertEqual("5",Decimal(signOf: Decimal(3), magnitudeOf: Decimal(5)).description)
- XCTAssertEqual("-5",Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(5)).description)
- XCTAssertEqual("5",Decimal(signOf: Decimal(3), magnitudeOf: Decimal(-5)).description)
- XCTAssertEqual("-5",Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(-5)).description)
+ XCTAssertEqual("0", Decimal().description)
+ XCTAssertEqual("0", Decimal(0).description)
+ XCTAssertEqual("10", Decimal(_exponent: 1, _length: 1, _isNegative: 0, _isCompact: 1, _reserved: 0, _mantissa: (1, 0, 0, 0, 0, 0, 0, 0)).description)
+ XCTAssertEqual("10", Decimal(10).description)
+ XCTAssertEqual("123.458", Decimal(_exponent: -3, _length: 2, _isNegative: 0, _isCompact:1, _reserved: 0, _mantissa: (57922, 1, 0, 0, 0, 0, 0, 0)).description)
+ XCTAssertEqual("123.458", Decimal(123.458).description)
+ XCTAssertEqual("123", Decimal(UInt8(123)).description)
+ XCTAssertEqual("45", Decimal(Int8(45)).description)
+ XCTAssertEqual("3.14159265358979323846264338327950288419", Decimal.pi.description)
+ XCTAssertEqual("-30000000000", Decimal(sign: .minus, exponent: 10, significand: Decimal(3)).description)
+ XCTAssertEqual("300000", Decimal(sign: .plus, exponent: 5, significand: Decimal(3)).description)
+ XCTAssertEqual("5", Decimal(signOf: Decimal(3), magnitudeOf: Decimal(5)).description)
+ XCTAssertEqual("-5", Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(5)).description)
+ XCTAssertEqual("5", Decimal(signOf: Decimal(3), magnitudeOf: Decimal(-5)).description)
+ XCTAssertEqual("-5", Decimal(signOf: Decimal(-3), magnitudeOf: Decimal(-5)).description)
}
func test_ExplicitConstruction() {
@@ -109,7 +183,7 @@
_isNegative: 3,
_isCompact: 4,
_reserved: UInt32(1<<18 + 1<<17 + 1),
- _mantissa: (6,7,8,9,10,11,12,13)
+ _mantissa: (6, 7, 8, 9, 10, 11, 12, 13)
)
XCTAssertEqual(0x7f, explicit._exponent)
XCTAssertEqual(0x7f, explicit.exponent)
@@ -119,7 +193,7 @@
XCTAssertTrue(explicit.isSignMinus)
XCTAssertEqual(0, explicit._isCompact)
XCTAssertEqual(UInt32(1<<17 + 1), explicit._reserved)
- let (m0,m1,m2,m3,m4,m5,m6,m7) = explicit._mantissa
+ let (m0, m1, m2, m3, m4, m5, m6, m7) = explicit._mantissa
XCTAssertEqual(6, m0)
XCTAssertEqual(7, m1)
XCTAssertEqual(8, m2)
@@ -143,7 +217,7 @@
XCTAssertEqual(0, significand._isNegative)
XCTAssertEqual(1, significand._isCompact)
XCTAssertEqual(0, significand._reserved)
- let (sm0,sm1,sm2,sm3,sm4,sm5,sm6,sm7) = significand._mantissa
+ let (sm0, sm1, sm2, sm3, sm4, sm5, sm6, sm7) = significand._mantissa
XCTAssertEqual(6, sm0)
XCTAssertEqual(7, sm1)
XCTAssertEqual(8, sm2)
@@ -204,14 +278,14 @@
}
func test_Misc() {
- XCTAssertEqual(.minus,Decimal(-5.2).sign)
- XCTAssertEqual(.plus,Decimal(5.2).sign)
+ XCTAssertEqual(.minus, Decimal(-5.2).sign)
+ XCTAssertEqual(.plus, Decimal(5.2).sign)
var d = Decimal(5.2)
- XCTAssertEqual(.plus,d.sign)
+ XCTAssertEqual(.plus, d.sign)
d.negate()
- XCTAssertEqual(.minus,d.sign)
+ XCTAssertEqual(.minus, d.sign)
d.negate()
- XCTAssertEqual(.plus,d.sign)
+ XCTAssertEqual(.plus, d.sign)
XCTAssertTrue(Decimal(3.5).isEqual(to: Decimal(3.5)))
XCTAssertTrue(Decimal.nan.isEqual(to: Decimal.nan))
XCTAssertTrue(Decimal(1.28).isLess(than: Decimal(2.24)))
@@ -228,46 +302,226 @@
XCTAssertFalse(Decimal.nan.isTotallyOrdered(belowOrEqualTo: Decimal(2.3)))
XCTAssertTrue(Decimal(2) < Decimal(3))
XCTAssertTrue(Decimal(3) > Decimal(2))
- XCTAssertEqual(3275573729074,Decimal(1234).hashValue)
+ XCTAssertEqual(3275573729074, Decimal(1234).hashValue)
XCTAssertEqual(Decimal(-9), Decimal(1) - Decimal(10))
- XCTAssertEqual(Decimal(3),Decimal(2).nextUp)
- XCTAssertEqual(Decimal(2),Decimal(3).nextDown)
- XCTAssertEqual(Decimal(-476),Decimal(1024).distance(to: Decimal(1500)))
- XCTAssertEqual(Decimal(68040),Decimal(386).advanced(by: Decimal(67654)))
- XCTAssertEqual(Decimal(1.234),abs(Decimal(1.234)))
- XCTAssertEqual(Decimal(1.234),abs(Decimal(-1.234)))
+ XCTAssertEqual(Decimal(3), Decimal(2).nextUp)
+ XCTAssertEqual(Decimal(2), Decimal(3).nextDown)
+ XCTAssertEqual(Decimal(-476), Decimal(1024).distance(to: Decimal(1500)))
+ XCTAssertEqual(Decimal(68040), Decimal(386).advanced(by: Decimal(67654)))
+ XCTAssertEqual(Decimal(1.234), abs(Decimal(1.234)))
+ XCTAssertEqual(Decimal(1.234), abs(Decimal(-1.234)))
var a = Decimal(1234)
- XCTAssertEqual(.noError,NSDecimalMultiplyByPowerOf10(&a,&a,1,.plain))
- XCTAssertEqual(Decimal(12340),a)
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, 1, .plain))
+ XCTAssertEqual(Decimal(12340), a)
a = Decimal(1234)
- XCTAssertEqual(.noError,NSDecimalMultiplyByPowerOf10(&a,&a,2,.plain))
- XCTAssertEqual(Decimal(123400),a)
- XCTAssertEqual(.overflow,NSDecimalMultiplyByPowerOf10(&a,&a,128,.plain))
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, 2, .plain))
+ XCTAssertEqual(Decimal(123400), a)
+ XCTAssertEqual(.overflow, NSDecimalMultiplyByPowerOf10(&a, &a, 128, .plain))
XCTAssertTrue(a.isNaN)
a = Decimal(1234)
- XCTAssertEqual(.noError,NSDecimalMultiplyByPowerOf10(&a,&a,-2,.plain))
- XCTAssertEqual(Decimal(12.34),a)
- XCTAssertEqual(.underflow,NSDecimalMultiplyByPowerOf10(&a,&a,-128,.plain))
+ XCTAssertEqual(.noError, NSDecimalMultiplyByPowerOf10(&a, &a, -2, .plain))
+ XCTAssertEqual(Decimal(12.34), a)
+ XCTAssertEqual(.underflow, NSDecimalMultiplyByPowerOf10(&a, &a, -128, .plain))
XCTAssertTrue(a.isNaN)
a = Decimal(1234)
- XCTAssertEqual(.noError,NSDecimalPower(&a,&a,0,.plain))
- XCTAssertEqual(Decimal(1),a)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 0, .plain))
+ XCTAssertEqual(Decimal(1), a)
a = Decimal(8)
- XCTAssertEqual(.noError,NSDecimalPower(&a,&a,2,.plain))
- XCTAssertEqual(Decimal(64),a)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 2, .plain))
+ XCTAssertEqual(Decimal(64), a)
a = Decimal(-2)
- XCTAssertEqual(.noError,NSDecimalPower(&a,&a,3,.plain))
- XCTAssertEqual(Decimal(-8),a)
+ XCTAssertEqual(.noError, NSDecimalPower(&a, &a, 3, .plain))
+ XCTAssertEqual(Decimal(-8), a)
for i in -2...10 {
for j in 0...5 {
var actual = Decimal(i)
- XCTAssertEqual(.noError,NSDecimalPower(&actual,&actual,j,.plain))
- let expected = Decimal(pow(Double(i),Double(j)))
+ XCTAssertEqual(.noError, NSDecimalPower(&actual, &actual, j, .plain))
+ let expected = Decimal(pow(Double(i), Double(j)))
XCTAssertEqual(expected, actual, "\(actual) == \(i)^\(j)")
}
}
}
+ func test_MultiplicationOverflow() {
+ var multiplicand = Decimal(_exponent: 0, _length: 8, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: ( 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff ))
+
+ var result = Decimal()
+ var multiplier = Decimal(1)
+
+ multiplier._mantissa.0 = 2
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "2 * max mantissa")
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplier, &multiplicand, .plain), "max mantissa * 2")
+
+ multiplier._exponent = 0x7f
+ XCTAssertEqual(.overflow, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "2e127 * max mantissa")
+ XCTAssertEqual(.overflow, NSDecimalMultiply(&result, &multiplier, &multiplicand, .plain), "max mantissa * 2e127")
+ }
+
+ func test_NaNInput() {
+ var NaN = Decimal.nan
+ var one = Decimal(1)
+ var result = Decimal()
+
+ XCTAssertNotEqual(.noError, NSDecimalAdd(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN + 1")
+ XCTAssertNotEqual(.noError, NSDecimalAdd(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 + NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalSubtract(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN - 1")
+ XCTAssertNotEqual(.noError, NSDecimalSubtract(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 - NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalMultiply(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN * 1")
+ XCTAssertNotEqual(.noError, NSDecimalMultiply(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 * NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalDivide(&result, &NaN, &one, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN / 1")
+ XCTAssertNotEqual(.noError, NSDecimalDivide(&result, &one, &NaN, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "1 / NaN")
+
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 0, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 0")
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 4, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 4")
+ XCTAssertNotEqual(.noError, NSDecimalPower(&result, &NaN, 5, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN ^ 5")
+
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 0, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e0")
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 4, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e4")
+ XCTAssertNotEqual(.noError, NSDecimalMultiplyByPowerOf10(&result, &NaN, 5, .plain))
+ XCTAssertTrue(NSDecimalIsNotANumber(&result), "NaN e5")
+ }
+
+ func test_NegativeAndZeroMultiplication() {
+ var one = Decimal(1)
+ var zero = Decimal(0)
+ var negativeOne = Decimal(-1)
+
+ var result = Decimal()
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &one, .plain), "1 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "1 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &negativeOne, .plain), "1 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&negativeOne, &result), "1 * -1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &one, .plain), "-1 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&negativeOne, &result), "-1 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &negativeOne, .plain), "-1 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&one, &result), "-1 * -1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &one, &zero, .plain), "1 * 0")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "1 * 0")
+ XCTAssertEqual(0, result._isNegative, "1 * 0")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &zero, &one, .plain), "0 * 1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "0 * 1")
+ XCTAssertEqual(0, result._isNegative, "0 * 1")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &negativeOne, &zero, .plain), "-1 * 0")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "-1 * 0")
+ XCTAssertEqual(0, result._isNegative, "-1 * 0")
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &zero, &negativeOne, .plain), "0 * -1")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&zero, &result), "0 * -1")
+ XCTAssertEqual(0, result._isNegative, "0 * -1")
+ }
+
+ func test_Normalise() {
+ var one = Decimal(1)
+ var ten = Decimal(-10)
+ XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain))
+ XCTAssertEqual(Decimal(1), one)
+ XCTAssertEqual(Decimal(-10), ten)
+ XCTAssertEqual(1, one._length)
+ XCTAssertEqual(1, ten._length)
+ one = Decimal(1)
+ ten = Decimal(10)
+ XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain))
+ XCTAssertEqual(Decimal(1), one)
+ XCTAssertEqual(Decimal(10), ten)
+ XCTAssertEqual(1, one._length)
+ XCTAssertEqual(1, ten._length)
+ }
+
+ func test_NSDecimal() {
+ var nan = Decimal.nan
+ XCTAssertTrue(NSDecimalIsNotANumber(&nan))
+ var zero = Decimal()
+ XCTAssertFalse(NSDecimalIsNotANumber(&zero))
+ var three = Decimal(3)
+ var guess = Decimal()
+ NSDecimalCopy(&guess, &three)
+ XCTAssertEqual(three, guess)
+
+ var f = Decimal(_exponent: 0, _length: 2, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
+ let before = f.description
+ XCTAssertEqual(0, f._isCompact)
+ NSDecimalCompact(&f)
+ XCTAssertEqual(1, f._isCompact)
+ let after = f.description
+ XCTAssertEqual(before, after)
+ }
+
+ func test_PositivePowers() {
+ let six = NSDecimalNumber(integerLiteral: 6)
+
+ XCTAssertEqual(6, six.raising(toPower:1).intValue)
+ XCTAssertEqual(36, six.raising(toPower:2).intValue)
+ XCTAssertEqual(216, six.raising(toPower:3).intValue)
+ XCTAssertEqual(1296, six.raising(toPower:4).intValue)
+ XCTAssertEqual(7776, six.raising(toPower:5).intValue)
+ XCTAssertEqual(46656, six.raising(toPower:6).intValue)
+ XCTAssertEqual(279936, six.raising(toPower:7).intValue)
+ XCTAssertEqual(1679616, six.raising(toPower:8).intValue)
+ XCTAssertEqual(10077696, six.raising(toPower:9).intValue)
+
+ let negativeSix = NSDecimalNumber(integerLiteral: -6)
+
+ XCTAssertEqual(-6, negativeSix.raising(toPower:1).intValue)
+ XCTAssertEqual(36, negativeSix.raising(toPower:2).intValue)
+ XCTAssertEqual(-216, negativeSix.raising(toPower:3).intValue)
+ XCTAssertEqual(1296, negativeSix.raising(toPower:4).intValue)
+ XCTAssertEqual(-7776, negativeSix.raising(toPower:5).intValue)
+ XCTAssertEqual(46656, negativeSix.raising(toPower:6).intValue)
+ XCTAssertEqual(-279936, negativeSix.raising(toPower:7).intValue)
+ XCTAssertEqual(1679616, negativeSix.raising(toPower:8).intValue)
+ XCTAssertEqual(-10077696, negativeSix.raising(toPower:9).intValue)
+ }
+
+ func test_RepeatingDivision() {
+ let repeatingNumerator = Decimal(16)
+ let repeatingDenominator = Decimal(9)
+ let repeating = repeatingNumerator / repeatingDenominator
+
+ let numerator = Decimal(1010)
+ var result = numerator / repeating
+
+ var expected = Decimal()
+ expected._exponent = -35;
+ expected._length = 8;
+ expected._isNegative = 0;
+ expected._isCompact = 1;
+ expected._reserved = 0;
+ expected._mantissa.0 = 51946;
+ expected._mantissa.1 = 3;
+ expected._mantissa.2 = 15549;
+ expected._mantissa.3 = 55864;
+ expected._mantissa.4 = 57984;
+ expected._mantissa.5 = 55436;
+ expected._mantissa.6 = 45186;
+ expected._mantissa.7 = 10941;
+
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "568.12500000000000000000000000000248554: \(expected.description) != \(result.description)");
+ }
+
func test_Round() {
let testCases = [
// expected, start, scale, round
@@ -290,48 +544,65 @@
( -5.5, -5.5, 1, Decimal.RoundingMode.up ),
( -6.5, -6.5, 1, Decimal.RoundingMode.plain ),
( -7.5, -7.5, 1, Decimal.RoundingMode.bankers ),
- ]
+ ]
for testCase in testCases {
let (expected, start, scale, mode) = testCase
var num = Decimal(start)
- NSDecimalRound(&num,&num,scale,mode)
+ NSDecimalRound(&num, &num, scale, mode)
XCTAssertEqual(Decimal(expected), num)
}
}
- func test_Normalise() {
- var one = Decimal(1)
- var ten = Decimal(-10)
- XCTAssertEqual(.noError,NSDecimalNormalize(&one,&ten,.plain))
- XCTAssertEqual(Decimal(1),one)
- XCTAssertEqual(Decimal(-10),ten)
- XCTAssertEqual(1,one._length)
- XCTAssertEqual(1,ten._length)
- one = Decimal(1)
- ten = Decimal(10)
- XCTAssertEqual(.noError,NSDecimalNormalize(&one,&ten,.plain))
- XCTAssertEqual(Decimal(1),one)
- XCTAssertEqual(Decimal(10),ten)
- XCTAssertEqual(1,one._length)
- XCTAssertEqual(1,ten._length)
+ func test_SimpleMultiplication() {
+ var multiplicand = Decimal()
+ multiplicand._isNegative = 0
+ multiplicand._isCompact = 0
+ multiplicand._length = 1
+ multiplicand._exponent = 1
+
+ var multiplier = multiplicand
+ multiplier._exponent = 2
+
+ var expected = multiplicand
+ expected._isNegative = 0
+ expected._isCompact = 0
+ expected._exponent = 3
+ expected._length = 1
+
+ var result = Decimal()
+
+ for i in 1..<UInt8.max {
+ multiplicand._mantissa.0 = UInt16(i)
+
+ for j in 1..<UInt8.max {
+ multiplier._mantissa.0 = UInt16(j)
+ expected._mantissa.0 = UInt16(i) * UInt16(j)
+
+ XCTAssertEqual(.noError, NSDecimalMultiply(&result, &multiplicand, &multiplier, .plain), "\(i) * \(j)")
+ XCTAssertEqual(.orderedSame, NSDecimalCompare(&expected, &result), "\(expected._mantissa.0) == \(i) * \(j)");
+ }
+ }
}
- func test_NSDecimal() {
- var nan = Decimal.nan
- XCTAssertTrue(NSDecimalIsNotANumber(&nan))
- var zero = Decimal()
- XCTAssertFalse(NSDecimalIsNotANumber(&zero))
- var three = Decimal(3)
- var guess = Decimal()
- NSDecimalCopy(&guess,&three)
- XCTAssertEqual(three,guess)
+ func test_SmallerNumbers() {
+ var number = NSDecimalNumber(booleanLiteral:true)
+ XCTAssertTrue(number.boolValue, "Should have received true")
- var f = Decimal(_exponent: 0, _length: 2, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000))
- let before = f.description
- XCTAssertEqual(0,f._isCompact)
- NSDecimalCompact(&f)
- XCTAssertEqual(1,f._isCompact)
- let after = f.description
- XCTAssertEqual(before,after)
+ number = NSDecimalNumber(mantissa:0, exponent:0, isNegative:false)
+ XCTAssertFalse(number.boolValue, "Should have received false")
+
+ number = NSDecimalNumber(mantissa:1, exponent:0, isNegative:false)
+ XCTAssertTrue(number.boolValue, "Should have received true")
+
+ XCTAssertEqual(100,number.objCType.pointee, "ObjC type for NSDecimalNumber is 'd'")
}
+
+ func test_ZeroPower() {
+ let six = NSDecimalNumber(integerLiteral: 6)
+ XCTAssertEqual(1, six.raising(toPower: 0))
+
+ let negativeSix = NSDecimalNumber(integerLiteral: -6)
+ XCTAssertEqual(1, negativeSix.raising(toPower: 0))
+ }
+
}
diff --git a/TestFoundation/TestNSKeyedArchiver.swift b/TestFoundation/TestNSKeyedArchiver.swift
index 19ba3d0..6e6b529 100644
--- a/TestFoundation/TestNSKeyedArchiver.swift
+++ b/TestFoundation/TestNSKeyedArchiver.swift
@@ -16,7 +16,7 @@
import SwiftXCTest
#endif
-public class UserClass : NSObject, NSSecureCoding {
+public class NSUserClass : NSObject, NSSecureCoding {
var ivar : Int
public class var supportsSecureCoding: Bool {
@@ -37,12 +37,12 @@
public override var description: String {
get {
- return "UserClass \(ivar)"
+ return "NSUserClass \(ivar)"
}
}
public override func isEqual(_ object: Any?) -> Bool {
- if let custom = object as? UserClass {
+ if let custom = object as? NSUserClass {
return self.ivar == custom.ivar
} else {
return false
@@ -50,6 +50,40 @@
}
}
+public class UserClass : CustomStringConvertible, Equatable, Hashable, NSSecureCoding {
+ var ivar : Int
+
+ public class var supportsSecureCoding: Bool {
+ return true
+ }
+
+ public func encode(with aCoder : NSCoder) {
+ aCoder.encode(ivar, forKey:"$ivar") // also test escaping
+ }
+
+ init(_ value: Int) {
+ self.ivar = value
+ }
+
+ public required init?(coder aDecoder: NSCoder) {
+ self.ivar = aDecoder.decodeInteger(forKey: "$ivar")
+ }
+
+ public var description: String {
+ get {
+ return "UserClass \(ivar)"
+ }
+ }
+
+ public static func ==(lhs: UserClass, rhs: UserClass) -> Bool {
+ return lhs.ivar == rhs.ivar
+ }
+
+ public var hashValue: Int {
+ return ivar
+ }
+}
+
class TestNSKeyedArchiver : XCTestCase {
static var allTests: [(String, (TestNSKeyedArchiver) -> () throws -> Void)] {
return [
@@ -62,6 +96,7 @@
("test_archive_string", test_archive_string),
("test_archive_mutable_array", test_archive_mutable_array),
("test_archive_mutable_dictionary", test_archive_mutable_dictionary),
+ ("test_archive_ns_user_class", test_archive_ns_user_class),
("test_archive_nspoint", test_archive_nspoint),
("test_archive_nsrange", test_archive_nsrange),
("test_archive_nsrect", test_archive_nsrect),
@@ -69,7 +104,8 @@
("test_archive_set", test_archive_set),
("test_archive_url", test_archive_url),
("test_archive_user_class", test_archive_user_class),
- ("test_archive_uuid", test_archive_uuid),
+ ("test_archive_uuid_bvref", test_archive_uuid_byref),
+ ("test_archive_uuid_byvalue", test_archive_uuid_byvalue),
]
}
@@ -85,7 +121,7 @@
XCTAssertTrue(decode(unarchiver))
}
- private func test_archive(_ object: NSObject, classes: [AnyClass], allowsSecureCoding: Bool = true, outputFormat: PropertyListSerialization.PropertyListFormat) {
+ private func test_archive(_ object: Any, classes: [AnyClass], allowsSecureCoding: Bool = true, outputFormat: PropertyListSerialization.PropertyListFormat) {
test_archive({ archiver -> Bool in
archiver.requiresSecureCoding = allowsSecureCoding
archiver.outputFormat = outputFormat
@@ -97,12 +133,12 @@
unarchiver.requiresSecureCoding = allowsSecureCoding
do {
- let rootObj = try unarchiver.decodeTopLevelObject(of: classes, forKey: NSKeyedArchiveRootObjectKey)
- guard let root = rootObj as? NSObject else {
+ guard let rootObj = try unarchiver.decodeTopLevelObject(of: classes, forKey: NSKeyedArchiveRootObjectKey) else {
XCTFail("Unable to decode data")
return false
}
- XCTAssertEqual(object, root, "unarchived object \(root) does not match \(object)")
+
+ XCTAssertEqual(object as? AnyHashable, rootObj as? AnyHashable, "unarchived object \(rootObj) does not match \(object)")
} catch {
XCTFail("Error thrown: \(error)")
}
@@ -110,13 +146,13 @@
})
}
- private func test_archive(_ object: NSObject, classes: [AnyClass], allowsSecureCoding: Bool = true) {
+ private func test_archive(_ object: Any, classes: [AnyClass], allowsSecureCoding: Bool = true) {
// test both XML and binary encodings
test_archive(object, classes: classes, allowsSecureCoding: allowsSecureCoding, outputFormat: PropertyListSerialization.PropertyListFormat.xml)
test_archive(object, classes: classes, allowsSecureCoding: allowsSecureCoding, outputFormat: PropertyListSerialization.PropertyListFormat.binary)
}
- private func test_archive(_ object: NSObject, allowsSecureCoding: Bool = true) {
+ private func test_archive(_ object: AnyObject, allowsSecureCoding: Bool = true) {
return test_archive(object, classes: [type(of: object)], allowsSecureCoding: allowsSecureCoding)
}
@@ -252,8 +288,18 @@
test_archive(userClass)
}
- func test_archive_uuid() {
+ func test_archive_ns_user_class() {
+ let nsUserClass = NSUserClass(5678)
+ test_archive(nsUserClass)
+ }
+
+ func test_archive_uuid_byref() {
let uuid = NSUUID()
test_archive(uuid)
}
+
+ func test_archive_uuid_byvalue() {
+ let uuid = UUID()
+ return test_archive(uuid, classes: [NSUUID.self])
+ }
}
diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift
index 5ce2ae4..927e989 100644
--- a/TestFoundation/TestNSRange.swift
+++ b/TestFoundation/TestNSRange.swift
@@ -23,7 +23,13 @@
return [
// currently disabled due to pending requirements for NSString
// ("test_NSRangeFromString", test_NSRangeFromString ),
- ("test_NSRangeBridging", test_NSRangeBridging)
+ ("test_NSRangeBridging", test_NSRangeBridging),
+ ("test_NSMaxRange", test_NSMaxRange),
+ ("test_NSLocationInRange", test_NSLocationInRange),
+ ("test_NSEqualRanges", test_NSEqualRanges),
+ ("test_NSUnionRange", test_NSUnionRange),
+ ("test_NSIntersectionRange", test_NSIntersectionRange),
+ ("test_NSStringFromRange", test_NSStringFromRange),
]
}
@@ -66,4 +72,69 @@
let swiftRange2 = range.toRange()
XCTAssertEqual(swiftRange, swiftRange2)
}
+
+ func test_NSMaxRange() {
+ let ranges = [(NSMakeRange(0, 3), 3),
+ (NSMakeRange(7, 8), 15),
+ (NSMakeRange(56, 1), 57)]
+ for (range, result) in ranges {
+ XCTAssertEqual(NSMaxRange(range), result)
+ }
+ }
+
+ func test_NSLocationInRange() {
+ let ranges = [(3, NSMakeRange(0, 5), true),
+ (10, NSMakeRange(2, 9), true),
+ (7, NSMakeRange(2, 5), false),
+ (5, NSMakeRange(5, 1), true)];
+ for (location, range, result) in ranges {
+ XCTAssertEqual(NSLocationInRange(location, range), result);
+ }
+ }
+
+ func test_NSEqualRanges() {
+ let ranges = [(NSMakeRange(0, 3), NSMakeRange(0, 3), true),
+ (NSMakeRange(0, 4), NSMakeRange(0, 8), false),
+ (NSMakeRange(3, 6), NSMakeRange(3, 10), false),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), false)]
+ for (first, second, result) in ranges {
+ XCTAssertEqual(NSEqualRanges(first, second), result)
+ }
+ }
+
+
+ func test_NSUnionRange() {
+ let ranges = [(NSMakeRange(0, 5), NSMakeRange(3, 8), NSMakeRange(0, 11)),
+ (NSMakeRange(6, 10), NSMakeRange(3, 8), NSMakeRange(3, 13)),
+ (NSMakeRange(3, 8), NSMakeRange(6, 10), NSMakeRange(3, 13)),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), NSMakeRange(0, 15)),
+ (NSMakeRange(0, 3), NSMakeRange(1, 2), NSMakeRange(0, 3))]
+ for (first, second, result) in ranges {
+ XCTAssert(NSEqualRanges(NSUnionRange(first, second), result))
+ }
+ }
+
+ func test_NSIntersectionRange() {
+ let ranges = [(NSMakeRange(0, 5), NSMakeRange(3, 8), NSMakeRange(3, 2)),
+ (NSMakeRange(6, 10), NSMakeRange(3, 8), NSMakeRange(6, 5)),
+ (NSMakeRange(3, 8), NSMakeRange(6, 10), NSMakeRange(6, 5)),
+ (NSMakeRange(0, 5), NSMakeRange(7, 8), NSMakeRange(0, 0)),
+ (NSMakeRange(0, 3), NSMakeRange(1, 2), NSMakeRange(1, 2))]
+ for (first, second, result) in ranges {
+ XCTAssert(NSEqualRanges(NSIntersectionRange(first, second), result))
+ }
+ }
+
+ func test_NSStringFromRange() {
+ let ranges = ["{0, 0}": NSMakeRange(0, 0),
+ "{6, 4}": NSMakeRange(6, 4),
+ "{0, 10}": NSMakeRange(0, 10),
+ "{10, 200}": NSMakeRange(10, 200),
+ "{100, 10}": NSMakeRange(100, 10),
+ "{1000, 100000}": NSMakeRange(1000, 100_000)];
+
+ for (string, range) in ranges {
+ XCTAssertEqual(NSStringFromRange(range), string)
+ }
+ }
}
diff --git a/TestFoundation/TestNSString.swift b/TestFoundation/TestNSString.swift
index 1767982..ebb8fab 100644
--- a/TestFoundation/TestNSString.swift
+++ b/TestFoundation/TestNSString.swift
@@ -81,7 +81,11 @@
("test_resolvingSymlinksInPath", test_resolvingSymlinksInPath),
("test_expandingTildeInPath", test_expandingTildeInPath),
("test_standardizingPath", test_standardizingPath),
- ("test_removingPercentEncoding", test_removingPercentEncoding),
+ ("test_addingPercentEncoding", test_addingPercentEncoding),
+ ("test_removingPercentEncodingInLatin", test_removingPercentEncodingInLatin),
+ ("test_removingPercentEncodingInNonLatin", test_removingPercentEncodingInNonLatin),
+ ("test_removingPersentEncodingWithoutEncoding", test_removingPersentEncodingWithoutEncoding),
+ ("test_addingPercentEncodingAndBack", test_addingPercentEncodingAndBack),
("test_stringByAppendingPathExtension", test_stringByAppendingPathExtension),
("test_deletingPathExtension", test_deletingPathExtension),
("test_ExternalRepresentation", test_ExternalRepresentation),
@@ -602,6 +606,9 @@
let characterSet = CharacterSet.whitespaces
let string: NSString = " abc "
XCTAssertEqual(string.trimmingCharacters(in: characterSet), "abc")
+
+ let emojiString: NSString = " \u{1F62C} "
+ XCTAssertEqual(emojiString.trimmingCharacters(in: characterSet), "\u{1F62C}")
}
func test_initializeWithFormat() {
@@ -864,13 +871,66 @@
}
}
- func test_removingPercentEncoding() {
+ func test_addingPercentEncoding() {
+ let s1 = "a b".addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ XCTAssertEqual(s1, "a%20b")
+
+ let s2 = "\u{0434}\u{043E}\u{043C}".addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ XCTAssertEqual(s2, "%D0%B4%D0%BE%D0%BC")
+ }
+
+ func test_removingPercentEncodingInLatin() {
let s1 = "a%20b".removingPercentEncoding
XCTAssertEqual(s1, "a b")
let s2 = "a%1 b".removingPercentEncoding
XCTAssertNil(s2, "returns nil for a string with an invalid percent encoding")
}
+ func test_removingPercentEncodingInNonLatin() {
+ let s1 = "\u{043C}\u{043E}\u{0439}%20\u{0434}\u{043E}\u{043C}".removingPercentEncoding
+ XCTAssertEqual(s1, "\u{043C}\u{043E}\u{0439} \u{0434}\u{043E}\u{043C}")
+
+ let s2 = "%D0%B4%D0%BE%D0%BC".removingPercentEncoding
+ XCTAssertEqual(s2, "\u{0434}\u{043E}\u{043C}")
+
+ let s3 = "\u{00E0}a%1 b".removingPercentEncoding
+ XCTAssertNil(s3, "returns nil for a string with an invalid percent encoding")
+ }
+
+ func test_removingPersentEncodingWithoutEncoding() {
+ let cyrillicString = "\u{0434}\u{043E}\u{043C}"
+ let cyrillicEscapedString = cyrillicString.removingPercentEncoding
+ XCTAssertEqual(cyrillicString, cyrillicEscapedString)
+
+ let chineseString = "\u{623F}\u{5B50}"
+ let chineseEscapedString = chineseString.removingPercentEncoding
+ XCTAssertEqual(chineseString, chineseEscapedString)
+
+ let arabicString = "\u{0645}\u{0646}\u{0632}\u{0644}"
+ let arabicEscapedString = arabicString.removingPercentEncoding
+ XCTAssertEqual(arabicString, arabicEscapedString)
+
+ let randomString = "\u{00E0}\u{00E6}"
+ let randomEscapedString = randomString.removingPercentEncoding
+ XCTAssertEqual(randomString, randomEscapedString)
+
+ let latinString = "home"
+ let latinEscapedString = latinString.removingPercentEncoding
+ XCTAssertEqual(latinString, latinEscapedString)
+ }
+
+ func test_addingPercentEncodingAndBack() {
+ let latingString = "a b"
+ let escapedLatingString = latingString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ let returnedLatingString = escapedLatingString?.removingPercentEncoding
+ XCTAssertEqual(returnedLatingString, latingString)
+
+ let cyrillicString = "\u{0434}\u{043E}\u{043C}"
+ let escapedCyrillicString = cyrillicString.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
+ let returnedCyrillicString = escapedCyrillicString?.removingPercentEncoding
+ XCTAssertEqual(returnedCyrillicString, cyrillicString)
+ }
+
func test_stringByAppendingPathExtension() {
let values = [
NSString(string: "/tmp/scratch.old") : "/tmp/scratch.old.tiff",
diff --git a/TestFoundation/TestNSURLCredential.swift b/TestFoundation/TestNSURLCredential.swift
index 542c857..037b114 100644
--- a/TestFoundation/TestNSURLCredential.swift
+++ b/TestFoundation/TestNSURLCredential.swift
@@ -21,7 +21,8 @@
static var allTests: [(String, (TestNSURLCredential) -> () throws -> Void)] {
return [
("test_construction", test_construction),
- ("test_copy", test_copy)
+ ("test_copy", test_copy),
+ ("test_NSCoding", test_NSCoding)
]
}
@@ -39,4 +40,10 @@
let copy = credential.copy() as! URLCredential
XCTAssertTrue(copy.isEqual(credential))
}
+
+ func test_NSCoding() {
+ let credentialA = URLCredential(user: "swiftUser", password: "swiftPassword", persistence: .forSession)
+ let credentialB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: credentialA)) as! URLCredential
+ XCTAssertEqual(credentialA, credentialB, "Archived then unarchived url credential must be equal.")
+ }
}
diff --git a/TestFoundation/TestNotification.swift b/TestFoundation/TestNotification.swift
new file mode 100644
index 0000000..9c1bd38
--- /dev/null
+++ b/TestFoundation/TestNotification.swift
@@ -0,0 +1,56 @@
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+
+
+
+#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
+ import Foundation
+ import XCTest
+#else
+ import SwiftFoundation
+ import SwiftXCTest
+#endif
+
+
+
+class TestNotification : XCTestCase {
+
+ static var allTests: [(String, (TestNotification) -> () throws -> Void)] {
+ return [
+ ("test_customReflection", test_customReflection),
+ ]
+ }
+
+ func test_customReflection() {
+ let someName = "somenotifname"
+ let targetObject = NSObject()
+ let userInfo = ["hello": "world", "indexThis": 350] as [AnyHashable: Any]
+ let notif = Notification(name: Notification.Name(rawValue: someName), object: targetObject, userInfo: userInfo)
+ let mirror = notif.customMirror
+
+ XCTAssertEqual(mirror.displayStyle, .class)
+ XCTAssertNil(mirror.superclassMirror)
+
+ var children = Array(mirror.children).makeIterator()
+ let firstChild = children.next()
+ let secondChild = children.next()
+ let thirdChild = children.next()
+ XCTAssertEqual(firstChild?.label, "name")
+ XCTAssertEqual(firstChild?.value as? String, someName)
+
+ XCTAssertEqual(secondChild?.label, "object")
+ XCTAssertEqual(secondChild?.value as? NSObject, targetObject)
+
+ XCTAssertEqual(thirdChild?.label, "userInfo")
+ XCTAssertEqual((thirdChild?.value as? [AnyHashable: Any])?["hello"] as? String, "world")
+ XCTAssertEqual((thirdChild?.value as? [AnyHashable: Any])?["indexThis"] as? Int, 350)
+
+ }
+
+}
diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift
index 517d740..732bf17 100644
--- a/TestFoundation/main.swift
+++ b/TestFoundation/main.swift
@@ -87,4 +87,5 @@
testCase(TestProgressFraction.allTests),
testCase(TestProgress.allTests),
testCase(TestObjCRuntime.allTests),
+ testCase(TestNotification.allTests),
])