// // DocumentTests.swift // JSONAPITests // // Created by Mathew Polzin on 11/12/18. // import XCTest import JSONAPI import Poly class DocumentTests: XCTestCase { func test_genericDocFunc() { func test(_ doc: Doc) { let _ = encoded(value: doc) XCTAssert(Doc.PrimaryResourceBody.self == NoResourceBody.self) XCTAssert(Doc.MetaType.self == NoMetadata.self) XCTAssert(Doc.LinksType.self == NoLinks.self) XCTAssert(Doc.IncludeType.self == NoIncludes.self) XCTAssert(Doc.APIDescription.self == NoAPIDescription.self) XCTAssert(Doc.Error.self == UnknownJSONAPIError.self) } // Document test(JSONAPI.Document< NoResourceBody, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError >( apiDescription: .none, body: .none, includes: .none, meta: .none, links: .none )) // Document.SuccessDocument test(JSONAPI.Document< NoResourceBody, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError >.SuccessDocument( apiDescription: .none, body: .none, includes: .none, meta: .none, links: .none )) // Document.ErrorDocument test(JSONAPI.Document< NoResourceBody, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError >.ErrorDocument( apiDescription: .none, errors: [] )) } func test_singleDocumentNull() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_null) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryResource?.value) XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.links, NoLinks()) XCTAssertEqual(document.apiDescription, .none) // SuccessDocument let document2 = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.SuccessDocument.self, data: single_document_null) XCTAssert(document == document2) XCTAssertFalse(document2.body.isError) XCTAssertNil(document2.body.errors) XCTAssertNotNil(document2.body.primaryResource) XCTAssertEqual(document2.body.meta, NoMetadata()) XCTAssertNil(document2.body.primaryResource?.value) XCTAssertEqual(document2.body.includes?.count, 0) XCTAssertEqual(document2.body.links, NoLinks()) XCTAssertEqual(document2.apiDescription, .none) // ErrorDocument XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.ErrorDocument.self, from: single_document_null)) } func test_singleDocumentNull_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_null) // SuccessDocument test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.SuccessDocument.self, data: single_document_null) } func test_singleDocumentNullWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_null_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryResource?.value) XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.links, NoLinks()) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNullWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_null_with_api_description) } func test_singleDocumentNonOptionalFailsOnNull() { XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_null)) } func test_singleDocumentNullFailsWithNoAPIDescription() { XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, from: single_document_null)) } } // MARK: - Error Document Tests extension DocumentTests { func test_errorDocumentFailsWithNoAPIDescription() { XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: error_document_no_metadata)) // SuccessDocument XCTAssertThrowsError(try JSONDecoder().decode(Document.SuccessDocument.self, from: error_document_no_metadata)) // ErrorDocument XCTAssertThrowsError(try JSONDecoder().decode(Document.ErrorDocument.self, from: error_document_no_metadata)) } func test_unknownErrorDocumentNoMeta() { let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.data) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], .unknown) XCTAssertEqual(errors.meta, NoMetadata()) // SuccessDocument XCTAssertThrowsError(try JSONDecoder().decode(Document.SuccessDocument.self, from: error_document_no_metadata)) // ErrorDocument let document2 = decoded(type: Document.ErrorDocument.self, data: error_document_no_metadata) XCTAssert(document == document2) XCTAssertTrue(document2.body.isError) XCTAssertEqual(document2.body.meta, NoMetadata()) XCTAssertNil(document2.body.data) XCTAssertNil(document2.body.primaryResource) XCTAssertNil(document2.body.includes) guard case let .errors(errors2) = document2.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors2.0.count, 1) XCTAssertEqual(errors2.0, document2.body.errors) XCTAssertEqual(errors2.0[0], .unknown) XCTAssertEqual(errors2.meta, NoMetadata()) } func test_unknownErrorDocumentAddIncludingType() { let author = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document.self, data: error_document_no_metadata) let documentWithIncludes = document.including(Includes>(values: [.init(author)])) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertNil(documentWithIncludes.body.includes) } func test_unknownErrorDocumentAddIncludes() { let author = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document, NoAPIDescription, UnknownJSONAPIError>.self, data: error_document_no_metadata) let documentWithIncludes = document.including(.init(values: [.init(author)])) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertNil(documentWithIncludes.body.includes) } func test_unknownErrorDocumentNoMeta_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_unknownErrorDocumentNoMetaWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_no_metadata_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], .unknown) XCTAssertEqual(errors.meta, NoMetadata()) } func test_unknownErrorDocumentNoMetaWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata_with_api_description) } func test_unknownErrorDocumentMissingMeta() { let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.meta) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], .unknown) XCTAssertNil(errors.meta) } func test_unknownErrorDocumentMissingMeta_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_unknownErrorDocumentMissingMetaWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_no_metadata_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.meta) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], .unknown) XCTAssertNil(errors.meta) } func test_unknownErrorDocumentMissingMetaWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata_with_api_description) } func test_errorDocumentNoMeta() { let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], TestError.basic(.init(code: 1, description: "Boooo!"))) XCTAssertEqual(errors.meta, NoMetadata()) } func test_errorDocumentNoMeta_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_errorDocumentNoMetaWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_no_metadata_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.0[0], TestError.basic(.init(code: 1, description: "Boooo!"))) XCTAssertEqual(errors.meta, NoMetadata()) } func test_errorDocumentNoMetaWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata_with_api_description) } func test_unknownErrorDocumentWithMeta() { let document = decoded(type: Document.self, data: error_document_with_metadata) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) } func test_unknownErrorDocumentWithMeta_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata) } func test_unknownErrorDocumentWithMetaWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_with_metadata_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) } func test_unknownErrorDocumentWithMetaWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata_with_api_description) } func test_unknownErrorDocumentWithMetaWithLinks() { let document = decoded(type: Document.self, data: error_document_with_metadata_with_links) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_unknownErrorDocumentWithMetaWithLinks_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata_with_links) } func test_unknownErrorDocumentWithMetaWithLinksWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_with_metadata_with_links_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(errors.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_unknownErrorDocumentWithMetaWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata_with_links_with_api_description) } func test_unknownErrorDocumentWithLinks() { let document = decoded(type: Document.self, data: error_document_with_links) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_unknownErrorDocumentWithLinks_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_links) } func test_unknownErrorDocumentWithLinksWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_with_links_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_unknownErrorDocumentWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_with_links_with_api_description) } func test_unknownErrorDocumentMissingLinks() { let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertNil(document.body.links) } func test_unknownErrorDocumentMissingLinks_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_unknownErrorDocumentMissingLinksWithAPIDescription() { let document = decoded(type: Document.self, data: error_document_no_metadata_with_api_description) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.primaryResource) XCTAssertNil(document.body.includes) XCTAssertEqual(document.apiDescription.version, "1.0") guard case let .errors(errors) = document.body else { XCTFail("Needed body to be in errors case but it was not.") return } XCTAssertEqual(errors.0.count, 1) XCTAssertEqual(errors.0, document.body.errors) XCTAssertNil(document.body.links) } func test_unknownErrorDocumentMissingLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata_with_api_description) } } // MARK: - Meta Document Tests extension DocumentTests { func test_metaDataDocumentFailsIfMissingAPIDescription() { XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document)) } func test_metaDataDocument() { let document = decoded(type: Document.self, data: metadata_document) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertEqual(document.body.meta?.total, 100) XCTAssertEqual(document.body.meta?.limit, 50) XCTAssertEqual(document.body.meta?.offset, 0) } func test_metaDataDocument_encode() { test_DecodeEncodeEquality(type: Document.self, data: metadata_document) } func test_metaDataDocumentWithAPIDescription() { let document = decoded(type: Document.self, data: metadata_document_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertEqual(document.body.meta?.total, 100) XCTAssertEqual(document.body.meta?.limit, 50) XCTAssertEqual(document.body.meta?.offset, 0) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_metaDataDocumentWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: metadata_document_with_api_description) } func test_metaDataDocumentWithLinks() { let document = decoded(type: Document.self, data: metadata_document_with_links) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertEqual(document.body.meta?.total, 100) XCTAssertEqual(document.body.meta?.limit, 50) XCTAssertEqual(document.body.meta?.offset, 0) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_metaDataDocumentWithLinks_encode() { test_DecodeEncodeEquality(type: Document.self, data: metadata_document_with_links) } func test_metaDataDocumentWithLinksWithAPIDescription() { let document = decoded(type: Document.self, data: metadata_document_with_links_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertEqual(document.body.meta?.total, 100) XCTAssertEqual(document.body.meta?.limit, 50) XCTAssertEqual(document.body.meta?.offset, 0) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_metaDataDocumentWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document.self, data: metadata_document_with_links_with_api_description) } func test_metaDocumentMissingMeta() { XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata)) XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata2)) } } // MARK: Single Document Tests extension DocumentTests { func test_singleDocumentNoIncludesMissingAPIDescription() { XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, from: single_document_no_includes)) } func test_singleDocumentNoIncludes() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.data?.primary, document.body.primaryResource) XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) } func test_singleDocumentNoIncludes_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } func test_singleDocumentNoIncludesAddIncludingType() { let author = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document.self, data: single_document_no_includes) let documentWithIncludes = document.including(Includes>(values: [.init(author)])) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertEqual(document.body.includes, Includes.none) XCTAssertEqual(documentWithIncludes.body.includes?[Author.self], [author]) } func test_singleSuccessDocumentNoIncludesAddIncludingType() { // NOTE distinct from above for being Document.SuccessDocument let author = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document.SuccessDocument.self, data: single_document_no_includes) let documentWithIncludes = document.including(Includes>(values: [.init(author)])) XCTAssert(type(of: documentWithIncludes) == Document, NoAPIDescription, UnknownJSONAPIError>.SuccessDocument.self) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertEqual(document.body.includes, Includes.none) XCTAssertEqual(documentWithIncludes.body.includes?[Author.self], [author]) } func test_singleDocumentNoIncludesWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) } func test_singleDocumentNoIncludesOptionalNotNull() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value?.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) } func test_singleDocumentNoIncludesOptionalNotNull_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } func test_singleDocumentNoIncludesOptionalNotNullWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value?.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesOptionalNotNullWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) } func test_singleDocumentNoIncludesWithMetadata() { let document = decoded(type: Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) } func test_singleDocumentNoIncludesWithMetadata_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata) } func test_singleDocumentNoIncludesWithMetadataWithAPIDescription() { let document = decoded(type: Document, TestPageMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesWithMetadataWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_api_description) } func test_singleDocumentNoIncludesWithLinks() { let document = decoded(type: Document, NoMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_singleDocumentNoIncludesWithLinks_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links) } func test_singleDocumentNoIncludesWithLinksWithAPIDescription() { let document = decoded(type: Document, NoMetadata, TestLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, TestLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links_with_api_description) } func test_singleDocumentNoIncludesWithMetadataWithLinks() { let document = decoded(type: Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) } func test_singleDocumentNoIncludesWithMetadataWithLinks_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links) } func test_singleDocumentNoIncludesWithMetadataWithLinksWithAPIDescription() { let document = decoded(type: Document, TestPageMetadata, TestLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesWithMetadataWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links_with_api_description) } func test_singleDocumentNoIncludesWithMetadataMissingLinks() { XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_no_includes_with_metadata)) } func test_singleDocumentNoIncludesMissingMetadata() { XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_no_includes)) } func test_singleDocumentSomeIncludes() { let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") } func test_singleDocumentSomeIncludes_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes) } func test_singleDocumentSomeIncludesAddIncludes() { let existingAuthor = Author(id: "33", attributes: .none, relationships: .none, meta: .none, links: .none) let newAuthor = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes) let documentWithIncludes = document.including(.init(values: [.init(newAuthor)])) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertEqual(documentWithIncludes.body.includes?[Author.self], [existingAuthor, newAuthor]) } func test_singleSuccessDocumentSomeIncludesAddIncludes() { // NOTE distinct from above for being Document.SuccessDocument let existingAuthor = Author(id: "33", attributes: .none, relationships: .none, meta: .none, links: .none) let newAuthor = Author(id: "1", attributes: .none, relationships: .none, meta: .none, links: .none) let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.SuccessDocument.self, data: single_document_some_includes) let documentWithIncludes = document.including(.init(values: [.init(newAuthor)])) XCTAssertEqual(document.body.errors, documentWithIncludes.body.errors) XCTAssertEqual(document.body.meta, documentWithIncludes.body.meta) XCTAssertEqual(document.body.links, documentWithIncludes.body.links) XCTAssertEqual(documentWithIncludes.body.includes?[Author.self], [existingAuthor, newAuthor]) } func test_singleDocumentSomeIncludesWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentSomeIncludesWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_api_description) } func test_singleDocumentSomeIncludesWithMetadata() { let document = decoded(type: Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) } func test_singleDocumentSomeIncludesWithMetadata_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata) } func test_singleDocumentSomeIncludesWithMetadataWithAPIDescription() { let document = decoded(type: Document, TestPageMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentSomeIncludesWithMetadataWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_api_description) } func test_singleDocumentNoIncludesWithSomeIncludesWithMetadataWithLinks() { let document = decoded(type: Document, TestPageMetadata, TestLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") } func test_singleDocumentNoIncludesWithSomeIncludesMetadataWithLinks_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links) } func test_singleDocumentNoIncludesWithSomeIncludesWithMetadataWithLinksWithAPIDescription() { let document = decoded(type: Document, TestPageMetadata, TestLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.value.id.rawValue, "1") XCTAssertEqual(document.body.meta, TestPageMetadata(total: 70, limit: 40, offset: 10)) XCTAssertEqual(document.body.links?.link.url, "https://website.com") XCTAssertEqual(document.body.links?.link.meta, NoMetadata()) XCTAssertEqual(document.body.links?.link2.url, "https://othersite.com") XCTAssertEqual(document.body.links?.link2.meta, TestLinks.TestMetadata(hello: "world")) XCTAssertEqual(document.body.includes?.count, 1) XCTAssertEqual(document.body.includes?[Author.self].count, 1) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocumentNoIncludesWithSomeIncludesMetadataWithLinksWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links_with_api_description) } } // MARK: Sparse Fieldset Documents extension DocumentTests { func test_sparsePrimaryResource() { let primaryResource = Book(attributes: .init(pageCount: 100), relationships: .init(author: "1234", series: []), meta: .none, links: .none) .sparse(with: [.pageCount]) let document = Document< SingleResourceBody, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError >(apiDescription: .none, body: .init(resourceObject: primaryResource), includes: .none, meta: .none, links: .none) let encoded = try! JSONEncoder().encode(document) let deserialized = try! JSONSerialization.jsonObject(with: encoded, options: []) let deserializedObj = deserialized as? [String: Any] guard let deserializedObj1 = deserializedObj?["data"] as? [String: Any] else { XCTFail("Expected to deserialize one object from document data") return } XCTAssertNotNil(deserializedObj1["id"]) XCTAssertEqual(deserializedObj1["id"] as? String, primaryResource.resourceObject.id.rawValue) XCTAssertNotNil(deserializedObj1["type"]) XCTAssertEqual(deserializedObj1["type"] as? String, Book.jsonType) XCTAssertEqual((deserializedObj1["attributes"] as? [String: Any])?.count, 1) XCTAssertEqual((deserializedObj1["attributes"] as? [String: Any])?["pageCount"] as? Int, 100) XCTAssertNotNil(deserializedObj1["relationships"]) } func test_sparsePrimaryResourceOptionalAndNil() { let document = Document< SingleResourceBody, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError >(apiDescription: .none, body: .init(resourceObject: nil), includes: .none, meta: .none, links: .none) let encoded = try! JSONEncoder().encode(document) let deserialized = try! JSONSerialization.jsonObject(with: encoded, options: []) let deserializedObj = deserialized as? [String: Any] XCTAssertNotNil(deserializedObj?["data"] as? NSNull) } func test_sparseIncludeFullPrimaryResource() { let bookInclude = Book(id: "444", attributes: .init(pageCount: 113), relationships: .init(author: "1234", series: ["443"]), meta: .none, links: .none) .sparse(with: []) let primaryResource = Book(id: "443", attributes: .init(pageCount: 100), relationships: .init(author: "1234", series: ["444"]), meta: .none, links: .none) let document = Document< SingleResourceBody, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError >(apiDescription: .none, body: .init(resourceObject: primaryResource), includes: .init(values: [.init(bookInclude)]), meta: .none, links: .none) let encoded = try! JSONEncoder().encode(document) let deserialized = try! JSONSerialization.jsonObject(with: encoded, options: []) let deserializedObj = deserialized as? [String: Any] guard let deserializedObj1 = deserializedObj?["data"] as? [String: Any] else { XCTFail("Expected to deserialize one object from document data") return } XCTAssertNotNil(deserializedObj1["id"]) XCTAssertEqual(deserializedObj1["id"] as? String, primaryResource.id.rawValue) XCTAssertNotNil(deserializedObj1["type"]) XCTAssertEqual(deserializedObj1["type"] as? String, Book.jsonType) XCTAssertEqual((deserializedObj1["attributes"] as? [String: Any])?.count, 1) XCTAssertEqual((deserializedObj1["attributes"] as? [String: Any])?["pageCount"] as? Int, 100) XCTAssertNotNil(deserializedObj1["relationships"]) guard let deserializedIncludes = deserializedObj?["included"] as? [Any], let deserializedObj2 = deserializedIncludes.first as? [String: Any] else { XCTFail("Expected to deserialize one incude object") return } XCTAssertNotNil(deserializedObj2["id"]) XCTAssertEqual(deserializedObj2["id"] as? String, bookInclude.resourceObject.id.rawValue) XCTAssertNotNil(deserializedObj2["type"]) XCTAssertEqual(deserializedObj2["type"] as? String, Book.jsonType) XCTAssertEqual((deserializedObj2["attributes"] as? [String: Any])?.count, 0) XCTAssertNotNil(deserializedObj2["relationships"]) } func test_sparseIncludeSparsePrimaryResource() { let bookInclude = Book(id: "444", attributes: .init(pageCount: 113), relationships: .init(author: "1234", series: ["443"]), meta: .none, links: .none) .sparse(with: []) let primaryResource = Book(id: "443", attributes: .init(pageCount: 100), relationships: .init(author: "1234", series: ["444"]), meta: .none, links: .none) .sparse(with: []) let document = Document< SingleResourceBody, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError >(apiDescription: .none, body: .init(resourceObject: primaryResource), includes: .init(values: [.init(bookInclude)]), meta: .none, links: .none) let encoded = try! JSONEncoder().encode(document) let deserialized = try! JSONSerialization.jsonObject(with: encoded, options: []) let deserializedObj = deserialized as? [String: Any] guard let deserializedObj1 = deserializedObj?["data"] as? [String: Any] else { XCTFail("Expected to deserialize one object from document data") return } XCTAssertNotNil(deserializedObj1["id"]) XCTAssertEqual(deserializedObj1["id"] as? String, primaryResource.resourceObject.id.rawValue) XCTAssertNotNil(deserializedObj1["type"]) XCTAssertEqual(deserializedObj1["type"] as? String, Book.jsonType) XCTAssertEqual((deserializedObj1["attributes"] as? [String: Any])?.count, 0) XCTAssertNotNil(deserializedObj1["relationships"]) guard let deserializedIncludes = deserializedObj?["included"] as? [Any], let deserializedObj2 = deserializedIncludes.first as? [String: Any] else { XCTFail("Expected to deserialize one incude object") return } XCTAssertNotNil(deserializedObj2["id"]) XCTAssertEqual(deserializedObj2["id"] as? String, bookInclude.resourceObject.id.rawValue) XCTAssertNotNil(deserializedObj2["type"]) XCTAssertEqual(deserializedObj2["type"] as? String, Book.jsonType) XCTAssertEqual((deserializedObj2["attributes"] as? [String: Any])?.count, 0) XCTAssertNotNil(deserializedObj2["relationships"]) } } // MARK: Poly PrimaryResource Tests extension DocumentTests { func test_singleDocument_PolyPrimaryResource() { let article = Article(id: Id(rawValue: "1"), attributes: .none, relationships: .init(author: ToOneRelationship(id: Id(rawValue: "33"))), meta: .none, links: .none) let document = decoded(type: Document>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertEqual(document.body.primaryResource?.value[Article.self], article) XCTAssertNil(document.body.primaryResource?.value[Author.self]) } func test_singleDocument_PolyPrimaryResource_encode() { test_DecodeEncodeEquality(type: Document>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } func test_singleDocument_PolyPrimaryResourceWithAPIDescription() { let article = Article(id: Id(rawValue: "1"), attributes: .none, relationships: .init(author: ToOneRelationship(id: Id(rawValue: "33"))), meta: .none, links: .none) let document = decoded(type: Document>, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) XCTAssertEqual(document.body.primaryResource?.value[Article.self], article) XCTAssertNil(document.body.primaryResource?.value[Author.self]) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_singleDocument_PolyPrimaryResourceWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document>, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_api_description) } } // MARK: - ManyResourceBody Tests extension DocumentTests { func test_manyDocumentNoIncludes() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.values.count, 3) XCTAssertEqual(document.body.primaryResource?.values[0].id.rawValue, "1") XCTAssertEqual(document.body.primaryResource?.values[1].id.rawValue, "2") XCTAssertEqual(document.body.primaryResource?.values[2].id.rawValue, "3") XCTAssertEqual(document.body.includes?.count, 0) } func test_manyDocumentNoIncludes_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes) } func test_manyDocumentNoIncludesWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.values.count, 3) XCTAssertEqual(document.body.primaryResource?.values[0].id.rawValue, "1") XCTAssertEqual(document.body.primaryResource?.values[1].id.rawValue, "2") XCTAssertEqual(document.body.primaryResource?.values[2].id.rawValue, "3") XCTAssertEqual(document.body.includes?.count, 0) XCTAssertEqual(document.apiDescription.version, "1.0") } func test_manyDocumentNoIncludesWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes_with_api_description) } func test_manyDocumentSomeIncludes() { let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.values.count, 3) XCTAssertEqual(document.body.primaryResource?.values[0].id.rawValue, "1") XCTAssertEqual(document.body.primaryResource?.values[1].id.rawValue, "2") XCTAssertEqual(document.body.primaryResource?.values[2].id.rawValue, "3") XCTAssertEqual(document.body.includes?.count, 3) XCTAssertEqual(document.body.includes?[Author.self].count, 3) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.body.includes?[Author.self][1].id.rawValue, "22") XCTAssertEqual(document.body.includes?[Author.self][2].id.rawValue, "11") } func test_manyDocumentSomeIncludes_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes) } func test_manyDocumentSomeIncludesWithAPIDescription() { let document = decoded(type: Document, NoMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes_with_api_description) XCTAssertFalse(document.body.isError) XCTAssertNil(document.body.errors) XCTAssertNotNil(document.body.primaryResource) XCTAssertEqual(document.body.primaryResource?.values.count, 3) XCTAssertEqual(document.body.primaryResource?.values[0].id.rawValue, "1") XCTAssertEqual(document.body.primaryResource?.values[1].id.rawValue, "2") XCTAssertEqual(document.body.primaryResource?.values[2].id.rawValue, "3") XCTAssertEqual(document.body.includes?.count, 3) XCTAssertEqual(document.body.includes?[Author.self].count, 3) XCTAssertEqual(document.body.includes?[Author.self][0].id.rawValue, "33") XCTAssertEqual(document.body.includes?[Author.self][1].id.rawValue, "22") XCTAssertEqual(document.body.includes?[Author.self][2].id.rawValue, "11") XCTAssertEqual(document.apiDescription.version, "1.0") } func test_manyDocumentSomeIncludesWithAPIDescription_encode() { test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, TestAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes_with_api_description) } } // MARK: - Merging extension DocumentTests { public func test_MergeBodyDataBasic(){ let entity1 = Article(attributes: .none, relationships: .init(author: "2"), meta: .none, links: .none) let entity2 = Article(attributes: .none, relationships: .init(author: "3"), meta: .none, links: .none) let bodyData1 = Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.Body.Data(primary: .init(resourceObjects: [entity1]), includes: .none, meta: .none, links: .none) let bodyData2 = Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.Body.Data(primary: .init(resourceObjects: [entity2]), includes: .none, meta: .none, links: .none) let combined = bodyData1.merging(bodyData2) XCTAssertEqual(combined.primary.values, bodyData1.primary.values + bodyData2.primary.values) } public func test_MergeBodyDataWithMergeFunctions() { let article1 = Article(attributes: .none, relationships: .init(author: "2"), meta: .none, links: .none) let author1 = Author(id: "2", attributes: .none, relationships: .none, meta: .none, links: .none) let article2 = Article(attributes: .none, relationships: .init(author: "3"), meta: .none, links: .none) let author2 = Author(id: "3", attributes: .none, relationships: .none, meta: .none, links: .none) let bodyData1 = Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.Body.Data(primary: .init(resourceObjects: [article1]), includes: .init(values: [.init(author1)]), meta: .init(total: 50, limit: 5, offset: 5), links: .none) let bodyData2 = Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.Body.Data(primary: .init(resourceObjects: [article2]), includes: .init(values: [.init(author2)]), meta: .init(total: 60, limit: 5, offset: 5), links: .none) let combined = bodyData1.merging(bodyData2, combiningMetaWith: { (meta1, meta2) in return .init(total: max(meta1.total, meta2.total), limit: max(meta1.limit, meta2.limit), offset: max(meta1.offset, meta2.offset)) }, combiningLinksWith: { _, _ in .none }) XCTAssertEqual(combined.meta.total, bodyData2.meta.total) XCTAssertEqual(combined.meta.limit, bodyData2.meta.limit) XCTAssertEqual(combined.meta.offset, bodyData1.meta.offset) XCTAssertEqual(combined.includes, bodyData1.includes + bodyData2.includes) XCTAssertEqual(combined.primary, bodyData1.primary + bodyData2.primary) } } // MARK: - Test Types extension DocumentTests { enum AuthorType: ResourceObjectDescription { static var jsonType: String { return "authors" } typealias Attributes = NoAttributes typealias Relationships = NoRelationships } typealias Author = BasicEntity enum ArticleType: ResourceObjectDescription { static var jsonType: String { return "articles" } typealias Attributes = NoAttributes struct Relationships: JSONAPI.Relationships { let author: ToOneRelationship } } typealias Article = BasicEntity enum BookType: ResourceObjectDescription { static var jsonType: String { return "books" } struct Attributes: JSONAPI.SparsableAttributes { let pageCount: Attribute enum CodingKeys: String, SparsableCodingKey { case pageCount } } struct Relationships: JSONAPI.Relationships { let author: ToOneRelationship let series: ToManyRelationship } } typealias Book = BasicEntity struct TestPageMetadata: JSONAPI.Meta { let total: Int let limit: Int let offset: Int } struct TestLinks: JSONAPI.Links { let link: Link let link2: Link struct TestMetadata: JSONAPI.Meta { let hello: String } } typealias TestAPIDescription = APIDescription enum TestError: JSONAPIError { case unknownError case basic(BasicError) struct BasicError: Codable, Equatable { let code: Int let description: String } public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() self = (try? .basic(container.decode(BasicError.self))) ?? .unknown } public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .unknownError: try container.encode("unknown") case .basic(let error): try container.encode(error) } } public static var unknown: DocumentTests.TestError { return .unknownError } } }