Skip to content

Commit

Permalink
Convert tests to Swift Testing
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Sep 26, 2024
1 parent 4c009d5 commit 72264f1
Show file tree
Hide file tree
Showing 24 changed files with 1,643 additions and 3,957 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- run: sudo xcode-select -switch /Applications/Xcode_15.3.app
- run: sudo xcode-select -switch /Applications/Xcode_16.app
- run: swift test
lint:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version:5.11
import PackageDescription

let package = Package(
Expand Down
6 changes: 4 additions & 2 deletions Sources/Defaults/Defaults+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,13 @@ extension UserDefaults: DefaultsKeyValueStore {}

extension DefaultsLockProtocol {
@discardableResult
func with<R>(_ body: @Sendable () throws -> R) rethrows -> R where R: Sendable {
func with<R, E>(_ body: @Sendable () throws(E) -> R) throws(E) -> R where R: Sendable {
lock()

defer {
self.unlock()
unlock()
}

return try body()
}
}
2 changes: 1 addition & 1 deletion Sources/Defaults/Defaults+Protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,5 @@ protocol DefaultsLockProtocol {

func unlock()

func with<R>(_ body: @Sendable () throws -> R) rethrows -> R where R: Sendable
func with<R, E>(_ body: @Sendable () throws(E) -> R) throws(E) -> R where R: Sendable
}
156 changes: 77 additions & 79 deletions Tests/DefaultsTests/Defaults+iCloudTests.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@testable import Defaults
import SwiftUI
import XCTest
import Testing
@testable import Defaults

final class MockStorage: DefaultsKeyValueStore {
private final class MockStorage: DefaultsKeyValueStore {
private var pairs: [String: Any] = [:]
private let queue = DispatchQueue(label: "a")

Expand Down Expand Up @@ -51,89 +51,83 @@ final class MockStorage: DefaultsKeyValueStore {

@discardableResult
func synchronize() -> Bool {
let pairs = queue.sync {
Array(self.pairs.keys)
}
let pairs = queue.sync { Array(self.pairs.keys) }
NotificationCenter.default.post(Notification(name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, userInfo: [NSUbiquitousKeyValueStoreChangedKeysKey: pairs]))
return true
}
}

private let mockStorage = MockStorage()

@available(iOS 15, tvOS 15, watchOS 8, visionOS 1.0, *)
final class DefaultsICloudTests: XCTestCase {
override final class func setUp() {
@Suite(.serialized)
final class DefaultsICloudTests {
private let suite = createSuite()

init() {
Defaults.iCloud.isDebug = true
Defaults.iCloud.syncOnChange = true
Defaults.iCloud.synchronizer = iCloudSynchronizer(remoteStorage: mockStorage)
}

override func setUp() {
super.setUp()
mockStorage.removeAll()
Defaults.iCloud.removeAll()
Defaults.removeAll()
}

override func tearDown() {
super.tearDown()
deinit {
mockStorage.removeAll()
Defaults.iCloud.removeAll()
Defaults.removeAll()
Defaults.removeAll(suite: suite)
}

private func updateMockStorage(key: String, value: some Any, _ date: Date? = nil) {
mockStorage.set([date ?? Date(), value], forKey: key)
}

@Test
func testICloudInitialize() async {
let name = Defaults.Key<String>("testICloudInitialize_name", default: "0", iCloud: true)
let quality = Defaults.Key<Double>("testICloudInitialize_quality", default: 0.0, iCloud: true)
let name = Defaults.Key<String>("testICloudInitialize_name", default: "0", suite: suite, iCloud: true)
let quality = Defaults.Key<Double>("testICloudInitialize_quality", default: 0.0, suite: suite, iCloud: true)

await Defaults.iCloud.waitForSyncCompletion()
XCTAssertNil(mockStorage.data(forKey: name.name))
XCTAssertNil(mockStorage.data(forKey: quality.name))
#expect(mockStorage.data(forKey: name.name) == nil)
#expect(mockStorage.data(forKey: quality.name) == nil)
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]

for index in 0..<name_expected.count {
Defaults[name] = name_expected[index]
Defaults[quality] = quality_expected[index]
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), name_expected[index])
XCTAssertEqual(mockStorage.data(forKey: quality.name), quality_expected[index])
#expect(mockStorage.data(forKey: name.name) == name_expected[index])
#expect(mockStorage.data(forKey: quality.name) == quality_expected[index])
}

updateMockStorage(key: quality.name, value: 8.0)
updateMockStorage(key: name.name, value: "8")
mockStorage.synchronize()
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[quality], 8.0)
XCTAssertEqual(Defaults[name], "8")
#expect(Defaults[quality] == 8.0)
#expect(Defaults[name] == "8")

Defaults[name] = "9"
Defaults[quality] = 9.0
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "9")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 9.0)
#expect(mockStorage.data(forKey: name.name) == "9")
#expect(mockStorage.data(forKey: quality.name) == 9.0)

updateMockStorage(key: quality.name, value: 10)
updateMockStorage(key: name.name, value: "10")
mockStorage.synchronize()
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[quality], 10.0)
XCTAssertEqual(Defaults[name], "10")
#expect(Defaults[quality] == 10.0)
#expect(Defaults[name] == "10")
}

@Test
func testDidChangeExternallyNotification() async {
updateMockStorage(key: "testDidChangeExternallyNotification_name", value: "0")
updateMockStorage(key: "testDidChangeExternallyNotification_quality", value: 0.0)
let name = Defaults.Key<String?>("testDidChangeExternallyNotification_name", iCloud: true)
let quality = Defaults.Key<Double?>("testDidChangeExternallyNotification_quality", iCloud: true)
let name = Defaults.Key<String?>("testDidChangeExternallyNotification_name", suite: suite, iCloud: true)
let quality = Defaults.Key<Double?>("testDidChangeExternallyNotification_quality", suite: suite, iCloud: true)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[name], "0")
XCTAssertEqual(Defaults[quality], 0.0)
#expect(Defaults[name] == "0")
#expect(Defaults[quality] == 0.0)
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]

Expand All @@ -143,60 +137,63 @@ final class DefaultsICloudTests: XCTestCase {
mockStorage.synchronize()
}
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[name], "7")
XCTAssertEqual(Defaults[quality], 7.0)
#expect(Defaults[name] == "7")
#expect(Defaults[quality] == 7.0)

Defaults[name] = "8"
Defaults[quality] = 8.0
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "8")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 8.0)
#expect(mockStorage.data(forKey: name.name) == "8")
#expect(mockStorage.data(forKey: quality.name) == 8.0)

Defaults[name] = nil
Defaults[quality] = nil
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertNil(mockStorage.data(forKey: name.name))
XCTAssertNil(mockStorage.data(forKey: quality.name))
#expect(mockStorage.data(forKey: name.name) == nil)
#expect(mockStorage.data(forKey: quality.name) == nil)
}

@Test
func testICloudInitializeSyncLast() async {
let name = Defaults.Key<String>("testICloudInitializeSyncLast_name", default: "0", iCloud: true)
let quality = Defaults.Key<Double>("testICloudInitializeSyncLast_quality", default: 0.0, iCloud: true)
let name = Defaults.Key<String>("testICloudInitializeSyncLast_name", default: "0", suite: suite, iCloud: true)
let quality = Defaults.Key<Double>("testICloudInitializeSyncLast_quality", default: 0.0, suite: suite, iCloud: true)
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]

for index in 0..<name_expected.count {
Defaults[name] = name_expected[index]
Defaults[quality] = quality_expected[index]
XCTAssertEqual(Defaults[name], name_expected[index])
XCTAssertEqual(Defaults[quality], quality_expected[index])
#expect(Defaults[name] == name_expected[index])
#expect(Defaults[quality] == quality_expected[index])
}

await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "7")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 7.0)
#expect(mockStorage.data(forKey: name.name) == "7")
#expect(mockStorage.data(forKey: quality.name) == 7.0)
}

@Test
func testRemoveKey() async {
let name = Defaults.Key<String>("testRemoveKey_name", default: "0", iCloud: true)
let quality = Defaults.Key<Double>("testRemoveKey_quality", default: 0.0, iCloud: true)
let name = Defaults.Key<String>("testRemoveKey_name", default: "0", suite: suite, iCloud: true)
let quality = Defaults.Key<Double>("testRemoveKey_quality", default: 0.0, suite: suite, iCloud: true)
Defaults[name] = "1"
Defaults[quality] = 1.0
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "1")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 1.0)
#expect(mockStorage.data(forKey: name.name) == "1")
#expect(mockStorage.data(forKey: quality.name) == 1.0)

Defaults.iCloud.remove(quality)
Defaults[name] = "2"
Defaults[quality] = 1.0
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "2")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 1.0)
#expect(mockStorage.data(forKey: name.name) == "2")
#expect(mockStorage.data(forKey: quality.name) == 1.0)
}

@Test
func testSyncKeysFromLocal() async {
let name = Defaults.Key<String>("testSyncKeysFromLocal_name", default: "0")
let quality = Defaults.Key<Double>("testSyncKeysFromLocal_quality", default: 0.0)
let name = Defaults.Key<String>("testSyncKeysFromLocal_name", default: "0", suite: suite)
let quality = Defaults.Key<Double>("testSyncKeysFromLocal_quality", default: 0.0, suite: suite)
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]

Expand All @@ -205,21 +202,22 @@ final class DefaultsICloudTests: XCTestCase {
Defaults[quality] = quality_expected[index]
Defaults.iCloud.syncWithoutWaiting(name, quality, source: .local)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), name_expected[index])
XCTAssertEqual(mockStorage.data(forKey: quality.name), quality_expected[index])
#expect(mockStorage.data(forKey: name.name) == name_expected[index])
#expect(mockStorage.data(forKey: quality.name) == quality_expected[index])
}

updateMockStorage(key: name.name, value: "8")
updateMockStorage(key: quality.name, value: 8)
Defaults.iCloud.syncWithoutWaiting(name, quality, source: .remote)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[quality], 8.0)
XCTAssertEqual(Defaults[name], "8")
#expect(Defaults[quality] == 8.0)
#expect(Defaults[name] == "8")
}

@Test
func testSyncKeysFromRemote() async {
let name = Defaults.Key<String?>("testSyncKeysFromRemote_name")
let quality = Defaults.Key<Double?>("testSyncKeysFromRemote_quality")
let name = Defaults.Key<String?>("testSyncKeysFromRemote_name", suite: suite)
let quality = Defaults.Key<Double?>("testSyncKeysFromRemote_quality", suite: suite)
let name_expected = ["1", "2", "3", "4", "5", "6", "7"]
let quality_expected = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]

Expand All @@ -228,47 +226,47 @@ final class DefaultsICloudTests: XCTestCase {
updateMockStorage(key: quality.name, value: quality_expected[index])
Defaults.iCloud.syncWithoutWaiting(name, quality, source: .remote)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(Defaults[name], name_expected[index])
XCTAssertEqual(Defaults[quality], quality_expected[index])
#expect(Defaults[name] == name_expected[index])
#expect(Defaults[quality] == quality_expected[index])
}

Defaults[name] = "8"
Defaults[quality] = 8.0
Defaults.iCloud.syncWithoutWaiting(name, quality, source: .local)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "8")
XCTAssertEqual(mockStorage.data(forKey: quality.name), 8.0)
#expect(mockStorage.data(forKey: name.name) == "8")
#expect(mockStorage.data(forKey: quality.name) == 8.0)

Defaults[name] = nil
Defaults[quality] = nil
Defaults.iCloud.syncWithoutWaiting(name, quality, source: .local)
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertNil(mockStorage.object(forKey: name.name))
XCTAssertNil(mockStorage.object(forKey: quality.name))
#expect(mockStorage.object(forKey: name.name) == nil)
#expect(mockStorage.object(forKey: quality.name) == nil)
}

@Test
func testAddFromDetached() async {
let name = Defaults.Key<String>("testInitAddFromDetached_name", default: "0")
let quantity = Defaults.Key<Bool>("testInitAddFromDetached_quantity", default: false)
let task = Task.detached {
let name = Defaults.Key<String>("testInitAddFromDetached_name", default: "0", suite: suite)
let quantity = Defaults.Key<Bool>("testInitAddFromDetached_quantity", default: false, suite: suite)
await Task.detached {
Defaults.iCloud.add(name, quantity)
Defaults.iCloud.syncWithoutWaiting()
await Defaults.iCloud.waitForSyncCompletion()
}
await task.value
XCTAssertEqual(mockStorage.data(forKey: name.name), "0")
}.value
#expect(mockStorage.data(forKey: name.name) == "0")
Defaults[name] = "1"
await Defaults.iCloud.waitForSyncCompletion()
XCTAssertEqual(mockStorage.data(forKey: name.name), "1")
#expect(mockStorage.data(forKey: name.name) == "1")
}

@Test
func testICloudInitializeFromDetached() async {
let task = Task.detached {
let name = Defaults.Key<String>("testICloudInitializeFromDetached_name", default: "0", iCloud: true)
await Task.detached {
let name = Defaults.Key<String>("testICloudInitializeFromDetached_name", default: "0", suite: self.suite, iCloud: true)

await Defaults.iCloud.waitForSyncCompletion()
XCTAssertNil(mockStorage.data(forKey: name.name))
}
await task.value
#expect(mockStorage.data(forKey: name.name) == nil)
}.value
}
}
Loading

0 comments on commit 72264f1

Please sign in to comment.