diff --git a/Package.swift b/Package.swift
index 818b20253..2c5576e35 100644
--- a/Package.swift
+++ b/Package.swift
@@ -63,6 +63,7 @@ var package = Package(
.target(name: "OktaClientMacros"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
+ .product(name: "SwiftSyntaxMacrosGenericTestSupport", package: "swift-syntax"),
]),
.target(name: "OktaClientMacros",
dependencies: [
@@ -72,9 +73,7 @@ var package = Package(
path: "Sources/OktaClientMacros/Interface"),
// Concurrency & locking
- .target(name: "OktaConcurrency",
- exclude: exclude(),
- resources: include()),
+ .target(name: "OktaConcurrency"),
.testTarget(name: "OktaConcurrencyTests",
dependencies: [
.target(name: "OktaConcurrency"),
@@ -90,9 +89,7 @@ var package = Package(
dependencies: [
.target(name: "OktaConcurrency"),
.target(name: "OktaClientMacros")
- ],
- exclude: exclude(),
- resources: include()),
+ ]),
.target(name: "KeychainTestCommon",
dependencies: [
.target(name: "Keychain")
@@ -110,9 +107,7 @@ var package = Package(
dependencies: [
.target(name: "OktaConcurrency"),
.target(name: "OktaClientMacros")
- ],
- exclude: exclude(),
- resources: include()),
+ ]),
.testTarget(name: "OktaUtilitiesTests",
dependencies: [
.target(name: "OktaUtilities"),
@@ -129,9 +124,7 @@ var package = Package(
.target(name: "APIClient",
dependencies: [
.target(name: "OktaUtilities"),
- ],
- exclude: exclude(),
- resources: include()),
+ ]),
.testTarget(name: "APIClientTests",
dependencies: [
.target(name: "APIClient"),
@@ -155,8 +148,7 @@ var package = Package(
.target(name: "OktaConcurrency"),
.target(name: "APIClient")
],
- exclude: exclude(),
- resources: include(.process("Resources"))),
+ resources: [ .process("Resources") ]),
.testTarget(name: "JWTTests",
dependencies: [
.target(name: "OktaConcurrency"),
@@ -239,7 +231,9 @@ var package = Package(
#if compiler(>=6)
for target in package.targets where target.type != .system && target.type != .test {
- target.swiftSettings = target.swiftSettings ?? []
+ target.swiftSettings = target.swiftSettings ?? [
+ .enableExperimentalFeature("StrictConcurrency=complete")
+ ]
target.swiftSettings?.append(contentsOf: [
.enableExperimentalFeature("StrictConcurrency"),
.enableUpcomingFeature("ExistentialAny"),
diff --git a/Sources/APIClient/PrivacyInfo.xcprivacy b/Sources/APIClient/PrivacyInfo.xcprivacy
deleted file mode 100644
index c6bdf9c11..000000000
--- a/Sources/APIClient/PrivacyInfo.xcprivacy
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- NSPrivacyAccessedAPITypes
-
- NSPrivacyTracking
-
- NSPrivacyTrackingDomains
-
- NSPrivacyCollectedDataTypes
-
-
-
diff --git a/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift b/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift
index bd517cb84..b29ce00b5 100644
--- a/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift
+++ b/Sources/AuthFoundation/Migration/Migrators/OIDCLegacyMigrator.swift
@@ -15,7 +15,7 @@ import OktaUtilities
import Keychain
import JWT
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
private let accountIdRegex = try? NSRegularExpression(pattern: "0oa[0-9a-zA-Z]{17}")
diff --git a/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift
index 1a0015d6f..467bc11d4 100644
--- a/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift
+++ b/Sources/AuthFoundation/Token Management/Internal/KeychainTokenStorage.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import Foundation
import Keychain
@@ -56,6 +56,10 @@ final class KeychainTokenStorage: TokenStorage {
_defaultTokenID = id
try saveDefault()
+
+ DispatchQueue.global().async {
+ self.delegate?.token(storage: self, defaultChanged: id)
+ }
}
var defaultTokenID: String? {
diff --git a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift
index 257f67eb5..e8b040fce 100644
--- a/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift
+++ b/Sources/AuthFoundation/Token Management/Internal/UserDefaultsTokenStorage.swift
@@ -78,6 +78,10 @@ final class UserDefaultsTokenStorage: TokenStorage {
userDefaults.removeObject(forKey: UserDefaultsKeys.defaultTokenKey)
}
userDefaults.synchronize()
+
+ DispatchQueue.global().async {
+ self.delegate?.token(storage: self, defaultChanged: id)
+ }
}
var defaultTokenID: String? {
diff --git a/Sources/AuthFoundation/Token Management/TokenStorage.swift b/Sources/AuthFoundation/Token Management/TokenStorage.swift
index 71cfb8f70..4800d7e49 100644
--- a/Sources/AuthFoundation/Token Management/TokenStorage.swift
+++ b/Sources/AuthFoundation/Token Management/TokenStorage.swift
@@ -67,6 +67,9 @@ public protocol TokenStorage: Sendable {
/// Protocol that custom ``TokenStorage`` instances are required to communicate changes to.
public protocol TokenStorageDelegate: AnyObject, Sendable {
+ /// Sent when the default token has been changed.
+ func token(storage: any TokenStorage, defaultChanged id: String?)
+
/// Sent when a new token has been added.
///
/// > Important: This message should only be sent when a token is actually new. If the token is semantically identical to another one already in storage, the ``token(storage:replaced:with:)`` message should be sent instead.
diff --git a/Sources/AuthFoundation/User Management/CredentialSecurity+StaticProperties.swift b/Sources/AuthFoundation/User Management/CredentialSecurity+StaticProperties.swift
index 472b7c7be..6a29a9b15 100644
--- a/Sources/AuthFoundation/User Management/CredentialSecurity+StaticProperties.swift
+++ b/Sources/AuthFoundation/User Management/CredentialSecurity+StaticProperties.swift
@@ -18,7 +18,7 @@ import OktaClientMacros
fileprivate let staticLock = Lock()
nonisolated(unsafe) fileprivate var _isDefaultSynchronizable: Bool = false
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
nonisolated(unsafe) fileprivate var _standard: [Credential.Security] = [.accessibility(.afterFirstUnlockThisDeviceOnly)]
#else
nonisolated(unsafe) fileprivate var _standard: [Credential.Security] = []
diff --git a/Sources/AuthFoundation/User Management/CredentialSecurity.swift b/Sources/AuthFoundation/User Management/CredentialSecurity.swift
index e0280f17e..dce54932d 100644
--- a/Sources/AuthFoundation/User Management/CredentialSecurity.swift
+++ b/Sources/AuthFoundation/User Management/CredentialSecurity.swift
@@ -27,7 +27,7 @@ extension Credential {
///
/// On Apple platforms, this controls the Keychain security settings for the underlying token's keychain item.
public enum Security {
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
/// Defines the accessibility level for a credential.
case accessibility(_ option: Keychain.Accessibility)
diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift
index af77e15ed..e5a192ca8 100644
--- a/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift
+++ b/Sources/AuthFoundation/User Management/Internal/CredentialCoordinatorImpl.swift
@@ -111,7 +111,7 @@ final class CredentialCoordinatorImpl: Sendable, CredentialCoordinator {
}
static func defaultTokenStorage() -> any TokenStorage {
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
KeychainTokenStorage()
#else
UserDefaultsTokenStorage()
@@ -216,23 +216,17 @@ extension CredentialCoordinatorImpl: OAuth2ClientDelegate {
}
extension CredentialCoordinatorImpl: TokenStorageDelegate {
-// func token(storage: any TokenStorage, defaultTokenChanged token: Token?) {
-// withLock {
-// // Ensure the default matches what the Token Storage says,
-// // and that the new token is indeed different from the local default.
-// guard _tokenStorage.defaultTokenID == token?.id,
-// _default?.id != token?.id
-// else {
-// return
-// }
-//
-// if let token = token {
-// _default = _credentialDataSource.credential(for: token, coordinator: self)
-// } else {
-// _default = nil
-// }
-// }
-// }
+ func token(storage: any TokenStorage, defaultChanged id: String?) {
+ // Almost all default ID changes will be triggered from the Credential Coordinator.
+ // In the rare event that the underlying value is changed from some other means,
+ // this operation will ensure the statei of this class will remain consistent.
+ withLock {
+ // Ensure the new token is indeed different from the local default.
+ if _default?.id != id {
+ _default = nil
+ }
+ }
+ }
func token(storage: any TokenStorage, added id: String, token: Token) {
}
@@ -243,7 +237,6 @@ extension CredentialCoordinatorImpl: TokenStorageDelegate {
func token(storage: any TokenStorage, replaced id: String, with newToken: Token) {
// Doing nothing with this, for now...
}
-
}
extension CredentialCoordinatorImpl: CredentialDataSourceDelegate {
diff --git a/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift b/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift
index 32049ecec..6d3cb3d89 100644
--- a/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift
+++ b/Sources/AuthFoundation/User Management/Internal/CredentialSecurity+Internal.swift
@@ -18,7 +18,7 @@ import LocalAuthentication
#endif
extension Array where Element == Credential.Security {
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
#if canImport(LocalAuthentication) && !os(tvOS)
var context: LAContext? {
for case let Credential.Security.context(value) in self {
diff --git a/Sources/JWT/Enums/JWTClaim.swift b/Sources/JWT/Enums/JWTClaim.swift
index b21011c47..0ff025d6b 100644
--- a/Sources/JWT/Enums/JWTClaim.swift
+++ b/Sources/JWT/Enums/JWTClaim.swift
@@ -277,7 +277,7 @@ public extension HasClaims where ClaimType == JWTClaim {
/// The person's preferred username.
var preferredUsername: String? { self[.preferredUsername] }
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
/// The person's name components, pre-assigned to a PersonNameComponents object.
///
/// This property can be used as a convenience to generate a string representation of the user's name, based on the user's current locale.
diff --git a/Sources/JWT/PrivacyInfo.xcprivacy b/Sources/JWT/PrivacyInfo.xcprivacy
deleted file mode 100644
index c6bdf9c11..000000000
--- a/Sources/JWT/PrivacyInfo.xcprivacy
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- NSPrivacyAccessedAPITypes
-
- NSPrivacyTracking
-
- NSPrivacyTrackingDomains
-
- NSPrivacyCollectedDataTypes
-
-
-
diff --git a/Sources/Keychain/Internal/Keychain+Extensions.swift b/Sources/Keychain/Internal/Keychain+Extensions.swift
index 143f83e5c..2087a45e9 100644
--- a/Sources/Keychain/Internal/Keychain+Extensions.swift
+++ b/Sources/Keychain/Internal/Keychain+Extensions.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
@preconcurrency import Foundation
diff --git a/Sources/Keychain/Internal/KeychainProtocol.swift b/Sources/Keychain/Internal/KeychainProtocol.swift
index 89d45bc15..7bbd4914c 100644
--- a/Sources/Keychain/Internal/KeychainProtocol.swift
+++ b/Sources/Keychain/Internal/KeychainProtocol.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import Foundation
diff --git a/Sources/Keychain/Keychain.swift b/Sources/Keychain/Keychain.swift
index 46e176b02..806e3849d 100644
--- a/Sources/Keychain/Keychain.swift
+++ b/Sources/Keychain/Keychain.swift
@@ -14,7 +14,7 @@ import Foundation
import OktaConcurrency
import OktaClientMacros
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
#if canImport(LocalAuthentication) && !os(tvOS)
import LocalAuthentication
diff --git a/Sources/Keychain/KeychainError.swift b/Sources/Keychain/KeychainError.swift
index 884e5988a..baa118cfb 100644
--- a/Sources/Keychain/KeychainError.swift
+++ b/Sources/Keychain/KeychainError.swift
@@ -12,7 +12,7 @@
import Foundation
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
/// Describes errors that may occur when interacting with the keychain.
public enum KeychainError: Error {
diff --git a/Sources/OktaConcurrency/PrivacyInfo.xcprivacy b/Sources/OktaConcurrency/PrivacyInfo.xcprivacy
deleted file mode 100644
index c6bdf9c11..000000000
--- a/Sources/OktaConcurrency/PrivacyInfo.xcprivacy
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- NSPrivacyAccessedAPITypes
-
- NSPrivacyTracking
-
- NSPrivacyTrackingDomains
-
- NSPrivacyCollectedDataTypes
-
-
-
diff --git a/Sources/OktaUtilities/PrivacyInfo.xcprivacy b/Sources/OktaUtilities/PrivacyInfo.xcprivacy
deleted file mode 100644
index c6bdf9c11..000000000
--- a/Sources/OktaUtilities/PrivacyInfo.xcprivacy
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- NSPrivacyAccessedAPITypes
-
- NSPrivacyTracking
-
- NSPrivacyTrackingDomains
-
- NSPrivacyCollectedDataTypes
-
-
-
diff --git a/Tests/AuthFoundationTests/CredentialCoordinatorTests.swift b/Tests/AuthFoundationTests/CredentialCoordinatorTests.swift
index f7c3a4d8c..be5933558 100644
--- a/Tests/AuthFoundationTests/CredentialCoordinatorTests.swift
+++ b/Tests/AuthFoundationTests/CredentialCoordinatorTests.swift
@@ -19,7 +19,7 @@ import FoundationNetworking
@testable import TestCommon
@testable import AuthFoundation
-final class UserCoordinatorTests: XCTestCase {
+final class CredentialCoordinatorTests: XCTestCase {
var userDefaults: UserDefaults!
var storage: UserDefaultsTokenStorage!
var coordinator: CredentialCoordinatorImpl!
@@ -80,10 +80,31 @@ final class UserCoordinatorTests: XCTestCase {
}
func testImplicitCredentialForToken() throws {
+ XCTAssertNil(storage.defaultTokenID)
+ XCTAssertNil(coordinator.default)
+
let credential = try coordinator.store(token: token, security: [])
XCTAssertEqual(storage.allIDs, [token.id])
XCTAssertEqual(storage.defaultTokenID, token.id)
XCTAssertEqual(coordinator.default, credential)
+
+ XCTAssertNoThrow(try credential.remove())
+ XCTAssertNil(storage.defaultTokenID)
+ XCTAssertNil(coordinator.default)
+ }
+
+ func testRespondToStorageDelegate() throws {
+ coordinator.default = try coordinator.store(token: token, security: [])
+
+ XCTAssertEqual(storage.allIDs, [token.id])
+ XCTAssertEqual(storage.defaultTokenID, token.id)
+ XCTAssertEqual(coordinator.default?.id, token.id)
+
+ XCTAssertNoThrow(try storage.remove(id: token.id))
+ XCTAssertNil(storage.defaultTokenID)
+
+ sleep(for: .standard)
+ XCTAssertNil(coordinator.default)
}
}
diff --git a/Tests/AuthFoundationTests/CredentialNotificationTests.swift b/Tests/AuthFoundationTests/CredentialNotificationTests.swift
index 0922fd12e..eb54f2173 100644
--- a/Tests/AuthFoundationTests/CredentialNotificationTests.swift
+++ b/Tests/AuthFoundationTests/CredentialNotificationTests.swift
@@ -57,25 +57,22 @@ final class CredentialNotificationTests: XCTestCase {
}
func testNotifications() throws {
- let wait = expectation(description: "Main actor")
+ let oldCredential = coordinator.default
- Task { @MainActor in
- let oldCredential = coordinator.default
-
- let recorder = NotificationRecorder(observing: [.defaultCredentialChanged])
-
- let credential = try coordinator.store(token: token, security: [])
- self.wait(for: .standard)
- XCTAssertEqual(recorder.notifications.count, 1)
- XCTAssertEqual(recorder.notifications.first?.object as? Credential, credential)
- XCTAssertNotEqual(oldCredential, credential)
-
- recorder.reset()
- coordinator.default = nil
- self.wait(for: .standard)
- XCTAssertEqual(recorder.notifications.count, 1)
- XCTAssertNil(recorder.notifications.first?.object)
- }
- waitForExpectations(timeout: .long)
+ let recorder = NotificationRecorder(observing: [.defaultCredentialChanged])
+
+ let credential = try coordinator.store(token: token, security: [])
+ sleep(for: .short)
+
+ XCTAssertEqual(recorder.notifications.count, 1)
+ XCTAssertEqual(recorder.notifications.first?.object as? Credential, credential)
+ XCTAssertNotEqual(oldCredential, credential)
+
+ recorder.reset()
+ coordinator.default = nil
+ sleep(for: .short)
+
+ XCTAssertEqual(recorder.notifications.count, 1)
+ XCTAssertNil(recorder.notifications.first?.object)
}
}
diff --git a/Tests/AuthFoundationTests/CredentialRefreshTests.swift b/Tests/AuthFoundationTests/CredentialRefreshTests.swift
index 0c13ab780..32893bbc8 100644
--- a/Tests/AuthFoundationTests/CredentialRefreshTests.swift
+++ b/Tests/AuthFoundationTests/CredentialRefreshTests.swift
@@ -310,7 +310,7 @@ final class CredentialRefreshTests: XCTestCase, OAuth2ClientDelegate {
// Stopping should prevent subsequent refreshes
credential.automaticRefresh = false
- sleep(1)
+ sleep(for: .short)
XCTAssertEqual(urlSession.requests.count, 0)
}
diff --git a/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift b/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift
index 1c8c4a9d8..54dd9f905 100644
--- a/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift
+++ b/Tests/AuthFoundationTests/KeychainTokenStorageTests.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import XCTest
@testable import AuthFoundation
diff --git a/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift b/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift
index 4d6deacf0..9422204eb 100644
--- a/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift
+++ b/Tests/AuthFoundationTests/OIDCLegacyMigratorTests.swift
@@ -18,7 +18,7 @@ import XCTest
@testable import Keychain
@testable import KeychainTestCommon
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
final class OIDCLegacyMigratorTests: XCTestCase {
typealias LegacyOIDC = SDKVersion.Migration.LegacyOIDC
diff --git a/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift b/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift
index 8d85a2294..658ab23e2 100644
--- a/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift
+++ b/Tests/AuthFoundationTests/UserDefaultsTokenStorageTests.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import XCTest
@testable import AuthFoundation
import TestCommon
@@ -73,7 +73,7 @@ final class UserDefaultTokenStorageTests: XCTestCase {
XCTAssertThrowsError(try storage.add(token: token, security: []))
XCTAssertEqual(storage.allIDs.count, 1)
- XCTAssertNoThrow(try storage.update(token: newToken, security: nil))
+ XCTAssertThrowsError(try storage.update(token: newToken, security: nil))
XCTAssertEqual(storage.allIDs.count, 1)
XCTAssertNoThrow(try storage.remove(id: token.id))
@@ -85,11 +85,12 @@ final class UserDefaultTokenStorageTests: XCTestCase {
func testImplicitDefaultToken() throws {
XCTAssertNil(storage.defaultTokenID)
-
+ XCTAssertTrue(storage.allIDs.isEmpty)
+
XCTAssertNoThrow(try storage.add(token: token, security: []))
XCTAssertEqual(storage.allIDs.count, 1)
- XCTAssertEqual(storage.defaultTokenID, token.id)
+ XCTAssertNil(storage.defaultTokenID)
}
func testRemoveDefaultToken() throws {
diff --git a/Tests/AuthFoundationTests/UserInfoTests.swift b/Tests/AuthFoundationTests/UserInfoTests.swift
index 55783fb7f..af318205f 100644
--- a/Tests/AuthFoundationTests/UserInfoTests.swift
+++ b/Tests/AuthFoundationTests/UserInfoTests.swift
@@ -30,7 +30,7 @@ final class UserInfoTests: XCTestCase {
XCTAssertTrue(info.emailVerified!)
XCTAssertEqual(info.address?["street_address"], "155 Country Lane")
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
if #available(iOS 15, macCatalyst 15, macOS 12.0, tvOS 15, watchOS 8, *) {
let formatter = PersonNameComponentsFormatter()
formatter.style = .long
diff --git a/Tests/KeychainTestCommon/MockKeychain.swift b/Tests/KeychainTestCommon/MockKeychain.swift
index 6728c7a1b..478952184 100644
--- a/Tests/KeychainTestCommon/MockKeychain.swift
+++ b/Tests/KeychainTestCommon/MockKeychain.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import Foundation
@testable import Keychain
diff --git a/Tests/KeychainTests/KeychainErrorTests.swift b/Tests/KeychainTests/KeychainErrorTests.swift
index 6bd020487..64f5a1e43 100644
--- a/Tests/KeychainTests/KeychainErrorTests.swift
+++ b/Tests/KeychainTests/KeychainErrorTests.swift
@@ -15,7 +15,7 @@ import XCTest
final class KeychainErrorTests: XCTestCase {
func testKeychainError() {
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
XCTAssertNotEqual(KeychainError.cannotGet(code: noErr).errorDescription,
"keychain_cannot_get")
XCTAssertNotEqual(KeychainError.cannotList(code: noErr).errorDescription,
diff --git a/Tests/KeychainTests/KeychainTests.swift b/Tests/KeychainTests/KeychainTests.swift
index f4ab7e019..3ce7309df 100644
--- a/Tests/KeychainTests/KeychainTests.swift
+++ b/Tests/KeychainTests/KeychainTests.swift
@@ -10,7 +10,7 @@
// See the License for the specific language governing permissions and limitations under the License.
//
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+#if canImport(Darwin)
import XCTest
@testable import Keychain
diff --git a/Tests/OktaDirectAuthTests/ErrorTests.swift b/Tests/OktaDirectAuthTests/ErrorTests.swift
index d0cd956ec..7c509add2 100644
--- a/Tests/OktaDirectAuthTests/ErrorTests.swift
+++ b/Tests/OktaDirectAuthTests/ErrorTests.swift
@@ -67,7 +67,7 @@ final class ErrorTests: XCTestCase {
XCTAssertEqual(DirectAuthenticationFlowError(APIClientError.serverError(serverError)),
.server(error: serverError))
- #if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+ #if canImport(Darwin)
// Ensure a generic error embedded in OAuth2Error becomes the appropriate error type
XCTAssertEqual(DirectAuthenticationFlowError(OAuth2Error.error(KeychainError.invalidFormat)),
.other(error: KeychainError.invalidFormat))
diff --git a/Tests/TestCommon/XCTestCase+Extensions.swift b/Tests/TestCommon/XCTestCase+Extensions.swift
index e0726dd92..49e26a712 100644
--- a/Tests/TestCommon/XCTestCase+Extensions.swift
+++ b/Tests/TestCommon/XCTestCase+Extensions.swift
@@ -104,12 +104,11 @@ public extension XCTestCase {
_ = group.wait(timeout: .short)
}
- @MainActor
- func wait(for interval: TimeInterval) {
- let waitExpectation = expectation(description: "Wait for \(interval)s")
- DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
- waitExpectation.fulfill()
+ func sleep(for duration: TimeInterval) {
+ let sleepExpectation = expectation(description: "Sleep for \(duration) seconds")
+ DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
+ sleepExpectation.fulfill()
}
- waitForExpectations(timeout: interval * 1.5)
+ wait(for: [sleepExpectation])
}
}
diff --git a/Tests/WebAuthenticationUITests/WebAuthenticationFlowTests.swift b/Tests/WebAuthenticationUITests/WebAuthenticationFlowTests.swift
index f8e11ed4d..ca86964a7 100644
--- a/Tests/WebAuthenticationUITests/WebAuthenticationFlowTests.swift
+++ b/Tests/WebAuthenticationUITests/WebAuthenticationFlowTests.swift
@@ -53,7 +53,7 @@ class WebAuthenticationUITests: XCTestCase {
let webAuth = WebAuthentication(loginFlow: loginFlow, logoutFlow: logoutFlow)
webAuth.signIn(from: nil, options: [.state("qwe")]) { _ in }
- wait(for: .short)
+ sleep(for: .short)
let webAuthProvider = try XCTUnwrap(webAuth.provider as? WebAuthenticationProviderMock)
@@ -65,7 +65,7 @@ class WebAuthenticationUITests: XCTestCase {
let webAuth = WebAuthentication(loginFlow: loginFlow, logoutFlow: logoutFlow)
webAuth.signOut(from: nil, token: "idToken", options: [.state("qwe")]) { _ in }
- wait(for: .short)
+ sleep(for: .short)
let provider = try XCTUnwrap(webAuth.provider as? WebAuthenticationProviderMock)
XCTAssertNil(webAuth.completionBlock)
@@ -78,7 +78,7 @@ class WebAuthenticationUITests: XCTestCase {
XCTAssertNil(webAuth.provider)
webAuth.signIn(from: nil, options: [.state("qwe")]) { _ in }
- wait(for: .short)
+ sleep(for: .short)
let webAuthProvider = try XCTUnwrap(webAuth.provider as? WebAuthenticationProviderMock)