From 52279bac4dc3cd07fb5bb9ffdd12d9088fca1303 Mon Sep 17 00:00:00 2001 From: Darktt Date: Wed, 3 Jul 2024 13:32:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20NumberArrayProtection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project.pbxproj | 8 ++ .../NumberArrayProtectionTest.swift | 70 +++++++++++++++++ .../ObjectProtectionTest.swift | 2 +- README.md | 22 +++++- .../NumberArrayProtection.swift | 75 +++++++++++++++++++ .../JsonProtection/NumberProtection.swift | 13 +++- .../JsonProtection/NumbersProtection.swift | 4 +- 7 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 JsonDecodeProtectionTests/NumberArrayProtectionTest.swift create mode 100644 SourceCode/JsonProtection/NumberArrayProtection.swift diff --git a/JsonDecodeProtection.xcodeproj/project.pbxproj b/JsonDecodeProtection.xcodeproj/project.pbxproj index 94fc5a9..5275175 100644 --- a/JsonDecodeProtection.xcodeproj/project.pbxproj +++ b/JsonDecodeProtection.xcodeproj/project.pbxproj @@ -32,6 +32,8 @@ F264CAD2293F1F4400AEC100 /* MultipleKeyProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F264CAD1293F1F4400AEC100 /* MultipleKeyProtection.swift */; }; F297055C29E3E69D003CF4B2 /* AESDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F297055B29E3E69D003CF4B2 /* AESDecoder.swift */; }; F297056029E3EF11003CF4B2 /* AESDecoderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F297055F29E3EF11003CF4B2 /* AESDecoderTest.swift */; }; + F2B0B0032C34F3F800680EBE /* NumberArrayProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B0B0022C34F3F800680EBE /* NumberArrayProtection.swift */; }; + F2B0B0052C34F5FF00680EBE /* NumberArrayProtectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B0B0042C34F5FF00680EBE /* NumberArrayProtectionTest.swift */; }; F2E188542AA9CCFD00E7F0B5 /* DateProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2E188532AA9CCFD00E7F0B5 /* DateProtection.swift */; }; F2E188562AAAAF8C00E7F0B5 /* DateProtectionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2E188552AAAAF8C00E7F0B5 /* DateProtectionTest.swift */; }; /* End PBXBuildFile section */ @@ -76,6 +78,8 @@ F264CAD1293F1F4400AEC100 /* MultipleKeyProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultipleKeyProtection.swift; sourceTree = ""; }; F297055B29E3E69D003CF4B2 /* AESDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESDecoder.swift; sourceTree = ""; }; F297055F29E3EF11003CF4B2 /* AESDecoderTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESDecoderTest.swift; sourceTree = ""; }; + F2B0B0022C34F3F800680EBE /* NumberArrayProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberArrayProtection.swift; sourceTree = ""; }; + F2B0B0042C34F5FF00680EBE /* NumberArrayProtectionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberArrayProtectionTest.swift; sourceTree = ""; }; F2E188532AA9CCFD00E7F0B5 /* DateProtection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateProtection.swift; sourceTree = ""; }; F2E188552AAAAF8C00E7F0B5 /* DateProtectionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateProtectionTest.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -141,6 +145,7 @@ F2E188552AAAAF8C00E7F0B5 /* DateProtectionTest.swift */, 55F3EC812AD97D1800BAEABB /* DecimalTest.swift */, 552C7BE4293A1E3E00B4B5EE /* MissingKeyProtectionTest.swift */, + F2B0B0042C34F5FF00680EBE /* NumberArrayProtectionTest.swift */, 55A1DAA12940AF3A00244FE2 /* NumberProtectionTest.swift */, F257F85A294C5CAA00FED754 /* NumbersProtectionTest.swift */, 559545A6293E12140060F43D /* ObjectProtectionTest.swift */, @@ -166,6 +171,7 @@ F22A05A629E40BFD003D30C1 /* DTAES.swift */, 551D305329377FEB00C375F0 /* MissingKeyProtection.swift */, F264CAD1293F1F4400AEC100 /* MultipleKeyProtection.swift */, + F2B0B0022C34F3F800680EBE /* NumberArrayProtection.swift */, 551D305229377FEB00C375F0 /* NumberProtection.swift */, 551D305429377FEB00C375F0 /* NumbersProtection.swift */, 551D305029377FEB00C375F0 /* ObjectProtection.swift */, @@ -288,6 +294,7 @@ F297055C29E3E69D003CF4B2 /* AESDecoder.swift in Sources */, 551D301D29377FBA00C375F0 /* AppDelegate.swift in Sources */, 551D305929377FEB00C375F0 /* NumberProtection.swift in Sources */, + F2B0B0032C34F3F800680EBE /* NumberArrayProtection.swift in Sources */, 551D305A29377FEB00C375F0 /* MissingKeyProtection.swift in Sources */, 551D301F29377FBA00C375F0 /* SceneDelegate.swift in Sources */, 551D305C29377FEB00C375F0 /* URLProtection.swift in Sources */, @@ -302,6 +309,7 @@ F257F85D294C5E4600FED754 /* URLProtectionTest.swift in Sources */, F297056029E3EF11003CF4B2 /* AESDecoderTest.swift in Sources */, 559545A7293E12140060F43D /* ObjectProtectionTest.swift in Sources */, + F2B0B0052C34F5FF00680EBE /* NumberArrayProtectionTest.swift in Sources */, F257F85B294C5CAA00FED754 /* NumbersProtectionTest.swift in Sources */, 55A1DAA22940AF3A00244FE2 /* NumberProtectionTest.swift in Sources */, 55F3EC822AD97D1800BAEABB /* DecimalTest.swift in Sources */, diff --git a/JsonDecodeProtectionTests/NumberArrayProtectionTest.swift b/JsonDecodeProtectionTests/NumberArrayProtectionTest.swift new file mode 100644 index 0000000..8ad28f0 --- /dev/null +++ b/JsonDecodeProtectionTests/NumberArrayProtectionTest.swift @@ -0,0 +1,70 @@ +// +// NumberArrayProtectionTest.swift +// JsonDecodeProtectionTests +// +// Created by Eden on 2024/7/3. +// + +import XCTest +@testable +import JsonDecodeProtection + +private +struct SomeObject: Decodable +{ + @ObjectProtection + var subObjects: Array? + + @NumberArrayProtection + var dices: Array? +} + +extension SomeObject +{ + struct SubObject: Decodable + { + private(set) + var name: String? + + private(set) + var number: Int? + } +} + +final class NumberArrayProtectionTest: XCTestCase +{ + var jsonString: String! + + override func setUpWithError() throws + { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // Arrange + + // Act + + // Assert + } + + func testNumberObjectProtectionSuccess() throws + { + // Arrange + self.jsonString = """ + { + "subObjects": "[{\\"name\\": \\"Jo\\", \\"number\\": 233}, {\\"name\\": \\"Ana\\", \\"number\\": 4565}]", + "dices": "[1, 5.2, 1.0]" + } + """ + let jsonData: Data = self.jsonString.data(using: .utf8)! + let jsonDecoder = JSONDecoder() + + // Act + let object = try jsonDecoder.decode(SomeObject.self, from: jsonData) + + // Assert + let actual: Array? = object.dices + let expect: Array = [1, 5, 1] + + XCTAssertEqual(actual, expect) + } +} diff --git a/JsonDecodeProtectionTests/ObjectProtectionTest.swift b/JsonDecodeProtectionTests/ObjectProtectionTest.swift index bf3ccca..cfa8080 100644 --- a/JsonDecodeProtectionTests/ObjectProtectionTest.swift +++ b/JsonDecodeProtectionTests/ObjectProtectionTest.swift @@ -74,7 +74,7 @@ final class ObjectProtectionTest: XCTestCase self.jsonString = """ { "subObjects": "[{\\"name\\": \\"Jo\\", \\"number\\": 233}, {\\"name\\": \\"Ana\\", \\"number\\": 4565}]", - "dices": "[1,5,1]" + "dices": "[1, 5, 1]" } """ diff --git a/README.md b/README.md index 073108c..8f22e4e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ * File > Swift Packages > Add Package Dependency * Add https://github.com/Darktt/JsonProtection -* Select "Up to Next Major" with "1.0.7" +* Select "Up to Next Major" with "1.1.0" ## 功能說明 @@ -125,6 +125,26 @@ struct Library: Decodable > 支援的數字型態: > * 與 NumberProtection 相同 ---- +## NumberArrayProtection +處理 json 裡應為數字內用的 jsonArray 資料,但實際上是 String 型態的問題 +```json +{ + "dices": "[1, 5.2, 1.0]" +} +``` + +將要解析成數字陣列型態的 property 套上 `@NumberArrayProtection` 進行型態保護 +```swift +struct NumberArray: Decodable +{ + @NumberArrayProtection + var dices: [Double]? +} +``` + +> 支援的數字型態 (陣列內的數字型態必定要相同,不能混入字串): +> * 與 NumberProtection 相同 +---- ## ObjectProtection 處理 json 裡應為 jsonObject 資料,但實際上是 String 型態的問題 ```json diff --git a/SourceCode/JsonProtection/NumberArrayProtection.swift b/SourceCode/JsonProtection/NumberArrayProtection.swift new file mode 100644 index 0000000..e6edcca --- /dev/null +++ b/SourceCode/JsonProtection/NumberArrayProtection.swift @@ -0,0 +1,75 @@ +// +// NumberArrayProtection.swift +// +// Created by Darktt on 2024/7/3. +// Copyright © 2024 Darktt. All rights reserved. +// + +import Foundation + +@propertyWrapper +public +struct NumberArrayProtection where Element: Decodable, Element: NumberType +{ + // MARK: - Properties - + + public + typealias WarppedValue = Array + + public + var wrappedValue: WarppedValue? + + // MARK: - Methods - + // MARK: Initial Method + + public + init() { } +} + +// MARK: - Conform Protocols - + +extension NumberArrayProtection: Decodable +{ + public + init(from decoder: Decoder) throws + { + let container: SingleValueDecodingContainer = try decoder.singleValueContainer() + + if container.decodeNil() { + + self.wrappedValue = nil + return + } + + let jsonString: String = try container.decode(String.self) + let wrappedValue: Array? = try self.decode(with: jsonString) + + self.wrappedValue = wrappedValue + } + + private + func decode(with string: String) throws -> Array? + { + guard let data: Data = string.data(using: .utf8) else { + + return nil + } + + let jsonDecoder = JSONDecoder() + let wrapperValue = try jsonDecoder.decode(NumbersProtection.self, from: data) + + return wrapperValue.wrappedValue + } +} + +extension NumberArrayProtection: CustomStringConvertible +{ + public + var description: String + { + self.wrappedValue.map { + + "\($0)" + } ?? "nil" + } +} diff --git a/SourceCode/JsonProtection/NumberProtection.swift b/SourceCode/JsonProtection/NumberProtection.swift index eca3e39..60a735c 100644 --- a/SourceCode/JsonProtection/NumberProtection.swift +++ b/SourceCode/JsonProtection/NumberProtection.swift @@ -228,16 +228,19 @@ extension Double: NumberType // MARK: - NumberProtection - @propertyWrapper -public struct NumberProtection: MissingKeyProtecting where DecodeType: Decodable, DecodeType: NumberType +public +struct NumberProtection: MissingKeyProtecting where DecodeType: Decodable, DecodeType: NumberType { // MARK: - Properties - - public var wrappedValue: DecodeType? + public + var wrappedValue: DecodeType? // MARK: - Methods - // MARK: Initial Method - public init(wrappedValue: DecodeType?) + public + init(wrappedValue: DecodeType?) { self.wrappedValue = wrappedValue } @@ -245,7 +248,8 @@ public struct NumberProtection: MissingKeyProtecting where DecodeTyp extension NumberProtection { - public init(from decoder: Decoder) throws + public + init(from decoder: Decoder) throws { let container: SingleValueDecodingContainer = try decoder.singleValueContainer() @@ -254,6 +258,7 @@ extension NumberProtection self.wrappedValue = wrappedValue } + private func decode(from container: SingleValueDecodingContainer) -> DecodeType? { var wrappedValue: DecodeType? diff --git a/SourceCode/JsonProtection/NumbersProtection.swift b/SourceCode/JsonProtection/NumbersProtection.swift index c8147ab..8d2861f 100644 --- a/SourceCode/JsonProtection/NumbersProtection.swift +++ b/SourceCode/JsonProtection/NumbersProtection.swift @@ -26,6 +26,8 @@ struct NumbersProtection: MissingKeyProtecting where Element: Decodable } } +// MARK: - Conform Protocol - + extension NumbersProtection: Decodable { public @@ -72,8 +74,6 @@ extension NumbersProtection: Decodable } } -// MARK: - Conform Protocol - - extension NumbersProtection: CustomStringConvertible { public