Skip to content

Commit 074e3dc

Browse files
Added sendable and equatable conformances to error types
1 parent a4c08bf commit 074e3dc

File tree

7 files changed

+92
-11
lines changed

7 files changed

+92
-11
lines changed

Sources/WebPush/Errors/BadSubscriberError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Foundation
1111
/// The subscription is no longer valid and should be removed and re-registered.
1212
///
1313
/// - Warning: Do not continue to send notifications to invalid subscriptions or you'll risk being rate limited by push services.
14-
public struct BadSubscriberError: LocalizedError, Hashable {
14+
public struct BadSubscriberError: LocalizedError, Hashable, Sendable {
1515
public init() {}
1616

1717
public var errorDescription: String? {

Sources/WebPush/Errors/Base64URLDecodingError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import Foundation
1010

1111
/// An error encountered while decoding Base64 data.
12-
public struct Base64URLDecodingError: LocalizedError, Hashable {
12+
public struct Base64URLDecodingError: LocalizedError, Hashable, Sendable {
1313
public init() {}
1414

1515
public var errorDescription: String? {

Sources/WebPush/Errors/HTTPError.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,26 @@ import Foundation
1414
/// - SeeAlso: [RFC 8030 Generic Event Delivery Using HTTP Push](https://datatracker.ietf.org/doc/html/rfc8030)
1515
/// - SeeAlso: [RFC 8292 Voluntary Application Server Identification (VAPID) for Web Push](https://datatracker.ietf.org/doc/html/rfc8292)
1616
/// - SeeAlso: [Sending web push notifications in web apps and browsers — Review responses for push notification errors](https://developer.apple.com/documentation/usernotifications/sending-web-push-notifications-in-web-apps-and-browsers#Review-responses-for-push-notification-errors)
17-
public struct HTTPError: LocalizedError {
18-
let response: HTTPClientResponse
17+
public struct HTTPError: LocalizedError, Sendable {
18+
public let response: HTTPClientResponse
19+
let capturedResponseDescription: String
1920

20-
init(response: HTTPClientResponse) {
21+
public init(response: HTTPClientResponse) {
2122
self.response = response
23+
self.capturedResponseDescription = "\(response)"
2224
}
2325

2426
public var errorDescription: String? {
25-
"A \(response.status) HTTP error was encountered: \(response)."
27+
"A \(response.status) HTTP error was encountered: \(capturedResponseDescription)."
28+
}
29+
}
30+
31+
extension HTTPError: Hashable {
32+
public static func == (lhs: Self, rhs: Self) -> Bool {
33+
"\(lhs.capturedResponseDescription)" == "\(rhs.capturedResponseDescription)"
34+
}
35+
36+
public func hash(into hasher: inout Hasher) {
37+
hasher.combine("\(capturedResponseDescription)")
2638
}
2739
}

Sources/WebPush/Errors/MessageTooLargeError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Foundation
1111
/// The message was too large, and could not be delivered to the push service.
1212
///
1313
/// - SeeAlso: ``WebPushManager/maximumMessageSize``
14-
public struct MessageTooLargeError: LocalizedError, Hashable {
14+
public struct MessageTooLargeError: LocalizedError, Hashable, Sendable {
1515
public init() {}
1616

1717
public var errorDescription: String? {

Sources/WebPush/Errors/UserAgentKeyMaterialError.swift

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import Foundation
1010

1111
/// An error encountered during ``VAPID/Configuration`` initialization or decoding.
12-
public struct UserAgentKeyMaterialError: LocalizedError {
12+
public struct UserAgentKeyMaterialError: LocalizedError, Sendable {
1313
enum Kind {
1414
case invalidPublicKey
1515
case invalidAuthenticationSecret
@@ -31,9 +31,20 @@ public struct UserAgentKeyMaterialError: LocalizedError {
3131
public var errorDescription: String? {
3232
switch kind {
3333
case .invalidPublicKey:
34-
"Subscriber Public Key (`\(UserAgentKeyMaterial.CodingKeys.publicKey)`) was invalid: \(underlyingError.localizedDescription)."
34+
"Subscriber Public Key (`\(UserAgentKeyMaterial.CodingKeys.publicKey.stringValue)`) was invalid: \(underlyingError.localizedDescription)"
3535
case .invalidAuthenticationSecret:
36-
"Subscriber Authentication Secret (`\(UserAgentKeyMaterial.CodingKeys.authenticationSecret)`) was invalid: \(underlyingError.localizedDescription)."
36+
"Subscriber Authentication Secret (`\(UserAgentKeyMaterial.CodingKeys.authenticationSecret.stringValue)`) was invalid: \(underlyingError.localizedDescription)"
3737
}
3838
}
3939
}
40+
41+
extension UserAgentKeyMaterialError: Hashable {
42+
public static func == (lhs: Self, rhs: Self) -> Bool {
43+
lhs.kind == rhs.kind && lhs.underlyingError.localizedDescription == rhs.underlyingError.localizedDescription
44+
}
45+
46+
public func hash(into hasher: inout Hasher) {
47+
hasher.combine(kind)
48+
hasher.combine(underlyingError.localizedDescription)
49+
}
50+
}

Sources/WebPush/Errors/VAPIDConfigurationError.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010

1111
extension VAPID {
1212
/// An error encountered during ``VAPID/Configuration`` initialization or decoding.
13-
public struct ConfigurationError: LocalizedError, Hashable {
13+
public struct ConfigurationError: LocalizedError, Hashable, Sendable {
1414
enum Kind {
1515
case keysNotProvided
1616
case matchingKeyNotFound
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// ErrorTests.swift
3+
// swift-webpush
4+
//
5+
// Created by Dimitri Bouniol on 2024-12-21.
6+
// Copyright © 2024 Mochi Development, Inc. All rights reserved.
7+
//
8+
9+
import AsyncHTTPClient
10+
import Foundation
11+
import Testing
12+
@testable import WebPush
13+
14+
@Suite struct ErrorTests {
15+
@Test func badSubscriberError() {
16+
#expect(BadSubscriberError() == BadSubscriberError())
17+
#expect("\(BadSubscriberError().localizedDescription)" == "The subscription is no longer valid.")
18+
}
19+
20+
@Test func base64URLDecodingError() {
21+
#expect(Base64URLDecodingError() == Base64URLDecodingError())
22+
#expect("\(Base64URLDecodingError().localizedDescription)" == "The Base64 data could not be decoded.")
23+
}
24+
25+
@Test func httpError() {
26+
let response = HTTPClientResponse(status: .notFound)
27+
#expect(HTTPError(response: response) == HTTPError(response: response))
28+
#expect(HTTPError(response: response).hashValue == HTTPError(response: response).hashValue)
29+
#expect(HTTPError(response: response) != HTTPError(response: HTTPClientResponse(status: .internalServerError)))
30+
#expect("\(HTTPError(response: response).localizedDescription)" == "A 404 Not Found HTTP error was encountered: \(response).")
31+
}
32+
33+
@Test func messageTooLargeError() {
34+
#expect(MessageTooLargeError() == MessageTooLargeError())
35+
#expect("\(MessageTooLargeError().localizedDescription)" == "The message was too large, and could not be delivered to the push service.")
36+
}
37+
38+
@Test func userAgentKeyMaterialError() {
39+
#expect(UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()) == .invalidPublicKey(underlyingError: Base64URLDecodingError()))
40+
#expect(UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()).hashValue == UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()).hashValue)
41+
#expect(UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()) != .invalidPublicKey(underlyingError: BadSubscriberError()))
42+
#expect(UserAgentKeyMaterialError.invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()) == .invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()))
43+
#expect(UserAgentKeyMaterialError.invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()).hashValue == UserAgentKeyMaterialError.invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()).hashValue)
44+
#expect(UserAgentKeyMaterialError.invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()) != .invalidAuthenticationSecret(underlyingError: BadSubscriberError()))
45+
#expect(UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()) != .invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()))
46+
47+
#expect("\(UserAgentKeyMaterialError.invalidPublicKey(underlyingError: Base64URLDecodingError()).localizedDescription)" == "Subscriber Public Key (`p256dh`) was invalid: The Base64 data could not be decoded.")
48+
#expect("\(UserAgentKeyMaterialError.invalidAuthenticationSecret(underlyingError: Base64URLDecodingError()).localizedDescription)" == "Subscriber Authentication Secret (`auth`) was invalid: The Base64 data could not be decoded.")
49+
}
50+
51+
@Test func vapidConfigurationError() {
52+
#expect(VAPID.ConfigurationError.keysNotProvided == .keysNotProvided)
53+
#expect(VAPID.ConfigurationError.matchingKeyNotFound == .matchingKeyNotFound)
54+
#expect(VAPID.ConfigurationError.keysNotProvided != .matchingKeyNotFound)
55+
#expect("\(VAPID.ConfigurationError.keysNotProvided.localizedDescription)" == "VAPID keys not found during initialization.")
56+
#expect("\(VAPID.ConfigurationError.matchingKeyNotFound.localizedDescription)" == "A VAPID key for the subscriber was not found.")
57+
}
58+
}

0 commit comments

Comments
 (0)