diff --git a/Sources/XXClient/Helpers/JSONDecoder.swift b/Sources/XXClient/Helpers/JSONDecoder.swift new file mode 100644 index 0000000000000000000000000000000000000000..751a8b3997f956d4ea535947a4c418a2dc48d6a6 --- /dev/null +++ b/Sources/XXClient/Helpers/JSONDecoder.swift @@ -0,0 +1,64 @@ +import CustomDump +import Foundation + +class JSONDecoder: Foundation.JSONDecoder { + override init() { + super.init() + } + + override func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: Decodable { + do { + let data = convertNumberToString(in: data, at: "Value") + return try super.decode(type, from: data) + } catch { + throw JSONDecodingError(error, data: data) + } + } + + func convertNumberToString( + in input: Data, + at key: String + ) -> Data { + guard var string = String(data: input, encoding: .utf8) else { + return input + } + string = string.replacingOccurrences( + of: #""\#(key)"( *):( *)([0-9]+)( *)(,*)"#, + with: #""\#(key)"$1:$2"$3"$4$5"#, + options: [.regularExpression] + ) + guard let output = string.data(using: .utf8) else { + return input + } + return output + } +} + +public struct JSONDecodingError: Error, CustomStringConvertible, CustomDumpReflectable { + public init(_ underlayingError: Error, data: Data) { + self.underlayingError = underlayingError + self.data = data + self.string = String(data: data, encoding: .utf8) + } + + public var underlayingError: Error + public var data: Data + public var string: String? + + public var description: String { + var description = "" + customDump(self, to: &description) + return description + } + + public var customDumpMirror: Mirror { + Mirror( + self, + children: [ + "underlayingError": underlayingError, + "data": String(data: data, encoding: .utf8) ?? data + ], + displayStyle: .struct + ) + } +} diff --git a/Sources/XXClient/Helpers/JSONEncoder.swift b/Sources/XXClient/Helpers/JSONEncoder.swift new file mode 100644 index 0000000000000000000000000000000000000000..69b368594111f33a8b2c207a9104facf628f4143 --- /dev/null +++ b/Sources/XXClient/Helpers/JSONEncoder.swift @@ -0,0 +1,52 @@ +import CustomDump +import Foundation + +class JSONEncoder: Foundation.JSONEncoder { + override init() { + super.init() + } + + override func encode<T>(_ value: T) throws -> Data where T: Encodable { + do { + var data = try super.encode(value) + data = convertStringToNumber(in: data, at: "Value") + return data + } catch { + throw JSONEncodingError(error, value: value) + } + } + + func convertStringToNumber( + in input: Data, + at key: String + ) -> Data { + guard var string = String(data: input, encoding: .utf8) else { + return input + } + string = string.replacingOccurrences( + of: #""\#(key)"( *):( *)"([0-9]+)"( *)(,*)"#, + with: #""\#(key)"$1:$2$3$4$5"#, + options: [.regularExpression] + ) + guard let output = string.data(using: .utf8) else { + return input + } + return output + } +} + +public struct JSONEncodingError: Error, CustomStringConvertible { + public init(_ underlayingError: Error, value: Any) { + self.underlayingError = underlayingError + self.value = value + } + + public var underlayingError: Error + public var value: Any + + public var description: String { + var description = "" + customDump(self, to: &description) + return description + } +} diff --git a/Sources/XXClient/Helpers/JSONHelpers.swift b/Sources/XXClient/Helpers/JSONHelpers.swift deleted file mode 100644 index 7527ac9ae217c188ff837501fd472b23ff478862..0000000000000000000000000000000000000000 --- a/Sources/XXClient/Helpers/JSONHelpers.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation - -/// Replaces all numbers at provided key with string equivalents -/// -/// Example input: -/// { -/// "key": 123, -/// "object": { -/// "hello": "world", -/// "key": 321 -/// } -/// } -/// -/// Example output: -/// { -/// "key": "123", -/// "object": { -/// "hello": "world", -/// "key": "321" -/// } -/// } -/// -/// - Parameters: -/// - input: JSON data -/// - key: the key which values should be converted -/// - Returns: JSON data -func convertJsonNumberToString( - in input: Data, - at key: String -) -> Data { - guard var string = String(data: input, encoding: .utf8) else { - return input - } - string = string.replacingOccurrences( - of: #""\#(key)"( *):( *)([0-9]+)( *)(,*)"#, - with: #""\#(key)"$1:$2"$3"$4$5"#, - options: [.regularExpression] - ) - guard let output = string.data(using: .utf8) else { - return input - } - return output -} - -/// Replaces all strings at provided key with number equivalents -/// -/// Example input: -/// { -/// "key": "123", -/// "object": { -/// "hello": "world", -/// "key": "321" -/// } -/// } -/// -/// Example output: -/// { -/// "key": 123, -/// "object": { -/// "hello": "world", -/// "key": 321 -/// } -/// } -/// -/// - Parameters: -/// - input: JSON data -/// - key: the key which values should be converted -/// - Returns: JSON data -func convertJsonStringToNumber( - in input: Data, - at key: String -) -> Data { - guard var string = String(data: input, encoding: .utf8) else { - return input - } - string = string.replacingOccurrences( - of: #""\#(key)"( *):( *)"([0-9]+)"( *)(,*)"#, - with: #""\#(key)"$1:$2$3$4$5"#, - options: [.regularExpression] - ) - guard let output = string.data(using: .utf8) else { - return input - } - return output -} diff --git a/Sources/XXClient/Models/DHKey.swift b/Sources/XXClient/Models/DHKey.swift index 5dc94983016cced7c2d4b2c0dc450c63f07acdcc..9ca08dfcfd46652c2cb9d91b040d77401278a564 100644 --- a/Sources/XXClient/Models/DHKey.swift +++ b/Sources/XXClient/Models/DHKey.swift @@ -17,12 +17,10 @@ extension DHKey: Codable { } public static func decode(_ data: Data) throws -> Self { - let data = convertJsonNumberToString(in: data, at: "Value") - return try JSONDecoder().decode(Self.self, from: data) + try JSONDecoder().decode(Self.self, from: data) } public func encode() throws -> Data { - let data = try JSONEncoder().encode(self) - return convertJsonStringToNumber(in: data, at: "Value") + try JSONEncoder().encode(self) } } diff --git a/Sources/XXClient/Models/GroupMember.swift b/Sources/XXClient/Models/GroupMember.swift index cb5d9843bce2a661bdeb93560fbc77860b71d28c..8b8c2b75356c244898c86f2f52dbfba333b2838b 100644 --- a/Sources/XXClient/Models/GroupMember.swift +++ b/Sources/XXClient/Models/GroupMember.swift @@ -17,24 +17,20 @@ extension GroupMember: Codable { } public static func decode(_ data: Data) throws -> Self { - let data = convertJsonNumberToString(in: data, at: "Value") - return try JSONDecoder().decode(Self.self, from: data) + try JSONDecoder().decode(Self.self, from: data) } public func encode() throws -> Data { - let data = try JSONEncoder().encode(self) - return convertJsonStringToNumber(in: data, at: "Value") + try JSONEncoder().encode(self) } } extension Array where Element == GroupMember { public static func decode(_ data: Data) throws -> Self { - let data = convertJsonNumberToString(in: data, at: "Value") - return try JSONDecoder().decode(Self.self, from: data) + try JSONDecoder().decode(Self.self, from: data) } public func encode() throws -> Data { - let data = try JSONEncoder().encode(self) - return convertJsonStringToNumber(in: data, at: "Value") + try JSONEncoder().encode(self) } } diff --git a/Tests/XXClientTests/Helpers/JSONDecoderTests.swift b/Tests/XXClientTests/Helpers/JSONDecoderTests.swift new file mode 100644 index 0000000000000000000000000000000000000000..16f2afcbf4e909fa428500289ab58ae73356b8b7 --- /dev/null +++ b/Tests/XXClientTests/Helpers/JSONDecoderTests.swift @@ -0,0 +1,84 @@ +import CustomDump +import XCTest +@testable import XXClient + +final class JSONDecoderTests: XCTestCase { + func testConvertingNumberToString() { + assertConvertingNumberToString( + input: #"{"number":1234567890,"text":"hello"}"#, + key: "number", + expectedOutput: #"{"number":"1234567890","text":"hello"}"# + ) + + assertConvertingNumberToString( + input: #"{"text":"hello","number":1234567890}"#, + key: "number", + expectedOutput: #"{"text":"hello","number":"1234567890"}"# + ) + + assertConvertingNumberToString( + input: #"{ "number" : 1234567890 , "text" : "hello" }"#, + key: "number", + expectedOutput: #"{ "number" : "1234567890" , "text" : "hello" }"# + ) + + assertConvertingNumberToString( + input: #"{ "text" : "hello" , "number" : 1234567890 }"#, + key: "number", + expectedOutput: #"{ "text" : "hello" , "number" : "1234567890" }"# + ) + + assertConvertingNumberToString( + input: """ + { + "number": 1234567890, + "text": "hello" + } + """, + key: "number", + expectedOutput: """ + { + "number": "1234567890", + "text": "hello" + } + """ + ) + + assertConvertingNumberToString( + input: """ + { + "text": "hello", + "number": 1234567890 + } + """, + key: "number", + expectedOutput: """ + { + "text": "hello", + "number": "1234567890" + } + """ + ) + } +} + +private func assertConvertingNumberToString( + input: String, + key: String, + expectedOutput: String, + file: StaticString = #file, + line: UInt = #line +) { + XCTAssertNoDifference( + String( + data: JSONDecoder().convertNumberToString( + in: input.data(using: .utf8)!, + at: key + ), + encoding: .utf8 + )!, + expectedOutput, + file: file, + line: line + ) +} diff --git a/Tests/XXClientTests/Helpers/JSONEncoderTests.swift b/Tests/XXClientTests/Helpers/JSONEncoderTests.swift new file mode 100644 index 0000000000000000000000000000000000000000..58fbfae7a4bc41ec1feb620fdb8cd75031252889 --- /dev/null +++ b/Tests/XXClientTests/Helpers/JSONEncoderTests.swift @@ -0,0 +1,84 @@ +import CustomDump +import XCTest +@testable import XXClient + +final class JSONEncoderTests: XCTestCase { + func testConvertingStringToNumber() { + assertConvertingStringToNumber( + input: #"{"number":"1234567890","text":"hello"}"#, + key: "number", + expectedOutput: #"{"number":1234567890,"text":"hello"}"# + ) + + assertConvertingStringToNumber( + input: #"{"text":"hello","number":"1234567890"}"#, + key: "number", + expectedOutput: #"{"text":"hello","number":1234567890}"# + ) + + assertConvertingStringToNumber( + input: #"{ "number" : "1234567890" , "text" : "hello" }"#, + key: "number", + expectedOutput: #"{ "number" : 1234567890 , "text" : "hello" }"# + ) + + assertConvertingStringToNumber( + input: #"{ "text" : "hello" , "number" : "1234567890" }"#, + key: "number", + expectedOutput: #"{ "text" : "hello" , "number" : 1234567890 }"# + ) + + assertConvertingStringToNumber( + input: """ + { + "number": "1234567890", + "text": "hello" + } + """, + key: "number", + expectedOutput: """ + { + "number": 1234567890, + "text": "hello" + } + """ + ) + + assertConvertingStringToNumber( + input: """ + { + "text": "hello", + "number": "1234567890" + } + """, + key: "number", + expectedOutput: """ + { + "text": "hello", + "number": 1234567890 + } + """ + ) + } +} + +private func assertConvertingStringToNumber( + input: String, + key: String, + expectedOutput: String, + file: StaticString = #file, + line: UInt = #line +) { + XCTAssertNoDifference( + String( + data: JSONEncoder().convertStringToNumber( + in: input.data(using: .utf8)!, + at: key + ), + encoding: .utf8 + )!, + expectedOutput, + file: file, + line: line + ) +} diff --git a/Tests/XXClientTests/Helpers/JSONHelpersTests.swift b/Tests/XXClientTests/Helpers/JSONHelpersTests.swift deleted file mode 100644 index 2ebe853034c56ea04fcbb52791fe6dbd56c079b2..0000000000000000000000000000000000000000 --- a/Tests/XXClientTests/Helpers/JSONHelpersTests.swift +++ /dev/null @@ -1,163 +0,0 @@ -import CustomDump -import XCTest -@testable import XXClient - -final class JSONHelpersTests: XCTestCase { - func testConvertingNumberToStringByKey() { - assertConvertingJsonNumberToString( - input: #"{"number":1234567890,"text":"hello"}"#, - key: "number", - expected: #"{"number":"1234567890","text":"hello"}"# - ) - - assertConvertingJsonNumberToString( - input: #"{"text":"hello","number":1234567890}"#, - key: "number", - expected: #"{"text":"hello","number":"1234567890"}"# - ) - - assertConvertingJsonNumberToString( - input: #"{ "number" : 1234567890 , "text" : "hello" }"#, - key: "number", - expected: #"{ "number" : "1234567890" , "text" : "hello" }"# - ) - - assertConvertingJsonNumberToString( - input: #"{ "text" : "hello" , "number" : 1234567890 }"#, - key: "number", - expected: #"{ "text" : "hello" , "number" : "1234567890" }"# - ) - - assertConvertingJsonNumberToString( - input: """ - { - "number": 1234567890, - "text": "hello" - } - """, - key: "number", - expected: """ - { - "number": "1234567890", - "text": "hello" - } - """ - ) - - assertConvertingJsonNumberToString( - input: """ - { - "text": "hello", - "number": 1234567890 - } - """, - key: "number", - expected: """ - { - "text": "hello", - "number": "1234567890" - } - """ - ) - } - - func testConvertingStringToNumber() { - assertConvertingJsonStringToNumber( - input: #"{"number":"1234567890","text":"hello"}"#, - key: "number", - expected: #"{"number":1234567890,"text":"hello"}"# - ) - - assertConvertingJsonStringToNumber( - input: #"{"text":"hello","number":"1234567890"}"#, - key: "number", - expected: #"{"text":"hello","number":1234567890}"# - ) - - assertConvertingJsonStringToNumber( - input: #"{ "number" : "1234567890" , "text" : "hello" }"#, - key: "number", - expected: #"{ "number" : 1234567890 , "text" : "hello" }"# - ) - - assertConvertingJsonStringToNumber( - input: #"{ "text" : "hello" , "number" : "1234567890" }"#, - key: "number", - expected: #"{ "text" : "hello" , "number" : 1234567890 }"# - ) - - assertConvertingJsonStringToNumber( - input: """ - { - "number": "1234567890", - "text": "hello" - } - """, - key: "number", - expected: """ - { - "number": 1234567890, - "text": "hello" - } - """ - ) - - assertConvertingJsonStringToNumber( - input: """ - { - "text": "hello", - "number": "1234567890" - } - """, - key: "number", - expected: """ - { - "text": "hello", - "number": 1234567890 - } - """ - ) - } -} - -private func assertConvertingJsonNumberToString( - input: String, - key: String, - expected: String, - file: StaticString = #file, - line: UInt = #line -) { - XCTAssertNoDifference( - String( - data: convertJsonNumberToString( - in: input.data(using: .utf8)!, - at: key - ), - encoding: .utf8 - )!, - expected, - file: file, - line: line - ) -} - -private func assertConvertingJsonStringToNumber( - input: String, - key: String, - expected: String, - file: StaticString = #file, - line: UInt = #line -) { - XCTAssertNoDifference( - String( - data: convertJsonStringToNumber( - in: input.data(using: .utf8)!, - at: key - ), - encoding: .utf8 - )!, - expected, - file: file, - line: line - ) -}