From e0e672322233a35823cad7705812a6d4ecefcde3 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 2 Aug 2019 07:27:17 -0700 Subject: [PATCH 1/3] Make Xcode Beta happy by explicitly creating optionals where they used to be implied. --- Tests/JSONAPITests/Entity/EntityTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/JSONAPITests/Entity/EntityTests.swift b/Tests/JSONAPITests/Entity/EntityTests.swift index 7076358..5fe168f 100644 --- a/Tests/JSONAPITests/Entity/EntityTests.swift +++ b/Tests/JSONAPITests/Entity/EntityTests.swift @@ -29,8 +29,8 @@ class EntityTests: XCTestCase { let entity1 = TestEntity1(attributes: .none, relationships: .none, meta: .none, links: .none) let entity = TestEntity9(attributes: .none, relationships: .init(one: entity1.pointer, nullableOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalOne: .init(resourceObject: entity1, meta: .none, links: .none), optionalNullableOne: nil, optionalMany: .init(resourceObjects: [entity1, entity1], meta: .none, links: .none)), meta: .none, links: .none) - XCTAssertEqual(entity ~> \.optionalOne, entity1.id) - XCTAssertEqual((entity ~> \.optionalOne).rawValue, entity1.id.rawValue) + XCTAssertEqual(entity ~> \.optionalOne, Optional(entity1.id)) + XCTAssertEqual((entity ~> \.optionalOne).rawValue, Optional(entity1.id.rawValue)) } func test_toMany_relationship_operator_access() { From 7ec185bfe837addf84adf9b25c0b870a7438a8e4 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 2 Aug 2019 08:45:38 -0700 Subject: [PATCH 2/3] Add a couple tests and a bit of code doc. --- Sources/JSONAPI/Resource/Transformer.swift | 2 + .../Attribute/TransformerTests.swift | 51 +++++++++++++++++++ Tests/JSONAPITests/XCTestManifests.swift | 13 +++++ 3 files changed, 66 insertions(+) create mode 100644 Tests/JSONAPITests/Attribute/TransformerTests.swift diff --git a/Sources/JSONAPI/Resource/Transformer.swift b/Sources/JSONAPI/Resource/Transformer.swift index 920b9d4..04d3c04 100644 --- a/Sources/JSONAPI/Resource/Transformer.swift +++ b/Sources/JSONAPI/Resource/Transformer.swift @@ -42,6 +42,8 @@ extension Validator { return value } + /// Validate the given value and then return it if valid. + /// throws if invalid. public static func validate(_ value: To) throws -> To { let _ = try transform(value) return value diff --git a/Tests/JSONAPITests/Attribute/TransformerTests.swift b/Tests/JSONAPITests/Attribute/TransformerTests.swift new file mode 100644 index 0000000..1988f40 --- /dev/null +++ b/Tests/JSONAPITests/Attribute/TransformerTests.swift @@ -0,0 +1,51 @@ +// +// TransformerTests.swift +// +// +// Created by Mathew Polzin on 8/2/19. +// + +import XCTest +import JSONAPI +import JSONAPITesting + +class TransformerTests: XCTestCase { + func testIdentityTransform() { + let inString = "hello world" + + XCTAssertNoThrow(try IdentityTransformer.transform(inString)) + XCTAssertEqual(inString, try? IdentityTransformer.transform(inString)) + + XCTAssertNoThrow(try IdentityTransformer.reverse(inString)) + XCTAssertEqual(inString, try? IdentityTransformer.reverse(inString)) + } + + func testValidator() { + let string1 = "hello" + let string2 = "hello world" + + XCTAssertThrowsError(try MoreThanFiveCharValidator.validate(string1)) + XCTAssertThrowsError(try MoreThanFiveCharValidator.transform(string1)) + XCTAssertThrowsError(try MoreThanFiveCharValidator.reverse(string1)) + + XCTAssertNoThrow(try MoreThanFiveCharValidator.validate(string2)) + XCTAssertNoThrow(try MoreThanFiveCharValidator.transform(string2)) + XCTAssertNoThrow(try MoreThanFiveCharValidator.reverse(string2)) + + XCTAssertEqual(string2, try MoreThanFiveCharValidator.transform(string2)) + XCTAssertEqual(string2, try MoreThanFiveCharValidator.reverse(string2)) + } +} + +enum MoreThanFiveCharValidator: Validator { + public static func transform(_ value: String) throws -> String { + guard value.count > 5 else { + throw Error.fewerThanFiveChars + } + return value + } + + enum Error: Swift.Error { + case fewerThanFiveChars + } +} diff --git a/Tests/JSONAPITests/XCTestManifests.swift b/Tests/JSONAPITests/XCTestManifests.swift index a7b9e90..46edbba 100644 --- a/Tests/JSONAPITests/XCTestManifests.swift +++ b/Tests/JSONAPITests/XCTestManifests.swift @@ -8,6 +8,7 @@ extension APIDescriptionTests { static let __allTests__APIDescriptionTests = [ ("test_empty", test_empty), ("test_failsMissingMeta", test_failsMissingMeta), + ("test_init", test_init), ("test_NoDescriptionString", test_NoDescriptionString), ("test_WithMeta", test_WithMeta), ("test_WithVersion", test_WithVersion), @@ -235,6 +236,7 @@ extension EntityTests { ("test_RleationshipsOfSameType", test_RleationshipsOfSameType), ("test_RleationshipsOfSameType_encode", test_RleationshipsOfSameType_encode), ("test_toMany_relationship_operator_access", test_toMany_relationship_operator_access), + ("test_toManyMetaRelationshipAccessWorks", test_toManyMetaRelationshipAccessWorks), ("test_UnidentifiedEntity", test_UnidentifiedEntity), ("test_UnidentifiedEntity_encode", test_UnidentifiedEntity_encode), ("test_unidentifiedEntityAttributeAccess", test_unidentifiedEntityAttributeAccess), @@ -407,6 +409,16 @@ extension ResourceBodyTests { ] } +extension TransformerTests { + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__TransformerTests = [ + ("testIdentityTransform", testIdentityTransform), + ("testValidator", testValidator), + ] +} + public func __allTests() -> [XCTestCaseEntry] { return [ testCase(APIDescriptionTests.__allTests__APIDescriptionTests), @@ -423,6 +435,7 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(PolyTests.__allTests__PolyTests), testCase(RelationshipTests.__allTests__RelationshipTests), testCase(ResourceBodyTests.__allTests__ResourceBodyTests), + testCase(TransformerTests.__allTests__TransformerTests), ] } #endif From 5335f24e9b9a328c70d7238b04d57327320ee05d Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 2 Aug 2019 09:30:30 -0700 Subject: [PATCH 3/3] Add test coverage for EmptyObjectDecoder's keyed container --- .../EmptyObjectDecoderTests.swift | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 Tests/JSONAPITests/Empty Object Decoder/EmptyObjectDecoderTests.swift diff --git a/Tests/JSONAPITests/Empty Object Decoder/EmptyObjectDecoderTests.swift b/Tests/JSONAPITests/Empty Object Decoder/EmptyObjectDecoderTests.swift new file mode 100644 index 0000000..bda37d1 --- /dev/null +++ b/Tests/JSONAPITests/Empty Object Decoder/EmptyObjectDecoderTests.swift @@ -0,0 +1,220 @@ +// +// File.swift +// +// +// Created by Mathew Polzin on 8/2/19. +// + +import XCTest +@testable import JSONAPI + +class EmptyObjectDecoderTests: XCTestCase { + func testEmptyStruct() { + XCTAssertNoThrow(try EmptyStruct.init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try EmptyStructWithCodingKeys.init(from: EmptyObjectDecoder())) + } + + func testEmptyArray() { + XCTAssertNoThrow(try [EmptyStruct].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [String].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Int].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Double].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Bool].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Float].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Int8].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Int16].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Int32].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [Int64].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [UInt].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [UInt8].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [UInt16].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [UInt32].init(from: EmptyObjectDecoder())) + XCTAssertNoThrow(try [UInt64].init(from: EmptyObjectDecoder())) + } + + func testNonEmptyStruct() { + XCTAssertThrowsError(try NonEmptyStruct.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructString.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructInt.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructDouble.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructBool.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructFloat.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructInt8.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructInt16.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructInt32.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructInt64.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructUInt.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructUInt8.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructUInt16.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructUInt32.init(from: EmptyObjectDecoder())) + XCTAssertThrowsError(try NonEmptyStructUInt64.init(from: EmptyObjectDecoder())) + } + + func testWantingNil() { + XCTAssertThrowsError(try StructWithNil.init(from: EmptyObjectDecoder())) + } + + func testWantingSingleValue() { + XCTAssertThrowsError(try StructWithSingleValue.init(from: EmptyObjectDecoder())) + } + + func testWantingNestedKeyed() { + XCTAssertThrowsError(try StructWithNestedKeyedCall.init(from: EmptyObjectDecoder())) + } + + func testWantingNestedUnkeyed() { + XCTAssertThrowsError(try StructWithNestedUnkeyedCall.init(from: EmptyObjectDecoder())) + } + + func testWantsSuper() { + XCTAssertThrowsError(try StructWithUnkeyedSuper.init(from: EmptyObjectDecoder())) + + XCTAssertThrowsError(try StructWithKeyedSuper.init(from: EmptyObjectDecoder())) + } + + func testKeysAndCodingPath() { + XCTAssertEqual(try? EmptyObjectDecoder().container(keyedBy: EmptyStructWithCodingKeys.CodingKeys.self).allKeys.count, 0) + XCTAssertEqual(try? EmptyObjectDecoder().container(keyedBy: EmptyStructWithCodingKeys.CodingKeys.self).codingPath.count, 0) + } +} + +struct EmptyStruct: Decodable { + +} + +struct EmptyStructWithCodingKeys: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + init(from decoder: Decoder) throws {} +} + +struct NonEmptyStruct: Decodable { + let value: T +} + +struct NonEmptyStructString: Decodable { + let value: String +} + +struct NonEmptyStructInt: Decodable { + let value: Int +} + +struct NonEmptyStructDouble: Decodable { + let value: Double +} + +struct NonEmptyStructBool: Decodable { + let value: Bool +} + +struct NonEmptyStructFloat: Decodable { + let value: Float +} + +struct NonEmptyStructInt8: Decodable { + let value: Int8 +} + +struct NonEmptyStructInt16: Decodable { + let value: Int16 +} + +struct NonEmptyStructInt32: Decodable { + let value: Int32 +} + +struct NonEmptyStructInt64: Decodable { + let value: Int64 +} + +struct NonEmptyStructUInt: Decodable { + let value: UInt +} + +struct NonEmptyStructUInt8: Decodable { + let value: UInt8 +} + +struct NonEmptyStructUInt16: Decodable { + let value: UInt16 +} + +struct NonEmptyStructUInt32: Decodable { + let value: UInt32 +} + +struct NonEmptyStructUInt64: Decodable { + let value: UInt64 +} + +struct StructWithNil: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let _ = try container.decodeNil(forKey: .hello) + } +} + +struct StructWithSingleValue: Decodable { + let value: String + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + value = try container.decode(String.self) + } +} + +struct StructWithNestedKeyedCall: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + enum NestedKeys: String, CodingKey { + case world + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let _ = try container.nestedContainer(keyedBy: NestedKeys.self, forKey: .hello) + } +} + +struct StructWithNestedUnkeyedCall: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let _ = try container.nestedUnkeyedContainer(forKey: .hello) + } +} + +struct StructWithUnkeyedSuper: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + init(from decoder: Decoder) throws { + let _ = try decoder.container(keyedBy: CodingKeys.self).superDecoder() + } +} + +struct StructWithKeyedSuper: Decodable { + enum CodingKeys: String, CodingKey { + case hello + } + + init(from decoder: Decoder) throws { + let _ = try decoder.container(keyedBy: CodingKeys.self).superDecoder(forKey: .hello) + } +}