Skip to content

Commit ca58521

Browse files
committed
More tests.
1 parent 9d47821 commit ca58521

File tree

4 files changed

+135
-7
lines changed

4 files changed

+135
-7
lines changed

Foundation/NSNumber.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,34 @@ open class NSNumber : NSValue {
622622
fatalError("unsupported CFNumberType: '\(numberType)'")
623623
}
624624
}
625+
626+
internal var _swiftValueOfOptimalType: Any {
627+
if self === kCFBooleanTrue {
628+
return true
629+
} else if self === kCFBooleanFalse {
630+
return false
631+
}
632+
633+
let numberType = _CFNumberGetType2(_cfObject)
634+
switch numberType {
635+
case kCFNumberSInt8Type:
636+
return Int(int8Value)
637+
case kCFNumberSInt16Type:
638+
return Int(int16Value)
639+
case kCFNumberSInt32Type:
640+
return Int(int32Value)
641+
case kCFNumberSInt64Type:
642+
return int64Value < Int.max ? Int(int64Value) : int64Value
643+
case kCFNumberFloat32Type:
644+
return floatValue
645+
case kCFNumberFloat64Type:
646+
return doubleValue
647+
case kCFNumberSInt128Type:
648+
return int128Value
649+
default:
650+
fatalError("unsupported CFNumberType: '\(numberType)'")
651+
}
652+
}
625653

626654
deinit {
627655
_CFDeinit(self)

Foundation/UserDefaults.swift

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ internal func plistValueAsNSObject(_ value: Any) -> NSObject? {
2929
nsValue = NSNumber(value: val)
3030
} else if let val = value as? Data {
3131
nsValue = val._nsObject
32+
} else if let val = value as? Date {
33+
nsValue = val._nsObject
34+
} else if let val = value as? [Any] {
35+
var nsValues: [NSObject] = []
36+
for innerValue in val {
37+
guard let nsInnerValue = plistValueAsNSObject(innerValue) else { return nil }
38+
nsValues.append(nsInnerValue)
39+
}
40+
return NSArray(array: nsValues)
41+
} else if let val = value as? [String: Any] {
42+
var nsValues: [String: NSObject] = [:]
43+
for (key, innerValue) in val {
44+
guard let nsInnerValue = plistValueAsNSObject(innerValue) else { return nil }
45+
nsValues[key] = nsInnerValue
46+
}
47+
return NSDictionary(dictionary: nsValues)
3248
} else if let val = value as? NSObject {
3349
nsValue = val
3450
} else {
@@ -38,6 +54,48 @@ internal func plistValueAsNSObject(_ value: Any) -> NSObject? {
3854
return nsValue
3955
}
4056

57+
internal func plistNSObjectAsValue(_ nsValue: NSObject) -> Any {
58+
let value: Any
59+
60+
// Converts a value to the internal representation. Internalized values are
61+
// stored as NSObject derived objects in the registration dictionary.
62+
if let val = nsValue as? NSString {
63+
value = val._swiftObject
64+
} else if let val = nsValue as? NSNumber {
65+
value = val._swiftValueOfOptimalType
66+
} else if let val = nsValue as? NSData {
67+
value = val._swiftObject
68+
} else if let val = nsValue as? NSArray {
69+
value = val._swiftObject.map { plistNSObjectAsValue($0 as! NSObject) }
70+
} else if let val = nsValue as? NSDictionary {
71+
var values: [String: Any] = [:]
72+
for (currentKey, currentInnerValue) in val {
73+
let key: String
74+
75+
if let swiftKey = currentKey as? String {
76+
key = swiftKey
77+
} else if let nsKey = currentKey as? NSString {
78+
key = nsKey._swiftObject
79+
} else {
80+
continue
81+
}
82+
83+
if let nsInnerValue = currentInnerValue as? NSObject {
84+
values[key] = plistNSObjectAsValue(nsInnerValue)
85+
} else {
86+
values[key] = currentInnerValue
87+
}
88+
}
89+
value = values
90+
} else if let val = nsValue as? NSDate {
91+
value = val._swiftObject
92+
} else {
93+
value = nsValue
94+
}
95+
96+
return value
97+
}
98+
4199
private extension Dictionary {
42100
func convertingValuesToNSObjects() -> [Key: NSObject]? {
43101
var result: [Key: NSObject] = [:]
@@ -63,6 +121,14 @@ private extension Dictionary where Value == NSObject {
63121
return false
64122
}
65123
}
124+
125+
func convertingValuesFromPlistNSObject() -> [Key: Any] {
126+
var result: [Key: Any] = [:]
127+
for (key, value) in self {
128+
result[key] = plistNSObjectAsValue(value)
129+
}
130+
return result
131+
}
66132
}
67133

68134
open class UserDefaults: NSObject {
@@ -354,7 +420,7 @@ open class UserDefaults: NSObject {
354420
return allDefaults
355421
}
356422

357-
private static let _parsedArgumentsDomain: [String: Any] = UserDefaults._parseArguments(ProcessInfo.processInfo.arguments)
423+
private static let _parsedArgumentsDomain: [String: NSObject] = UserDefaults._parseArguments(ProcessInfo.processInfo.arguments).convertingValuesToNSObjects() ?? [:]
358424

359425
private var _volatileDomains: [String: [String: NSObject]] = [:]
360426
private let _volatileDomainsLock = NSLock()
@@ -372,7 +438,7 @@ open class UserDefaults: NSObject {
372438
let domain = _volatileDomains[domainName]
373439
_volatileDomainsLock.unlock()
374440

375-
return domain ?? [:]
441+
return domain?.convertingValuesFromPlistNSObject() ?? [:]
376442
}
377443

378444
open func setVolatileDomain(_ domain: [String : Any], forName domainName: String) {

Foundation/UserDefaults_Arguments.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,17 @@ internal extension UserDefaults {
3232
var parsed = false
3333
if let prefix = value.first, propertyListPrefixes.contains(prefix) {
3434
if let data = value.data(using: .utf8),
35-
let plist = try? PropertyListSerialization.propertyList(from: data, format: nil),
36-
let plistNS = plistValueAsNSObject(plist) {
35+
let plist = try? PropertyListSerialization.propertyList(from: data, format: nil) {
3736

3837
// If we can parse that argument as a plist, use the parsed value.
3938
parsed = true
40-
result[key] = plistNS
39+
result[key] = plist
4140

4241
}
4342
}
4443

45-
if !parsed, let valueNS = plistValueAsNSObject(value) {
46-
result[key] = valueNS
44+
if !parsed {
45+
result[key] = value
4746
}
4847
}
4948

TestFoundation/TestUserDefaults.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class TestUserDefaults : XCTestCase {
3939
("test_setValue_IntFromString", test_setValue_IntFromString ),
4040
("test_setValue_DoubleFromString", test_setValue_DoubleFromString ),
4141
("test_parseArguments", test_parseArguments),
42+
("test_volatileDomains", test_volatileDomains),
4243
]
4344
}
4445

@@ -287,4 +288,38 @@ class TestUserDefaults : XCTestCase {
287288
XCTAssertEqual(result["SomeDefault2"] as! [String: String], [ "SomeKey": "SomeValue" ])
288289
XCTAssertEqual(result["SomeDefault3"] as! String, "SomeValue")
289290
}
291+
292+
func test_volatileDomains() {
293+
let dateKey = "A Date",
294+
stringKey = "A String",
295+
arrayKey = "An Array",
296+
dictionaryKey = "A Dictionary",
297+
dataKey = "Some Data",
298+
boolKey = "A Bool"
299+
300+
let defaultsIn: [String: Any] = [
301+
dateKey: Date(),
302+
stringKey: "The String",
303+
arrayKey: [1, 2, 3],
304+
dictionaryKey: ["Swift": "Imperative", "Haskell": "Functional", "LISP": "LISP"],
305+
dataKey: "The Data".data(using: .utf8)!,
306+
boolKey: true
307+
]
308+
309+
let domainName = "TestDomain"
310+
311+
let defaults = UserDefaults(suiteName: nil)!
312+
XCTAssertFalse(defaults.volatileDomainNames.contains(domainName))
313+
314+
defaults.setVolatileDomain(defaultsIn, forName: domainName)
315+
let defaultsOut = defaults.volatileDomain(forName: domainName)
316+
317+
XCTAssertEqual(defaultsIn.count, defaultsOut.count)
318+
XCTAssertEqual(defaultsIn[dateKey] as! Date, defaultsOut[dateKey] as! Date)
319+
XCTAssertEqual(defaultsIn[stringKey] as! String, defaultsOut[stringKey] as! String)
320+
XCTAssertEqual(defaultsIn[arrayKey] as! [Int], defaultsOut[arrayKey] as! [Int])
321+
XCTAssertEqual(defaultsIn[dictionaryKey] as! [String: String], defaultsOut[dictionaryKey] as! [String: String])
322+
XCTAssertEqual(defaultsIn[dataKey] as! Data, defaultsOut[dataKey] as! Data)
323+
XCTAssertEqual(defaultsIn[boolKey] as! Bool, defaultsOut[boolKey] as! Bool)
324+
}
290325
}

0 commit comments

Comments
 (0)