Skip to content
Snippets Groups Projects
Commit 85bd2d7e authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Implement custom JSONEncoder and JSONDecoder

parent 52c2a173
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!53Custom JSONEncoder & JSONDecoder
import CustomDump
import Foundation
public class JSONDecoder: Foundation.JSONDecoder {
public override init() {
super.init()
}
public 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
)
}
}
import CustomDump
import Foundation
public class JSONEncoder: Foundation.JSONEncoder {
public override init() {
super.init()
}
public 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
}
}
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
)
}
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
)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment