From 9802efd917ec870e81a2dbfdfccecd88c32411ec Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 16 Nov 2018 18:21:37 -0800 Subject: [PATCH] Add encoding to ResourceBody and test it --- Sources/JSONAPI/Document/ResourceBody.swift | 27 ++++++- Tests/JSONAPITests/Entity/EntityTests.swift | 32 ++++----- .../JSONAPITests/Includes/IncludeTests.swift | 72 +++++-------------- .../Relationships/RelationshipTests.swift | 30 +++++--- .../ResourceBody/ResourceBodyTests.swift | 40 +++++++---- .../stubs/ResourceBudyStubs.swift | 5 ++ .../Test Helpers/EncodeDecode.swift | 2 +- 7 files changed, 114 insertions(+), 94 deletions(-) diff --git a/Sources/JSONAPI/Document/ResourceBody.swift b/Sources/JSONAPI/Document/ResourceBody.swift index 1c7c55e..62bfec0 100644 --- a/Sources/JSONAPI/Document/ResourceBody.swift +++ b/Sources/JSONAPI/Document/ResourceBody.swift @@ -5,7 +5,7 @@ // Created by Mathew Polzin on 11/10/18. // -public protocol ResourceBody: Decodable { +public protocol ResourceBody: Codable, Equatable { } public struct SingleResourceBody: ResourceBody { @@ -20,8 +20,25 @@ public struct ManyResourceBody: ResourceBody { extension SingleResourceBody { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() + + if container.decodeNil() { + value = nil + return + } + value = try container.decode(Entity.self) } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + if value == nil { + try container.encodeNil() + return + } + + try container.encode(value) + } } extension ManyResourceBody { @@ -33,4 +50,12 @@ extension ManyResourceBody { } values = valueAggregator } + + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + + for value in values { + try container.encode(value) + } + } } diff --git a/Tests/JSONAPITests/Entity/EntityTests.swift b/Tests/JSONAPITests/Entity/EntityTests.swift index d4b4e72..caa01e4 100644 --- a/Tests/JSONAPITests/Entity/EntityTests.swift +++ b/Tests/JSONAPITests/Entity/EntityTests.swift @@ -45,7 +45,7 @@ class EntityTests: XCTestCase { extension EntityTests { func test_EntityNoRelationshipsNoAttributes() { - let entity = decodedTestType(type: TestEntity1.self, + let entity = decoded(type: TestEntity1.self, data: entity_no_relationships_no_attributes) XCTAssert(type(of: entity.relationships) == NoRelatives.self) @@ -58,7 +58,7 @@ extension EntityTests { } func test_EntityNoRelationshipsSomeAttributes() { - let entity = decodedTestType(type: TestEntity5.self, + let entity = decoded(type: TestEntity5.self, data: entity_no_relationships_some_attributes) XCTAssert(type(of: entity.relationships) == NoRelatives.self) @@ -72,7 +72,7 @@ extension EntityTests { } func test_EntitySomeRelationshipsNoAttributes() { - let entity = decodedTestType(type: TestEntity3.self, + let entity = decoded(type: TestEntity3.self, data: entity_some_relationships_no_attributes) XCTAssert(type(of: entity.attributes) == NoAttributes.self) @@ -86,7 +86,7 @@ extension EntityTests { } func test_EntitySomeRelationshipsSomeAttributes() { - let entity = decodedTestType(type: TestEntity4.self, + let entity = decoded(type: TestEntity4.self, data: entity_some_relationships_some_attributes) XCTAssertEqual(entity[\.word], "coolio") @@ -104,7 +104,7 @@ extension EntityTests { extension EntityTests { func test_entityOneOmittedAttribute() { - let entity = decodedTestType(type: TestEntity6.self, + let entity = decoded(type: TestEntity6.self, data: entity_one_omitted_attribute) XCTAssertEqual(entity[\.here], "Hello") @@ -118,7 +118,7 @@ extension EntityTests { } func test_entityOneNullAttribute() { - let entity = decodedTestType(type: TestEntity6.self, + let entity = decoded(type: TestEntity6.self, data: entity_one_null_attribute) XCTAssertEqual(entity[\.here], "Hello") @@ -132,7 +132,7 @@ extension EntityTests { } func test_entityAllAttribute() { - let entity = decodedTestType(type: TestEntity6.self, + let entity = decoded(type: TestEntity6.self, data: entity_all_attributes) XCTAssertEqual(entity[\.here], "Hello") @@ -146,7 +146,7 @@ extension EntityTests { } func test_entityOneNullAndOneOmittedAttribute() { - let entity = decodedTestType(type: TestEntity6.self, + let entity = decoded(type: TestEntity6.self, data: entity_one_null_and_one_missing_attribute) XCTAssertEqual(entity[\.here], "Hello") @@ -165,7 +165,7 @@ extension EntityTests { } func test_NullOptionalNullableAttribute() { - let entity = decodedTestType(type: TestEntity7.self, + let entity = decoded(type: TestEntity7.self, data: entity_null_optional_nullable_attribute) XCTAssertEqual(entity[\.here], "Hello") @@ -178,7 +178,7 @@ extension EntityTests { } func test_NonNullOptionalNullableAttribute() { - let entity = decodedTestType(type: TestEntity7.self, + let entity = decoded(type: TestEntity7.self, data: entity_non_null_optional_nullable_attribute) XCTAssertEqual(entity[\.here], "Hello") @@ -194,7 +194,7 @@ extension EntityTests { // MARK: Attribute Transformation extension EntityTests { func test_IntToString() { - let entity = decodedTestType(type: TestEntity8.self, + let entity = decoded(type: TestEntity8.self, data: entity_int_to_string_attribute) XCTAssertEqual(entity[\.string], "22") @@ -214,7 +214,7 @@ extension EntityTests { // MARK: Relationship omission and nullification extension EntityTests { func test_nullableRelationshipNotNull() { - let entity = decodedTestType(type: TestEntity9.self, + let entity = decoded(type: TestEntity9.self, data: entity_omitted_relationship) XCTAssertEqual((entity ~> \.nullableOne)?.rawValue, "3323") @@ -227,7 +227,7 @@ extension EntityTests { } func test_nullableRelationshipIsNull() { - let entity = decodedTestType(type: TestEntity9.self, + let entity = decoded(type: TestEntity9.self, data: entity_nulled_relationship) XCTAssertNil(entity ~> \.nullableOne) @@ -244,7 +244,7 @@ extension EntityTests { extension EntityTests { func test_RleationshipsOfSameType() { - let entity = decodedTestType(type: TestEntity10.self, + let entity = decoded(type: TestEntity10.self, data: entity_self_ref_relationship) XCTAssertEqual((entity ~> \.selfRef).rawValue, "1") @@ -260,7 +260,7 @@ extension EntityTests { extension EntityTests { func test_UnidentifiedEntity() { - let entity = decodedTestType(type: UnidentifiedTestEntity.self, + let entity = decoded(type: UnidentifiedTestEntity.self, data: entity_unidentified) XCTAssertNil(entity[\.me]) @@ -273,7 +273,7 @@ extension EntityTests { } func test_UnidentifiedEntityWithAttributes() { - let entity = decodedTestType(type: UnidentifiedTestEntity.self, + let entity = decoded(type: UnidentifiedTestEntity.self, data: entity_unidentified_with_attributes) XCTAssertEqual(entity[\.me], "unknown") diff --git a/Tests/JSONAPITests/Includes/IncludeTests.swift b/Tests/JSONAPITests/Includes/IncludeTests.swift index 83fdc20..8bc229c 100644 --- a/Tests/JSONAPITests/Includes/IncludeTests.swift +++ b/Tests/JSONAPITests/Includes/IncludeTests.swift @@ -7,62 +7,37 @@ class IncludedTests: XCTestCase { let decoder = JSONDecoder() func test_zeroIncludes() { - let maybeIncludes = try? decoder.decode(Includes.self, from: two_same_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes.self, + data: two_same_type_includes) XCTAssertEqual(includes.count, 0) } func test_OneInclude() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: one_include) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: one_include) XCTAssertEqual(includes[TestEntity.self].count, 1) } func test_TwoSameIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: two_same_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: two_same_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 2) } func test_TwoDifferentIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: two_different_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: two_different_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) } func test_ThreeDifferentIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: three_different_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: three_different_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) @@ -70,13 +45,8 @@ class IncludedTests: XCTestCase { } func test_FourDifferentIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: four_different_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: four_different_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) @@ -85,13 +55,8 @@ class IncludedTests: XCTestCase { } func test_FiveDifferentIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: five_different_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: five_different_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) @@ -101,13 +66,8 @@ class IncludedTests: XCTestCase { } func test_SixDifferentIncludes() { - let maybeIncludes = try? decoder.decode(Includes>.self, from: six_different_type_includes) - - XCTAssertNotNil(maybeIncludes) - - guard let includes = maybeIncludes else { - return - } + let includes = decoded(type: Includes>.self, + data: six_different_type_includes) XCTAssertEqual(includes[TestEntity.self].count, 1) XCTAssertEqual(includes[TestEntity2.self].count, 1) diff --git a/Tests/JSONAPITests/Relationships/RelationshipTests.swift b/Tests/JSONAPITests/Relationships/RelationshipTests.swift index 4b142f6..3460e51 100644 --- a/Tests/JSONAPITests/Relationships/RelationshipTests.swift +++ b/Tests/JSONAPITests/Relationships/RelationshipTests.swift @@ -31,24 +31,38 @@ class RelationshipTests: XCTestCase { XCTAssertEqual(relationship.ids.count, 4) XCTAssertEqual(relationship.ids, [entity1, entity2, entity3, entity4].map { $0.id }) } +} +// MARK: - Encode/Decode +extension RelationshipTests { func test_ToOneRelationship() { - let relationship = try? JSONDecoder().decode(ToOneRelationship.self, from: to_one_relationship) + let relationship = decoded(type: ToOneRelationship.self, + data: to_one_relationship) - XCTAssertNotNil(relationship) + XCTAssertEqual(relationship.id.rawValue, "2DF03B69-4B0A-467F-B52E-B0C9E44FCECF") + XCTAssertEqual(relationship.ids.count, 1) + } - XCTAssertEqual(relationship?.id.rawValue, "2DF03B69-4B0A-467F-B52E-B0C9E44FCECF") - XCTAssertEqual(relationship?.ids.count, 1) + func test_ToOneRelationship_encode() { + test_DecodeEncodeEquality(type: ToOneRelationship.self, + data: to_one_relationship) } func test_ToManyRelationship() { - let relationship = try? JSONDecoder().decode(ToManyRelationship.self, from: to_many_relationship) + let relationship = decoded(type: ToManyRelationship.self, + data: to_many_relationship) - XCTAssertNotNil(relationship) - - XCTAssertEqual(relationship?.ids.map { $0.rawValue }, ["2DF03B69-4B0A-467F-B52E-B0C9E44FCECF", "90F03B69-4DF1-467F-B52E-B0C9E44FC333", "2DF03B69-4B0A-467F-B52E-B0C9E44FCECF"]) + XCTAssertEqual(relationship.ids.map { $0.rawValue }, ["2DF03B69-4B0A-467F-B52E-B0C9E44FCECF", "90F03B69-4DF1-467F-B52E-B0C9E44FC333", "2DF03B69-4B0A-467F-B52E-B0C9E44FCECF"]) } + func test_ToManyRelationship_encode() { + test_DecodeEncodeEquality(type: ToManyRelationship.self, + data: to_many_relationship) + } +} + +// MARK: - Test types +extension RelationshipTests { enum TestEntityType1: EntityDescription { typealias Attributes = NoAttributes diff --git a/Tests/JSONAPITests/ResourceBody/ResourceBodyTests.swift b/Tests/JSONAPITests/ResourceBody/ResourceBodyTests.swift index a121bfe..c7feb87 100644 --- a/Tests/JSONAPITests/ResourceBody/ResourceBodyTests.swift +++ b/Tests/JSONAPITests/ResourceBody/ResourceBodyTests.swift @@ -11,30 +11,46 @@ import JSONAPI class ResourceBodyTests: XCTestCase { func test_singleResourceBody() { - let body = try? JSONDecoder().decode(SingleResourceBody
.self, from: single_resource_body) + let body = decoded(type: SingleResourceBody
.self, + data: single_resource_body) - XCTAssertNotNil(body) - - guard let b = body else { return } - - XCTAssertEqual(b.value, Article(id: Id(rawValue: "1"), + XCTAssertEqual(body.value, Article(id: Id(rawValue: "1"), attributes: ArticleType.Attributes(title: try! .init(rawValue: "JSON:API paints my bikeshed!")))) } + func test_singleResourceBody_encode() { + test_DecodeEncodeEquality(type: SingleResourceBody
.self, + data: single_resource_body) + } + func test_manyResourceBody() { - let body = try? JSONDecoder().decode(ManyResourceBody
.self, from: many_resource_body) + let body = decoded(type: ManyResourceBody
.self, + data: many_resource_body) - XCTAssertNotNil(body) - - guard let b = body else { return } - - XCTAssertEqual(b.values, [ + XCTAssertEqual(body.values, [ Article(id: .init(rawValue: "1"), attributes: try! .init(title: .init(rawValue: "JSON:API paints my bikeshed!"))), Article(id: .init(rawValue: "2"), attributes: try! .init(title: .init(rawValue: "Sick"))), Article(id: .init(rawValue: "3"), attributes: try! .init(title: .init(rawValue: "Hello World"))) ]) } + func test_manyResourceBody_encode() { + test_DecodeEncodeEquality(type: ManyResourceBody
.self, + data: many_resource_body) + } + + func test_manyResourceBodyEmpty() { + let body = decoded(type: ManyResourceBody
.self, + data: many_resource_body_empty) + + XCTAssertEqual(body.values.count, 0) + } + + func test_manyResourceBodyEmpty_encode() { + test_DecodeEncodeEquality(type: ManyResourceBody
.self, + data: many_resource_body_empty) + } + enum ArticleType: EntityDescription { public static var type: String { return "articles" } diff --git a/Tests/JSONAPITests/ResourceBody/stubs/ResourceBudyStubs.swift b/Tests/JSONAPITests/ResourceBody/stubs/ResourceBudyStubs.swift index 4f92e64..f33b837 100644 --- a/Tests/JSONAPITests/ResourceBody/stubs/ResourceBudyStubs.swift +++ b/Tests/JSONAPITests/ResourceBody/stubs/ResourceBudyStubs.swift @@ -40,3 +40,8 @@ let many_resource_body = """ } ] """.data(using: .utf8)! + +let many_resource_body_empty = """ +[ +] +""".data(using: .utf8)! diff --git a/Tests/JSONAPITests/Test Helpers/EncodeDecode.swift b/Tests/JSONAPITests/Test Helpers/EncodeDecode.swift index 7497696..3a9bbc9 100644 --- a/Tests/JSONAPITests/Test Helpers/EncodeDecode.swift +++ b/Tests/JSONAPITests/Test Helpers/EncodeDecode.swift @@ -8,7 +8,7 @@ import Foundation import XCTest -func decodedTestType(type: T.Type, data: Data) -> T { +func decoded(type: T.Type, data: Data) -> T { return try! JSONDecoder().decode(T.self, from: data) }