2024-01-18 17:58:06 +08:00
|
|
|
// swiftlint:disable discouraged_optional_boolean
|
2018-04-16 17:19:45 +08:00
|
|
|
import Foundation
|
2020-01-21 00:41:13 +08:00
|
|
|
import Combine
|
2020-01-21 15:29:57 +08:00
|
|
|
import XCTest
|
2022-12-13 01:17:27 +08:00
|
|
|
@testable import Defaults
|
2018-04-12 01:19:30 +08:00
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
let fixtureURL = URL(string: "https://sindresorhus.com")!
|
2021-05-16 20:21:17 +08:00
|
|
|
let fixtureFileURL = URL(string: "file://~/icon.png")!
|
2018-10-17 18:22:10 +08:00
|
|
|
let fixtureURL2 = URL(string: "https://example.com")!
|
|
|
|
let fixtureDate = Date()
|
|
|
|
|
2018-04-12 01:19:30 +08:00
|
|
|
extension Defaults.Keys {
|
2018-10-17 18:22:10 +08:00
|
|
|
static let key = Key<Bool>("key", default: false)
|
|
|
|
static let url = Key<URL>("url", default: fixtureURL)
|
2021-05-16 20:21:17 +08:00
|
|
|
static let file = Key<URL>("fileURL", default: fixtureFileURL)
|
2019-07-25 09:53:47 +08:00
|
|
|
static let data = Key<Data>("data", default: Data([]))
|
2018-10-17 18:22:10 +08:00
|
|
|
static let date = Key<Date>("date", default: fixtureDate)
|
2022-01-27 23:14:21 +08:00
|
|
|
static let uuid = Key<UUID?>("uuid")
|
2022-11-17 18:36:29 +08:00
|
|
|
static let defaultDynamicDate = Key<Date>("defaultDynamicOptionalDate") { Date(timeIntervalSince1970: 0) }
|
|
|
|
static let defaultDynamicOptionalDate = Key<Date?>("defaultDynamicOptionalDate") { Date(timeIntervalSince1970: 1) }
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
final class DefaultsTests: XCTestCase {
|
|
|
|
override func setUp() {
|
|
|
|
super.setUp()
|
2019-09-11 15:32:18 +08:00
|
|
|
Defaults.removeAll()
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
override func tearDown() {
|
2021-01-24 20:50:11 +08:00
|
|
|
super.tearDown()
|
2019-09-11 15:32:18 +08:00
|
|
|
Defaults.removeAll()
|
2018-10-17 18:22:10 +08:00
|
|
|
}
|
|
|
|
|
2018-04-16 17:00:33 +08:00
|
|
|
func testKey() {
|
2018-10-17 18:22:10 +08:00
|
|
|
let key = Defaults.Key<Bool>("independentKey", default: false)
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertFalse(Defaults[key])
|
|
|
|
Defaults[key] = true
|
|
|
|
XCTAssertTrue(Defaults[key])
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
2022-12-13 01:17:27 +08:00
|
|
|
func testValidKeyName() {
|
|
|
|
let validKey = Defaults.Key<Bool>("test", default: false)
|
|
|
|
let containsDotKey = Defaults.Key<Bool>("test.a", default: false)
|
|
|
|
let startsWithAtKey = Defaults.Key<Bool>("@test", default: false)
|
|
|
|
XCTAssertTrue(Defaults.isValidKeyPath(name: validKey.name))
|
|
|
|
XCTAssertFalse(Defaults.isValidKeyPath(name: containsDotKey.name))
|
|
|
|
XCTAssertFalse(Defaults.isValidKeyPath(name: startsWithAtKey.name))
|
|
|
|
}
|
|
|
|
|
2018-04-12 01:19:30 +08:00
|
|
|
func testOptionalKey() {
|
2020-01-21 15:29:57 +08:00
|
|
|
let key = Defaults.Key<Bool?>("independentOptionalKey")
|
2021-05-16 20:21:17 +08:00
|
|
|
let url = Defaults.Key<URL?>("independentOptionalURLKey")
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertNil(Defaults[key])
|
2021-05-16 20:21:17 +08:00
|
|
|
XCTAssertNil(Defaults[url])
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = true
|
2021-05-16 20:21:17 +08:00
|
|
|
Defaults[url] = fixtureURL
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertTrue(Defaults[key]!)
|
2021-05-16 20:21:17 +08:00
|
|
|
XCTAssertEqual(Defaults[url], fixtureURL)
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = nil
|
2021-05-16 20:21:17 +08:00
|
|
|
Defaults[url] = nil
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertNil(Defaults[key])
|
2021-05-16 20:21:17 +08:00
|
|
|
XCTAssertNil(Defaults[url])
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = false
|
2021-05-16 20:21:17 +08:00
|
|
|
Defaults[url] = fixtureURL2
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertFalse(Defaults[key]!)
|
2021-05-16 20:21:17 +08:00
|
|
|
XCTAssertEqual(Defaults[url], fixtureURL2)
|
2018-10-17 18:22:10 +08:00
|
|
|
}
|
|
|
|
|
2022-11-17 18:36:29 +08:00
|
|
|
func testInitializeDynamicDateKey() {
|
|
|
|
_ = Defaults.Key<Date>("independentInitializeDynamicDateKey") {
|
|
|
|
XCTFail("Init dynamic key should not trigger getter")
|
|
|
|
return Date()
|
|
|
|
}
|
|
|
|
_ = Defaults.Key<Date?>("independentInitializeDynamicOptionalDateKey") {
|
|
|
|
XCTFail("Init dynamic optional key should not trigger getter")
|
|
|
|
return Date()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
func testKeyRegistersDefault() {
|
|
|
|
let keyName = "registersDefault"
|
2021-01-24 20:50:11 +08:00
|
|
|
XCTAssertFalse(UserDefaults.standard.bool(forKey: keyName))
|
2018-10-17 18:22:10 +08:00
|
|
|
_ = Defaults.Key<Bool>(keyName, default: true)
|
2021-01-24 20:50:11 +08:00
|
|
|
XCTAssertTrue(UserDefaults.standard.bool(forKey: keyName))
|
2018-10-17 18:22:10 +08:00
|
|
|
|
2019-09-11 15:56:11 +08:00
|
|
|
// Test that it works with multiple keys with `Defaults`.
|
2018-10-17 18:22:10 +08:00
|
|
|
let keyName2 = "registersDefault2"
|
|
|
|
_ = Defaults.Key<String>(keyName2, default: keyName2)
|
|
|
|
XCTAssertEqual(UserDefaults.standard.string(forKey: keyName2), keyName2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testKeyWithUserDefaultSubscript() {
|
|
|
|
let key = Defaults.Key<Bool>("keyWithUserDeaultSubscript", default: false)
|
|
|
|
XCTAssertFalse(UserDefaults.standard[key])
|
2018-04-12 01:19:30 +08:00
|
|
|
UserDefaults.standard[key] = true
|
2018-10-17 18:22:10 +08:00
|
|
|
XCTAssertTrue(UserDefaults.standard[key])
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func testKeys() {
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertFalse(Defaults[.key])
|
|
|
|
Defaults[.key] = true
|
|
|
|
XCTAssertTrue(Defaults[.key])
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func testUrlType() {
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertEqual(Defaults[.url], fixtureURL)
|
2018-04-12 01:19:30 +08:00
|
|
|
let newUrl = URL(string: "https://twitter.com")!
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[.url] = newUrl
|
|
|
|
XCTAssertEqual(Defaults[.url], newUrl)
|
2018-04-12 01:19:30 +08:00
|
|
|
}
|
|
|
|
|
2018-04-16 02:09:53 +08:00
|
|
|
func testDataType() {
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertEqual(Defaults[.data], Data([]))
|
2019-07-25 09:53:47 +08:00
|
|
|
let newData = Data([0xFF])
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[.data] = newData
|
|
|
|
XCTAssertEqual(Defaults[.data], newData)
|
2018-04-16 02:09:53 +08:00
|
|
|
}
|
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
func testDateType() {
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertEqual(Defaults[.date], fixtureDate)
|
2018-10-17 18:22:10 +08:00
|
|
|
let newDate = Date()
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[.date] = newDate
|
|
|
|
XCTAssertEqual(Defaults[.date], newDate)
|
2018-10-17 18:22:10 +08:00
|
|
|
}
|
|
|
|
|
2022-11-17 18:36:29 +08:00
|
|
|
func testDynamicDateType() {
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicDate], Date(timeIntervalSince1970: 0))
|
|
|
|
let next = Date(timeIntervalSince1970: 1)
|
|
|
|
Defaults[.defaultDynamicDate] = next
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicDate], next)
|
|
|
|
XCTAssertEqual(UserDefaults.standard.object(forKey: Defaults.Key<Date>.defaultDynamicDate.name) as! Date, next)
|
|
|
|
Defaults.Key<Date>.defaultDynamicDate.reset()
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicDate], Date(timeIntervalSince1970: 0))
|
|
|
|
}
|
|
|
|
|
|
|
|
func testDynamicOptionalDateType() {
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicOptionalDate], Date(timeIntervalSince1970: 1))
|
|
|
|
let next = Date(timeIntervalSince1970: 2)
|
|
|
|
Defaults[.defaultDynamicOptionalDate] = next
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicOptionalDate], next)
|
|
|
|
XCTAssertEqual(UserDefaults.standard.object(forKey: Defaults.Key<Date>.defaultDynamicOptionalDate.name) as! Date, next)
|
|
|
|
Defaults[.defaultDynamicOptionalDate] = nil
|
|
|
|
XCTAssertEqual(Defaults[.defaultDynamicOptionalDate], Date(timeIntervalSince1970: 1))
|
|
|
|
XCTAssertNil(UserDefaults.standard.object(forKey: Defaults.Key<Date>.defaultDynamicOptionalDate.name))
|
|
|
|
}
|
|
|
|
|
2021-05-16 20:21:17 +08:00
|
|
|
func testFileURLType() {
|
|
|
|
XCTAssertEqual(Defaults[.file], fixtureFileURL)
|
|
|
|
}
|
|
|
|
|
2022-01-27 23:14:21 +08:00
|
|
|
func testUUIDType() {
|
|
|
|
let fixture = UUID()
|
|
|
|
Defaults[.uuid] = fixture
|
|
|
|
XCTAssertEqual(Defaults[.uuid], fixture)
|
|
|
|
}
|
|
|
|
|
2019-09-11 15:32:18 +08:00
|
|
|
func testRemoveAll() {
|
|
|
|
let key = Defaults.Key<Bool>("removeAll", default: false)
|
|
|
|
let key2 = Defaults.Key<Bool>("removeAll2", default: false)
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = true
|
2019-09-11 15:32:18 +08:00
|
|
|
Defaults[key2] = true
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertTrue(Defaults[key])
|
2019-09-11 15:32:18 +08:00
|
|
|
XCTAssertTrue(Defaults[key2])
|
|
|
|
Defaults.removeAll()
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertFalse(Defaults[key])
|
2019-09-11 15:32:18 +08:00
|
|
|
XCTAssertFalse(Defaults[key2])
|
2018-10-17 18:22:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func testCustomSuite() {
|
|
|
|
let customSuite = UserDefaults(suiteName: "com.sindresorhus.customSuite")!
|
|
|
|
let key = Defaults.Key<Bool>("customSuite", default: false, suite: customSuite)
|
|
|
|
XCTAssertFalse(customSuite[key])
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertFalse(Defaults[key])
|
|
|
|
Defaults[key] = true
|
2018-10-17 18:22:10 +08:00
|
|
|
XCTAssertTrue(customSuite[key])
|
2019-09-11 12:59:28 +08:00
|
|
|
XCTAssertTrue(Defaults[key])
|
2019-09-11 15:32:18 +08:00
|
|
|
Defaults.removeAll(suite: customSuite)
|
2018-10-17 18:22:10 +08:00
|
|
|
}
|
|
|
|
|
2024-08-13 04:50:47 +08:00
|
|
|
func testIsDefaultValue() {
|
|
|
|
let key = Defaults.Key<Bool>("isDefaultValue", default: false)
|
|
|
|
XCTAssert(key.isDefaultValue)
|
|
|
|
Defaults[key].toggle()
|
|
|
|
XCTAssert(!key.isDefaultValue)
|
|
|
|
}
|
|
|
|
|
2020-01-21 00:41:13 +08:00
|
|
|
func testObserveKeyCombine() {
|
|
|
|
let key = Defaults.Key<Bool>("observeKey", default: false)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
let publisher = Defaults
|
2020-04-13 13:14:55 +08:00
|
|
|
.publisher(key, options: [])
|
2020-01-21 00:41:13 +08:00
|
|
|
.map { ($0.oldValue, $0.newValue) }
|
|
|
|
.collect(2)
|
|
|
|
|
|
|
|
let cancellable = publisher.sink { tuples in
|
2021-01-24 20:50:11 +08:00
|
|
|
for (index, expected) in [(false, true), (true, false)].enumerated() {
|
|
|
|
XCTAssertEqual(expected.0, tuples[index].0)
|
|
|
|
XCTAssertEqual(expected.1, tuples[index].1)
|
2020-01-21 00:41:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key] = true
|
|
|
|
Defaults.reset(key)
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testObserveOptionalKeyCombine() {
|
2020-01-21 15:29:57 +08:00
|
|
|
let key = Defaults.Key<Bool?>("observeOptionalKey")
|
2020-01-21 00:41:13 +08:00
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
let publisher = Defaults
|
2020-04-13 13:14:55 +08:00
|
|
|
.publisher(key, options: [])
|
2020-01-21 00:41:13 +08:00
|
|
|
.map { ($0.oldValue, $0.newValue) }
|
|
|
|
.collect(3)
|
|
|
|
|
|
|
|
let expectedValues: [(Bool?, Bool?)] = [(nil, true), (true, false), (false, nil)]
|
|
|
|
|
|
|
|
let cancellable = publisher.sink { actualValues in
|
|
|
|
for (expected, actual) in zip(expectedValues, actualValues) {
|
|
|
|
XCTAssertEqual(expected.0, actual.0)
|
|
|
|
XCTAssertEqual(expected.1, actual.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key] = true
|
|
|
|
Defaults[key] = false
|
|
|
|
Defaults.reset(key)
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2022-11-17 18:36:29 +08:00
|
|
|
func testDynamicOptionalDateTypeCombine() {
|
|
|
|
let first = Date(timeIntervalSince1970: 0)
|
|
|
|
let second = Date(timeIntervalSince1970: 1)
|
|
|
|
let third = Date(timeIntervalSince1970: 2)
|
|
|
|
let key = Defaults.Key<Date?>("combineDynamicOptionalDateKey") { first }
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
let publisher = Defaults
|
|
|
|
.publisher(key, options: [])
|
|
|
|
.map { ($0.oldValue, $0.newValue) }
|
|
|
|
.collect(3)
|
|
|
|
|
|
|
|
let expectedValues: [(Date?, Date?)] = [(first, second), (second, third), (third, first)]
|
|
|
|
|
|
|
|
let cancellable = publisher.sink { actualValues in
|
|
|
|
for (expected, actual) in zip(expectedValues, actualValues) {
|
|
|
|
XCTAssertEqual(expected.0, actual.0)
|
|
|
|
XCTAssertEqual(expected.1, actual.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key] = second
|
|
|
|
Defaults[key] = third
|
|
|
|
Defaults.reset(key)
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2020-01-21 00:41:13 +08:00
|
|
|
func testObserveMultipleKeysCombine() {
|
2020-04-18 14:19:38 +08:00
|
|
|
let key1 = Defaults.Key<String>("observeKey1", default: "x")
|
2020-01-21 00:41:13 +08:00
|
|
|
let key2 = Defaults.Key<Bool>("observeKey2", default: true)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 13:14:55 +08:00
|
|
|
let publisher = Defaults.publisher(keys: key1, key2, options: []).collect(2)
|
2020-01-21 00:41:13 +08:00
|
|
|
|
|
|
|
let cancellable = publisher.sink { _ in
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2020-04-18 14:19:38 +08:00
|
|
|
Defaults[key1] = "y"
|
2020-01-21 00:41:13 +08:00
|
|
|
Defaults[key2] = false
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testObserveMultipleOptionalKeysCombine() {
|
2020-04-18 14:19:38 +08:00
|
|
|
let key1 = Defaults.Key<String?>("observeOptionalKey1")
|
2020-01-21 15:29:57 +08:00
|
|
|
let key2 = Defaults.Key<Bool?>("observeOptionalKey2")
|
2020-01-21 00:41:13 +08:00
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 13:14:55 +08:00
|
|
|
let publisher = Defaults.publisher(keys: key1, key2, options: []).collect(2)
|
2020-01-21 00:41:13 +08:00
|
|
|
|
|
|
|
let cancellable = publisher.sink { _ in
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2020-04-18 14:19:38 +08:00
|
|
|
Defaults[key1] = "x"
|
2020-01-21 00:41:13 +08:00
|
|
|
Defaults[key2] = false
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2020-04-05 22:56:59 +08:00
|
|
|
func testReceiveValueBeforeSubscriptionCombine() {
|
|
|
|
let key = Defaults.Key<String>("receiveValueBeforeSubscription", default: "hello")
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
2020-06-07 02:14:12 +08:00
|
|
|
|
2020-04-05 22:56:59 +08:00
|
|
|
let publisher = Defaults
|
2020-04-13 13:14:55 +08:00
|
|
|
.publisher(key)
|
2020-08-29 04:38:56 +08:00
|
|
|
.map(\.newValue)
|
2020-04-05 22:56:59 +08:00
|
|
|
.eraseToAnyPublisher()
|
|
|
|
.collect(2)
|
|
|
|
|
|
|
|
let cancellable = publisher.sink { values in
|
|
|
|
XCTAssertEqual(["hello", "world"], values)
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2020-06-07 02:14:12 +08:00
|
|
|
Defaults[key] = "world"
|
2020-04-05 22:56:59 +08:00
|
|
|
cancellable.cancel()
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
func testObserveKey() {
|
|
|
|
let key = Defaults.Key<Bool>("observeKey", default: false)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 12:31:54 +08:00
|
|
|
var observation: Defaults.Observation!
|
2020-04-13 13:14:55 +08:00
|
|
|
observation = Defaults.observe(key, options: []) { change in
|
2018-10-17 18:22:10 +08:00
|
|
|
XCTAssertFalse(change.oldValue)
|
|
|
|
XCTAssertTrue(change.newValue)
|
|
|
|
observation.invalidate()
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = true
|
2018-10-17 18:22:10 +08:00
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testObserveOptionalKey() {
|
2020-01-21 15:29:57 +08:00
|
|
|
let key = Defaults.Key<Bool?>("observeOptionalKey")
|
2018-10-17 18:22:10 +08:00
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 12:31:54 +08:00
|
|
|
var observation: Defaults.Observation!
|
2020-04-13 13:14:55 +08:00
|
|
|
observation = Defaults.observe(key, options: []) { change in
|
2018-10-17 18:22:10 +08:00
|
|
|
XCTAssertNil(change.oldValue)
|
|
|
|
XCTAssertTrue(change.newValue!)
|
|
|
|
observation.invalidate()
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = true
|
2018-10-17 18:22:10 +08:00
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObserveMultipleKeys() {
|
|
|
|
let key1 = Defaults.Key<String>("observeKey1", default: "x")
|
|
|
|
let key2 = Defaults.Key<Bool>("observeKey2", default: true)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
var observation: Defaults.Observation!
|
|
|
|
var counter = 0
|
|
|
|
observation = Defaults.observe(keys: key1, key2, options: []) {
|
|
|
|
counter += 1
|
|
|
|
if counter == 2 {
|
|
|
|
expect.fulfill()
|
|
|
|
} else if counter > 2 {
|
2023-09-03 14:39:57 +08:00
|
|
|
XCTFail() // swiftlint:disable:this xctfail_message
|
2020-08-29 04:12:29 +08:00
|
|
|
}
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
Defaults[key1] = "y"
|
|
|
|
Defaults[key2] = false
|
|
|
|
observation.invalidate()
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2018-10-17 18:22:10 +08:00
|
|
|
func testObserveKeyURL() {
|
|
|
|
let key = Defaults.Key<URL>("observeKeyURL", default: fixtureURL)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 12:31:54 +08:00
|
|
|
var observation: Defaults.Observation!
|
2020-04-13 13:14:55 +08:00
|
|
|
observation = Defaults.observe(key, options: []) { change in
|
2018-10-17 18:22:10 +08:00
|
|
|
XCTAssertEqual(change.oldValue, fixtureURL)
|
|
|
|
XCTAssertEqual(change.newValue, fixtureURL2)
|
|
|
|
observation.invalidate()
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults[key] = fixtureURL2
|
2018-10-17 18:22:10 +08:00
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2022-11-17 18:36:29 +08:00
|
|
|
func testObserveDynamicOptionalDateKey() {
|
|
|
|
let first = Date(timeIntervalSince1970: 0)
|
|
|
|
let second = Date(timeIntervalSince1970: 1)
|
|
|
|
let key = Defaults.Key<Date?>("observeDynamicOptionalDate") { first }
|
|
|
|
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
var observation: Defaults.Observation!
|
|
|
|
observation = Defaults.observe(key, options: []) { change in
|
|
|
|
XCTAssertEqual(change.oldValue, first)
|
|
|
|
XCTAssertEqual(change.newValue, second)
|
|
|
|
observation.invalidate()
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key] = second
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagation() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation0", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
|
|
|
|
|
|
|
var observation: Defaults.Observation!
|
|
|
|
var wasInside = false
|
|
|
|
observation = Defaults.observe(key1, options: []) { _ in
|
|
|
|
XCTAssertFalse(wasInside)
|
|
|
|
wasInside = true
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key1] = false
|
|
|
|
observation.invalidate()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationMultipleKeys() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation1", default: nil)
|
|
|
|
let key2 = Defaults.Key<Bool?>("preventPropagation2", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
|
|
|
|
|
|
|
var observation: Defaults.Observation!
|
|
|
|
var wasInside = false
|
|
|
|
observation = Defaults.observe(keys: key1, key2, options: []) {
|
|
|
|
XCTAssertFalse(wasInside)
|
|
|
|
wasInside = true
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
Defaults[key1] = false
|
|
|
|
observation.invalidate()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
|
|
|
// This checks if the callback is still being called if the value is changed on a second thread while the initial thread is doing some long running task.
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationMultipleThreads() {
|
|
|
|
let key1 = Defaults.Key<Int?>("preventPropagation3", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
var observation: Defaults.Observation!
|
|
|
|
observation = Defaults.observe(key1, options: []) { _ in
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1]! += 1
|
|
|
|
}
|
|
|
|
print("--- Main Thread: \(Thread.isMainThread)")
|
|
|
|
if !Thread.isMainThread {
|
2023-09-03 14:39:57 +08:00
|
|
|
XCTAssertEqual(Defaults[key1]!, 4)
|
2020-08-29 04:12:29 +08:00
|
|
|
expect.fulfill()
|
|
|
|
} else {
|
2021-05-16 20:21:17 +08:00
|
|
|
usleep(300_000)
|
2020-08-29 04:12:29 +08:00
|
|
|
print("--- Release: \(Thread.isMainThread)")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DispatchQueue.global().asyncAfter(deadline: .now() + 0.05) {
|
|
|
|
Defaults[key1]! += 1
|
|
|
|
}
|
|
|
|
Defaults[key1] = 1
|
|
|
|
observation.invalidate()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
|
|
|
// Check if propagation prevention works across multiple observations.
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationMultipleObservations() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation4", default: nil)
|
|
|
|
let key2 = Defaults.Key<Bool?>("preventPropagation5", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
|
|
|
|
|
|
|
let observation1 = Defaults.observe(key2, options: []) { _ in
|
2023-09-03 14:39:57 +08:00
|
|
|
XCTFail() // swiftlint:disable:this xctfail_message
|
2020-08-29 04:12:29 +08:00
|
|
|
}
|
2021-01-24 20:50:11 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
let observation2 = Defaults.observe(keys: key1, key2, options: []) {
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key2] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
Defaults[key1] = false
|
|
|
|
observation1.invalidate()
|
|
|
|
observation2.invalidate()
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationCombine() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation6", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
|
|
|
|
|
|
|
var wasInside = false
|
|
|
|
let cancellable = Defaults.publisher(key1, options: []).sink { _ in
|
|
|
|
XCTAssertFalse(wasInside)
|
|
|
|
wasInside = true
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
Defaults[key1] = false
|
|
|
|
cancellable.cancel()
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationMultipleKeysCombine() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation7", default: nil)
|
|
|
|
let key2 = Defaults.Key<Bool?>("preventPropagation8", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
|
|
|
|
|
|
|
var wasInside = false
|
|
|
|
let cancellable = Defaults.publisher(keys: key1, key2, options: []).sink { _ in
|
|
|
|
XCTAssertFalse(wasInside)
|
|
|
|
wasInside = true
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
Defaults[key2] = false
|
|
|
|
cancellable.cancel()
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
func testObservePreventPropagationModifiersCombine() {
|
|
|
|
let key1 = Defaults.Key<Bool?>("preventPropagation9", default: nil)
|
|
|
|
let expect = expectation(description: "No infinite recursion")
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
var wasInside = false
|
|
|
|
var cancellable: AnyCancellable!
|
|
|
|
cancellable = Defaults.publisher(key1, options: [])
|
|
|
|
.receive(on: DispatchQueue.main)
|
|
|
|
.delay(for: 0.5, scheduler: DispatchQueue.global())
|
|
|
|
.sink { _ in
|
|
|
|
XCTAssertFalse(wasInside)
|
|
|
|
wasInside = true
|
|
|
|
Defaults.withoutPropagation {
|
|
|
|
Defaults[key1] = true
|
|
|
|
}
|
|
|
|
expect.fulfill()
|
|
|
|
cancellable.cancel()
|
|
|
|
}
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
Defaults[key1] = false
|
2020-08-29 04:38:56 +08:00
|
|
|
|
2020-08-29 04:12:29 +08:00
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2020-01-21 01:07:30 +08:00
|
|
|
|
2021-05-16 20:21:17 +08:00
|
|
|
func testRemoveDuplicatesObserveKeyCombine() {
|
|
|
|
let key = Defaults.Key<Bool>("observeKey", default: false)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
let inputArray = [true, false, false, false, false, false, false, true]
|
|
|
|
let expectedArray = [true, false, true]
|
|
|
|
|
|
|
|
let cancellable = Defaults
|
|
|
|
.publisher(key, options: [])
|
|
|
|
.removeDuplicates()
|
|
|
|
.map(\.newValue)
|
|
|
|
.collect(expectedArray.count)
|
|
|
|
.sink { result in
|
|
|
|
print("Result array: \(result)")
|
2022-10-22 01:04:15 +08:00
|
|
|
|
|
|
|
if result == expectedArray {
|
|
|
|
expect.fulfill()
|
|
|
|
} else {
|
|
|
|
XCTFail("Expected Array is not matched")
|
|
|
|
}
|
2021-05-16 20:21:17 +08:00
|
|
|
}
|
|
|
|
|
2024-03-29 00:45:39 +08:00
|
|
|
for item in inputArray {
|
|
|
|
Defaults[key] = item
|
2021-05-16 20:21:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Defaults.reset(key)
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRemoveDuplicatesOptionalObserveKeyCombine() {
|
|
|
|
let key = Defaults.Key<Bool?>("observeOptionalKey", default: nil)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
|
|
|
let inputArray = [true, nil, nil, nil, false, false, false, nil]
|
|
|
|
let expectedArray = [true, nil, false, nil]
|
|
|
|
|
|
|
|
let cancellable = Defaults
|
|
|
|
.publisher(key, options: [])
|
|
|
|
.removeDuplicates()
|
|
|
|
.map(\.newValue)
|
|
|
|
.collect(expectedArray.count)
|
|
|
|
.sink { result in
|
|
|
|
print("Result array: \(result)")
|
2022-10-22 01:04:15 +08:00
|
|
|
|
|
|
|
if result == expectedArray {
|
|
|
|
expect.fulfill()
|
|
|
|
} else {
|
|
|
|
XCTFail("Expected Array is not matched")
|
|
|
|
}
|
2021-05-16 20:21:17 +08:00
|
|
|
}
|
|
|
|
|
2024-03-29 00:45:39 +08:00
|
|
|
for item in inputArray {
|
|
|
|
Defaults[key] = item
|
2021-05-16 20:21:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Defaults.reset(key)
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2019-09-11 15:09:12 +08:00
|
|
|
func testResetKey() {
|
2020-04-17 22:32:44 +08:00
|
|
|
let defaultFixture1 = "foo1"
|
|
|
|
let defaultFixture2 = 0
|
|
|
|
let newFixture1 = "bar1"
|
|
|
|
let newFixture2 = 1
|
|
|
|
let key1 = Defaults.Key<String>("key1", default: defaultFixture1)
|
|
|
|
let key2 = Defaults.Key<Int>("key2", default: defaultFixture2)
|
|
|
|
Defaults[key1] = newFixture1
|
|
|
|
Defaults[key2] = newFixture2
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults.reset(key1)
|
2020-04-17 22:32:44 +08:00
|
|
|
XCTAssertEqual(Defaults[key1], defaultFixture1)
|
|
|
|
XCTAssertEqual(Defaults[key2], newFixture2)
|
2019-09-11 15:09:12 +08:00
|
|
|
}
|
2020-01-21 01:07:30 +08:00
|
|
|
|
2020-04-17 22:32:44 +08:00
|
|
|
func testResetMultipleKeys() {
|
|
|
|
let defaultFxiture1 = "foo1"
|
|
|
|
let defaultFixture2 = 0
|
|
|
|
let defaultFixture3 = "foo3"
|
|
|
|
let newFixture1 = "bar1"
|
|
|
|
let newFixture2 = 1
|
|
|
|
let newFixture3 = "bar3"
|
|
|
|
let key1 = Defaults.Key<String>("akey1", default: defaultFxiture1)
|
|
|
|
let key2 = Defaults.Key<Int>("akey2", default: defaultFixture2)
|
|
|
|
let key3 = Defaults.Key<String>("akey3", default: defaultFixture3)
|
|
|
|
Defaults[key1] = newFixture1
|
|
|
|
Defaults[key2] = newFixture2
|
|
|
|
Defaults[key3] = newFixture3
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults.reset(key1, key2)
|
2020-04-17 22:32:44 +08:00
|
|
|
XCTAssertEqual(Defaults[key1], defaultFxiture1)
|
|
|
|
XCTAssertEqual(Defaults[key2], defaultFixture2)
|
|
|
|
XCTAssertEqual(Defaults[key3], newFixture3)
|
2019-09-11 15:09:12 +08:00
|
|
|
}
|
2020-01-21 01:07:30 +08:00
|
|
|
|
2020-04-17 22:32:44 +08:00
|
|
|
func testResetMultipleOptionalKeys() {
|
|
|
|
let newFixture1 = "bar1"
|
|
|
|
let newFixture2 = 1
|
|
|
|
let newFixture3 = "bar3"
|
2020-01-21 15:29:57 +08:00
|
|
|
let key1 = Defaults.Key<String?>("aoptionalKey1")
|
2020-04-17 22:32:44 +08:00
|
|
|
let key2 = Defaults.Key<Int?>("aoptionalKey2")
|
2020-01-21 15:29:57 +08:00
|
|
|
let key3 = Defaults.Key<String?>("aoptionalKey3")
|
2020-04-17 22:32:44 +08:00
|
|
|
Defaults[key1] = newFixture1
|
|
|
|
Defaults[key2] = newFixture2
|
|
|
|
Defaults[key3] = newFixture3
|
2019-09-11 12:59:28 +08:00
|
|
|
Defaults.reset(key1, key2)
|
2021-01-24 20:50:11 +08:00
|
|
|
XCTAssertNil(Defaults[key1])
|
|
|
|
XCTAssertNil(Defaults[key2])
|
2020-04-17 22:32:44 +08:00
|
|
|
XCTAssertEqual(Defaults[key3], newFixture3)
|
2019-09-11 15:09:12 +08:00
|
|
|
}
|
2019-10-30 19:50:24 +08:00
|
|
|
|
|
|
|
func testObserveWithLifetimeTie() {
|
|
|
|
let key = Defaults.Key<Bool>("lifetimeTie", default: false)
|
|
|
|
let expect = expectation(description: "Observation closure being called")
|
|
|
|
|
2020-04-13 12:31:54 +08:00
|
|
|
weak var observation: Defaults.Observation!
|
2020-06-07 02:14:12 +08:00
|
|
|
observation = Defaults.observe(key, options: []) { _ in
|
2019-10-30 19:50:24 +08:00
|
|
|
observation.invalidate()
|
|
|
|
expect.fulfill()
|
2021-01-24 20:50:11 +08:00
|
|
|
}
|
|
|
|
.tieToLifetime(of: self)
|
2019-10-30 19:50:24 +08:00
|
|
|
|
|
|
|
Defaults[key] = true
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testObserveWithLifetimeTieManualBreak() {
|
|
|
|
let key = Defaults.Key<Bool>("lifetimeTieManualBreak", default: false)
|
|
|
|
|
2020-04-13 12:31:54 +08:00
|
|
|
weak var observation: Defaults.Observation? = Defaults.observe(key, options: []) { _ in }.tieToLifetime(of: self)
|
2019-10-30 19:50:24 +08:00
|
|
|
observation!.removeLifetimeTie()
|
|
|
|
|
2021-01-24 20:50:11 +08:00
|
|
|
for index in 1...10 {
|
2019-10-30 19:50:24 +08:00
|
|
|
if observation == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
sleep(1)
|
|
|
|
|
2021-01-24 20:50:11 +08:00
|
|
|
if index == 10 {
|
2023-09-03 14:39:57 +08:00
|
|
|
XCTFail() // swiftlint:disable:this xctfail_message
|
2019-10-30 19:50:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-20 21:29:15 +08:00
|
|
|
|
2021-04-19 00:45:37 +08:00
|
|
|
func testImmediatelyFinishingPublisherCombine() {
|
|
|
|
let key = Defaults.Key<Bool>("observeKey", default: false)
|
|
|
|
let expect = expectation(description: "Observation closure being called without crashing")
|
|
|
|
|
|
|
|
let cancellable = Defaults
|
|
|
|
.publisher(key, options: [.initial])
|
|
|
|
.first()
|
|
|
|
.sink { _ in
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
cancellable.cancel()
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
2022-06-04 20:08:34 +08:00
|
|
|
|
2023-09-04 06:37:37 +08:00
|
|
|
func testImmediatelyFinishingMultiplePublisherCombine() {
|
|
|
|
let key1 = Defaults.Key<Bool>("observeKey1", default: false)
|
|
|
|
let key2 = Defaults.Key<String>("observeKey2", default: "🦄")
|
|
|
|
let expect = expectation(description: "Observation closure being called without crashing")
|
|
|
|
|
|
|
|
let cancellable = Defaults
|
|
|
|
.publisher(keys: [key1, key2], options: [.initial])
|
|
|
|
.first()
|
|
|
|
.sink { _ in
|
|
|
|
expect.fulfill()
|
|
|
|
}
|
|
|
|
|
|
|
|
cancellable.cancel()
|
|
|
|
|
|
|
|
waitForExpectations(timeout: 10)
|
|
|
|
}
|
|
|
|
|
2022-06-04 20:08:34 +08:00
|
|
|
func testKeyEquatable() {
|
|
|
|
XCTAssertEqual(Defaults.Key<Bool>("equatableKeyTest", default: false), Defaults.Key<Bool>("equatableKeyTest", default: false))
|
|
|
|
}
|
|
|
|
|
|
|
|
func testKeyHashable() {
|
|
|
|
_ = Set([Defaults.Key<Bool>("hashableKeyTest", default: false)])
|
|
|
|
}
|
2022-11-18 20:22:02 +08:00
|
|
|
|
|
|
|
func testUpdates() async {
|
|
|
|
let key = Defaults.Key<Bool>("updatesKey", default: false)
|
|
|
|
|
|
|
|
async let waiter = Defaults.updates(key, initial: false).first { $0 }
|
|
|
|
|
2024-05-15 01:59:24 +08:00
|
|
|
try? await Task.sleep(for: .seconds(0.1))
|
2022-11-18 20:22:02 +08:00
|
|
|
|
|
|
|
Defaults[key] = true
|
|
|
|
|
|
|
|
guard let result = await waiter else {
|
2023-09-03 14:39:57 +08:00
|
|
|
XCTFail() // swiftlint:disable:this xctfail_message
|
2022-11-18 20:22:02 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
XCTAssertTrue(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testUpdatesMultipleKeys() async {
|
|
|
|
let key1 = Defaults.Key<Bool>("updatesMultipleKey1", default: false)
|
|
|
|
let key2 = Defaults.Key<Bool>("updatesMultipleKey2", default: false)
|
|
|
|
let counter = Counter()
|
|
|
|
|
|
|
|
async let waiter: Void = {
|
|
|
|
for await _ in Defaults.updates([key1, key2], initial: false) {
|
|
|
|
await counter.increment()
|
|
|
|
|
|
|
|
if await counter.count == 2 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2024-05-15 01:59:24 +08:00
|
|
|
try? await Task.sleep(for: .seconds(0.1))
|
2022-11-18 20:22:02 +08:00
|
|
|
|
|
|
|
Defaults[key1] = true
|
|
|
|
Defaults[key2] = true
|
|
|
|
|
|
|
|
await waiter
|
|
|
|
|
|
|
|
let count = await counter.count
|
|
|
|
XCTAssertEqual(count, 2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
actor Counter {
|
|
|
|
private var _count = 0
|
|
|
|
|
|
|
|
var count: Int { _count }
|
|
|
|
|
|
|
|
func increment() {
|
|
|
|
_count += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-18 17:58:06 +08:00
|
|
|
// swiftlint:enable discouraged_optional_boolean
|