diff --git a/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift b/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift deleted file mode 100644 index 8390ba1ced0f8a0aff92287b899a81fca0247c77..0000000000000000000000000000000000000000 --- a/Sources/XXClient/Helpers/ConvertJsonNumberToString.swift +++ /dev/null @@ -1,37 +0,0 @@ -import Foundation - -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 -} - -func convertJsonNumberToString( - in input: Data, - minNumberLength: Int -) -> Data { - guard var string = String(data: input, encoding: .utf8) else { - return input - } - string = string.replacingOccurrences( - of: #":( *)([0-9]{\#(minNumberLength),})( *)(,*)"#, - with: #":$1"$2"$3$4"#, - options: [.regularExpression] - ) - guard let output = string.data(using: .utf8) else { - return input - } - return output -} diff --git a/Sources/XXClient/Helpers/JSONHelpers.swift b/Sources/XXClient/Helpers/JSONHelpers.swift new file mode 100644 index 0000000000000000000000000000000000000000..7527ac9ae217c188ff837501fd472b23ff478862 --- /dev/null +++ b/Sources/XXClient/Helpers/JSONHelpers.swift @@ -0,0 +1,85 @@ +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 new file mode 100644 index 0000000000000000000000000000000000000000..5dc94983016cced7c2d4b2c0dc450c63f07acdcc --- /dev/null +++ b/Sources/XXClient/Models/DHKey.swift @@ -0,0 +1,28 @@ +import Foundation + +public struct DHKey: Equatable { + public init(value: String, fingerprint: UInt64) { + self.value = value + self.fingerprint = fingerprint + } + + public var value: String + public var fingerprint: UInt64 +} + +extension DHKey: Codable { + enum CodingKeys: String, CodingKey { + case value = "Value" + case fingerprint = "Fingerprint" + } + + public static func decode(_ data: Data) throws -> Self { + let data = convertJsonNumberToString(in: data, at: "Value") + return try JSONDecoder().decode(Self.self, from: data) + } + + public func encode() throws -> Data { + let data = try JSONEncoder().encode(self) + return convertJsonStringToNumber(in: data, at: "Value") + } +} diff --git a/Sources/XXClient/Models/GroupMember.swift b/Sources/XXClient/Models/GroupMember.swift index 8ce7120a58880ab94f9f8a590ad6872565684bfd..cb5d9843bce2a661bdeb93560fbc77860b71d28c 100644 --- a/Sources/XXClient/Models/GroupMember.swift +++ b/Sources/XXClient/Models/GroupMember.swift @@ -1,27 +1,40 @@ import Foundation public struct GroupMember: Equatable { - public init(id: Data) { + public init(id: Data, dhKey: DHKey) { self.id = id + self.dhKey = dhKey } public var id: Data + public var dhKey: DHKey } -extension GroupMember: Decodable { +extension GroupMember: Codable { enum CodingKeys: String, CodingKey { case id = "ID" + case dhKey = "DhKey" } public static func decode(_ data: Data) throws -> Self { - let data = convertJsonNumberToString(in: data, minNumberLength: 19) + let data = convertJsonNumberToString(in: data, at: "Value") return try JSONDecoder().decode(Self.self, from: data) } + + public func encode() throws -> Data { + let data = try JSONEncoder().encode(self) + return convertJsonStringToNumber(in: data, at: "Value") + } } extension Array where Element == GroupMember { public static func decode(_ data: Data) throws -> Self { - let data = convertJsonNumberToString(in: data, minNumberLength: 19) + let data = convertJsonNumberToString(in: data, at: "Value") return try JSONDecoder().decode(Self.self, from: data) } + + public func encode() throws -> Data { + let data = try JSONEncoder().encode(self) + return convertJsonStringToNumber(in: data, at: "Value") + } } diff --git a/Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift b/Tests/XXClientTests/Helpers/JSONHelpersTests.swift similarity index 52% rename from Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift rename to Tests/XXClientTests/Helpers/JSONHelpersTests.swift index 4fc1ecd7f1b729f65f934d11adcac502c0127cf4..2ebe853034c56ea04fcbb52791fe6dbd56c079b2 100644 --- a/Tests/XXClientTests/Helpers/ConvertJsonNumberToStringTests.swift +++ b/Tests/XXClientTests/Helpers/JSONHelpersTests.swift @@ -2,33 +2,33 @@ import CustomDump import XCTest @testable import XXClient -final class ConvertJsonNumberToStringTests: XCTestCase { - func testConverting() { - assert( +final class JSONHelpersTests: XCTestCase { + func testConvertingNumberToStringByKey() { + assertConvertingJsonNumberToString( input: #"{"number":1234567890,"text":"hello"}"#, key: "number", expected: #"{"number":"1234567890","text":"hello"}"# ) - assert( + assertConvertingJsonNumberToString( input: #"{"text":"hello","number":1234567890}"#, key: "number", expected: #"{"text":"hello","number":"1234567890"}"# ) - assert( + assertConvertingJsonNumberToString( input: #"{ "number" : 1234567890 , "text" : "hello" }"#, key: "number", expected: #"{ "number" : "1234567890" , "text" : "hello" }"# ) - assert( + assertConvertingJsonNumberToString( input: #"{ "text" : "hello" , "number" : 1234567890 }"#, key: "number", expected: #"{ "text" : "hello" , "number" : "1234567890" }"# ) - assert( + assertConvertingJsonNumberToString( input: """ { "number": 1234567890, @@ -44,7 +44,7 @@ final class ConvertJsonNumberToStringTests: XCTestCase { """ ) - assert( + assertConvertingJsonNumberToString( input: """ { "text": "hello", @@ -59,32 +59,68 @@ final class ConvertJsonNumberToStringTests: XCTestCase { } """ ) + } + + 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" + } + """ + ) - assert( + assertConvertingJsonStringToNumber( input: """ { "text": "hello", - "number1": 123456789, - "number2": 1234567890, - "number3": 123456789, - "number4": 1234567890 + "number": "1234567890" } """, - minNumberLength: 10, + key: "number", expected: """ { "text": "hello", - "number1": 123456789, - "number2": "1234567890", - "number3": 123456789, - "number4": "1234567890" + "number": 1234567890 } """ ) } } -private func assert( +private func assertConvertingJsonNumberToString( input: String, key: String, expected: String, @@ -105,18 +141,18 @@ private func assert( ) } -private func assert( +private func assertConvertingJsonStringToNumber( input: String, - minNumberLength: Int, + key: String, expected: String, file: StaticString = #file, line: UInt = #line ) { XCTAssertNoDifference( String( - data: convertJsonNumberToString( + data: convertJsonStringToNumber( in: input.data(using: .utf8)!, - minNumberLength: minNumberLength + at: key ), encoding: .utf8 )!, diff --git a/Tests/XXClientTests/Models/DHKeyTests.swift b/Tests/XXClientTests/Models/DHKeyTests.swift new file mode 100644 index 0000000000000000000000000000000000000000..eea82bf385ff766676d881c5ae930c6a965f5668 --- /dev/null +++ b/Tests/XXClientTests/Models/DHKeyTests.swift @@ -0,0 +1,31 @@ +import CustomDump +import XCTest +@testable import XXClient + +final class DHKeyTests: XCTestCase { + func testCoding() throws { + let value = "1759426033802606996617132861414734059978289057332806031357800676138355264622676606691435603603751978195460163638145821347601916259127578968570412642641025630452893097179266022832268525346700655861033031712000288680395716922501450233258587788020541937373196899001184700899008948530359980753630443486308876999029238453979779103124291315202352475056237021681172884599194016245219278368648568458514708567045834427853469072638665888791358582182353417065794210125797368093469194927663862565508608719835557592421245749381164023134450699040591219966988201315627676532245052123725278573237006510683695959381015415110970848376498637637944431576313526294020390694483472829278364602405292767170719547347485307956614210210673321959886410245334772057212077704024337636501108566655549055129066343309591274727538343075929837698653965640646190405582788894021694347212874155979958144038307500444865955516612526623220973497735316081265793063949" + let fingerprint: UInt64 = 15989433043166758754 + let jsonString = """ + { + "Value": \(value), + "Fingerprint": \(fingerprint) + } + """ + let jsonData = jsonString.data(using: .utf8)! + let model = try DHKey.decode(jsonData) + + XCTAssertNoDifference(model, DHKey( + value: value, + fingerprint: fingerprint + )) + + let encodedModel = try model.encode() + let encodedModelString = String(data: encodedModel, encoding: .utf8) + + XCTAssertNoDifference( + encodedModelString, + #"{"Value":\#(value),"Fingerprint":\#(fingerprint)}"# + ) + } +} diff --git a/Tests/XXClientTests/Models/GroupMemberTests.swift b/Tests/XXClientTests/Models/GroupMemberTests.swift index 36e178c08f37b0bec719f4c3b7747043a9920491..eed1a4739d05b5832a40867c4842ccb18a280903 100644 --- a/Tests/XXClientTests/Models/GroupMemberTests.swift +++ b/Tests/XXClientTests/Models/GroupMemberTests.swift @@ -4,13 +4,15 @@ import XCTest final class GroupMemberTests: XCTestCase { func testCoding() throws { - let idB64 = "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID" + let idB64 = "SGVsbG8sIFdvcmxkISBHcm91cCBNZW1iZXIgVGVzdCBJRA==" + let dhKeyValue = "1759426033802606996617132861414734059978289057332806031357800676138355264622676606691435603603751978195460163638145821347601916259127578968570412642641025630452893097179266022832268525346700655861033031712000288680395716922501450233258587788020541937373196899001184700899008948530359980753630443486308876999029238453979779103124291315202352475056237021681172884599194016245219278368648568458514708567045834427853469072638665888791358582182353417065794210125797368093469194927663862565508608719835557592421245749381164023134450699040591219966988201315627676532245052123725278573237006510683695959381015415110970848376498637637944431576313526294020390694483472829278364602405292767170719547347485307956614210210673321959886410245334772057212077704024337636501108566655549055129066343309591274727538343075929837698653965640646190405582788894021694347212874155979958144038307500444865955516612526623220973497735316081265793063949" + let dhKeyFingerprint: UInt64 = 15989433043166758754 let jsonString = """ { "ID": "\(idB64)", "DhKey": { - "Value": 1759426033802606996617132861414734059978289057332806031357800676138355264622676606691435603603751978195460163638145821347601916259127578968570412642641025630452893097179266022832268525346700655861033031712000288680395716922501450233258587788020541937373196899001184700899008948530359980753630443486308876999029238453979779103124291315202352475056237021681172884599194016245219278368648568458514708567045834427853469072638665888791358582182353417065794210125797368093469194927663862565508608719835557592421245749381164023134450699040591219966988201315627676532245052123725278573237006510683695959381015415110970848376498637637944431576313526294020390694483472829278364602405292767170719547347485307956614210210673321959886410245334772057212077704024337636501108566655549055129066343309591274727538343075929837698653965640646190405582788894021694347212874155979958144038307500444865955516612526623220973497735316081265793063949, - "Fingerprint": 15989433043166758754 + "Value": \(dhKeyValue), + "Fingerprint": \(dhKeyFingerprint) } } """ @@ -18,13 +20,34 @@ final class GroupMemberTests: XCTestCase { let model = try GroupMember.decode(jsonData) XCTAssertNoDifference(model, GroupMember( - id: Data(base64Encoded: idB64)! + id: Data(base64Encoded: idB64)!, + dhKey: DHKey( + value: dhKeyValue, + fingerprint: dhKeyFingerprint + ) )) + let encodedModel = try model.encode() + let encodedModelString = String(data: encodedModel, encoding: .utf8)! + XCTAssertNoDifference( + encodedModelString, + """ + {"ID":"\(idB64)","DhKey":{"Value":\(dhKeyValue),"Fingerprint":\(dhKeyFingerprint)}} + """ + ) + let jsonArrayString = "[\(jsonString)]" let jsonArrayData = jsonArrayString.data(using: .utf8)! let decodedModels = try [GroupMember].decode(jsonArrayData) XCTAssertNoDifference(decodedModels, [model]) + + let encodedModels = try decodedModels.encode() + let encodedModelsString = String(data: encodedModels, encoding: .utf8)! + + XCTAssertNoDifference( + encodedModelsString, + "[\(encodedModelString)]" + ) } }