diff --git a/Maskbook/Scene/Setting/Backup/Recovery/Model/RestoreFile.swift b/Maskbook/Scene/Setting/Backup/Recovery/Model/RestoreFile.swift index d9a7d13e..8c01c154 100644 --- a/Maskbook/Scene/Setting/Backup/Recovery/Model/RestoreFile.swift +++ b/Maskbook/Scene/Setting/Backup/Recovery/Model/RestoreFile.swift @@ -626,9 +626,11 @@ struct MaybeUInt64ToTimeInterval: Codable { } func encode(to encoder: Encoder) throws { + guard let value = wrappedValue else { + return + } var container = encoder.singleValueContainer() - let value = (wrappedValue ?? 0) * 1000 - try container.encode(UInt64(value)) + try container.encode(UInt64(value * 1000)) } } @@ -661,3 +663,42 @@ struct MaybeUInt64ToDate: Codable { } } } + +// will replace JSONDecoder().decode(_:) and JSONEncoder().encode(_:) + +extension KeyedDecodingContainer { + func decode( + _ type: MaybeUInt64ToDate.Type, + forKey key: Key + ) throws -> MaybeUInt64ToDate { + try decodeIfPresent(type, forKey: key) ?? .init(nil) + } + + func decode( + _ type: MaybeUInt64ToTimeInterval.Type, + forKey key: Key + ) throws -> MaybeUInt64ToTimeInterval { + try decodeIfPresent(type, forKey: key) ?? .init(nil) + } +} + +extension KeyedEncodingContainer { + mutating func encode( + _ value: MaybeUInt64ToDate, + forKey key: Key + ) throws { + let wrappedValue = value.wrappedValue + .flatMap { $0.timeIntervalSince1970 } + .flatMap { UInt64($0 * 1000) } + try encodeIfPresent(wrappedValue, forKey: key) + } + + mutating func encode( + _ value: MaybeUInt64ToTimeInterval, + forKey key: Key + ) throws { + if let wrappedValue = value.wrappedValue { + try encodeIfPresent(UInt64(wrappedValue * 1000), forKey: key) + } + } +} diff --git a/MaskbookTests/BackupAndResotreTests.swift b/MaskbookTests/BackupAndResotreTests.swift index 31b6b900..d12baab4 100644 --- a/MaskbookTests/BackupAndResotreTests.swift +++ b/MaskbookTests/BackupAndResotreTests.swift @@ -150,7 +150,7 @@ class BackupAndResotreTests: XCTestCase { var date: Date? } - let json1 = #"{"date":192813313000}"#.data(using: .utf8)! + let json1 = #"{"date":1813313000}"#.data(using: .utf8)! let result = Result { try JSONDecoder().decode(Meta.self, from: json1) @@ -158,10 +158,33 @@ class BackupAndResotreTests: XCTestCase { switch result { case let .success(value): - XCTAssert(value.date?.timeIntervalSince1970 == 192813313) + XCTAssert(value.date?.timeIntervalSince1970 == 1813313) let encoding = try! JSONEncoder().encode(value) let string = String(data: encoding, encoding: .utf8) - XCTAssert(string == #"{"date":192813313000}"#) + XCTAssert(string == #"{"date":1813313000}"#) + + case let .failure(error): + XCTFail("\(error)") + } + } + + func dateDecodingFailed() { + struct Meta: Codable { + @MaybeUInt64ToDate + var date: Date? + } + + let json1 = #"{"name":192813313000}"#.data(using: .utf8)! + let result = Result { + try JSONDecoder().decode(Meta.self, from: json1) + } + + switch result { + case let .success(value): + XCTAssertNil(value.date?.timeIntervalSince1970) + let encoding = try! JSONEncoder().encode(value) + let string = String(data: encoding, encoding: .utf8) + XCTAssert(string == #"{}"#) case let .failure(error): XCTFail("\(error)") @@ -193,8 +216,35 @@ class BackupAndResotreTests: XCTestCase { } } + func timeDecodingFailed() { + struct Meta: Codable { + @MaybeUInt64ToTimeInterval + var time: TimeInterval? + } + + let json1 = #"{"date":192813313000}"#.data(using: .utf8)! + + let result = Result { + try JSONDecoder().decode(Meta.self, from: json1) + } + + switch result { + case let .success(value): + XCTAssertNil(value.time) + + let encoding = try! JSONEncoder().encode(value) + let string = String(data: encoding, encoding: .utf8) + XCTAssert(string == #"{}"#) + + case let .failure(error): + XCTFail("\(error)") + } + } + boolDecoding() dateDecoding() + dateDecodingFailed() timeIntervalDecoding() + timeDecodingFailed() } }