From d390bc7c941ebbbf84f914188b73ea40ba70e0ae Mon Sep 17 00:00:00 2001 From: Francesco Paolo Severino Date: Sat, 26 Oct 2024 15:55:38 +0200 Subject: [PATCH] Get rid of `JSONSerialization` --- Sources/Passes/DTOs/PersonalizationJSON.swift | 4 +-- Tests/OrdersTests/OrderData.swift | 20 +++++++++++-- Tests/OrdersTests/OrdersTests.swift | 13 +++++---- Tests/PassesTests/PassData.swift | 27 +++++++++++++---- Tests/PassesTests/PassesTests.swift | 29 ++++++++++--------- 5 files changed, 64 insertions(+), 29 deletions(-) diff --git a/Sources/Passes/DTOs/PersonalizationJSON.swift b/Sources/Passes/DTOs/PersonalizationJSON.swift index e73e5aa..08fd2a5 100644 --- a/Sources/Passes/DTOs/PersonalizationJSON.swift +++ b/Sources/Passes/DTOs/PersonalizationJSON.swift @@ -4,7 +4,7 @@ /// It also contains a description of the program and (optionally) the program’s terms and conditions. /// /// > Tip: See the [documentation](https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/PassPersonalization.html#//apple_ref/doc/uid/TP40012195-CH12-SW2) to understand the keys. -public struct PersonalizationJSON: Encodable, Sendable { +public struct PersonalizationJSON: Codable, Sendable { /// The contents of this array define the data requested from the user. /// /// The signup form’s fields are generated based on these keys. @@ -42,7 +42,7 @@ public struct PersonalizationJSON: Encodable, Sendable { extension PersonalizationJSON { /// Personal information requested by the signup form. - public enum PersonalizationField: String, Encodable, Sendable { + public enum PersonalizationField: String, Codable, Sendable { /// Prompts the user for their name. /// /// `fullName`, `givenName`, and `familyName` are submitted in the personalize request. diff --git a/Tests/OrdersTests/OrderData.swift b/Tests/OrdersTests/OrderData.swift index d51c128..32e4dc9 100644 --- a/Tests/OrdersTests/OrderData.swift +++ b/Tests/OrdersTests/OrderData.swift @@ -46,7 +46,11 @@ extension OrderData { } } -struct OrderJSONData: OrderJSON.Properties { +extension OrderJSON.SchemaVersion: Decodable {} +extension OrderJSON.OrderType: Decodable {} +extension OrderJSON.OrderStatus: Decodable {} + +struct OrderJSONData: OrderJSON.Properties, Decodable { let schemaVersion = OrderJSON.SchemaVersion.v1 let orderTypeIdentifier = "order.com.example.pet-store" let orderIdentifier: String @@ -61,11 +65,23 @@ struct OrderJSONData: OrderJSON.Properties { private let webServiceURL = "https://www.example.com/api/orders/" - struct MerchantData: OrderJSON.Merchant { + enum CodingKeys: String, CodingKey { + case schemaVersion + case orderTypeIdentifier, orderIdentifier, orderType, orderNumber + case createdAt, updatedAt + case status, merchant + case orderManagementURL, authenticationToken, webServiceURL + } + + struct MerchantData: OrderJSON.Merchant, Decodable { let merchantIdentifier = "com.example.pet-store" let displayName: String let url = "https://www.example.com/" let logo = "pet_store_logo.png" + + enum CodingKeys: String, CodingKey { + case merchantIdentifier, displayName, url, logo + } } init(data: OrderData, order: Order) { diff --git a/Tests/OrdersTests/OrdersTests.swift b/Tests/OrdersTests/OrdersTests.swift index e2214ac..5c2156d 100644 --- a/Tests/OrdersTests/OrdersTests.swift +++ b/Tests/OrdersTests/OrdersTests.swift @@ -9,6 +9,7 @@ import Zip @Suite("Orders Tests") struct OrdersTests { let ordersURI = "/api/orders/v1/" + let decoder = JSONDecoder() @Test("Order Generation", arguments: [true, false]) func orderGeneration(useEncryptedKey: Bool) async throws { @@ -24,17 +25,17 @@ struct OrdersTests { #expect(FileManager.default.fileExists(atPath: orderFolder.path.appending("/signature"))) #expect(FileManager.default.fileExists(atPath: orderFolder.path.appending("/order.json"))) - let passJSONData = try String(contentsOfFile: orderFolder.path.appending("/order.json")).data(using: .utf8) - let passJSON = try JSONSerialization.jsonObject(with: passJSONData!) as! [String: Any] - #expect(passJSON["authenticationToken"] as? String == order.authenticationToken) + let orderJSONData = try String(contentsOfFile: orderFolder.path.appending("/order.json")).data(using: .utf8) + let orderJSON = try decoder.decode(OrderJSONData.self, from: orderJSONData!) + #expect(orderJSON.authenticationToken == order.authenticationToken) let orderID = try order.requireID().uuidString - #expect(passJSON["orderIdentifier"] as? String == orderID) + #expect(orderJSON.orderIdentifier == orderID) let manifestJSONData = try String(contentsOfFile: orderFolder.path.appending("/manifest.json")).data(using: .utf8) - let manifestJSON = try JSONSerialization.jsonObject(with: manifestJSONData!) as! [String: Any] + let manifestJSON = try decoder.decode([String: String].self, from: manifestJSONData!) let iconData = try Data(contentsOf: orderFolder.appendingPathComponent("/icon.png")) let iconHash = Array(SHA256.hash(data: iconData)).hex - #expect(manifestJSON["icon.png"] as? String == iconHash) + #expect(manifestJSON["icon.png"] == iconHash) #expect(manifestJSON["pet_store_logo.png"] != nil) } } diff --git a/Tests/PassesTests/PassData.swift b/Tests/PassesTests/PassData.swift index 313d479..38614f5 100644 --- a/Tests/PassesTests/PassData.swift +++ b/Tests/PassesTests/PassData.swift @@ -46,7 +46,11 @@ extension PassData { } } -struct PassJSONData: PassJSON.Properties { +extension PassJSON.FormatVersion: Decodable {} +extension PassJSON.BarcodeFormat: Decodable {} +extension PassJSON.TransitType: Decodable {} + +struct PassJSONData: PassJSON.Properties, Decodable { let description: String let formatVersion = PassJSON.FormatVersion.v1 let organizationName = "vapor-community" @@ -55,21 +59,25 @@ struct PassJSONData: PassJSON.Properties { let teamIdentifier = "K6512ZA2S5" private let webServiceURL = "https://www.example.com/api/passes/" - private let authenticationToken: String + let authenticationToken: String private let logoText = "Vapor Community" private let sharingProhibited = true let backgroundColor = "rgb(207, 77, 243)" let foregroundColor = "rgb(255, 255, 255)" let barcodes = Barcode(message: "test") - struct Barcode: PassJSON.Barcodes { + struct Barcode: PassJSON.Barcodes, Decodable { let format = PassJSON.BarcodeFormat.qr let message: String let messageEncoding = "iso-8859-1" + + enum CodingKeys: String, CodingKey { + case format, message, messageEncoding + } } let boardingPass = Boarding(transitType: .air) - struct Boarding: PassJSON.BoardingPass { + struct Boarding: PassJSON.BoardingPass, Decodable { let transitType: PassJSON.TransitType let headerFields: [PassField] let primaryFields: [PassField] @@ -77,7 +85,7 @@ struct PassJSONData: PassJSON.Properties { let auxiliaryFields: [PassField] let backFields: [PassField] - struct PassField: PassJSON.PassFieldContent { + struct PassField: PassJSON.PassFieldContent, Decodable { let key: String let label: String let value: String @@ -93,6 +101,15 @@ struct PassJSONData: PassJSON.Properties { } } + enum CodingKeys: String, CodingKey { + case description + case formatVersion + case organizationName, passTypeIdentifier, serialNumber, teamIdentifier + case webServiceURL, authenticationToken + case logoText, sharingProhibited, backgroundColor, foregroundColor + case barcodes, boardingPass + } + init(data: PassData, pass: Pass) { self.description = data.title self.serialNumber = pass.id!.uuidString diff --git a/Tests/PassesTests/PassesTests.swift b/Tests/PassesTests/PassesTests.swift index 06c8519..9da4885 100644 --- a/Tests/PassesTests/PassesTests.swift +++ b/Tests/PassesTests/PassesTests.swift @@ -9,6 +9,7 @@ import Zip @Suite("Passes Tests") struct PassesTests { let passesURI = "/api/passes/v1/" + let decoder = JSONDecoder() @Test("Pass Generation", arguments: [true, false]) func passGeneration(useEncryptedKey: Bool) async throws { @@ -25,17 +26,17 @@ struct PassesTests { #expect(FileManager.default.fileExists(atPath: passFolder.path.appending("/pass.json"))) let passJSONData = try String(contentsOfFile: passFolder.path.appending("/pass.json")).data(using: .utf8) - let passJSON = try JSONSerialization.jsonObject(with: passJSONData!) as! [String: Any] - #expect(passJSON["authenticationToken"] as? String == pass.authenticationToken) + let passJSON = try decoder.decode(PassJSONData.self, from: passJSONData!) + #expect(passJSON.authenticationToken == pass.authenticationToken) let passID = try pass.requireID().uuidString - #expect(passJSON["serialNumber"] as? String == passID) - #expect(passJSON["description"] as? String == passData.title) + #expect(passJSON.serialNumber == passID) + #expect(passJSON.description == passData.title) let manifestJSONData = try String(contentsOfFile: passFolder.path.appending("/manifest.json")).data(using: .utf8) - let manifestJSON = try JSONSerialization.jsonObject(with: manifestJSONData!) as! [String: Any] + let manifestJSON = try decoder.decode([String: String].self, from: manifestJSONData!) let iconData = try Data(contentsOf: passFolder.appendingPathComponent("/icon.png")) let iconHash = Array(Insecure.SHA1.hash(data: iconData)).hex - #expect(manifestJSON["icon.png"] as? String == iconHash) + #expect(manifestJSON["icon.png"] == iconHash) #expect(manifestJSON["logo.png"] != nil) #expect(manifestJSON["personalizationLogo.png"] != nil) } @@ -79,21 +80,21 @@ struct PassesTests { #expect(FileManager.default.fileExists(atPath: passFolder.path.appending("/pass.json"))) let passJSONData = try String(contentsOfFile: passFolder.path.appending("/pass.json")).data(using: .utf8) - let passJSON = try JSONSerialization.jsonObject(with: passJSONData!) as! [String: Any] - #expect(passJSON["authenticationToken"] as? String == pass.authenticationToken) + let passJSON = try decoder.decode(PassJSONData.self, from: passJSONData!) + #expect(passJSON.authenticationToken == pass.authenticationToken) let passID = try pass.requireID().uuidString - #expect(passJSON["serialNumber"] as? String == passID) - #expect(passJSON["description"] as? String == passData.title) + #expect(passJSON.serialNumber == passID) + #expect(passJSON.description == passData.title) let personalizationJSONData = try String(contentsOfFile: passFolder.path.appending("/personalization.json")).data(using: .utf8) - let personalizationJSON = try JSONSerialization.jsonObject(with: personalizationJSONData!) as! [String: Any] - #expect(personalizationJSON["description"] as? String == "Hello, World!") + let personalizationJSON = try decoder.decode(PersonalizationJSON.self, from: personalizationJSONData!) + #expect(personalizationJSON.description == "Hello, World!") let manifestJSONData = try String(contentsOfFile: passFolder.path.appending("/manifest.json")).data(using: .utf8) - let manifestJSON = try JSONSerialization.jsonObject(with: manifestJSONData!) as! [String: Any] + let manifestJSON = try decoder.decode([String: String].self, from: manifestJSONData!) let iconData = try Data(contentsOf: passFolder.appendingPathComponent("/personalizationLogo.png")) let iconHash = Array(Insecure.SHA1.hash(data: iconData)).hex - #expect(manifestJSON["personalizationLogo.png"] as? String == iconHash) + #expect(manifestJSON["personalizationLogo.png"] == iconHash) } }