From e0f0520e5c58eca9f8cde7bb0437f3f0cd27a8d9 Mon Sep 17 00:00:00 2001 From: Richard Piazza Date: Fri, 20 Feb 2026 08:48:09 -0600 Subject: [PATCH] Apple Platform Checks; Swiftformat --- .github/workflows/pull_request.yml | 82 +++++++++++++++++++ .github/workflows/swift.yml | 35 -------- .swiftformat | 16 ++++ Package.swift | 7 +- Sources/CodablePlus/AnyEncodable.swift | 4 +- Sources/CodablePlus/DictionaryKeys.swift | 6 +- .../KeyedDecodingContainerProtocol+Any.swift | 8 +- ...DecodingContainerProtocol+Containers.swift | 34 ++++---- ...odingContainerProtocol+DefaultValues.swift | 11 +-- ...codingContainerProtocol+MultipleKeys.swift | 8 +- .../KeyedEncodingContainerProtocol+Any.swift | 18 ++-- ...EncodingContainerProtocol+Containers.swift | 30 +++---- .../UnkeyedDecodingContainer+Containers.swift | 22 ++--- .../UnkeyedEncodingContainer+Containers.swift | 18 ++-- .../AnyEncodingDecodingTests.swift | 58 ++++++------- .../ArrayEncodingDecodingTests.swift | 20 ++--- .../CodablePlusTestCase.swift | 11 +-- .../DefaultValueDecodingTests.swift | 16 ++-- .../DictionaryEncodingDecodingTests.swift | 14 ++-- .../KeyedDecodingContainerTests.swift | 39 +++++---- .../MultipleKeysDecodingTests.swift | 12 +-- 21 files changed, 263 insertions(+), 206 deletions(-) create mode 100644 .github/workflows/pull_request.yml delete mode 100644 .github/workflows/swift.yml create mode 100644 .swiftformat diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..4ce8072 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,82 @@ +name: Pull Request + +on: + pull_request: + branches: [ main ] + workflow_dispatch: + +env: + SCHEME: "CodablePlus" + +jobs: + Lint: + runs-on: macos-26 + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Lint + run: swiftformat --lint . --reporter github-actions-log + + Swift: + strategy: + fail-fast: false + matrix: + os: [ + macos-26, + ubuntu-latest, + ] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Cache + uses: actions/cache@v5 + with: + path: | + .build + ~/Library/Developer/Xcode/DerivedData/ModuleCache.noindex + ~/Library/Caches/org.swift.swiftpm + ~/Library/org.swift.swiftpm + key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.swift', '**/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-spm- + - name: Package Resolution + run: swift package resolve + - name: Build + run: swift build + - name: Test + run: swift test + + Xcode: + strategy: + fail-fast: false + matrix: + platform: [ + "macOS", + "iOS", + "tvOS", + "watchOS", + "visionOS", + "macOS,variant=Mac Catalyst", + ] + runs-on: macos-26 + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Cache + uses: actions/cache@v5 + with: + path: | + .build + ~/Library/Developer/Xcode/DerivedData/ModuleCache.noindex + ~/Library/Caches/org.swift.swiftpm + ~/Library/org.swift.swiftpm + key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.swift', '**/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-spm- + - name: Package Resolution + run: set -o pipefail && xcodebuild -resolvePackageDependencies | xcbeautify + - name: Build + env: + DESTINATION: "generic/platform=${{ matrix.platform }}" + run: set -o pipefail && xcodebuild build -scheme "$SCHEME" -destination "$DESTINATION" | xcbeautify diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml deleted file mode 100644 index af43337..0000000 --- a/.github/workflows/swift.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Swift - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - - SwiftLang: - strategy: - fail-fast: false - matrix: - os: [macOS-15, ubuntu-latest] - - runs-on: ${{ matrix.os }} - - steps: - - - name: Checkout - uses: actions/checkout@v4 - - - name: Package Resolution - shell: bash - run: swift package resolve - - - name: Build - shell: bash - run: swift build - - - name: Test - shell: bash - run: swift test - \ No newline at end of file diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 0000000..1544e58 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,16 @@ +# Compiler +--languagemode 5 +--swiftversion 5.9 + +# Options +--exclude derivedData +--ifdef no-indent +--indent 4 + +# Rules +--disable blankLinesAtStartOfScope +--disable hoistPatternLet +--disable redundantType +--disable unusedArguments +--disable wrapArguments +--disable wrapPropertyBodies diff --git a/Package.swift b/Package.swift index 7b5b01e..4aec396 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.8 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -10,7 +10,8 @@ let package = Package( .macCatalyst(.v15), .iOS(.v15), .tvOS(.v15), - .watchOS(.v8) + .watchOS(.v8), + .visionOS(.v1), ], products: [ .library( @@ -18,7 +19,7 @@ let package = Package( targets: ["CodablePlus"]), ], dependencies: [ - + ], targets: [ .target( diff --git a/Sources/CodablePlus/AnyEncodable.swift b/Sources/CodablePlus/AnyEncodable.swift index 16ff192..b07f574 100644 --- a/Sources/CodablePlus/AnyEncodable.swift +++ b/Sources/CodablePlus/AnyEncodable.swift @@ -1,11 +1,11 @@ /// A type-erased container that supports encoding its value to a `SingleValueEncodingContainer`. public struct AnyEncodable: Encodable { let value: Encodable - + public init(_ value: Encodable) { self.value = value } - + public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try value.encode(to: &container) diff --git a/Sources/CodablePlus/DictionaryKeys.swift b/Sources/CodablePlus/DictionaryKeys.swift index 2975022..aa3c053 100644 --- a/Sources/CodablePlus/DictionaryKeys.swift +++ b/Sources/CodablePlus/DictionaryKeys.swift @@ -20,13 +20,13 @@ import Foundation public struct DictionaryKeys: CodingKey { public var stringValue: String public var intValue: Int? - + public init(stringValue: String) { self.stringValue = stringValue } - + public init(intValue: Int) { - self.stringValue = "\(intValue)" + stringValue = "\(intValue)" self.intValue = intValue } } diff --git a/Sources/CodablePlus/KeyedDecodingContainerProtocol+Any.swift b/Sources/CodablePlus/KeyedDecodingContainerProtocol+Any.swift index b75f83a..7142247 100644 --- a/Sources/CodablePlus/KeyedDecodingContainerProtocol+Any.swift +++ b/Sources/CodablePlus/KeyedDecodingContainerProtocol+Any.swift @@ -13,9 +13,9 @@ public extension KeyedDecodingContainerProtocol { return doubleValue } else if let stringValue = try? decode(String.self, forKey: key) { return stringValue - } else if let nestedDictionary = try? decode(Dictionary.self, forKey: key) { + } else if let nestedDictionary = try? decode([String: Any].self, forKey: key) { return nestedDictionary - } else if let nestedArray = try? decode(Array.self, forKey: key) { + } else if let nestedArray = try? decode([Any].self, forKey: key) { return nestedArray } else if try decodeNil(forKey: key) { return NSNull() @@ -24,7 +24,7 @@ public extension KeyedDecodingContainerProtocol { throw DecodingError.dataCorrupted(context) } } - + /// Decodes a value of any decodable type, if present. /// /// - parameter key: The key that the decoded value is associated with. @@ -32,7 +32,7 @@ public extension KeyedDecodingContainerProtocol { guard contains(key) else { return nil } - + return try decodeAny(forKey: key) } } diff --git a/Sources/CodablePlus/KeyedDecodingContainerProtocol+Containers.swift b/Sources/CodablePlus/KeyedDecodingContainerProtocol+Containers.swift index a1f603d..54d6dd0 100644 --- a/Sources/CodablePlus/KeyedDecodingContainerProtocol+Containers.swift +++ b/Sources/CodablePlus/KeyedDecodingContainerProtocol+Containers.swift @@ -13,8 +13,8 @@ public extension KeyedDecodingContainerProtocol { /// for the given key. /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for /// the given key. - func decode(_ type: Dictionary.Type, forKey key: Key) throws -> Dictionary { - let container = try self.nestedContainer(keyedBy: DictionaryKeys.self, forKey: key) + func decode(_ type: [String: Any].Type, forKey key: Key) throws -> [String: Any] { + let container = try nestedContainer(keyedBy: DictionaryKeys.self, forKey: key) return try container.decode(type) } @@ -30,8 +30,8 @@ public extension KeyedDecodingContainerProtocol { /// for the given key. /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for /// the given key. - func decode(_ type: Array.Type, forKey key: Key) throws -> Array { - var container = try self.nestedUnkeyedContainer(forKey: key) + func decode(_ type: [Any].Type, forKey key: Key) throws -> [Any] { + var container = try nestedUnkeyedContainer(forKey: key) return try container.decode(type) } @@ -48,7 +48,7 @@ public extension KeyedDecodingContainerProtocol { /// the value is a null value. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value /// is not convertible to the requested type. - func decodeIfPresent(_ type: Dictionary.Type, forKey key: Key) throws -> Dictionary? { + func decodeIfPresent(_ type: [String: Any].Type, forKey key: Key) throws -> [String: Any]? { guard contains(key) else { return nil } @@ -69,7 +69,7 @@ public extension KeyedDecodingContainerProtocol { /// the value is a null value. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value /// is not convertible to the requested type. - func decodeIfPresent(_ type: Array.Type, forKey key: Key) throws -> Array? { + func decodeIfPresent(_ type: [Any].Type, forKey key: Key) throws -> [Any]? { guard contains(key) else { return nil } @@ -86,28 +86,28 @@ public extension KeyedDecodingContainerProtocol where Key == DictionaryKeys { /// and convertible to the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value /// is not convertible to the requested type. - func decode(_ type: Dictionary.Type) throws -> Dictionary { + func decode(_ type: [String: Any].Type) throws -> [String: Any] { var dictionary: [String: Any] = [:] - + for key in allKeys { if let boolValue = try? decode(Bool.self, forKey: key) { dictionary[key.stringValue] = boolValue - + } else if let intValue = try? decode(Int.self, forKey: key) { dictionary[key.stringValue] = intValue - + } else if let doubleValue = try? decode(Double.self, forKey: key) { dictionary[key.stringValue] = doubleValue - + } else if let stringValue = try? decode(String.self, forKey: key) { dictionary[key.stringValue] = stringValue - - } else if let nestedDictionary = try? decode(Dictionary.self, forKey: key) { + + } else if let nestedDictionary = try? decode([String: Any].self, forKey: key) { dictionary[key.stringValue] = nestedDictionary - - } else if let nestedArray = try? decode(Array.self, forKey: key) { + + } else if let nestedArray = try? decode([Any].self, forKey: key) { dictionary[key.stringValue] = nestedArray - + } else if try decodeNil(forKey: key) { dictionary[key.stringValue] = NSNull() } else { @@ -115,7 +115,7 @@ public extension KeyedDecodingContainerProtocol where Key == DictionaryKeys { throw DecodingError.typeMismatch(type, context) } } - + return dictionary } } diff --git a/Sources/CodablePlus/KeyedDecodingContainerProtocol+DefaultValues.swift b/Sources/CodablePlus/KeyedDecodingContainerProtocol+DefaultValues.swift index a3f6ed3..ebf728b 100644 --- a/Sources/CodablePlus/KeyedDecodingContainerProtocol+DefaultValues.swift +++ b/Sources/CodablePlus/KeyedDecodingContainerProtocol+DefaultValues.swift @@ -20,7 +20,7 @@ public extension KeyedDecodingContainerProtocol { /// /// - parameter key: The key that the decoded value is associated with. /// - parameter defaultValue: Closure called to produce a value when needed. - func decode(_ key: Key, defaultValue: @autoclosure () -> T) -> T where T: Decodable { + func decode(_ key: Key, defaultValue: @autoclosure () -> T) -> T { guard contains(key) else { return defaultValue() } @@ -51,7 +51,7 @@ public extension KeyedDecodingContainerProtocol { /// /// - parameter keys: the keys that the given value may be associate with. /// - parameter defaultValue: Closure called to produce a value when needed. - func decode(_ keys: [Key], defaultValue: @autoclosure () -> T) -> T where T: Decodable { + func decode(_ keys: [Key], defaultValue: @autoclosure () -> T) -> T { guard !keys.isEmpty else { return defaultValue() } @@ -62,11 +62,8 @@ public extension KeyedDecodingContainerProtocol { } do { - let value = try decode(T.self, forKey: key) - return value - } catch { - - } + return try decode(T.self, forKey: key) + } catch {} } return defaultValue() diff --git a/Sources/CodablePlus/KeyedDecodingContainerProtocol+MultipleKeys.swift b/Sources/CodablePlus/KeyedDecodingContainerProtocol+MultipleKeys.swift index 23d01cf..0f3d09c 100644 --- a/Sources/CodablePlus/KeyedDecodingContainerProtocol+MultipleKeys.swift +++ b/Sources/CodablePlus/KeyedDecodingContainerProtocol+MultipleKeys.swift @@ -18,10 +18,10 @@ public extension KeyedDecodingContainerProtocol { return true } } - + return false } - + /// Decodes a value of the given type for any of the given keys. /// /// This method will attempt to decode data in the order the keys are given. @@ -35,7 +35,7 @@ public extension KeyedDecodingContainerProtocol { /// one of the keys is not convertible to the requested type. /// - throws: `DecodingError.valueNotFound` if `self` has a null entry for all /// of the given keys. - func decode(_ type: T.Type, forKeys keys: [Key]) throws -> T where T: Decodable { + func decode(_ type: T.Type, forKeys keys: [Key]) throws -> T { guard keys.count > 0 else { let context = DecodingError.Context(codingPath: [], debugDescription: "No Keys Specified") throw DecodingError.dataCorrupted(context) @@ -70,7 +70,7 @@ public extension KeyedDecodingContainerProtocol { } for key in keys { - if let value = try self.decodeIfPresent(type, forKey: key) { + if let value = try decodeIfPresent(type, forKey: key) { return value } } diff --git a/Sources/CodablePlus/KeyedEncodingContainerProtocol+Any.swift b/Sources/CodablePlus/KeyedEncodingContainerProtocol+Any.swift index 8d047e0..5e80494 100644 --- a/Sources/CodablePlus/KeyedEncodingContainerProtocol+Any.swift +++ b/Sources/CodablePlus/KeyedEncodingContainerProtocol+Any.swift @@ -15,17 +15,17 @@ public extension KeyedEncodingContainerProtocol { try encode(primitive, forKey: key) case let primitive as String: try encode(primitive, forKey: key) - case let primitive as Dictionary: + case let primitive as [String: Any]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [Bool]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [Int]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [Double]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [String]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [Any]: try encode(primitive, forKey: key) case is NSNull: try encodeNil(forKey: key) @@ -34,16 +34,16 @@ public extension KeyedEncodingContainerProtocol { throw EncodingError.invalidValue(value, context) } } - + /// Encodes the given value if present for the key. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in the current context for this format. mutating func encodeAnyIfPresent(_ value: Any?, forKey key: Key) throws { - guard let value = value else { + guard let value else { return } - + try encodeAny(value, forKey: key) } } diff --git a/Sources/CodablePlus/KeyedEncodingContainerProtocol+Containers.swift b/Sources/CodablePlus/KeyedEncodingContainerProtocol+Containers.swift index 2cfc187..974d549 100644 --- a/Sources/CodablePlus/KeyedEncodingContainerProtocol+Containers.swift +++ b/Sources/CodablePlus/KeyedEncodingContainerProtocol+Containers.swift @@ -7,47 +7,47 @@ public extension KeyedEncodingContainerProtocol { /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encode(_ value: Dictionary, forKey key: Key) throws { + mutating func encode(_ value: [String: Any], forKey key: Key) throws { var container = nestedContainer(keyedBy: DictionaryKeys.self, forKey: key) try container.encode(value) } - + /// Encodes the given value for the given key. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encode(_ value: Array, forKey key: Key) throws { + mutating func encode(_ value: [Any], forKey key: Key) throws { var container = nestedUnkeyedContainer(forKey: key) try container.encode(value) } - + /// Encodes the given value for the given key if it is not `nil`. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encodeIfPresent(_ value: Dictionary?, forKey key: Key) throws { - guard let value = value else { + mutating func encodeIfPresent(_ value: [String: Any]?, forKey key: Key) throws { + guard let value else { return } - + try encode(value, forKey: key) } - + /// Encodes the given value for the given key if it is not `nil`. /// /// - parameter value: The value to encode. /// - parameter key: The key to associate the value with. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encodeIfPresent(_ value: Array?, forKey key: Key) throws { - guard let value = value else { + mutating func encodeIfPresent(_ value: [Any]?, forKey key: Key) throws { + guard let value else { return } - + try encode(value, forKey: key) } } @@ -58,10 +58,10 @@ public extension KeyedEncodingContainerProtocol where Key == DictionaryKeys { /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encode(_ value: Dictionary) throws { + mutating func encode(_ value: [String: Any]) throws { for (index, element) in value { let key = DictionaryKeys(stringValue: index) - + switch element { case let primitive as Bool: try encode(primitive, forKey: key) @@ -71,9 +71,9 @@ public extension KeyedEncodingContainerProtocol where Key == DictionaryKeys { try encode(primitive, forKey: key) case let primitive as String: try encode(primitive, forKey: key) - case let primitive as Dictionary: + case let primitive as [String: Any]: try encode(primitive, forKey: key) - case let primitive as Array: + case let primitive as [Any]: try encode(primitive, forKey: key) case is NSNull: try encodeNil(forKey: key) diff --git a/Sources/CodablePlus/UnkeyedDecodingContainer+Containers.swift b/Sources/CodablePlus/UnkeyedDecodingContainer+Containers.swift index d73e3e6..c3dbb93 100644 --- a/Sources/CodablePlus/UnkeyedDecodingContainer+Containers.swift +++ b/Sources/CodablePlus/UnkeyedDecodingContainer+Containers.swift @@ -8,11 +8,11 @@ public extension UnkeyedDecodingContainer { /// and convertible to the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value /// is not convertible to the requested type. - mutating func decode(_ type: Dictionary.Type) throws -> Dictionary { + mutating func decode(_ type: [String: Any].Type) throws -> [String: Any] { let container = try nestedContainer(keyedBy: DictionaryKeys.self) return try container.decode(type) } - + /// Decodes a value of the given type. /// /// - parameter type: The type of value to decode. @@ -20,9 +20,9 @@ public extension UnkeyedDecodingContainer { /// and convertible to the requested type. /// - throws: `DecodingError.typeMismatch` if the encountered encoded value /// is not convertible to the requested type. - mutating func decode(_ type: Array.Type) throws -> Array { + mutating func decode(_ type: [Any].Type) throws -> [Any] { var array: [Any] = [] - + while isAtEnd == false { if let value = try? decode(Bool.self) { array.append(value) @@ -32,17 +32,17 @@ public extension UnkeyedDecodingContainer { array.append(value) } else if let value = try? decode(String.self) { array.append(value) - } else if let nestedDictionary = try? decode(Dictionary.self) { + } else if let nestedDictionary = try? decode([String: Any].self) { array.append(nestedDictionary) - } else if let nestedArray = try? decode(Array.self) { + } else if let nestedArray = try? decode([Bool].self) { array.append(nestedArray) - } else if let nestedArray = try? decode(Array.self) { + } else if let nestedArray = try? decode([Int].self) { array.append(nestedArray) - } else if let nestedArray = try? decode(Array.self) { + } else if let nestedArray = try? decode([Double].self) { array.append(nestedArray) - } else if let nestedArray = try? decode(Array.self) { + } else if let nestedArray = try? decode([String].self) { array.append(nestedArray) - } else if let nestedArray = try? decode(Array.self) { + } else if let nestedArray = try? decode([Any].self) { array.append(nestedArray) } else if let _ = try? decodeNil() { array.append(NSNull()) @@ -51,7 +51,7 @@ public extension UnkeyedDecodingContainer { throw DecodingError.typeMismatch(type, context) } } - + return array } } diff --git a/Sources/CodablePlus/UnkeyedEncodingContainer+Containers.swift b/Sources/CodablePlus/UnkeyedEncodingContainer+Containers.swift index 8ba4b30..5170905 100644 --- a/Sources/CodablePlus/UnkeyedEncodingContainer+Containers.swift +++ b/Sources/CodablePlus/UnkeyedEncodingContainer+Containers.swift @@ -6,17 +6,17 @@ public extension UnkeyedEncodingContainer { /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encode(_ value: Dictionary) throws { + mutating func encode(_ value: [String: Any]) throws { var container = nestedContainer(keyedBy: DictionaryKeys.self) try container.encode(value) } - + /// Encodes the given value. /// /// - parameter value: The value to encode. /// - throws: `EncodingError.invalidValue` if the given value is invalid in /// the current context for this format. - mutating func encode(_ value: Array) throws { + mutating func encode(_ value: [Any]) throws { for (index, element) in value.enumerated() { switch element { case let primitive as Bool: @@ -27,17 +27,17 @@ public extension UnkeyedEncodingContainer { try encode(primitive) case let primitive as String: try encode(primitive) - case let primitive as Dictionary: + case let primitive as [String: Any]: try encode(primitive) - case let primitive as Array: + case let primitive as [Bool]: try encode(primitive) - case let primitive as Array: + case let primitive as [Int]: try encode(primitive) - case let primitive as Array: + case let primitive as [Double]: try encode(primitive) - case let primitive as Array: + case let primitive as [String]: try encode(primitive) - case let primitive as Array: + case let primitive as [Any]: try encode(primitive) case is NSNull: try encodeNil() diff --git a/Tests/CodablePlusTests/AnyEncodingDecodingTests.swift b/Tests/CodablePlusTests/AnyEncodingDecodingTests.swift index a6b87fa..cd8c35e 100644 --- a/Tests/CodablePlusTests/AnyEncodingDecodingTests.swift +++ b/Tests/CodablePlusTests/AnyEncodingDecodingTests.swift @@ -1,102 +1,102 @@ -import XCTest @testable import CodablePlus +import XCTest final class AnyEncodingDecodingTests: CodablePlusTestCase { - + private struct Demo: Codable { - + enum CodingKeys: String, CodingKey { case value } - + let value: Any - + init(value: Any) { self.value = value } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) value = try container.decodeAny(forKey: .value) } - + func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeAny(value, forKey: .value) } } - + func testEncodingAny() throws { var demo = Demo(value: "Hello World") var data = try encoder.encode(demo) var json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + XCTAssertEqual(json, #"{"value":"Hello World"}"#) - + demo = Demo(value: 47) data = try encoder.encode(demo) json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + XCTAssertEqual(json, #"{"value":47}"#) - + demo = Demo(value: 3.14) data = try encoder.encode(demo) json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + var object = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any]) let value = try XCTUnwrap(object["value"] as? Double) - + XCTAssertEqual(value, 3.14, accuracy: 0.1) - + demo = Demo(value: false) data = try encoder.encode(demo) json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + XCTAssertEqual(json, #"{"value":false}"#) - + demo = Demo(value: ["1", "2", "3"]) data = try encoder.encode(demo) json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + XCTAssertEqual(json, #"{"value":["1","2","3"]}"#) - + demo = Demo(value: ["1", 2, 3.1, true]) data = try encoder.encode(demo) json = try XCTUnwrap(String(data: data, encoding: .utf8)) - + object = try XCTUnwrap(JSONSerialization.jsonObject(with: data) as? [String: Any]) let array = try XCTUnwrap(object["value"] as? [Any]) XCTAssertTrue(array.count == 4) - + XCTAssertEqual(array[0] as? String, "1") XCTAssertEqual(array[1] as? Int, 2) XCTAssertEqual(array[2] as? Double ?? 0.0, 3.1, accuracy: 0.1) XCTAssertEqual(array[3] as? Bool, true) } - + func testDecodeAny() throws { var json = #"{"value":"string"}"# var data = try XCTUnwrap(json.data(using: .utf8)) var demo = try decoder.decode(Demo.self, from: data) - + XCTAssertEqual(demo.value as? String, "string") - + json = #"{"value":88}"# data = try XCTUnwrap(json.data(using: .utf8)) demo = try decoder.decode(Demo.self, from: data) - + XCTAssertEqual(demo.value as? Int, 88) - + json = #"{"value":43.21}"# data = try XCTUnwrap(json.data(using: .utf8)) demo = try decoder.decode(Demo.self, from: data) - + XCTAssertEqual(demo.value as? Double ?? 0.0, 43.21, accuracy: 0.1) - + json = #"{"value":true}"# data = try XCTUnwrap(json.data(using: .utf8)) demo = try decoder.decode(Demo.self, from: data) - + XCTAssertEqual(demo.value as? Bool, true) } } diff --git a/Tests/CodablePlusTests/ArrayEncodingDecodingTests.swift b/Tests/CodablePlusTests/ArrayEncodingDecodingTests.swift index 7a89dcc..51629ad 100644 --- a/Tests/CodablePlusTests/ArrayEncodingDecodingTests.swift +++ b/Tests/CodablePlusTests/ArrayEncodingDecodingTests.swift @@ -1,13 +1,13 @@ -import XCTest @testable import CodablePlus +import XCTest class ArrayEncodingDecodingTests: XCTestCase { - + fileprivate let decoder = JSONDecoder() fileprivate let encoder = JSONEncoder() func testDecodingArray() throws { - let data = arrayJSON.data(using: .utf8)! + let data = try XCTUnwrap(arrayJSON.data(using: .utf8)) let catalog = try decoder.decode(Catalog.self, from: data) XCTAssertEqual(catalog.activities.count, 3) @@ -34,7 +34,7 @@ class ArrayEncodingDecodingTests: XCTestCase { } XCTAssertEqual(coding["location"] as? String, "Everywhere") - XCTAssertEqual(coding["linesOfCode"] as? Int, 8327563) + XCTAssertEqual(coding["linesOfCode"] as? Int, 8_327_563) } func testEncodingArray() throws { @@ -51,7 +51,7 @@ class ArrayEncodingDecodingTests: XCTestCase { var coding: [String: Any] = [:] coding["name"] = "Coding" coding["location"] = "Everywhere" - coding["linesOfCode"] = 8327563 + coding["linesOfCode"] = 8_327_563 let catalog = Catalog(activities: [swimming, reading, coding]) let data = try encoder.encode(catalog) @@ -92,7 +92,7 @@ class ArrayEncodingDecodingTests: XCTestCase { case "Coding": XCTAssertEqual(location, "Everywhere") let linesOfCode = activity["linesOfCode"] as? Int - XCTAssertEqual(linesOfCode, 8327563) + XCTAssertEqual(linesOfCode, 8_327_563) default: XCTFail("Encoding or JSONSerialization failed.") } @@ -128,7 +128,7 @@ class ArrayEncodingDecodingTests: XCTestCase { } func testDecodeNull() throws { - let data = arrayWithNullJSON.data(using: .utf8)! + let data = try XCTUnwrap(arrayWithNullJSON.data(using: .utf8)) let catalog = try decoder.decode(Catalog.self, from: data) guard let activity = catalog.activities.first else { @@ -140,9 +140,9 @@ class ArrayEncodingDecodingTests: XCTestCase { XCTAssertTrue(activity["location"] is NSNull) } - func testEncodeInvalid() { + func testEncodeInvalid() throws { var activity: [String: Any] = [:] - activity["url"] = URL(string: "https://www.google.com")! + activity["url"] = try XCTUnwrap(URL(string: "https://www.google.com")) let catalog = Catalog(activities: [activity]) XCTAssertThrowsError(try encoder.encode(catalog)) @@ -188,7 +188,7 @@ class ArrayEncodingDecodingTests: XCTestCase { } func testDecodeOptional() throws { - let data = arrayWithInstructors.data(using: .utf8)! + let data = try XCTUnwrap(arrayWithInstructors.data(using: .utf8)) let catalog = try decoder.decode(Catalog.self, from: data) XCTAssertFalse(catalog.activities.isEmpty) XCTAssertNotNil(catalog.instructors) diff --git a/Tests/CodablePlusTests/CodablePlusTestCase.swift b/Tests/CodablePlusTests/CodablePlusTestCase.swift index c70c649..1d658fb 100644 --- a/Tests/CodablePlusTests/CodablePlusTestCase.swift +++ b/Tests/CodablePlusTests/CodablePlusTestCase.swift @@ -1,16 +1,13 @@ -import XCTest @testable import CodablePlus +import XCTest class CodablePlusTestCase: XCTestCase { - + let encoder: JSONEncoder = { let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys] return encoder }() - - let decoder: JSONDecoder = { - let decoder = JSONDecoder() - return decoder - }() + + let decoder: JSONDecoder = JSONDecoder() } diff --git a/Tests/CodablePlusTests/DefaultValueDecodingTests.swift b/Tests/CodablePlusTests/DefaultValueDecodingTests.swift index 430a873..01bcf1c 100644 --- a/Tests/CodablePlusTests/DefaultValueDecodingTests.swift +++ b/Tests/CodablePlusTests/DefaultValueDecodingTests.swift @@ -1,19 +1,19 @@ -import XCTest @testable import CodablePlus +import XCTest class DefaultValueDecodingTests: XCTestCase { - + struct GameSystem: Decodable { let name: String let manufacturer: String let price: Double - + enum CodingKeys: CodingKey { case name case manufacturer case price } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) @@ -21,7 +21,7 @@ class DefaultValueDecodingTests: XCTestCase { price = container.decode(.price, defaultValue: 299.99) } } - + let json1 = """ { "name": "Switch", @@ -29,16 +29,16 @@ class DefaultValueDecodingTests: XCTestCase { "price": 199.99 } """ - + let json2 = """ { "name": "Switch", "manufacturer": "Nintendo" } """ - + let decoder: JSONDecoder = .init() - + func testDefaultValueDecoding() throws { var data = try XCTUnwrap(json1.data(using: .utf8)) var gameSystem = try decoder.decode(GameSystem.self, from: data) diff --git a/Tests/CodablePlusTests/DictionaryEncodingDecodingTests.swift b/Tests/CodablePlusTests/DictionaryEncodingDecodingTests.swift index 9b70e9c..e3973c7 100644 --- a/Tests/CodablePlusTests/DictionaryEncodingDecodingTests.swift +++ b/Tests/CodablePlusTests/DictionaryEncodingDecodingTests.swift @@ -1,13 +1,13 @@ -import XCTest @testable import CodablePlus +import XCTest class DictionaryEncodingDecodingTests: XCTestCase { - + fileprivate let decoder = JSONDecoder() fileprivate let encoder = JSONEncoder() func testDecodingDictionary() throws { - let data = dictionaryJSON.data(using: .utf8)! + let data = try XCTUnwrap(dictionaryJSON.data(using: .utf8)) let container = try decoder.decode(Container.self, from: data) let string = container.dictionary["aString"] as? String @@ -111,23 +111,23 @@ class DictionaryEncodingDecodingTests: XCTestCase { } func testDecodeNull() throws { - let data = dictionaryWithNullJSON.data(using: .utf8)! + let data = try XCTUnwrap(dictionaryWithNullJSON.data(using: .utf8)) let container = try decoder.decode(Container.self, from: data) XCTAssertTrue(container.dictionary["nullValue"] is NSNull) XCTAssertEqual(container.dictionary["nonNullValue"] as? Int, 47) } - func testEncodeInvalid() { + func testEncodeInvalid() throws { var containerDictionary: [String: Any] = [:] - containerDictionary["url"] = URL(string: "https://www.google.com")! + containerDictionary["url"] = try XCTUnwrap(URL(string: "https://www.google.com")) let container = Container(dictionary: containerDictionary) XCTAssertThrowsError(try encoder.encode(container)) } func testDecodeSubarrays() throws { - let data = dictionaryWithSubArraysJSON.data(using: .utf8)! + let data = try XCTUnwrap(dictionaryWithSubArraysJSON.data(using: .utf8)) let container = try decoder.decode(Container.self, from: data) guard let array = container.dictionary["container"] as? [Any] else { diff --git a/Tests/CodablePlusTests/KeyedDecodingContainerTests.swift b/Tests/CodablePlusTests/KeyedDecodingContainerTests.swift index e27aa71..71f1d2a 100644 --- a/Tests/CodablePlusTests/KeyedDecodingContainerTests.swift +++ b/Tests/CodablePlusTests/KeyedDecodingContainerTests.swift @@ -1,15 +1,15 @@ -import XCTest @testable import CodablePlus +import XCTest class KeyedDecodingContainerTests: XCTestCase { - + let json1 = """ { "name": "Apple", "employees": 42000 } """ - + let json2 = """ { "companyName": "Microsoft", @@ -17,24 +17,24 @@ class KeyedDecodingContainerTests: XCTestCase { "ceoName": "Satya Nadella" } """ - + struct CompanyV1: Decodable { var name: String var employees: Int } - + struct CompanyV2: Decodable { var companyName: String var employees: Int var ceoName: String - + private enum CodingKeys: String, CodingKey { case name case companyName case employees case ceoName } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) companyName = try container.decode(String.self, forKeys: [.name, .companyName]) @@ -42,18 +42,17 @@ class KeyedDecodingContainerTests: XCTestCase { ceoName = try container.decodeIfPresent(String.self, forKey: .ceoName) ?? "" } } - + var decoder: JSONDecoder { - let decoder = JSONDecoder() - return decoder + JSONDecoder() } - + func testVersion1() { guard let data = json1.data(using: .utf8) else { XCTFail() return } - + let company: CompanyV1 do { company = try decoder.decode(CompanyV1.self, from: data) @@ -61,17 +60,17 @@ class KeyedDecodingContainerTests: XCTestCase { XCTFail() return } - + XCTAssertEqual(company.name, "Apple") XCTAssertEqual(company.employees, 42000) } - + func testVersion2() { guard let data = json2.data(using: .utf8) else { XCTFail() return } - + let company: CompanyV2 do { company = try decoder.decode(CompanyV2.self, from: data) @@ -79,18 +78,18 @@ class KeyedDecodingContainerTests: XCTestCase { XCTFail() return } - + XCTAssertEqual(company.companyName, "Microsoft") - XCTAssertEqual(company.employees, 600000) + XCTAssertEqual(company.employees, 600_000) XCTAssertEqual(company.ceoName, "Satya Nadella") } - + func testVersion2WithV1Data() { guard let data = json1.data(using: .utf8) else { XCTFail() return } - + let company: CompanyV2 do { company = try decoder.decode(CompanyV2.self, from: data) @@ -98,7 +97,7 @@ class KeyedDecodingContainerTests: XCTestCase { XCTFail() return } - + XCTAssertEqual(company.companyName, "Apple") XCTAssertEqual(company.employees, 42000) XCTAssertEqual(company.ceoName, "") diff --git a/Tests/CodablePlusTests/MultipleKeysDecodingTests.swift b/Tests/CodablePlusTests/MultipleKeysDecodingTests.swift index 29f6837..9e7509f 100644 --- a/Tests/CodablePlusTests/MultipleKeysDecodingTests.swift +++ b/Tests/CodablePlusTests/MultipleKeysDecodingTests.swift @@ -1,12 +1,12 @@ -import XCTest @testable import CodablePlus +import XCTest class MultipleKeysDecodingTests: XCTestCase { - + fileprivate let decoder = JSONDecoder() func testSchema1() throws { - let data = schema1json.data(using: .utf8)! + let data = try XCTUnwrap(schema1json.data(using: .utf8)) let company = try decoder.decode(CompanyV1.self, from: data) XCTAssertEqual(company.name, "Apple") @@ -14,16 +14,16 @@ class MultipleKeysDecodingTests: XCTestCase { } func testSchema2() throws { - let data = schema2json.data(using: .utf8)! + let data = try XCTUnwrap(schema2json.data(using: .utf8)) let company = try decoder.decode(CompanyV2.self, from: data) XCTAssertEqual(company.companyName, "Microsoft") - XCTAssertEqual(company.employees, 600000) + XCTAssertEqual(company.employees, 600_000) XCTAssertEqual(company.ceoName, "Satya Nadella") } func testSchema2WithSchema1Data() throws { - let data = schema1json.data(using: .utf8)! + let data = try XCTUnwrap(schema1json.data(using: .utf8)) let company = try decoder.decode(CompanyV2.self, from: data) XCTAssertEqual(company.companyName, "Apple")