diff --git a/Features/QRScanner/Package.swift b/Features/QRScanner/Package.swift index a082b1a61..d72ba3a30 100644 --- a/Features/QRScanner/Package.swift +++ b/Features/QRScanner/Package.swift @@ -23,9 +23,6 @@ let package = Package( "Localization" ], path: "Sources" - ), - .testTarget( - name: "QRScannerTests", - dependencies: ["QRScanner"]), + ) ] ) diff --git a/Features/QRScanner/Tests/QRScannerTests/QRScannerTests.swift b/Features/QRScanner/Tests/QRScannerTests/QRScannerTests.swift deleted file mode 100644 index deb772167..000000000 --- a/Features/QRScanner/Tests/QRScannerTests/QRScannerTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import QRScanner - -final class QRScannerTests: XCTestCase { - -} diff --git a/Features/Settings/Package.swift b/Features/Settings/Package.swift index 668dce8ae..fb8affe2f 100644 --- a/Features/Settings/Package.swift +++ b/Features/Settings/Package.swift @@ -63,9 +63,6 @@ let package = Package( ], path: "Sources" ), - .testTarget( - name: "SettingsTests", - dependencies: ["Settings"]), .testTarget( name: "CurrencyTests", dependencies: [ diff --git a/Features/Settings/Tests/SettingsTests/SettingsTests.swift b/Features/Settings/Tests/SettingsTests/SettingsTests.swift deleted file mode 100644 index b01ab0f40..000000000 --- a/Features/Settings/Tests/SettingsTests/SettingsTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import Settings - -final class SettingsTests: XCTestCase { - -} diff --git a/Packages/Components/Tests/ComponentsTests/ComponentsTests.swift b/Packages/Components/Tests/ComponentsTests/ComponentsTests.swift deleted file mode 100644 index 3b7a0572b..000000000 --- a/Packages/Components/Tests/ComponentsTests/ComponentsTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import Components - -final class ComponentsTests: XCTestCase { - -} diff --git a/Packages/FeatureServices/WalletService/TestKit/WalletService+TestKit.swift b/Packages/FeatureServices/WalletService/TestKit/WalletService+TestKit.swift deleted file mode 100644 index fe17786c1..000000000 --- a/Packages/FeatureServices/WalletService/TestKit/WalletService+TestKit.swift +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c). Gem Wallet. All rights reserved. - -import Foundation -import StoreTestKit -import KeystoreTestKit -import PreferencesTestKit -import WalletService -import Store -import Keystore -import Preferences -import AvatarService - -public extension WalletService { - static func mock( - keystore: any Keystore = LocalKeystore.mock(), - walletStore: WalletStore = .mock(), - preferences: ObservablePreferences = .mock(), - avatarService: AvatarService = AvatarService(store: .mock()) - ) -> WalletService { - WalletService( - keystore: keystore, - walletStore: walletStore, - preferences: preferences, - avatarService: avatarService - ) - } -} diff --git a/Packages/GemAPI/Tests/GemAPITests/DeviceRequestSignerTests.swift b/Packages/GemAPI/Tests/GemAPITests/DeviceRequestSignerTests.swift index 975dd6f5c..acbb8e328 100644 --- a/Packages/GemAPI/Tests/GemAPITests/DeviceRequestSignerTests.swift +++ b/Packages/GemAPI/Tests/GemAPITests/DeviceRequestSignerTests.swift @@ -1,51 +1,61 @@ // Copyright (c). Gem Wallet. All rights reserved. -import XCTest import Foundation import CryptoKit +import Testing import Primitives @testable import GemAPI -final class DeviceRequestSignerTests: XCTestCase { +struct DeviceRequestSignerTests { - func testKeyPairGeneratesValidHex() { + @Test + func keyPairGeneratesValidHex() { let keyPair = DeviceKeyPair() - XCTAssertEqual(keyPair.privateKeyHex.count, 64) - XCTAssertEqual(keyPair.publicKeyHex.count, 64) - XCTAssertNotEqual(keyPair.privateKeyHex, keyPair.publicKeyHex) + #expect(keyPair.privateKeyHex.count == 64) + #expect(keyPair.publicKeyHex.count == 64) + #expect(keyPair.privateKeyHex != keyPair.publicKeyHex) } - func testKeyPairGeneratesUniqueKeys() { + @Test + func keyPairGeneratesUniqueKeys() { let a = DeviceKeyPair() let b = DeviceKeyPair() - XCTAssertNotEqual(a.privateKeyHex, b.privateKeyHex) - XCTAssertNotEqual(a.publicKeyHex, b.publicKeyHex) + #expect(a.privateKeyHex != b.privateKeyHex) + #expect(a.publicKeyHex != b.publicKeyHex) } - func testKeyPairGeneratesValidData() { + @Test + func keyPairGeneratesValidData() { let keyPair = DeviceKeyPair() - XCTAssertEqual(keyPair.privateKey.count, 32) - XCTAssertEqual(keyPair.publicKey.count, 32) - XCTAssertNotEqual(keyPair.privateKey, keyPair.publicKey) + #expect(keyPair.privateKey.count == 32) + #expect(keyPair.publicKey.count == 32) + #expect(keyPair.privateKey != keyPair.publicKey) } - func testSignerInitFromPrivateKey() throws { + @Test + func signerInitFromPrivateKey() throws { let keyPair = DeviceKeyPair() let signer = try DeviceRequestSigner(privateKey: keyPair.privateKey) - XCTAssertEqual(signer.publicKeyHex, keyPair.publicKeyHex) + #expect(signer.publicKeyHex == keyPair.publicKeyHex) } - func testSignerInitFromPrivateKeyHex() throws { + @Test + func signerInitFromPrivateKeyHex() throws { let keyPair = DeviceKeyPair() let signer = try DeviceRequestSigner(privateKeyHex: keyPair.privateKeyHex) - XCTAssertEqual(signer.publicKeyHex, keyPair.publicKeyHex) + #expect(signer.publicKeyHex == keyPair.publicKeyHex) } - func testSignerRejectsInvalidHex() { - XCTAssertThrowsError(try DeviceRequestSigner(privateKeyHex: "not_valid_hex")) + @Test + func signerRejectsInvalidHex() { + do { + _ = try DeviceRequestSigner(privateKeyHex: "not_valid_hex") + Issue.record("Expected invalid hex to throw") + } catch {} } - func testSignSetsAuthorizationHeader() throws { + @Test + func signSetsAuthorizationHeader() throws { let keyPair = DeviceKeyPair() let signer = try DeviceRequestSigner(privateKeyHex: keyPair.privateKeyHex) var request = URLRequest(url: URL(string: "https://api.gemwallet.com/v2/devices")!) @@ -53,11 +63,12 @@ final class DeviceRequestSignerTests: XCTestCase { try signer.sign(request: &request) - let auth = request.value(forHTTPHeaderField: "Authorization")! - XCTAssertTrue(auth.hasPrefix("Gem ")) + let auth = try #require(request.value(forHTTPHeaderField: "Authorization")) + #expect(auth.hasPrefix("Gem ")) } - func testSignatureVerifiesWithPublicKey() throws { + @Test + func signatureVerifiesWithPublicKey() throws { let (signer, keyPair) = try makeSigner() var request = URLRequest(url: URL(string: "https://api.gemwallet.com/v2/devices")!) request.httpMethod = "GET" @@ -65,18 +76,19 @@ final class DeviceRequestSignerTests: XCTestCase { try signer.sign(request: &request) let parts = try decodePayload(from: request) - XCTAssertEqual(parts.count, 5) - XCTAssertEqual(parts[0], keyPair.publicKeyHex) - XCTAssertEqual(parts[2], "") + #expect(parts.count == 5) + #expect(parts[0] == keyPair.publicKeyHex) + #expect(parts[2] == "") let message = "\(parts[1]).GET./v2/devices.\(parts[2]).\(parts[3])" let sigData = try Data.from(hex: parts[4]) let publicKey = try Curve25519.Signing.PublicKey(rawRepresentation: Data.from(hex: keyPair.publicKeyHex)) - XCTAssertTrue(publicKey.isValidSignature(sigData, for: Data(message.utf8))) + #expect(publicKey.isValidSignature(sigData, for: Data(message.utf8))) } - func testSignWithWalletId() throws { + @Test + func signWithWalletId() throws { let (signer, _) = try makeSigner() var request = URLRequest(url: URL(string: "https://api.gemwallet.com/v2/devices/rewards")!) request.httpMethod = "GET" @@ -84,16 +96,17 @@ final class DeviceRequestSignerTests: XCTestCase { try signer.sign(request: &request, walletId: "multicoin_0xabc") let parts = try decodePayload(from: request) - XCTAssertEqual(parts[2], "multicoin_0xabc") + #expect(parts[2] == "multicoin_0xabc") let message = "\(parts[1]).GET./v2/devices/rewards.\(parts[2]).\(parts[3])" let sigData = try Data.from(hex: parts[4]) let publicKey = try Curve25519.Signing.PublicKey(rawRepresentation: Data.from(hex: parts[0])) - XCTAssertTrue(publicKey.isValidSignature(sigData, for: Data(message.utf8))) + #expect(publicKey.isValidSignature(sigData, for: Data(message.utf8))) } - func testSignWithBody() throws { + @Test + func signWithBody() throws { let (signer, _) = try makeSigner() var request = URLRequest(url: URL(string: "https://api.gemwallet.com/v2/devices")!) request.httpMethod = "POST" @@ -103,8 +116,8 @@ final class DeviceRequestSignerTests: XCTestCase { let parts = try decodePayload(from: request) let emptyHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - XCTAssertNotEqual(parts[3], emptyHash) - XCTAssertEqual(parts[3].count, 64) + #expect(parts[3] != emptyHash) + #expect(parts[3].count == 64) } // MARK: - Helpers @@ -116,9 +129,10 @@ final class DeviceRequestSignerTests: XCTestCase { } private func decodePayload(from request: URLRequest) throws -> [String] { - let auth = try XCTUnwrap(request.value(forHTTPHeaderField: "Authorization")) + let auth = try #require(request.value(forHTTPHeaderField: "Authorization")) let encoded = String(auth.dropFirst("Gem ".count)) - let decoded = String(data: try XCTUnwrap(Data(base64Encoded: encoded)), encoding: .utf8)! + let data = try #require(Data(base64Encoded: encoded)) + let decoded = try #require(String(data: data, encoding: .utf8)) return decoded.split(separator: ".", maxSplits: 4, omittingEmptySubsequences: false).map(String.init) } } diff --git a/Packages/GemAPI/Tests/GemAPITests/GemAPITests.swift b/Packages/GemAPI/Tests/GemAPITests/GemAPITests.swift index fc9916151..91fe74124 100644 --- a/Packages/GemAPI/Tests/GemAPITests/GemAPITests.swift +++ b/Packages/GemAPI/Tests/GemAPITests/GemAPITests.swift @@ -1,102 +1,121 @@ // Copyright (c). Gem Wallet. All rights reserved. import Foundation -import XCTest +import Testing import Primitives import SwiftHTTPClient @testable import GemAPI -final class GemAPITests: XCTestCase { +@Suite(.serialized) +struct GemAPITests { - override func tearDown() { - MockURLProtocol.handler = nil - MockURLProtocol.observer = nil - super.tearDown() - } - - func testWalletScopedRequestWaitsForPreflight() async throws { + @Test + func walletScopedRequestWaitsForPreflight() async throws { let events = RequestEvents() - let service = makeService( + let assetIds = try await withMockURLProtocol( observer: { _ in events.record("request") - }, - walletRequestPreflight: { - events.record("preflight-start") - try await Task.sleep(for: .milliseconds(20)) - events.record("preflight-end") } - ) - - let assetIds = try await service.getDeviceAssets(walletId: "wallet", fromTimestamp: 0) + ) { + let service = makeService( + walletRequestPreflight: { + events.record("preflight-start") + try await Task.sleep(for: .milliseconds(20)) + events.record("preflight-end") + } + ) + + return try await service.getDeviceAssets(walletId: "wallet", fromTimestamp: 0) + } - XCTAssertTrue(assetIds.isEmpty) - XCTAssertEqual(events.snapshot(), ["preflight-start", "preflight-end", "request"]) + #expect(assetIds.isEmpty) + #expect(events.snapshot() == ["preflight-start", "preflight-end", "request"]) } - func testNonWalletScopedRequestSkipsPreflight() async throws { + @Test + func nonWalletScopedRequestSkipsPreflight() async throws { let events = RequestEvents() - let service = makeService( - responseBody: Data("[]".utf8), + let names = try await withMockURLProtocol( observer: { _ in events.record("request") - }, - walletRequestPreflight: { - events.record("preflight") } - ) - - let names = try await service.getAddressNames(requests: []) + ) { + let service = makeService( + responseBody: Data("[]".utf8), + walletRequestPreflight: { + events.record("preflight") + } + ) + + return try await service.getAddressNames(requests: []) + } - XCTAssertTrue(names.isEmpty) - XCTAssertEqual(events.snapshot(), ["request"]) + #expect(names.isEmpty) + #expect(events.snapshot() == ["request"]) } - func testWalletScopedPreflightFailurePreventsDispatch() async { + @Test + func walletScopedPreflightFailurePreventsDispatch() async { let events = RequestEvents() - let service = makeService( + await withMockURLProtocol( observer: { _ in events.record("request") - }, - walletRequestPreflight: { - throw TestError.failed } - ) - - do { - _ = try await service.getDeviceAssets(walletId: "wallet", fromTimestamp: 0) - XCTFail("Expected preflight to throw") - } catch { - XCTAssertTrue(events.snapshot().isEmpty) + ) { + let service = makeService( + walletRequestPreflight: { + throw TestError.failed + } + ) + + do { + _ = try await service.getDeviceAssets(walletId: "wallet", fromTimestamp: 0) + Issue.record("Expected preflight to throw") + } catch { + #expect(events.snapshot().isEmpty) + } } } - func testGemDeviceAPIWalletIdClassifiesWalletScopedTargets() { - XCTAssertNil(GemDeviceAPI.getSubscriptions.walletId) - XCTAssertEqual(GemDeviceAPI.getAssetsList(walletId: "wallet", fromTimestamp: 0).walletId, "wallet") - XCTAssertEqual(GemDeviceAPI.getTransactions(walletId: "wallet", assetId: nil, fromTimestamp: 0).walletId, "wallet") - XCTAssertEqual(GemDeviceAPI.getFiatQuoteUrl(walletId: "wallet", quoteId: "quote").walletId, "wallet") + @Test + func gemDeviceAPIWalletIdClassifiesWalletScopedTargets() { + #expect(GemDeviceAPI.getSubscriptions.walletId == nil) + #expect(GemDeviceAPI.getAssetsList(walletId: "wallet", fromTimestamp: 0).walletId == "wallet") + #expect(GemDeviceAPI.getTransactions(walletId: "wallet", assetId: nil, fromTimestamp: 0).walletId == "wallet") + #expect(GemDeviceAPI.getFiatQuoteUrl(walletId: "wallet", quoteId: "quote").walletId == "wallet") } } private extension GemAPITests { - func makeService( + func withMockURLProtocol( responseBody: Data = Data("[]".utf8), observer: @escaping @Sendable (URLRequest) -> Void = { _ in }, - walletRequestPreflight: (@Sendable () async throws -> Void)? = nil - ) -> GemAPIService { - let configuration = URLSessionConfiguration.ephemeral - configuration.protocolClasses = [MockURLProtocol.self] - + _ body: () async throws -> T + ) async rethrows -> T { MockURLProtocol.observer = observer MockURLProtocol.handler = { request in + let url = try #require(request.url) let response = HTTPURLResponse( - url: try XCTUnwrap(request.url), + url: url, statusCode: 200, httpVersion: nil, headerFields: [:] )! return (response, responseBody) } + defer { + MockURLProtocol.handler = nil + MockURLProtocol.observer = nil + } + return try await body() + } + + func makeService( + responseBody: Data = Data("[]".utf8), + walletRequestPreflight: (@Sendable () async throws -> Void)? = nil + ) -> GemAPIService { + let configuration = URLSessionConfiguration.ephemeral + configuration.protocolClasses = [MockURLProtocol.self] let session = URLSession(configuration: configuration) return GemAPIService( diff --git a/Packages/Keystore/Tests/LocalKeystorePasswordTests.swift b/Packages/Keystore/Tests/LocalKeystorePasswordTests.swift deleted file mode 100644 index 66cd06ab4..000000000 --- a/Packages/Keystore/Tests/LocalKeystorePasswordTests.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c). Gem Wallet. All rights reserved. - -import XCTest -import Keystore - -final class LocalKeystorePasswordTests: XCTestCase { - -// func testSet() { -// let service = LocalKeystorePassword() -// -// XCTAssertEqual(try! service.getPassword(), "") -// } -} diff --git a/Packages/Style/Package.swift b/Packages/Style/Package.swift index 04741d28a..71a2b48cb 100644 --- a/Packages/Style/Package.swift +++ b/Packages/Style/Package.swift @@ -17,9 +17,6 @@ let package = Package( name: "Style", dependencies: [], path: "Sources" - ), - .testTarget( - name: "StyleTests", - dependencies: ["Style"]), + ) ] ) diff --git a/Packages/Style/Tests/StyleTests/StyleTests.swift b/Packages/Style/Tests/StyleTests/StyleTests.swift deleted file mode 100644 index bfef4d6ac..000000000 --- a/Packages/Style/Tests/StyleTests/StyleTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import Style - -final class StyleTests: XCTestCase { - -} diff --git a/Packages/SwiftHTTPClient/SwiftHTTPClient/Tests/SwiftHTTPClientTests.swift b/Packages/SwiftHTTPClient/SwiftHTTPClient/Tests/SwiftHTTPClientTests.swift deleted file mode 100644 index 877822717..000000000 --- a/Packages/SwiftHTTPClient/SwiftHTTPClient/Tests/SwiftHTTPClientTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest -@testable import SwiftHTTPClient - -final class SwiftHTTPClientTests: XCTestCase { - -}