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/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) + } +} diff --git a/Tests/JSONAPITests/XCTestManifests.swift b/Tests/JSONAPITests/XCTestManifests.swift index 2cb8f39..357ab3a 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), @@ -172,6 +173,23 @@ extension DocumentTests { ] } +extension EmptyObjectDecoderTests { + // DO NOT MODIFY: This is autogenerated, use: + // `swift test --generate-linuxmain` + // to regenerate. + static let __allTests__EmptyObjectDecoderTests = [ + ("testEmptyArray", testEmptyArray), + ("testEmptyStruct", testEmptyStruct), + ("testKeysAndCodingPath", testKeysAndCodingPath), + ("testNonEmptyStruct", testNonEmptyStruct), + ("testWantingNestedKeyed", testWantingNestedKeyed), + ("testWantingNestedUnkeyed", testWantingNestedUnkeyed), + ("testWantingNil", testWantingNil), + ("testWantingSingleValue", testWantingSingleValue), + ("testWantsSuper", testWantsSuper), + ] +} + extension IncludedTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` @@ -393,6 +411,7 @@ extension ResourceObjectTests { ("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 +426,16 @@ extension ResourceObjectTests { ] } +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), @@ -415,6 +444,7 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(ComputedPropertiesTests.__allTests__ComputedPropertiesTests), testCase(CustomAttributesTests.__allTests__CustomAttributesTests), testCase(DocumentTests.__allTests__DocumentTests), + testCase(EmptyObjectDecoderTests.__allTests__EmptyObjectDecoderTests), testCase(IncludedTests.__allTests__IncludedTests), testCase(LinksTests.__allTests__LinksTests), testCase(NonJSONAPIRelatableTests.__allTests__NonJSONAPIRelatableTests), @@ -423,6 +453,7 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(RelationshipTests.__allTests__RelationshipTests), testCase(ResourceBodyTests.__allTests__ResourceBodyTests), testCase(ResourceObjectTests.__allTests__ResourceObjectTests), + testCase(TransformerTests.__allTests__TransformerTests), ] } #endif