Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions Features/QRScanner/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ let package = Package(
"Localization"
],
path: "Sources"
),
.testTarget(
name: "QRScannerTests",
dependencies: ["QRScanner"]),
)
]
)
6 changes: 0 additions & 6 deletions Features/QRScanner/Tests/QRScannerTests/QRScannerTests.swift

This file was deleted.

3 changes: 0 additions & 3 deletions Features/Settings/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ let package = Package(
],
path: "Sources"
),
.testTarget(
name: "SettingsTests",
dependencies: ["Settings"]),
.testTarget(
name: "CurrencyTests",
dependencies: [
Expand Down
6 changes: 0 additions & 6 deletions Features/Settings/Tests/SettingsTests/SettingsTests.swift

This file was deleted.

This file was deleted.

This file was deleted.

84 changes: 49 additions & 35 deletions Packages/GemAPI/Tests/GemAPITests/DeviceRequestSignerTests.swift
Original file line number Diff line number Diff line change
@@ -1,99 +1,112 @@
// 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 {}
Comment on lines +51 to +54
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this do-catch block works, swift-testing provides a more idiomatic way to test for thrown errors using #expect(throws:). This makes the test more concise and clearly states the intent. The DeviceRequestSigner initializer is expected to throw an AnyError for invalid hex input.

        #expect(throws: AnyError.self) {
            _ = try DeviceRequestSigner(privateKeyHex: "not_valid_hex")
        }

}

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")!)
request.httpMethod = "GET"

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"

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"

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"
Expand All @@ -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
Expand All @@ -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)
}
}
Loading
Loading