diff --git a/Package.swift b/Package.swift index 8ea47ab..8f0d1b8 100644 --- a/Package.swift +++ b/Package.swift @@ -11,19 +11,10 @@ let package = Package( targets: ["JSONAPI"]), .library( name: "JSONAPITesting", - targets: ["JSONAPITesting"]), - .library( - name: "JSONAPIArbitrary", - targets: ["JSONAPIArbitrary"]), - .library( - name: "JSONAPIOpenAPI", - targets: ["JSONAPIOpenAPI"]) + targets: ["JSONAPITesting"]) ], dependencies: [ .package(url: "https://github.com/mattpolzin/Poly.git", from: "1.0.0"), - .package(url: "https://github.com/mattpolzin/Sampleable.git", from: "1.0.0"), - .package(url: "https://github.com/Flight-School/AnyCodable.git", from: "0.1.0"), - .package(url: "https://github.com/typelift/SwiftCheck.git", from: "0.11.0") ], targets: [ .target( @@ -32,24 +23,12 @@ let package = Package( .target( name: "JSONAPITesting", dependencies: ["JSONAPI"]), - .target( - name: "JSONAPIArbitrary", - dependencies: ["JSONAPI", "SwiftCheck"]), - .target( - name: "JSONAPIOpenAPI", - dependencies: ["JSONAPI", "AnyCodable", "JSONAPIArbitrary", "Sampleable"]), .testTarget( name: "JSONAPITests", dependencies: ["JSONAPI", "JSONAPITesting"]), .testTarget( name: "JSONAPITestingTests", - dependencies: ["JSONAPI", "JSONAPITesting"]), - .testTarget( - name: "JSONAPIArbitraryTests", - dependencies: ["JSONAPI", "SwiftCheck", "JSONAPIArbitrary"]), - .testTarget( - name: "JSONAPIOpenAPITests", - dependencies: ["JSONAPI", "JSONAPIOpenAPI"]) + dependencies: ["JSONAPI", "JSONAPITesting"]) ], swiftLanguageVersions: [.v4_2] ) diff --git a/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift b/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift deleted file mode 100644 index 05aea1f..0000000 --- a/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// APIDescription+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/21/19. -// - -import SwiftCheck -import JSONAPI - -extension APIDescription: Arbitrary where Meta: Arbitrary { - public static var arbitrary: Gen> { - return Gen.compose { c in - APIDescription(version: c.generate(), - meta: c.generate()) - } - } -} - -extension NoAPIDescription: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} diff --git a/Sources/JSONAPIArbitrary/Attribute+Arbitrary.swift b/Sources/JSONAPIArbitrary/Attribute+Arbitrary.swift deleted file mode 100644 index 90c6264..0000000 --- a/Sources/JSONAPIArbitrary/Attribute+Arbitrary.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Attribute+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/15/19. -// - -import SwiftCheck -import JSONAPI - -extension Attribute: Arbitrary where RawValue: Arbitrary { - public static var arbitrary: Gen> { - return RawValue.arbitrary.map { .init(value: $0) } - } -} - -// Cannot conform TransformedAttribute to Arbitrary here -// because there is no way to guarantee that an arbitrary -// RawValue will successfully transform or that an -// arbitrary Value will successfully reverse-transform. diff --git a/Sources/JSONAPIArbitrary/Document+Arbitrary.swift b/Sources/JSONAPIArbitrary/Document+Arbitrary.swift deleted file mode 100644 index 9920718..0000000 --- a/Sources/JSONAPIArbitrary/Document+Arbitrary.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// Document+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/21/19. -// - -import SwiftCheck -import JSONAPI - -extension Document.Body.Data: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary { - public static var arbitrary: Gen.Body.Data> { - return Gen.compose { c in - Document.Body.Data(primary: c.generate(), - includes: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension Document.Body: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary { - public static var arbitrary: Gen.Body> { - return Gen.one(of: [ - arbitraryData, - arbitraryErrors - ]) - } -} - -extension Document.Body where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary { - /// Arbitrary Document.Body with data (guaranteed to not - /// be an error body). - public static var arbitraryData: Gen.Body> { - return Document.Body.Data.arbitrary.map(Document.Body.data) - } -} - -extension Document.Body where MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary { - /// Arbitrary Document.Body with errors (guaranteed to not - /// be a data body). - public static var arbitraryErrors: Gen.Body> { - return Gen.compose { c in - Document.Body.errors(c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension Document.Body where Error: Arbitrary { - /// Arbitrary Document.Body with errors but no - /// metadata or links (also guaranteed to not - /// be a data body). - public static var arbitraryErrorsWithoutMetaOrLinks: Gen.Body> { - return Gen.compose { c in - Document.Body.errors(c.generate(), - meta: nil, - links: nil) - } - } -} - -extension Document: Arbitrary where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary, APIDescription: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - arbitraryData, - arbitraryErrors - ]) - } -} - -extension Document where PrimaryResourceBody: Arbitrary, IncludeType: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary, APIDescription: Arbitrary { - /// Arbitrary Document with data (guaranteed to not - /// be an error body). - public static var arbitraryData: Gen> { - return Gen.compose { c in - Document(apiDescription: c.generate(), - body: c.generate(), - includes: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension Document where MetaType: Arbitrary, LinksType: Arbitrary, Error: Arbitrary, APIDescription: Arbitrary { - /// Arbitrary Document with errors (guaranteed to not - /// be a data body). - public static var arbitraryErrors: Gen> { - return Gen.compose { c in - Document(apiDescription: c.generate(), - errors: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension Document where Error: Arbitrary, APIDescription: Arbitrary { - /// Arbitrary Document with errors but no - /// metadata or links (also guaranteed to not - /// be a data body). - public static var arbitraryErrors: Gen> { - return Gen.compose { c in - Document(apiDescription: c.generate(), - errors: c.generate()) - } - } -} diff --git a/Sources/JSONAPIArbitrary/Entity+Arbitrary.swift b/Sources/JSONAPIArbitrary/Entity+Arbitrary.swift deleted file mode 100644 index ac22b5f..0000000 --- a/Sources/JSONAPIArbitrary/Entity+Arbitrary.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// Entity+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/14/19. -// - -import SwiftCheck -import JSONAPI - -extension NoMetadata: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} - -extension NoLinks: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} - -extension NoAttributes: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} - -extension NoRelationships: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} - -// NOTE: Arbitrary conformance for MetaType, LinksType, Description.Attributes, -// and Description.Relationships must all be provided BY YOU for Entity to -// gain Arbitrary conformance (with the exception of NoMetadata, NoLinks, -// NoAttributes, and NoRelationships which all have Arbitrary conformance -// out of the box). -extension Entity: Arbitrary where MetaType: Arbitrary, LinksType: Arbitrary, Description.Attributes: Arbitrary, Description.Relationships: Arbitrary, EntityRawIdType: Arbitrary { - public static var arbitrary: Gen> { - return Gen.compose { c in - Entity(id: c.generate(), - attributes: c.generate(), - relationships: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} diff --git a/Sources/JSONAPIArbitrary/Error+Arbitrary.swift b/Sources/JSONAPIArbitrary/Error+Arbitrary.swift deleted file mode 100644 index 0369c69..0000000 --- a/Sources/JSONAPIArbitrary/Error+Arbitrary.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// Error+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/21/19. -// - -import SwiftCheck -import JSONAPI - -extension UnknownJSONAPIError: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.unknownError) - } -} diff --git a/Sources/JSONAPIArbitrary/Id+Arbitrary.swift b/Sources/JSONAPIArbitrary/Id+Arbitrary.swift deleted file mode 100644 index fbf6c32..0000000 --- a/Sources/JSONAPIArbitrary/Id+Arbitrary.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// Id+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/14/19. -// - -import SwiftCheck -import JSONAPI - -extension Unidentified: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.init()) - } -} - -extension Id: Arbitrary where RawType: Arbitrary { - public static var arbitrary: Gen> { - return RawType.arbitrary.map { Id(rawValue: $0) } - } -} diff --git a/Sources/JSONAPIArbitrary/Includes+Arbitrary.swift b/Sources/JSONAPIArbitrary/Includes+Arbitrary.swift deleted file mode 100644 index e04ed04..0000000 --- a/Sources/JSONAPIArbitrary/Includes+Arbitrary.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// Includes+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/21/19. -// - -import SwiftCheck -import JSONAPI - -extension Includes: Arbitrary where I: Arbitrary { - public static var arbitrary: Gen> { - return I - .arbitrary - .proliferate - .map(Includes.init(values:)) - } -} - -extension NoIncludes: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(NoIncludes()) - } -} - -extension Include1: Arbitrary where A: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - A.arbitrary.map(Include1.init) - ]) - } -} - -extension Include2: Arbitrary where A: Arbitrary, B: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - A.arbitrary.map(Include2.init), - B.arbitrary.map(Include2.init) - ]) - } -} - -extension Include3: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - A.arbitrary.map(Include3.init), - B.arbitrary.map(Include3.init), - C.arbitrary.map(Include3.init) - ]) - } -} - -extension Include4: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - A.arbitrary.map(Include4.init), - B.arbitrary.map(Include4.init), - C.arbitrary.map(Include4.init), - D.arbitrary.map(Include4.init) - ]) - } -} - -extension Include5: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary { - public static var arbitrary: Gen> { - return Gen.one(of: [ - A.arbitrary.map(Include5.init), - B.arbitrary.map(Include5.init), - C.arbitrary.map(Include5.init), - D.arbitrary.map(Include5.init), - E.arbitrary.map(Include5.init) - ]) - } -} - -extension Include6: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary { - public static var arbitrary: Gen> { - // Note broken up because compiler cannot typecheck entire array - // before it times out - let set1: [Gen>] = [ - A.arbitrary.map(Include6.init), - B.arbitrary.map(Include6.init), - C.arbitrary.map(Include6.init) - ] - - let set2: [Gen>] = [ - D.arbitrary.map(Include6.init), - E.arbitrary.map(Include6.init), - F.arbitrary.map(Include6.init) - ] - - return Gen.one(of: set1 + set2) - } -} - -extension Include7: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary { - public static var arbitrary: Gen> { - // Note broken up because compiler cannot typecheck entire array - // before it times out - let set1: [Gen>] = [ - A.arbitrary.map(Include7.init), - B.arbitrary.map(Include7.init), - C.arbitrary.map(Include7.init) - ] - - let set2: [Gen>] = [ - D.arbitrary.map(Include7.init), - E.arbitrary.map(Include7.init), - F.arbitrary.map(Include7.init), - G.arbitrary.map(Include7.init) - ] - - return Gen.one(of: set1 + set2) - } -} - -extension Include8: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary, H: Arbitrary { - public static var arbitrary: Gen> { - // Note broken up because compiler cannot typecheck entire array - // before it times out - let set1: [Gen>] = [ - A.arbitrary.map(Include8.init), - B.arbitrary.map(Include8.init), - C.arbitrary.map(Include8.init) - ] - - let set2: [Gen>] = [ - D.arbitrary.map(Include8.init), - E.arbitrary.map(Include8.init), - F.arbitrary.map(Include8.init) - ] - - let set3: [Gen>] = [ - G.arbitrary.map(Include8.init), - H.arbitrary.map(Include8.init) - ] - - return Gen.one(of: set1 + set2 + set3) - } -} - -extension Include9: Arbitrary where A: Arbitrary, B: Arbitrary, C: Arbitrary, D: Arbitrary, E: Arbitrary, F: Arbitrary, G: Arbitrary, H: Arbitrary, I: Arbitrary { - public static var arbitrary: Gen> { - // Note broken up because compiler cannot typecheck entire array - // before it times out - let set1: [Gen>] = [ - A.arbitrary.map(Include9.init), - B.arbitrary.map(Include9.init), - C.arbitrary.map(Include9.init) - ] - - let set2: [Gen>] = [ - D.arbitrary.map(Include9.init), - E.arbitrary.map(Include9.init), - F.arbitrary.map(Include9.init) - ] - - let set3: [Gen>] = [ - G.arbitrary.map(Include9.init), - H.arbitrary.map(Include9.init), - I.arbitrary.map(Include9.init) - ] - - return Gen.one(of: set1 + set2 + set3) - } -} diff --git a/Sources/JSONAPIArbitrary/Relationship+Arbitrary.swift b/Sources/JSONAPIArbitrary/Relationship+Arbitrary.swift deleted file mode 100644 index a1a8255..0000000 --- a/Sources/JSONAPIArbitrary/Relationship+Arbitrary.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// Relationship+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/15/19. -// - -import SwiftCheck -import JSONAPI - -extension ToOneRelationship: Arbitrary where Identifiable.Identifier: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary { - public static var arbitrary: Gen> { - return Gen.compose { c in - return .init(id: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension ToOneRelationship where MetaType: Arbitrary, LinksType: Arbitrary { - /// Create a generator of arbitrary ToOneRelationships that will all - /// point to one of the given entities. This allows you to create - /// arbitrary relationships that make sense in a broader context where - /// the relationship must actually point to another entity. - public static func arbitrary(givenEntities: [E]) -> Gen> where E.Id == Identifiable.Identifier { - - return Gen.compose { c in - let idGen = Gen.fromElements(of: givenEntities).map { $0.id } - return .init(id: c.generate(using: idGen), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension ToManyRelationship: Arbitrary where Relatable.Identifier: Arbitrary, MetaType: Arbitrary, LinksType: Arbitrary { - public static var arbitrary: Gen> { - return Gen.compose { c in - return .init(ids: c.generate(), - meta: c.generate(), - links: c.generate()) - } - } -} - -extension ToManyRelationship where MetaType: Arbitrary, LinksType: Arbitrary { - /// Create a generator of arbitrary ToManyRelationships that will all - /// point to some number of the given entities. This allows you to create - /// arbitrary relationships that make sense in a broader context where - /// the relationship must actually point to other existing entities. - public static func arbitrary(givenEntities: [E]) -> Gen> where E.Id == Relatable.Identifier { - return Gen.compose { c in - let idsGen = Gen.fromElements(of: givenEntities).map { $0.id }.proliferate - return .init(ids: c.generate(using: idsGen), - meta: c.generate(), - links: c.generate()) - } - } -} diff --git a/Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift b/Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift deleted file mode 100644 index 1c84939..0000000 --- a/Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// ResourceBody+Arbitrary.swift -// JSONAPIArbitrary -// -// Created by Mathew Polzin on 1/21/19. -// - -import SwiftCheck -import JSONAPI - -extension SingleResourceBody: Arbitrary where Entity: Arbitrary { - public static var arbitrary: Gen> { - return Entity.arbitrary.map(SingleResourceBody.init(entity:)) - } -} - -extension ManyResourceBody: Arbitrary where Entity: Arbitrary { - public static var arbitrary: Gen> { - return Entity.arbitrary.proliferate.map(ManyResourceBody.init(entities:)) - } -} - -extension NoResourceBody: Arbitrary { - public static var arbitrary: Gen { - return Gen.pure(.none) - } -} diff --git a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIAttribute+OpenAPI.swift b/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIAttribute+OpenAPI.swift deleted file mode 100644 index b6a9a64..0000000 --- a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIAttribute+OpenAPI.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// JSONAPIAttribute+OpenAPI.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/28/19. -// - -import JSONAPI -import Foundation -import AnyCodable - -private protocol _Optional {} -extension Optional: _Optional {} - -private protocol Wrapper { - associatedtype Wrapped -} -extension Optional: Wrapper {} - -// MARK: Attribute -extension Attribute: OpenAPINodeType where RawValue: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.openAPINode().required { - return try RawValue.openAPINode().requiredNode().nullableNode() - } - return try RawValue.openAPINode() - } -} - -extension Attribute: RawOpenAPINodeType where RawValue: RawRepresentable, RawValue.RawValue: OpenAPINodeType { - static public func rawOpenAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.RawValue.openAPINode().required { - return try RawValue.RawValue.openAPINode().requiredNode().nullableNode() - } - return try RawValue.RawValue.openAPINode() - } -} - -extension Attribute: WrappedRawOpenAPIType where RawValue: RawOpenAPINodeType { - public static func wrappedOpenAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.rawOpenAPINode().required { - return try RawValue.rawOpenAPINode().requiredNode().nullableNode() - } - return try RawValue.rawOpenAPINode() - } -} - -extension Attribute: GenericOpenAPINodeType where RawValue: GenericOpenAPINodeType { - public static func genericOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.genericOpenAPINode(using: encoder).required { - return try RawValue.genericOpenAPINode(using: encoder).requiredNode().nullableNode() - } - return try RawValue.genericOpenAPINode(using: encoder) - } -} - -extension Attribute: DateOpenAPINodeType where RawValue: DateOpenAPINodeType { - public static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if - !(RawValue.dateOpenAPINodeGuess(using: encoder)?.required ?? true) { - return RawValue.dateOpenAPINodeGuess(using: encoder)?.requiredNode().nullableNode() - } - return RawValue.dateOpenAPINodeGuess(using: encoder) - } -} - -extension Attribute: AnyJSONCaseIterable where RawValue: CaseIterable, RawValue: Codable { - public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { - return (try? allCases(from: Array(RawValue.allCases), using: encoder)) ?? [] - } -} - -extension Attribute: AnyWrappedJSONCaseIterable where RawValue: AnyJSONCaseIterable { - public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { - return RawValue.allCases(using: encoder) - } -} - -// MARK: - TransformedAttribute -extension TransformedAttribute: OpenAPINodeType where RawValue: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.openAPINode().required { - return try RawValue.openAPINode().requiredNode().nullableNode() - } - return try RawValue.openAPINode() - } -} - -extension TransformedAttribute: RawOpenAPINodeType where RawValue: RawRepresentable, RawValue.RawValue: OpenAPINodeType { - static public func rawOpenAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.RawValue.openAPINode().required { - return try RawValue.RawValue.openAPINode().requiredNode().nullableNode() - } - return try RawValue.RawValue.openAPINode() - } -} - -extension TransformedAttribute: WrappedRawOpenAPIType where RawValue: RawOpenAPINodeType { - public static func wrappedOpenAPINode() throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.rawOpenAPINode().required { - return try RawValue.rawOpenAPINode().requiredNode().nullableNode() - } - return try RawValue.rawOpenAPINode() - } -} - -extension TransformedAttribute: GenericOpenAPINodeType where RawValue: GenericOpenAPINodeType { - public static func genericOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if try !RawValue.genericOpenAPINode(using: encoder).required { - return try RawValue.genericOpenAPINode(using: encoder).requiredNode().nullableNode() - } - return try RawValue.genericOpenAPINode(using: encoder) - } -} - -extension TransformedAttribute: DateOpenAPINodeType where RawValue: DateOpenAPINodeType { - public static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? { - // If the RawValue is not required, we actually consider it - // nullable. To be not required is for the Attribute itself - // to be optional. - if - !(RawValue.dateOpenAPINodeGuess(using: encoder)?.required ?? true) { - return RawValue.dateOpenAPINodeGuess(using: encoder)?.requiredNode().nullableNode() - } - return RawValue.dateOpenAPINodeGuess(using: encoder) - } -} - -extension TransformedAttribute: AnyJSONCaseIterable where RawValue: CaseIterable, RawValue: Codable { - public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { - return (try? allCases(from: Array(RawValue.allCases), using: encoder)) ?? [] - } -} - -extension TransformedAttribute: AnyWrappedJSONCaseIterable where RawValue: AnyJSONCaseIterable { - public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { - return RawValue.allCases(using: encoder) - } -} diff --git a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIInclude+OpenAPI.swift b/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIInclude+OpenAPI.swift deleted file mode 100644 index c7afff0..0000000 --- a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPIInclude+OpenAPI.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// JSONAPIInclude+OpenAPI.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/22/19. -// - -import JSONAPI -import Foundation - -extension Includes: OpenAPIEncodedNodeType where I: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - let includeNode = try I.openAPINode(using: encoder) - - return .array(.init(format: .generic, - required: true), - .init(items: includeNode, - uniqueItems: true)) - } -} - -extension Include0: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - throw OpenAPITypeError.invalidNode - } -} - -extension Include1: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try A.openAPINode(using: encoder) - } -} - -extension Include2: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder) - ]) - } -} - -extension Include3: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder) - ]) - } -} - -extension Include4: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder) - ]) - } -} - -extension Include5: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType, E: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder), - E.openAPINode(using: encoder) - ]) - } -} - -extension Include6: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType, E: OpenAPIEncodedNodeType, F: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder), - E.openAPINode(using: encoder), - F.openAPINode(using: encoder) - ]) - } -} - -extension Include7: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType, E: OpenAPIEncodedNodeType, F: OpenAPIEncodedNodeType, G: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder), - E.openAPINode(using: encoder), - F.openAPINode(using: encoder), - G.openAPINode(using: encoder) - ]) - } -} - -extension Include8: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType, E: OpenAPIEncodedNodeType, F: OpenAPIEncodedNodeType, G: OpenAPIEncodedNodeType, H: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder), - E.openAPINode(using: encoder), - F.openAPINode(using: encoder), - G.openAPINode(using: encoder), - H.openAPINode(using: encoder) - ]) - } -} - -extension Include9: OpenAPIEncodedNodeType where A: OpenAPIEncodedNodeType, B: OpenAPIEncodedNodeType, C: OpenAPIEncodedNodeType, D: OpenAPIEncodedNodeType, E: OpenAPIEncodedNodeType, F: OpenAPIEncodedNodeType, G: OpenAPIEncodedNodeType, H: OpenAPIEncodedNodeType, I: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try .one(of: [ - A.openAPINode(using: encoder), - B.openAPINode(using: encoder), - C.openAPINode(using: encoder), - D.openAPINode(using: encoder), - E.openAPINode(using: encoder), - F.openAPINode(using: encoder), - G.openAPINode(using: encoder), - H.openAPINode(using: encoder), - I.openAPINode(using: encoder) - ]) - } -} diff --git a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPITypes+OpenAPI.swift b/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPITypes+OpenAPI.swift deleted file mode 100644 index cdd75c0..0000000 --- a/Sources/JSONAPIOpenAPI/JSONAPI/JSONAPITypes+OpenAPI.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// JSONAPIOpenAPITypes.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/13/19. -// - -import JSONAPI -import Foundation -import AnyCodable -import Sampleable - -private protocol _Optional {} -extension Optional: _Optional {} - -private protocol Wrapper { - associatedtype Wrapped -} -extension Optional: Wrapper {} - -extension RelationshipType { - static func relationshipNode(nullable: Bool, jsonType: String) -> JSONNode { - let propertiesDict: [String: JSONNode] = [ - "id": .string(.init(format: .generic, - required: true), - .init()), - "type": .string(.init(format: .generic, - required: true, - allowedValues: [.init(jsonType)]), - .init()) - ] - - return .object(.init(format: .generic, - required: true, - nullable: nullable), - .init(properties: propertiesDict)) - } -} - -extension ToOneRelationship: OpenAPINodeType { - // NOTE: const for json `type` not supported by OpenAPI 3.0 - // Will use "enum" with one possible value for now. - - // TODO: metadata & links - static public func openAPINode() throws -> JSONNode { - let nullable = Identifiable.self is _Optional.Type - return .object(.init(format: .generic, - required: true), - .init(properties: [ - "data": ToOneRelationship.relationshipNode(nullable: nullable, jsonType: Identifiable.jsonType) - ])) - } -} - -extension ToManyRelationship: OpenAPINodeType { - // NOTE: const for json `type` not supported by OpenAPI 3.0 - // Will use "enum" with one possible value for now. - - // TODO: metadata & links - static public func openAPINode() throws -> JSONNode { - return .object(.init(format: .generic, - required: true), - .init(properties: [ - "data": .array(.init(format: .generic, - required: true), - .init(items: ToManyRelationship.relationshipNode(nullable: false, jsonType: Relatable.jsonType))) - ])) - } -} - -extension Entity: OpenAPIEncodedNodeType where Description.Attributes: Sampleable, Description.Relationships: Sampleable { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - // NOTE: const for json `type` not supported by OpenAPI 3.0 - // Will use "enum" with one possible value for now. - - // TODO: metadata, links - - let idNode: JSONNode? = Id.RawType.self != Unidentified.self - ? JSONNode.string(.init(format: .generic, - required: true), - .init()) - : nil - let idProperty = idNode.map { ("id", $0) } - - let typeNode = JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init(Entity.jsonType)]), - .init()) - let typeProperty = ("type", typeNode) - - let attributesNode: JSONNode? = Description.Attributes.self == NoAttributes.self - ? nil - : try Description.Attributes.genericOpenAPINode(using: encoder) - - let attributesProperty = attributesNode.map { ("attributes", $0) } - - let relationshipsNode: JSONNode? = Description.Relationships.self == NoRelationships.self - ? nil - : try Description.Relationships.genericOpenAPINode(using: encoder) - - let relationshipsProperty = relationshipsNode.map { ("relationships", $0) } - - let propertiesDict = Dictionary([ - idProperty, - typeProperty, - attributesProperty, - relationshipsProperty - ].compactMap { $0 }) { _, value in value } - - return .object(.init(format: .generic, - required: true), - .init(properties: propertiesDict)) - } -} - -extension SingleResourceBody: OpenAPIEncodedNodeType where Entity: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return try Entity.openAPINode(using: encoder) - } -} - -extension ManyResourceBody: OpenAPIEncodedNodeType where Entity: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - return .array(.init(format: .generic, - required: true), - .init(items: try Entity.openAPINode(using: encoder))) - } -} - -extension Document: OpenAPIEncodedNodeType where PrimaryResourceBody: OpenAPIEncodedNodeType, IncludeType: OpenAPIEncodedNodeType { - public static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode { - // TODO: metadata, links, api description, errors - // TODO: represent data and errors as the two distinct possible outcomes - - let primaryDataNode: JSONNode? = try PrimaryResourceBody.openAPINode(using: encoder) - - let primaryDataProperty = primaryDataNode.map { ("data", $0) } - - let includeNode: JSONNode? - do { - includeNode = try Includes.openAPINode(using: encoder) - } catch let err as OpenAPITypeError { - guard case .invalidNode = err else { - throw err - } - includeNode = nil - } - - let includeProperty = includeNode.map { ("included", $0) } - - let propertiesDict = Dictionary([ - primaryDataProperty, - includeProperty - ].compactMap { $0 }) { _, value in value } - - return .object(.init(format: .generic, - required: true), - .init(properties: propertiesDict)) - } -} diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/Date+OpenAPI.swift b/Sources/JSONAPIOpenAPI/OpenAPI/Date+OpenAPI.swift deleted file mode 100644 index c153fe4..0000000 --- a/Sources/JSONAPIOpenAPI/OpenAPI/Date+OpenAPI.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Date+OpenAPI.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/24/19. -// - -import Foundation - -extension Date: DateOpenAPINodeType { - public static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? { - - switch encoder.dateEncodingStrategy { - case .deferredToDate, .custom: - // I don't know if we can say anything about this case without - // encoding the Date and looking at it, which is what `primitiveGuess()` - // does. - return nil - - case .secondsSince1970, - .millisecondsSince1970: - return .number(.init(format: .double, - required: true), - .init()) - - case .iso8601: - return .string(.init(format: .dateTime, - required: true), - .init()) - - case .formatted(let formatter): - let hasTime = formatter.timeStyle != .none - let format: JSONTypeFormat.StringFormat = hasTime ? .dateTime : .date - - return .string(.init(format: format, - required: true), - .init()) - } - } -} diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift deleted file mode 100644 index d764e67..0000000 --- a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes+Codable.swift +++ /dev/null @@ -1,454 +0,0 @@ -// -// OpenAPITypes+Codable.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/14/19. -// - -extension JSONNode.Context: Encodable { - - private enum CodingKeys: String, CodingKey { - case type - case format - case allowedValues = "enum" - case nullable - case example -// case constantValue = "const" - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(format.jsonType, forKey: .type) - - if format != Format.unspecified { - try container.encode(format, forKey: .format) - } - - if allowedValues != nil { - try container.encode(allowedValues, forKey: .allowedValues) - } - -// if constantValue != nil { -// try container.encode(constantValue, forKey: .constantValue) -// } - - try container.encode(nullable, forKey: .nullable) - - if example != nil { - try container.encode(example, forKey: .example) - } - } -} - -extension JSONNode.NumericContext: Encodable { - private enum CodingKeys: String, CodingKey { - case multipleOf - case maximum - case exclusiveMaximum - case minimum - case exclusiveMinimum - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if multipleOf != nil { - try container.encode(multipleOf, forKey: .multipleOf) - } - - if maximum != nil { - try container.encode(maximum, forKey: .maximum) - } - - if exclusiveMaximum != nil { - try container.encode(exclusiveMaximum, forKey: .exclusiveMaximum) - } - - if minimum != nil { - try container.encode(minimum, forKey: .minimum) - } - - if exclusiveMinimum != nil { - try container.encode(exclusiveMinimum, forKey: .exclusiveMinimum) - } - } -} - -extension JSONNode.StringContext: Encodable { - private enum CodingKeys: String, CodingKey { - case maxLength - case minLength - case pattern - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if maxLength != nil { - try container.encode(maxLength, forKey: .maxLength) - } - - try container.encode(minLength, forKey: .minLength) - - if pattern != nil { - try container.encode(pattern, forKey: .pattern) - } - } -} - -extension JSONNode.ArrayContext: Encodable { - private enum CodingKeys: String, CodingKey { - case items - case maxItems - case minItems - case uniqueItems - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(items, forKey: .items) - - if maxItems != nil { - try container.encode(maxItems, forKey: .maxItems) - } - - try container.encode(minItems, forKey: .minItems) - - try container.encode(uniqueItems, forKey: .uniqueItems) - } -} - -extension JSONNode.ObjectContext : Encodable { - private enum CodingKeys: String, CodingKey { - case maxProperties - case minProperties - case properties - case additionalProperties - case required - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if maxProperties != nil { - try container.encode(maxProperties, forKey: .maxProperties) - } - - try container.encode(properties, forKey: .properties) - - if additionalProperties != nil { - try container.encode(additionalProperties, forKey: .additionalProperties) - } - - try container.encode(requiredProperties, forKey: .required) - - try container.encode(minProperties, forKey: .minProperties) - } -} - -extension JSONNode: Encodable { - - private enum SubschemaCodingKeys: String, CodingKey { - case allOf - case oneOf - case anyOf - case not - } - - public func encode(to encoder: Encoder) throws { - switch self { - case .boolean(let context): - try context.encode(to: encoder) - - case .object(let contextA as Encodable, let contextB as Encodable), - .array(let contextA as Encodable, let contextB as Encodable), - .number(let contextA as Encodable, let contextB as Encodable), - .integer(let contextA as Encodable, let contextB as Encodable), - .string(let contextA as Encodable, let contextB as Encodable): - try contextA.encode(to: encoder) - try contextB.encode(to: encoder) - - case .all(of: let nodes): - var container = encoder.container(keyedBy: SubschemaCodingKeys.self) - - try container.encode(nodes, forKey: .allOf) - - case .one(of: let nodes): - var container = encoder.container(keyedBy: SubschemaCodingKeys.self) - - try container.encode(nodes, forKey: .oneOf) - - case .any(of: let nodes): - var container = encoder.container(keyedBy: SubschemaCodingKeys.self) - - try container.encode(nodes, forKey: .anyOf) - - case .not(let node): - var container = encoder.container(keyedBy: SubschemaCodingKeys.self) - - try container.encode(node, forKey: .not) - - case .reference(let reference): - var container = encoder.singleValueContainer() - - try container.encode(reference) - } - } -} - -extension JSONReference: Encodable { - private enum CodingKeys: String, CodingKey { - case ref = "$ref" - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - let referenceString: String = { - switch self { - case .file(let reference): - return reference - case .node(let reference): - return "#/\(Root.refName)/\(reference.refName)/\(reference.selector)" - } - }() - - try container.encode(referenceString, forKey: .ref) - } -} - -extension RefDict: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - - try container.encode(dict) - } -} - -extension OpenAPIResponse.Code: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - - let string: String - switch self { - case .`default`: - string = "default" - - case .status(code: let code): - string = String(code) - } - - try container.encode(string) - } -} - -extension OpenAPIRequestBody: Encodable { - private enum CodingKeys: String, CodingKey { - case description - case content - case required - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if description != nil { - try container.encode(description, forKey: .description) - } - - // Hack to work around Dictionary encoding - // itself as an array in this case: - let stringKeyedDict = Dictionary( - content.map { ($0.key.rawValue, $0.value) }, - uniquingKeysWith: { $1 } - ) - try container.encode(stringKeyedDict, forKey: .content) - - try container.encode(required, forKey: .required) - } -} - -extension OpenAPIPathItem.PathProperties.Operation: Encodable { - private enum CodingKeys: String, CodingKey { - case tags - case summary - case description - case externalDocs - case operationId - case parameters - case requestBody - case responses - case callbacks - case deprecated - case security - case servers - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if tags != nil { - try container.encode(tags, forKey: .tags) - } - - if summary != nil { - try container.encode(summary, forKey: .summary) - } - - if description != nil { - try container.encode(description, forKey: .description) - } - - try container.encode(operationId, forKey: .operationId) - - try container.encode(parameters, forKey: .parameters) - - if requestBody != nil { - try container.encode(requestBody, forKey: .requestBody) - } - - // Hack to work around Dictionary encoding - // itself as an array in this case: - let stringKeyedDict = Dictionary( - responses.map { ($0.key.rawValue, $0.value) }, - uniquingKeysWith: { $1 } - ) - try container.encode(stringKeyedDict, forKey: .responses) - - try container.encode(deprecated, forKey: .deprecated) - } -} - -extension OpenAPIPathItem.PathProperties: Encodable { - private enum CodingKeys: String, CodingKey { - case summary - case description - case servers - case parameters - - case get - case put - case post - case delete - case options - case head - case patch - case trace - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - if summary != nil { - try container.encode(summary, forKey: .summary) - } - - if description != nil { - try container.encode(description, forKey: .description) - } - - try container.encode(parameters, forKey: .parameters) - - if get != nil { - try container.encode(get, forKey: .get) - } - - if put != nil { - try container.encode(put, forKey: .put) - } - - if post != nil { - try container.encode(post, forKey: .post) - } - - if delete != nil { - try container.encode(delete, forKey: .delete) - } - - if options != nil { - try container.encode(options, forKey: .options) - } - - if head != nil { - try container.encode(head, forKey: .head) - } - - if patch != nil { - try container.encode(patch, forKey: .patch) - } - - if trace != nil { - try container.encode(trace, forKey: .trace) - } - } -} - -extension OpenAPIResponse: Encodable { - private enum CodingKeys: String, CodingKey { - case description - case headers - case content - case links - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(description, forKey: .description) - - // Hack to work around Dictionary encoding - // itself as an array in this case: - let stringKeyedDict = Dictionary( - content.map { ($0.key.rawValue, $0.value) }, - uniquingKeysWith: { $1 } - ) - try container.encode(stringKeyedDict, forKey: .content) - } -} - -extension OpenAPIPathItem: Encodable { - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - - switch self { - case .reference(let reference): - try container.encode(reference) - - case .operations(let operations): - try container.encode(operations) - } - } -} - -extension OpenAPISchema: Encodable { - private enum CodingKeys: String, CodingKey { - case openAPIVersion = "openapi" - case info - case servers - case paths - case components - case security - case tags - case externalDocs - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(openAPIVersion, forKey: .openAPIVersion) - - try container.encode(info, forKey: .info) - - // Hack to work around Dictionary encoding - // itself as an array in this case: - let stringKeyedDict = Dictionary( - paths.map { ($0.key.rawValue, $0.value) }, - uniquingKeysWith: { $1 } - ) - try container.encode(stringKeyedDict, forKey: .paths) - - try container.encode(components, forKey: .components) - } -} diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift b/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift deleted file mode 100644 index 1485026..0000000 --- a/Sources/JSONAPIOpenAPI/OpenAPI/OpenAPITypes.swift +++ /dev/null @@ -1,962 +0,0 @@ -// -// OpenAPITypes.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/13/19. -// - -import AnyCodable -import Foundation -import Poly -import Sampleable - -// MARK: Node (i.e. schema) Protocols - -/// Anything conforming to `OpenAPINodeType` can provide an -/// OpenAPI schema representing itself. -public protocol OpenAPINodeType { - static func openAPINode() throws -> JSONNode -} - -/// Anything conforming to `OpenAPIEncodedNodeType` can provide an -/// OpenAPI schema representing itself but it may need an Encoder -/// to do its job. -public protocol OpenAPIEncodedNodeType { - static func openAPINode(using encoder: JSONEncoder) throws -> JSONNode -} - -extension OpenAPIEncodedNodeType where Self: Sampleable, Self: Encodable { - public static func openAPINodeWithExample(using encoder: JSONEncoder = JSONEncoder()) throws -> JSONNode { - return try openAPINode(using: encoder).with(example: Self.successSample ?? Self.sample, using: encoder) - } -} - -/// Anything conforming to `RawOpenAPINodeType` can provide an -/// OpenAPI schema representing itself. This second protocol is -/// necessary so that one type can conditionally provide a -/// schema and then (under different conditions) provide a -/// different schema. The "different" conditions have to do -/// with Raw Representability, hence the name of this protocol. -public protocol RawOpenAPINodeType { - static func rawOpenAPINode() throws -> JSONNode -} - -/// Anything conforming to `RawOpenAPINodeType` can provide an -/// OpenAPI schema representing itself. This third protocol is -/// necessary so that one type can conditionally provide a -/// schema and then (under different conditions) provide a -/// different schema. The "different" conditions have to do -/// with Optionality, hence the name of this protocol. -public protocol WrappedRawOpenAPIType { - static func wrappedOpenAPINode() throws -> JSONNode -} - -/// Anything conforming to `RawOpenAPINodeType` can provide an -/// OpenAPI schema representing itself. This third protocol is -/// necessary so that one type can conditionally provide a -/// schema and then (under different conditions) provide a -/// different schema. The "different" conditions have to do -/// with Optionality, hence the name of this protocol. -public protocol DoubleWrappedRawOpenAPIType { - // NOTE: This is definitely a rabbit hole... hopefully I - // will realize I've been missing something obvious - // and dig my way back out at some point... - static func wrappedOpenAPINode() throws -> JSONNode -} - -/// A GenericOpenAPINodeType can take a stab at -/// determining its OpenAPINode because it is sampleable. -public protocol GenericOpenAPINodeType { - static func genericOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode -} - -/// Anything conforming to `DateOpenAPINodeType` is -/// able to attempt to represent itself as a date OpenAPINode -public protocol DateOpenAPINodeType { - static func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? -} - -/// Anything conforming to `AnyJSONCaseIterable` can provide a -/// list of its possible values. -public protocol AnyJSONCaseIterable { - static func allCases(using encoder: JSONEncoder) -> [AnyCodable] -} - -extension AnyJSONCaseIterable { - /// Given an array of Codable values, retrieve an array of AnyCodables. - static func allCases(from input: [T], using encoder: JSONEncoder) throws -> [AnyCodable] { - if let alreadyGoodToGo = input as? [AnyCodable] { - return alreadyGoodToGo - } - - // The following is messy, but it does get us the intended result: - // Given any array of things that can be encoded, we want - // to map to an array of AnyCodable so we can store later. We need to - // muck with JSONSerialization because something like an `enum` may - // very well be encoded as a string, and therefore representable - // by AnyCodable, but AnyCodable wants it to actually BE a String - // upon initialization. - - guard let arrayOfCodables = try JSONSerialization.jsonObject(with: encoder.encode(input), options: []) as? [Any] else { - throw OpenAPICodableError.allCasesArrayNotCodable - } - return arrayOfCodables.map(AnyCodable.init) - } -} - -/// Anything conforming to `AnyJSONCaseIterable` can provide a -/// list of its possible values. This second protocol is -/// necessary so that one type can conditionally provide a -/// list of possible values and then (under different conditions) -/// provide a different list of possible values. -/// The "different" conditions have to do -/// with Optionality, hence the name of this protocol. -public protocol AnyWrappedJSONCaseIterable { - static func allCases(using encoder: JSONEncoder) -> [AnyCodable] -} - -public protocol SwiftTyped { - associatedtype SwiftType: Codable, Equatable -} - -public protocol OpenAPIFormat: SwiftTyped, Codable, Equatable { - static var unspecified: Self { get } - - var jsonType: JSONType { get } -} - -public protocol JSONNodeContext { - var required: Bool { get } -} - -public enum JSONType: String, Codable { - case boolean = "boolean" - case object = "object" - case array = "array" - case number = "number" - case integer = "integer" - case string = "string" -} - -public enum JSONTypeFormat: Equatable { - case boolean(BooleanFormat) - case object(ObjectFormat) - case array(ArrayFormat) - case number(NumberFormat) - case integer(IntegerFormat) - case string(StringFormat) - - public enum BooleanFormat: String, Equatable, OpenAPIFormat { - case generic = "" - - public typealias SwiftType = Bool - - public static var unspecified: BooleanFormat { - return .generic - } - - public var jsonType: JSONType { - return .boolean - } - } - - public enum ObjectFormat: String, Equatable, OpenAPIFormat { - case generic = "" - - public typealias SwiftType = AnyCodable - - public static var unspecified: ObjectFormat { - return .generic - } - - public var jsonType: JSONType { - return .object - } - } - - public enum ArrayFormat: String, Equatable, OpenAPIFormat { - case generic = "" - - public typealias SwiftType = [AnyCodable] - - public static var unspecified: ArrayFormat { - return .generic - } - - public var jsonType: JSONType { - return .array - } - } - - public enum NumberFormat: String, Equatable, OpenAPIFormat { - case generic = "" - case float = "float" - case double = "double" - - public typealias SwiftType = Double - - public static var unspecified: NumberFormat { - return .generic - } - - public var jsonType: JSONType { - return .number - } - } - - public enum IntegerFormat: String, Equatable, OpenAPIFormat { - case generic = "" - case int32 = "int32" - case int64 = "int64" - - public typealias SwiftType = Int - - public static var unspecified: IntegerFormat { - return .generic - } - - public var jsonType: JSONType { - return .integer - } - } - - public enum StringFormat: String, Equatable, OpenAPIFormat { - case generic = "" - case byte = "byte" - case binary = "binary" - case date = "date" - case dateTime = "date-time" - case password = "password" - - public typealias SwiftType = String - - public static var unspecified: StringFormat { - return .generic - } - - public var jsonType: JSONType { - return .string - } - } - - public var jsonType: JSONType { - switch self { - case .boolean: - return .boolean - case .object: - return .object - case .array: - return .array - case .number: - return .number - case .integer: - return .integer - case .string: - return .string - } - } -} - -/// A JSON Node is what OpenAPI calls a -/// "Schema Object" -public enum JSONNode: Equatable { - case boolean(Context) - indirect case object(Context, ObjectContext) - indirect case array(Context, ArrayContext) - case number(Context, NumericContext) - case integer(Context, NumericContext) - case string(Context, StringContext) - indirect case all(of: [JSONNode]) - indirect case one(of: [JSONNode]) - indirect case any(of: [JSONNode]) - indirect case not(JSONNode) - case reference(JSONReference) - - public struct Context: JSONNodeContext, Equatable { - public let format: Format - public let required: Bool - public let nullable: Bool - - // NOTE: "const" is supported by the newest JSON Schema spec but not - // yet by OpenAPI. Instead, will use "enum" with one possible value for now. -// public let constantValue: Format.SwiftType? - - /// The OpenAPI spec calls this "enum" - /// If not specified, it is assumed that any - /// value of the given format is allowed. - /// NOTE: I would like the array of allowed - /// values to have the type `Format.SwiftType` - /// but this is not tractable because I also - /// want to be able to automatically turn any - /// Swift type that will get _encoded as - /// something compatible with_ `Format.SwiftType` - /// into an allowed value. - public let allowedValues: [AnyCodable]? - - // I wanted example to be AnyCodable, but alas that causes - // runtime problems when encoding in a very strange way. - // For now, a String (which is OK by the OpenAPI spec) will - // have to do. - public let example: String? - - public init(format: Format, - required: Bool, - nullable: Bool = false, -// constantValue: Format.SwiftType? = nil, - allowedValues: [AnyCodable]? = nil, - example: (codable: AnyCodable, encoder: JSONEncoder)? = nil) { - self.format = format - self.required = required - self.nullable = nullable -// self.constantValue = constantValue - self.allowedValues = allowedValues - self.example = example - .flatMap { try? $0.encoder.encode($0.codable)} - .flatMap { String(data: $0, encoding: .utf8) } - } - - /// Return the optional version of this Context - public func optionalContext() -> Context { - return .init(format: format, - required: false, - nullable: nullable, -// constantValue: constantValue, - allowedValues: allowedValues) - } - - /// Return the required version of this context - public func requiredContext() -> Context { - return .init(format: format, - required: true, - nullable: nullable, -// constantValue: constantValue, - allowedValues: allowedValues) - } - - /// Return the nullable version of this context - public func nullableContext() -> Context { - return .init(format: format, - required: required, - nullable: true, -// constantValue: constantValue, - allowedValues: allowedValues) - } - - /// Return this context with the given list of possible values - public func with(allowedValues: [AnyCodable]) -> Context { - return .init(format: format, - required: required, - nullable: nullable, -// constantValue: constantValue, - allowedValues: allowedValues) - } - - /// Return this context with the given example - public func with(example: AnyCodable, using encoder: JSONEncoder) -> Context { - return .init(format: format, - required: required, - nullable: nullable, -// constantValue: constantValue, - allowedValues: allowedValues, - example: (codable: example, encoder: encoder)) - } - } - - public struct NumericContext: Equatable { - /// A numeric instance is valid only if division by this keyword's value results in an integer. Defaults to nil. - public let multipleOf: Double? - public let maximum: Double? - public let exclusiveMaximum: Double? - public let minimum: Double? - public let exclusiveMinimum: Double? - - public init(multipleOf: Double? = nil, - maximum: Double? = nil, - exclusiveMaximum: Double? = nil, - minimum: Double? = nil, - exclusiveMinimum: Double? = nil) { - self.multipleOf = multipleOf - self.maximum = maximum - self.exclusiveMaximum = exclusiveMaximum - self.minimum = minimum - self.exclusiveMinimum = exclusiveMinimum - } - } - - public struct StringContext: Equatable { - public let maxLength: Int? - public let minLength: Int - - /// Regular expression - public let pattern: String? - - public init(maxLength: Int? = nil, - minLength: Int = 0, - pattern: String? = nil) { - self.maxLength = maxLength - self.minLength = minLength - self.pattern = pattern - } - } - - public struct ArrayContext: Equatable { - /// A JSON Type Node that describes - /// the type of each element in the array. - public let items: JSONNode - - /// Maximum number of items in array. - public let maxItems: Int? - - /// Minimum number of items in array. - /// Defaults to 0. - public let minItems: Int - - /// Setting to true indicates all - /// elements of the array are expected - /// to be unique. Defaults to false. - public let uniqueItems: Bool - - public init(items: JSONNode, - maxItems: Int? = nil, - minItems: Int = 0, - uniqueItems: Bool = false) { - self.items = items - self.maxItems = maxItems - self.minItems = minItems - self.uniqueItems = uniqueItems - } - } - - public struct ObjectContext: Equatable { - public let maxProperties: Int? - let _minProperties: Int - public let properties: [String: JSONNode] - public let additionalProperties: [String: JSONNode]? - - /* - // NOTE that an object's required properties - // array is determined by looking at its properties' - // required Bool. - */ - public var requiredProperties: [String] { - return Array(properties.filter { (name, node) in - node.required - }.keys) - } - - public var minProperties: Int { - return max(_minProperties, requiredProperties.count) - } - - public init(properties: [String: JSONNode], - additionalProperties: [String: JSONNode]? = nil, - maxProperties: Int? = nil, - minProperties: Int = 0) { - self.properties = properties - self.additionalProperties = additionalProperties - self.maxProperties = maxProperties - self._minProperties = minProperties - } - } - - public var jsonTypeFormat: JSONTypeFormat? { - switch self { - case .boolean(let context): - return .boolean(context.format) - case .object(let context, _): - return .object(context.format) - case .array(let context, _): - return .array(context.format) - case .number(let context, _): - return .number(context.format) - case .integer(let context, _): - return .integer(context.format) - case .string(let context, _): - return .string(context.format) - case .all, .one, .any, .not, .reference: - return nil - } - } - - public var required: Bool { - switch self { - case .boolean(let contextA as JSONNodeContext), - .object(let contextA as JSONNodeContext, _), - .array(let contextA as JSONNodeContext, _), - .number(let contextA as JSONNodeContext, _), - .integer(let contextA as JSONNodeContext, _), - .string(let contextA as JSONNodeContext, _): - return contextA.required - case .all, .one, .any, .not, .reference: - return true - } - } - - /// Return the optional version of this JSONNode - public func optionalNode() -> JSONNode { - switch self { - case .boolean(let context): - return .boolean(context.optionalContext()) - case .object(let contextA, let contextB): - return .object(contextA.optionalContext(), contextB) - case .array(let contextA, let contextB): - return .array(contextA.optionalContext(), contextB) - case .number(let context, let contextB): - return .number(context.optionalContext(), contextB) - case .integer(let context, let contextB): - return .integer(context.optionalContext(), contextB) - case .string(let context, let contextB): - return .string(context.optionalContext(), contextB) - case .all, .one, .any, .not, .reference: - return self - } - } - - /// Return the required version of this JSONNode - public func requiredNode() -> JSONNode { - switch self { - case .boolean(let context): - return .boolean(context.requiredContext()) - case .object(let contextA, let contextB): - return .object(contextA.requiredContext(), contextB) - case .array(let contextA, let contextB): - return .array(contextA.requiredContext(), contextB) - case .number(let context, let contextB): - return .number(context.requiredContext(), contextB) - case .integer(let context, let contextB): - return .integer(context.requiredContext(), contextB) - case .string(let context, let contextB): - return .string(context.requiredContext(), contextB) - case .all, .one, .any, .not, .reference: - return self - } - } - - /// Return the nullable version of this JSONNode - public func nullableNode() -> JSONNode { - switch self { - case .boolean(let context): - return .boolean(context.nullableContext()) - case .object(let contextA, let contextB): - return .object(contextA.nullableContext(), contextB) - case .array(let contextA, let contextB): - return .array(contextA.nullableContext(), contextB) - case .number(let context, let contextB): - return .number(context.nullableContext(), contextB) - case .integer(let context, let contextB): - return .integer(context.nullableContext(), contextB) - case .string(let context, let contextB): - return .string(context.nullableContext(), contextB) - case .all, .one, .any, .not, .reference: - return self - } - } - - public func with(allowedValues: [AnyCodable]) throws -> JSONNode { - - switch self { - case .boolean(let context): - return .boolean(context.with(allowedValues: allowedValues)) - case .object(let contextA, let contextB): - return .object(contextA.with(allowedValues: allowedValues), contextB) - case .array(let contextA, let contextB): - return .array(contextA.with(allowedValues: allowedValues), contextB) - case .number(let context, let contextB): - return .number(context.with(allowedValues: allowedValues), contextB) - case .integer(let context, let contextB): - return .integer(context.with(allowedValues: allowedValues), contextB) - case .string(let context, let contextB): - return .string(context.with(allowedValues: allowedValues), contextB) - case .all, .one, .any, .not, .reference: - return self - } - } - - public func with(example codableExample: T, - using encoder: JSONEncoder) throws -> JSONNode { - let example: AnyCodable - if let goodToGo = codableExample as? AnyCodable { - example = goodToGo - } else { - example = AnyCodable(try JSONSerialization.jsonObject(with: encoder.encode(codableExample), options: [])) - } - - switch self { - case .boolean(let context): - return .boolean(context.with(example: example, using: encoder)) - case .object(let contextA, let contextB): - return .object(contextA.with(example: example, using: encoder), contextB) - case .array(let contextA, let contextB): - return .array(contextA.with(example: example, using: encoder), contextB) - case .number(let context, let contextB): - return .number(context.with(example: example, using: encoder), contextB) - case .integer(let context, let contextB): - return .integer(context.with(example: example, using: encoder), contextB) - case .string(let context, let contextB): - return .string(context.with(example: example, using: encoder), contextB) - case .all, .one, .any, .not, .reference: - return self - } - } -} - -public enum OpenAPICodableError: Swift.Error, Equatable { - case allCasesArrayNotCodable - case exampleNotCodable - case primitiveGuessFailed -} - -public enum OpenAPITypeError: Swift.Error { - case invalidNode - case unknownNodeType(Any.Type) -} - -/// Anything conforming to RefName knows what to call itself -/// in the context of JSON References. -public protocol RefName { - static var refName: String { get } -} - -public protocol ReferenceRoot: RefName {} - -public protocol ReferenceDict: RefName { - associatedtype Value -} - -/// A RefDict knows what to call itself (Name) and where to -/// look for itself (Root) and it stores a dictionary of -/// JSONNodes (some of which might be other references). -public struct RefDict: ReferenceDict, Equatable { - public static var refName: String { return Name.refName } - - public typealias Value = RefType - public typealias Key = String - - let dict: [String: RefType] - - public init(_ dict: [String: RefType]) { - self.dict = dict - } - - public subscript(_ key: String) -> RefType? { - return dict[key] - } -} - -/// A Reference is the combination of -/// a path to a reference dictionary -/// and a selector that the dictionary is keyed off of. -public enum JSONReference: Equatable { - - case node(InternalReference) - case file(FileReference) - - public typealias FileReference = String - - public struct InternalReference: Equatable { - public let path: PartialKeyPath - public let selector: String - - public var refName: String { - // we require RD be a RefName in the initializer - // so it is safe to force cast here. - return (type(of: path).valueType as! RefName.Type).refName - } - - public init(type: KeyPath, - selector: String) where RD.Value == RefType { - self.path = type - self.selector = selector - } - } -} - -/// An OpenAPI Path Item -/// This type describes the endpoints a server has -/// bound to a particular path. -public enum OpenAPIPathItem: Equatable { - case reference(JSONReference) - case operations(PathProperties) - - public struct PathProperties: Equatable { - public let summary: String? - public let description: String? -// public let servers: - public let parameters: ParameterArray - - public let get: Operation? - public let put: Operation? - public let post: Operation? - public let delete: Operation? - public let options: Operation? - public let head: Operation? - public let patch: Operation? - public let trace: Operation? - - public init(summary: String? = nil, - description: String? = nil, - parameters: ParameterArray, - get: Operation? = nil, - put: Operation? = nil, - post: Operation? = nil, - delete: Operation? = nil, - options: Operation? = nil, - head: Operation? = nil, - patch: Operation? = nil, - trace: Operation? = nil) { - self.summary = summary - self.description = description - self.parameters = parameters - - self.get = get - self.put = put - self.post = post - self.delete = delete - self.options = options - self.head = head - self.patch = patch - self.trace = trace - } - - public typealias ParameterArray = [Either>] - - public struct Parameter: Equatable, Encodable { - private enum CodingKeys: String, CodingKey { - case name -// case parameterLocation = "in" - case description - case deprecated - } - - public let name: String -// public let parameterLocation: Location - public let description: String? - public let deprecated: Bool // default is false - // TODO: serialization rules - /* - Serialization Rules - */ - - public init(name: String, - description: String? = nil, - deprecated: Bool = false) { - self.name = name - self.description = description - self.deprecated = deprecated - } - -// public enum Location: Encodable { -// case query(required: Bool?) -// case header(required: Bool?) -// case path -// case cookie(required: Bool?) -// } - } - - public struct Operation: Equatable { - public let tags: [String]? - public let summary: String? - public let description: String? -// public let externalDocs: - public let operationId: String - public let parameters: ParameterArray - public let requestBody: OpenAPIRequestBody? - public let responses: ResponseMap -// public let callbacks: - public let deprecated: Bool // default is false -// public let security: -// public let servers: - - public init(tags: [String]? = nil, - summary: String? = nil, - description: String? = nil, - operationId: String, - parameters: ParameterArray, - requestBody: OpenAPIRequestBody? = nil, - responses: ResponseMap, - deprecated: Bool = false) { - self.tags = tags - self.summary = summary - self.description = description - self.operationId = operationId - self.parameters = parameters - self.requestBody = requestBody - self.responses = responses - self.deprecated = deprecated - } - - public typealias ResponseMap = [OpenAPIResponse.Code: Either>] - - public typealias ContentMap = [OpenAPIContentType: OpenAPIContent] - } - } -} - -public struct OpenAPIRequestBody: Equatable { - public let description: String? - public let content: OpenAPIPathItem.PathProperties.Operation.ContentMap - public let required: Bool - - public init(description: String? = nil, - content: OpenAPIPathItem.PathProperties.Operation.ContentMap, - required: Bool = true) { - self.description = description - self.content = content - self.required = required - } -} - -public struct OpenAPIResponse: Equatable { - public let description: String -// public let headers: - public let content: OpenAPIPathItem.PathProperties.Operation.ContentMap -// public let links: - - public init(description: String, - content: OpenAPIPathItem.PathProperties.Operation.ContentMap) { - self.description = description - self.content = content - } - - public enum Code: RawRepresentable, Equatable, Hashable { - public typealias RawValue = String - - case `default` - case status(code: Int) - - public var rawValue: String { - switch self { - case .default: - return "default" - - case .status(code: let code): - return String(code) - } - } - - public init?(rawValue: String) { - if let val = Int(rawValue) { - self = .status(code: val) - } else { - self = .default - } - } - } -} - -public enum OpenAPIContentType: String, Encodable, Equatable, Hashable { - case json = "application/json" -} - -public struct OpenAPIContent: Encodable, Equatable { - public let schema: Either> - // public let example: - // public let examples: - // public let encoding: - - public init(schema: Either>) { - self.schema = schema - } -} - -/// What the spec calls the "Components Object". -/// This is a place to put reusable components to -/// be referenced from other parts of the spec. -public struct OpenAPIComponents: Equatable, Encodable, ReferenceRoot { - public static var refName: String { return "components" } - - public let schemas: SchemasDict -// public let responses: - public let parameters: ParametersDict -// public let examples: -// public let requestBodies: -// public let headers: -// public let headers: -// public let securitySchemas: -// public let links: -// public let callbacks: - - public init(schemas: [String: SchemasDict.Value], parameters: [String: ParametersDict.Value]) { - self.schemas = SchemasDict(schemas) - self.parameters = ParametersDict(parameters) - } - - public enum SchemasName: RefName { - public static var refName: String { return "schemas" } - } - - public typealias SchemasDict = RefDict - - public enum ParametersName: RefName { - public static var refName: String { return "parameters" } - } - - public typealias ParametersDict = RefDict -} - -/// The root of an OpenAPI 3.0 document. -public struct OpenAPISchema { - public let openAPIVersion: Version - public let info: Info -// public let servers: - public let paths: [PathComponents: OpenAPIPathItem] - public let components: OpenAPIComponents -// public let security: -// public let tags: -// public let externalDocs: - - public init(openAPIVersion: Version = .v3_0_0, - info: Info, - paths: [PathComponents: OpenAPIPathItem], - components: OpenAPIComponents) { - self.openAPIVersion = openAPIVersion - self.info = info - self.paths = paths - self.components = components - } - - public enum Version: String, Encodable { - case v3_0_0 = "3.0.0" - } - - public struct Info: Encodable { - public let title: String - public let description: String? - public let termsOfService: URL? -// public let contact: -// public let license: - public let version: String - - public init(title: String, - description: String? = nil, - termsOfService: URL? = nil, - version: String) { - self.title = title - self.description = description - self.termsOfService = termsOfService - self.version = version - } - } - - public struct PathComponents: RawRepresentable, Encodable, Equatable, Hashable { - public let components: [String] - - public init(_ components: [String]) { - self.components = components - } - - public init?(rawValue: String) { - components = rawValue.split(separator: "/").map(String.init) - } - - public var rawValue: String { - return "/\(components.joined(separator: "/"))" - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - - try container.encode(rawValue) - } - } -} diff --git a/Sources/JSONAPIOpenAPI/OpenAPI/SwiftPrimitiveTypes+OpenAPI.swift b/Sources/JSONAPIOpenAPI/OpenAPI/SwiftPrimitiveTypes+OpenAPI.swift deleted file mode 100644 index 235cb82..0000000 --- a/Sources/JSONAPIOpenAPI/OpenAPI/SwiftPrimitiveTypes+OpenAPI.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// PrimitiveTypes.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 01/13/19. -// - -import AnyCodable -import Foundation - -/** - -Notable omissions in this library's default offerings: - -Base 64 encoded characters: -.string(.byte) - -Any sequence of octets: -.string(.binary) - -RFC3339 full-date: -.string(.date) - -RFC3339 date-time: -.string(.dateTime) - -A hint to UIs to obscure input: -.string(.password) - -Any object: -.object(.generic) - -**/ - -extension Optional: OpenAPINodeType where Wrapped: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return try Wrapped.openAPINode().optionalNode() - } -} - -extension Optional: RawOpenAPINodeType where Wrapped: RawRepresentable, Wrapped.RawValue: OpenAPINodeType { - static public func rawOpenAPINode() throws -> JSONNode { - return try Wrapped.RawValue.openAPINode().optionalNode() - } -} - -extension Optional: WrappedRawOpenAPIType where Wrapped: RawOpenAPINodeType { - static public func wrappedOpenAPINode() throws -> JSONNode { - return try Wrapped.rawOpenAPINode().optionalNode() - } -} - -extension Optional: DoubleWrappedRawOpenAPIType where Wrapped: WrappedRawOpenAPIType { - static public func wrappedOpenAPINode() throws -> JSONNode { - return try Wrapped.wrappedOpenAPINode().optionalNode() - } -} - -extension Optional: AnyJSONCaseIterable where Wrapped: CaseIterable, Wrapped: Codable { - public static func allCases(using encoder: JSONEncoder) -> [AnyCodable] { - return (try? allCases(from: Array(Wrapped.allCases), using: encoder)) ?? [] - } -} - -extension Optional: DateOpenAPINodeType where Wrapped: DateOpenAPINodeType { - static public func dateOpenAPINodeGuess(using encoder: JSONEncoder) -> JSONNode? { - return Wrapped.dateOpenAPINodeGuess(using: encoder)?.optionalNode() - } -} - -extension String: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .string(.init(format: .generic, - required: true), - .init()) - } -} - -extension Bool: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .boolean(.init(format: .generic, - required: true)) - } -} - -extension Array: OpenAPINodeType where Element: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .array(.init(format: .generic, - required: true), - .init(items: try Element.openAPINode())) - } -} - -extension Double: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .number(.init(format: .double, - required: true), - .init()) - } -} - -extension Float: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .number(.init(format: .float, - required: true), - .init()) - } -} - -extension Int: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .integer(.init(format: .generic, - required: true), - .init()) - } -} - -extension Int32: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .integer(.init(format: .int32, - required: true), - .init()) - } -} - -extension Int64: OpenAPINodeType { - static public func openAPINode() throws -> JSONNode { - return .integer(.init(format: .int64, - required: true), - .init()) - } -} diff --git a/Sources/JSONAPIOpenAPI/Optional+ZipWith.swift b/Sources/JSONAPIOpenAPI/Optional+ZipWith.swift deleted file mode 100644 index b04b7c2..0000000 --- a/Sources/JSONAPIOpenAPI/Optional+ZipWith.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Optional+ZipWith.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/19/19. -// - -/// Zip two optionals together with the given operation performed on -/// the unwrapped contents. If either optional is nil, the zip -/// yields nil. -func zip(_ left: X?, _ right: Y?, with fn: (X, Y) -> Z) -> Z? { - return left.flatMap { lft in right.map { rght in fn(lft, rght) }} -} diff --git a/Sources/JSONAPIOpenAPI/Sampleable/Include+Sampleable.swift b/Sources/JSONAPIOpenAPI/Sampleable/Include+Sampleable.swift deleted file mode 100644 index 750958a..0000000 --- a/Sources/JSONAPIOpenAPI/Sampleable/Include+Sampleable.swift +++ /dev/null @@ -1,185 +0,0 @@ -// -// Include+Sampleable.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/23/19. -// - -import JSONAPI -import Sampleable - -extension Includes: Sampleable where I: Sampleable { - public static var sample: Includes { - guard I.self != NoIncludes.self else { - return .none - } - - return .init(values: I.samples) - } -} - -extension NoIncludes: Sampleable { - public static var sample: NoIncludes { - return NoIncludes() - } -} - -extension Include1: Sampleable where A: Sampleable { - public static var sample: Include1 { - return .init(A.sample) - } - - public static var samples: [Include1] { - return A.samples.map(Include1.init) - } -} - -extension Include2: Sampleable where A: Sampleable, B: Sampleable { - public static var sample: Include2 { - let randomChoice = Int.random(in: 0..] { - return A.samples.map(Include2.init) - + B.samples.map(Include2.init) - } -} - -extension Include3: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable { - public static var sample: Include3 { - let randomChoice = Int.random(in: 0..] { - return A.samples.map(Include3.init) - + B.samples.map(Include3.init) - + C.samples.map(Include3.init) - } -} - -extension Include4: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable { - public static var sample: Include4 { - let randomChoice = Int.random(in: 0..] { - return A.samples.map(Include4.init) - + B.samples.map(Include4.init) - + C.samples.map(Include4.init) - + D.samples.map(Include4.init) - } -} - -extension Include5: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable, E: Sampleable { - public static var sample: Include5 { - let randomChoice = Int.random(in: 0..] { - let set1: [Include5] = A.samples.map(Include5.init) - + B.samples.map(Include5.init) - + C.samples.map(Include5.init) - - let set2: [Include5] = D.samples.map(Include5.init) - + E.samples.map(Include5.init) - - return set1 + set2 - } -} - -extension Include6: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable, E: Sampleable, F: Sampleable { - public static var sample: Include6 { - let randomChoice = Int.random(in: 0..] { - let set1: [Include6] = A.samples.map(Include6.init) - + B.samples.map(Include6.init) - + C.samples.map(Include6.init) - - let set2: [Include6] = D.samples.map(Include6.init) - + E.samples.map(Include6.init) - + F.samples.map(Include6.init) - - return set1 + set2 - } -} - -extension Include7: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable, E: Sampleable, F: Sampleable, G: Sampleable { - public static var sample: Include7 { - let randomChoice = Int.random(in: 0..] { - let set1: [Include7] = A.samples.map(Include7.init) - + B.samples.map(Include7.init) - + C.samples.map(Include7.init) - - let set2: [Include7] = D.samples.map(Include7.init) - + E.samples.map(Include7.init) - + F.samples.map(Include7.init) - - let set3: [Include7] = G.samples.map(Include7.init) - - return set1 + set2 + set3 - } -} - -extension Include8: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable, E: Sampleable, F: Sampleable, G: Sampleable, H: Sampleable { - public static var sample: Include8 { - let randomChoice = Int.random(in: 0..] { - let set1: [Include8] = A.samples.map(Include8.init) - + B.samples.map(Include8.init) - + C.samples.map(Include8.init) - - let set2: [Include8] = D.samples.map(Include8.init) - + E.samples.map(Include8.init) - + F.samples.map(Include8.init) - - let set3: [Include8] = G.samples.map(Include8.init) - + H.samples.map(Include8.init) - - return set1 + set2 + set3 - } -} - -extension Include9: Sampleable where A: Sampleable, B: Sampleable, C: Sampleable, D: Sampleable, E: Sampleable, F: Sampleable, G: Sampleable, H: Sampleable, I: Sampleable { - public static var sample: Include9 { - let randomChoice = Int.random(in: 0..] { - let set1: [Include9] = A.samples.map(Include9.init) - + B.samples.map(Include9.init) - + C.samples.map(Include9.init) - - let set2: [Include9] = D.samples.map(Include9.init) - + E.samples.map(Include9.init) - + F.samples.map(Include9.init) - - let set3: [Include9] = G.samples.map(Include9.init) - + H.samples.map(Include9.init) - + I.samples.map(Include9.init) - - return set1 + set2 + set3 - } -} diff --git a/Sources/JSONAPIOpenAPI/Sampleable/JSONAPI+Sampleable.swift b/Sources/JSONAPIOpenAPI/Sampleable/JSONAPI+Sampleable.swift deleted file mode 100644 index d0d24b7..0000000 --- a/Sources/JSONAPIOpenAPI/Sampleable/JSONAPI+Sampleable.swift +++ /dev/null @@ -1,69 +0,0 @@ -// -// JSONAPI+Sampleable.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/24/19. -// - -import JSONAPI -import Sampleable - -extension NoAttributes: Sampleable { - public static var sample: NoAttributes { - return .none - } -} - -extension NoRelationships: Sampleable { - public static var sample: NoRelationships { - return .none - } -} - -extension NoMetadata: Sampleable { - public static var sample: NoMetadata { - return .none - } -} - -extension NoLinks: Sampleable { - public static var sample: NoLinks { - return .none - } -} - -extension NoAPIDescription: Sampleable { - public static var sample: NoAPIDescription { - return .none - } -} - -extension UnknownJSONAPIError: Sampleable { - public static var sample: UnknownJSONAPIError { - return .unknownError - } -} - -extension Unidentified: Sampleable { - public static var sample: Unidentified { - return Unidentified() - } -} - -extension Attribute: Sampleable where RawValue: Sampleable { - public static var sample: Attribute { - return .init(value: RawValue.sample) - } -} - -extension SingleResourceBody: Sampleable where Entity: Sampleable { - public static var sample: SingleResourceBody { - return .init(entity: Entity.sample) - } -} - -extension ManyResourceBody: Sampleable where Entity: Sampleable { - public static var sample: ManyResourceBody { - return .init(entities: Entity.samples) - } -} diff --git a/Sources/JSONAPIOpenAPI/Sampleable/Sampleable+OpenAPI.swift b/Sources/JSONAPIOpenAPI/Sampleable/Sampleable+OpenAPI.swift deleted file mode 100644 index ee69d29..0000000 --- a/Sources/JSONAPIOpenAPI/Sampleable/Sampleable+OpenAPI.swift +++ /dev/null @@ -1,162 +0,0 @@ -// -// Sampleable+OpenAPI.swift -// JSONAPIOpenAPI -// -// Created by Mathew Polzin on 1/24/19. -// - -import Foundation -import AnyCodable -import Sampleable - -public typealias SampleableOpenAPIType = Sampleable & GenericOpenAPINodeType - -extension Sampleable where Self: Encodable { - public static func genericOpenAPINode(using encoder: JSONEncoder) throws -> JSONNode { - - // short circuit for dates - if let dateType = self as? Date.Type, - let node = try dateType.dateOpenAPINodeGuess(using: encoder) ?? primitiveGuess(using: encoder) { - return node - } - - let mirror = Mirror(reflecting: Self.sample) - let properties: [(String, JSONNode)] = try mirror.children.compactMap { child in - - // see if we can enumerate the possible values - let maybeAllCases: [AnyCodable]? = { - switch type(of: child.value) { - case let valType as AnyJSONCaseIterable.Type: - return valType.allCases(using: encoder) - case let valType as AnyWrappedJSONCaseIterable.Type: - return valType.allCases(using: encoder) - default: - return nil - } - }() - - // try to snag an OpenAPI Node - let maybeOpenAPINode: JSONNode? = try { - switch type(of: child.value) { - case let valType as OpenAPINodeType.Type: - return try valType.openAPINode() - - case let valType as RawOpenAPINodeType.Type: - return try valType.rawOpenAPINode() - - case let valType as WrappedRawOpenAPIType.Type: - return try valType.wrappedOpenAPINode() - - case let valType as DoubleWrappedRawOpenAPIType.Type: - return try valType.wrappedOpenAPINode() - - case let valType as GenericOpenAPINodeType.Type: - return try valType.genericOpenAPINode(using: encoder) - - case let valType as DateOpenAPINodeType.Type: - return valType.dateOpenAPINodeGuess(using: encoder) - - default: - throw OpenAPITypeError.unknownNodeType(self) -// return nil - } - }() - - // put it all together - let newNode: JSONNode? - if let allCases = maybeAllCases, - let openAPINode = maybeOpenAPINode { - newNode = try openAPINode.with(allowedValues: allCases) - } else { - newNode = maybeOpenAPINode - } - - return zip(child.label, newNode) { ($0, $1) } - } - - // if there are no properties, let's see if we are dealing - // with a primitive. - if properties.count == 0, - let primitive = try primitiveGuess(using: encoder) { - return primitive - } - - // There should not be any duplication of keys since these are - // property names, but rather than risk runtime exception, we just - // fail to the newer value arbitrarily - let propertiesDict = Dictionary(properties) { _, value2 in value2 } - - return .object(.init(format: .generic, - required: true), - .init(properties: propertiesDict)) - } - - private static func primitiveGuess(using encoder: JSONEncoder) throws -> JSONNode? { - - let data = try encoder.encode(PrimitiveWrapper(primitive: Self.sample)) - let wrappedValue = try JSONSerialization.jsonObject(with: data, options: [.allowFragments]) - - guard let wrapperDict = wrappedValue as? [String: Any], - wrapperDict.contains(where: { $0.key == "primitive" }) else { - throw OpenAPICodableError.primitiveGuessFailed - } - - let value = (wrappedValue as! [String: Any])["primitive"]! - - return try { - switch type(of: value) { - case let valType as OpenAPINodeType.Type: - return try valType.openAPINode() - - case let valType as RawOpenAPINodeType.Type: - return try valType.rawOpenAPINode() - - case let valType as WrappedRawOpenAPIType.Type: - return try valType.wrappedOpenAPINode() - - case let valType as DoubleWrappedRawOpenAPIType.Type: - return try valType.wrappedOpenAPINode() - - case let valType as GenericOpenAPINodeType.Type: - return try valType.genericOpenAPINode(using: encoder) - - case let valType as DateOpenAPINodeType.Type: - return valType.dateOpenAPINodeGuess(using: encoder) - - default: - return nil - } - }() ?? { - switch value { - case is String: - return .string(.init(format: .generic, - required: true), - .init()) - - case is Int: - return .integer(.init(format: .generic, - required: true), - .init()) - - case is Double: - return .number(.init(format: .double, - required: true), - .init()) - - case is Bool: - return .boolean(.init(format: .generic, - required: true)) - - default: - return nil - } - }() - } -} - -// The following wrapper is only needed because JSONEncoder cannot yet encode -// JSON fragments. It is a very unfortunate limitation that requires silly -// workarounds in edge cases like this. -private struct PrimitiveWrapper: Encodable { - let primitive: Wrapped -} diff --git a/Tests/JSONAPIArbitraryTests/PlaceholderTests.swift b/Tests/JSONAPIArbitraryTests/PlaceholderTests.swift deleted file mode 100644 index 61ceaa0..0000000 --- a/Tests/JSONAPIArbitraryTests/PlaceholderTests.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// PlaceholderTests.swift -// JSONAPIArbitraryTests -// -// Created by Mathew Polzin on 12/7/18. -// - -import XCTest -import JSONAPIArbitrary - -class PlaceholderTests: XCTestCase { - func test_Placeholder() { - - } -} diff --git a/Tests/JSONAPIArbitraryTests/XCTestManifests.swift b/Tests/JSONAPIArbitraryTests/XCTestManifests.swift deleted file mode 100644 index acb4b36..0000000 --- a/Tests/JSONAPIArbitraryTests/XCTestManifests.swift +++ /dev/null @@ -1,15 +0,0 @@ -import XCTest - -extension PlaceholderTests { - static let __allTests = [ - ("test_Placeholder", test_Placeholder), - ] -} - -#if !os(macOS) -public func __allTests() -> [XCTestCaseEntry] { - return [ - testCase(PlaceholderTests.__allTests), - ] -} -#endif diff --git a/Tests/JSONAPIOpenAPITests/JSONAPIAttributeOpenAPITests.swift b/Tests/JSONAPIOpenAPITests/JSONAPIAttributeOpenAPITests.swift deleted file mode 100644 index 1cee8f8..0000000 --- a/Tests/JSONAPIOpenAPITests/JSONAPIAttributeOpenAPITests.swift +++ /dev/null @@ -1,893 +0,0 @@ -// -// JSONAPIAttributeOpenAPITests.swift -// JSONAPIOpenAPITests -// -// Created by Mathew Polzin on 1/20/19. -// - -import XCTest -import JSONAPI -import JSONAPIOpenAPI -import SwiftCheck -import AnyCodable - -class JSONAPIAttributeOpenAPITests: XCTestCase { -} - -// MARK: - Boolean -extension JSONAPIAttributeOpenAPITests { - func test_BooleanAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - } - - func test_NullableBooleanAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - } - - func test_OptionalBooleanAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - } - - func test_OptionalNullableBooleanAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - } -} - -// MARK: - Array of Strings -extension JSONAPIAttributeOpenAPITests { - func test_Arrayttribute() { - let node = try! Attribute<[String]>.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_NullableArrayAttribute() { - let node = try! Attribute<[String]?>.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_OptionalArrayAttribute() { - let node = try! Attribute<[String]>?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_OptionalNullableArrayAttribute() { - let node = try! Attribute<[String]?>?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } -} - -// MARK: - Number -extension JSONAPIAttributeOpenAPITests { - func test_NumberAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_NullableNumberAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNumberAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNullableNumberAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_FloatNumberAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertEqual(node.jsonTypeFormat, .number(.float)) - } -} - -// MARK: - Integer -extension JSONAPIAttributeOpenAPITests { - func test_IntegerAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_NullableIntegerAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_OptionalIntegerAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_OptionalNullableIntegerAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } -} - -// MARK: - String -extension JSONAPIAttributeOpenAPITests { - func test_StringAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_NullableStringAttribute() { - let node = try! Attribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalStringAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalNullableStringAttribute() { - let node = try! Attribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } -} - -// MARK: - Enum -// NOTE: `enum` Attributes only gain the automatic support for allowed values -// (`enum` property in the OpenAPI Spec) at the Entity scope. These attributes -// will all still have `allowedValues: nil` at the attribute scope. -extension JSONAPIAttributeOpenAPITests { - func test_EnumAttribute() { - let node = try! Attribute.rawOpenAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_NullableEnumAttribute() { - let node = try! Attribute.wrappedOpenAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalEnumAttribute() { - let node = try! Attribute?.wrappedOpenAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalNullableEnumAttribute() { - let node = try! Attribute?.wrappedOpenAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } -} - -// MARK: - Date -extension JSONAPIAttributeOpenAPITests { - func test_DateStringAttribute() { - // TEST: - // Encoder is set to use - // formatter with date - // with no time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.date)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .date, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateStringAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // formatter with date - // with no time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! Attribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.date)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .date, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateTimeStringAttribute() { - // TEST: - // Encoder is set to use - // formatter with date - // with time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateTimeStringAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // formatter with date - // with time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! Attribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_8601DateStringAttribute() { - if #available(OSX 10.12, *) { - // TEST: - // Encoder is set to use - // iso8601 date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .iso8601 - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - } - - func test_8601DateStringAttribute_Sampleable() { - if #available(OSX 10.12, *) { - // TEST: - // Encoder is set to use - // iso8601 date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .iso8601 - - let node = try! Attribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - } - - func test_DateNumberAttribute() { - // TEST: - // Encoder is set to use - // seconds since 1970 as - // date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_DateNumberAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // seconds since 1970 as - // date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = try! Attribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_DateDeferredAttribute() { - // TEST: - // Encoder is set to use - // Date default encoding - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .deferredToDate - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNil(node) - } - - func test_DateDeferredAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // Date default encoding - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .deferredToDate - - let node = try! Attribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_NullableDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = Attribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = Attribute?.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertFalse(node?.required ?? true) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNullableDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = Attribute?.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertFalse(node?.required ?? true) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } -} - -// MARK: - Test Types -extension JSONAPIAttributeOpenAPITests { - enum EnumAttribute: String, Codable, CaseIterable { - case one - case two - } -} - -extension Date: SampleableOpenAPIType { - public static var sample: Date { - return TimeInterval.arbitrary.map { Date(timeIntervalSince1970: $0) }.generate - } -} diff --git a/Tests/JSONAPIOpenAPITests/JSONAPIDocumentOpenAPITests.swift b/Tests/JSONAPIOpenAPITests/JSONAPIDocumentOpenAPITests.swift deleted file mode 100644 index c2dad8c..0000000 --- a/Tests/JSONAPIOpenAPITests/JSONAPIDocumentOpenAPITests.swift +++ /dev/null @@ -1,377 +0,0 @@ -// -// JSONAPIDocumentOpenAPITests.swift -// JSONAPIOpenAPITests -// -// Created by Mathew Polzin on 1/21/19. -// - -import XCTest -import SwiftCheck -import JSONAPI -import JSONAPIOpenAPI -import Sampleable - -class JSONAPIDocumentOpenAPITests: XCTestCase { - func test_SingleResourceDocument() { - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! SingleEntityDocument.openAPINodeWithExample(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected JSON Document to be an Object Node") - return - } - - XCTAssertNotNil(contextA.example) - XCTAssertFalse(contextA.nullable) - XCTAssertEqual(contextA.format, .generic) - XCTAssertTrue(contextA.required) - - XCTAssertEqual(objectContext1.minProperties, 1) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["data"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["data"])) - - guard case let .object(contextB, objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected Data field of JSON Document to be an Object Node") - return - } - - XCTAssertFalse(contextB.nullable) - XCTAssertEqual(contextB.format, .generic) - XCTAssertTrue(contextB.required) - - XCTAssertEqual(objectContext2.minProperties, 3) - XCTAssertEqual(Set(objectContext2.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext2.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - } - - func test_ManyResourceDocument() { - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! ManyEntityDocument.openAPINodeWithExample(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected JSON Document to be an Object Node") - return - } - - XCTAssertNotNil(contextA.example) - XCTAssertFalse(contextA.nullable) - XCTAssertEqual(contextA.format, .generic) - XCTAssertTrue(contextA.required) - - XCTAssertEqual(objectContext1.minProperties, 1) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["data"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["data"])) - - guard case let .array(contextB, arrayContext)? = objectContext1.properties["data"] else { - XCTFail("Expected Data field of JSON Document to be an Array Node") - return - } - - XCTAssertFalse(contextB.nullable) - XCTAssertEqual(contextB.format, .generic) - XCTAssertTrue(contextB.required) - - XCTAssertFalse(arrayContext.uniqueItems) - XCTAssertEqual(arrayContext.minItems, 0) - - guard case let .object(contextC, objectContext2) = arrayContext.items else { - XCTFail("Expected Items of Array under Data to be an Object Node") - return - } - - XCTAssertFalse(contextC.nullable) - XCTAssertEqual(contextC.format, .generic) - XCTAssertTrue(contextC.required) - - XCTAssertEqual(objectContext2.minProperties, 3) - XCTAssertEqual(Set(objectContext2.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext2.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - } - - func test_DocumentWithOneIncludeType() { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! DocumentWithIncludes.openAPINodeWithExample(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected JSON Document to be an Object Node") - return - } - - XCTAssertNotNil(contextA.example) - XCTAssertFalse(contextA.nullable) - XCTAssertEqual(contextA.format, .generic) - XCTAssertTrue(contextA.required) - - XCTAssertEqual(objectContext1.minProperties, 2) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["data", "included"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["data", "included"])) - - guard case let .object(contextB, objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected Data field of JSON Document to be an Object Node") - return - } - - XCTAssertFalse(contextB.nullable) - XCTAssertEqual(contextB.format, .generic) - XCTAssertTrue(contextB.required) - - XCTAssertEqual(objectContext2.minProperties, 3) - XCTAssertEqual(Set(objectContext2.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext2.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - - guard case let .array(contextC, arrayContext)? = objectContext1.properties["included"] else { - XCTFail("Expected Includes field of JSON Document to be an Array Node") - return - } - - XCTAssertFalse(contextC.nullable) - XCTAssertEqual(contextC.format, .generic) - XCTAssertTrue(contextC.required) - - XCTAssertTrue(arrayContext.uniqueItems) - XCTAssertEqual(arrayContext.minItems, 0) - - guard case let .object(contextD, objectContext3) = arrayContext.items else { - XCTFail("Expected Items of Array under Data to be an Object Node") - return - } - - XCTAssertFalse(contextD.nullable) - XCTAssertEqual(contextD.format, .generic) - XCTAssertTrue(contextD.required) - - XCTAssertEqual(objectContext3.minProperties, 3) - XCTAssertEqual(Set(objectContext3.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext3.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext3.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - } - - func test_DocumentWithTwoIncludeTypes() { - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! DocumentWithMultipleTypesOfIncludes.openAPINodeWithExample(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected JSON Document to be an Object Node") - return - } - - XCTAssertNotNil(contextA.example) - XCTAssertFalse(contextA.nullable) - XCTAssertEqual(contextA.format, .generic) - XCTAssertTrue(contextA.required) - - XCTAssertEqual(objectContext1.minProperties, 2) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["data", "included"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["data", "included"])) - - guard case let .object(contextB, objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected Data field of JSON Document to be an Object Node") - return - } - - XCTAssertFalse(contextB.nullable) - XCTAssertEqual(contextB.format, .generic) - XCTAssertTrue(contextB.required) - - XCTAssertEqual(objectContext2.minProperties, 3) - XCTAssertEqual(Set(objectContext2.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext2.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - - guard case let .array(contextC, arrayContext)? = objectContext1.properties["included"] else { - XCTFail("Expected Includes field of JSON Document to be an Array Node") - return - } - - XCTAssertFalse(contextC.nullable) - XCTAssertEqual(contextC.format, .generic) - XCTAssertTrue(contextC.required) - - XCTAssertTrue(arrayContext.uniqueItems) - XCTAssertEqual(arrayContext.minItems, 0) - - guard case let .one(of: includeNodes) = arrayContext.items else { - XCTFail("Expected Included to contain multiple types of items.") - return - } - - XCTAssertEqual(includeNodes.count, 2) - - guard case let .object(contextD, objectContext3) = includeNodes[0] else { - XCTFail("Expected Items of OneOf under Array under Data to be an Object Node") - return - } - - XCTAssertFalse(contextD.nullable) - XCTAssertEqual(contextD.format, .generic) - XCTAssertTrue(contextD.required) - - XCTAssertEqual(objectContext3.minProperties, 3) - XCTAssertEqual(Set(objectContext3.requiredProperties), Set(["id", "attributes", "type"])) - XCTAssertEqual(Set(objectContext3.properties.keys), Set(["id", "attributes", "type"])) - - XCTAssertEqual(objectContext3.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test")]), - .init())) - - guard case let .object(contextE, objectContext4) = includeNodes[1] else { - XCTFail("Expected Items of OneOf under Array under Data to be an Object Node") - return - } - - XCTAssertFalse(contextE.nullable) - XCTAssertEqual(contextE.format, .generic) - XCTAssertTrue(contextE.required) - - XCTAssertEqual(objectContext4.minProperties, 2) - XCTAssertEqual(Set(objectContext4.requiredProperties), Set(["id", "type"])) - XCTAssertEqual(Set(objectContext4.properties.keys), Set(["id", "type"])) - - XCTAssertEqual(objectContext4.properties["type"], - JSONNode.string(.init(format: .generic, - required: true, - allowedValues: [.init("test2")]), - .init())) - } -} - -// MARK: - Test Types -extension JSONAPIDocumentOpenAPITests { - enum TestEntityDescription: EntityDescription { - static var jsonType: String { return "test" } - - struct Attributes: JSONAPI.Attributes, Sampleable { - let name: Attribute - let date: Attribute - - static var sample: Attributes { - return .init(name: "hello world", - date: .init(value: Date())) - } - } - - typealias Relationships = NoRelationships - } - - typealias TestEntity = BasicEntity - - typealias SingleEntityDocument = Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError> - - typealias ManyEntityDocument = Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError> - - typealias DocumentWithIncludes = Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError> - - enum TestEntityDescription2: EntityDescription { - static var jsonType: String { return "test2" } - - typealias Attributes = NoAttributes - - typealias Relationships = NoRelationships - } - - typealias TestEntity2 = BasicEntity - - typealias DocumentWithMultipleTypesOfIncludes = Document, NoMetadata, NoLinks, Include2, NoAPIDescription, UnknownJSONAPIError> -} - -extension Id: Sampleable where RawType == String { - public static var sample: Id { - return .init(rawValue: String.arbitrary.generate) - } -} - -extension JSONAPI.Entity: Sampleable where Description.Attributes: Sampleable, Description.Relationships: Sampleable, MetaType: Sampleable, LinksType: Sampleable, EntityRawIdType == String { - public static var sample: JSONAPI.Entity { - return JSONAPI.Entity(id: .sample, - attributes: .sample, - relationships: .sample, - meta: .sample, - links: .sample) - } -} - -extension Document: Sampleable where PrimaryResourceBody: Sampleable, MetaType: Sampleable, LinksType: Sampleable, IncludeType: Sampleable, APIDescription: Sampleable, Error: Sampleable { - public static var sample: Document { - return Document(apiDescription: .sample, - body: .sample, - includes: .sample, - meta: .sample, - links: .sample) - } -} diff --git a/Tests/JSONAPIOpenAPITests/JSONAPIEntityOpenAPITests.swift b/Tests/JSONAPIOpenAPITests/JSONAPIEntityOpenAPITests.swift deleted file mode 100644 index dde8cbb..0000000 --- a/Tests/JSONAPIOpenAPITests/JSONAPIEntityOpenAPITests.swift +++ /dev/null @@ -1,365 +0,0 @@ -// -// JSONAPIEntityOpenAPITests.swift -// JSONAPIOpenAPITests -// -// Created by Mathew Polzin on 1/15/19. -// - -import XCTest -import JSONAPI -import JSONAPIOpenAPI -import AnyCodable -import Sampleable - -class JSONAPIEntityOpenAPITests: XCTestCase { - func test_EmptyEntity() { - let node = try! TestType1.openAPINode(using: JSONEncoder()) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected Object node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(objectContext1.minProperties, 2) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["id", "type"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["id", "type"])) - XCTAssertEqual(objectContext1.properties["id"], .string(.init(format: .generic, - required: true), - .init())) - XCTAssertEqual(objectContext1.properties["type"], .string(.init(format: .generic, - required: true, - allowedValues: [.init(TestType1.jsonType)]), - .init())) - } - - func test_UnidentifiedEmptyEntity() { - let node = try! UnidentifiedTestType1.openAPINode(using: JSONEncoder()) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected Object node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(objectContext1.minProperties, 1) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["type"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["type"])) - XCTAssertEqual(objectContext1.properties["type"], .string(.init(format: .generic, - required: true, - allowedValues: [.init(TestType1.jsonType)]), - .init())) - } - - func test_AttributesEntity() { - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! TestType2.openAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected Object node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(objectContext1.minProperties, 3) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["id", "type", "attributes"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["id", "type", "attributes"])) - - XCTAssertEqual(objectContext1.properties["id"], .string(.init(format: .generic, - required: true), - .init())) - XCTAssertEqual(objectContext1.properties["type"], .string(.init(format: .generic, - required: true, - allowedValues: [.init(TestType2.jsonType)]), - .init())) - - let attributesNode = objectContext1.properties["attributes"] - - XCTAssertNotNil(attributesNode) - XCTAssertTrue(attributesNode?.required ?? false) - XCTAssertEqual(attributesNode?.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextB, attributesContext)? = attributesNode else { - XCTFail("Expected Object node for attributes") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(attributesContext.minProperties, 4) - XCTAssertEqual(Set(attributesContext.requiredProperties), Set(["stringProperty", "enumProperty", "dateProperty", "nullableProperty"])) - XCTAssertEqual(Set(attributesContext.properties.keys), Set(["stringProperty", "enumProperty", "dateProperty", "optionalProperty", "nullableProperty", "nullableOptionalProperty"])) - - XCTAssertEqual(attributesContext.properties["stringProperty"], - .string(.init(format: .generic, - required: true), - .init())) - - XCTAssertEqual(attributesContext.properties["enumProperty"], - .string(.init(format: .generic, - required: true, - nullable: false, - allowedValues: ["one", "two"].map(AnyCodable.init)), - .init())) - - XCTAssertEqual(attributesContext.properties["dateProperty"], - .string(.init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil), - .init())) - - XCTAssertEqual(attributesContext.properties["optionalProperty"], - .string(.init(format: .generic, - required: false, - nullable: false, - allowedValues: nil), - .init())) - - XCTAssertEqual(attributesContext.properties["nullableProperty"], - .string(.init(format: .generic, - required: true, - nullable: true, - allowedValues: nil), - .init())) - - XCTAssertEqual(attributesContext.properties["nullableOptionalProperty"], - .string(.init(format: .generic, - required: false, - nullable: true, - allowedValues: nil), - .init())) - } - - func test_RelationshipsEntity() { - let node = try! TestType3.openAPINode(using: JSONEncoder()) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextA, objectContext1) = node else { - XCTFail("Expected Object node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(objectContext1.minProperties, 3) - XCTAssertEqual(Set(objectContext1.requiredProperties), Set(["id", "type", "relationships"])) - XCTAssertEqual(Set(objectContext1.properties.keys), Set(["id", "type", "relationships"])) - - XCTAssertEqual(objectContext1.properties["id"], .string(.init(format: .generic, - required: true), - .init())) - XCTAssertEqual(objectContext1.properties["type"], .string(.init(format: .generic, - required: true, - allowedValues: [.init(TestType3.jsonType)]), - .init())) - - let relationshipsNode = objectContext1.properties["relationships"] - - XCTAssertNotNil(relationshipsNode) - XCTAssertTrue(relationshipsNode?.required ?? false) - XCTAssertEqual(relationshipsNode?.jsonTypeFormat, .object(.generic)) - - guard case let .object(contextB, relationshipsContext)? = relationshipsNode else { - XCTFail("Expected Object node for relationships") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(relationshipsContext.minProperties, 3) - XCTAssertEqual(Set(relationshipsContext.requiredProperties), Set(["toOne", "nullableToOne", "toMany"])) - XCTAssertEqual(Set(relationshipsContext.properties.keys), Set(["toOne", "optionalTooOne", "nullableToOne", "nullableOptionalToOne", "toMany", "optionalToMany"])) - - let pointerDataContext = JSONNode.ObjectContext(properties: ["id": .string(.init(format: .generic, - required: true), - .init()), - "type": .string(.init(format: .generic, - required: true, - allowedValues: [.init(TestType1.jsonType)]), - .init())]) - - let pointerContext = JSONNode.ObjectContext(properties: ["data": .object(.init(format: .generic, - required: true), - pointerDataContext)]) - - let nullablePointerContext = JSONNode.ObjectContext(properties: ["data": .object(.init(format: .generic, - required: true, - nullable: true), - pointerDataContext)]) - - let manyPointerContext = JSONNode.ObjectContext(properties: ["data": .array(.init(format: .generic, - required: true), - .init(items: .object(.init(format: .generic, - required: true), - pointerDataContext)))]) - - XCTAssertEqual(relationshipsContext.properties["toOne"], - .object(.init(format: .generic, - required: true), - pointerContext)) - - XCTAssertEqual(relationshipsContext.properties["optionalTooOne"], - .object(.init(format: .generic, - required: false, - nullable: false, - allowedValues: nil), - pointerContext)) - - XCTAssertEqual(relationshipsContext.properties["nullableToOne"], - .object(.init(format: .generic, - required: true, - nullable: false, - allowedValues: nil), - nullablePointerContext)) - - XCTAssertEqual(relationshipsContext.properties["nullableOptionalToOne"], - .object(.init(format: .generic, - required: false, - nullable: false, - allowedValues: nil), - nullablePointerContext)) - - XCTAssertEqual(relationshipsContext.properties["toMany"], - .object(.init(format: .generic, - required: true), - manyPointerContext)) - - XCTAssertEqual(relationshipsContext.properties["optionalToMany"], - .object(.init(format: .generic, - required: false, - nullable: false, - allowedValues: nil), - manyPointerContext)) - } - - func test_AttributesAndRelationshipsEntity() { - // TODO: write test - - /* - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - let string = String(data: try! encoder.encode(node), encoding: .utf8)! - print(string) - - */ - } -} - -// MARK: Test Types -extension JSONAPIEntityOpenAPITests { - enum TestType1Description: EntityDescription { - public static var jsonType: String { return "test1" } - - public typealias Attributes = NoAttributes - - public typealias Relationships = NoRelationships - } - - typealias TestType1 = BasicEntity - typealias UnidentifiedTestType1 = JSONAPI.Entity - - enum TestType2Description: EntityDescription { - public static var jsonType: String { return "test2" } - - public enum EnumType: String, CaseIterable, Codable, Equatable { - case one - case two - } - - public struct Attributes: JSONAPI.Attributes, Sampleable { - let stringProperty: Attribute - let enumProperty: Attribute - let dateProperty: Attribute - let optionalProperty: Attribute? - let nullableProperty: Attribute - let nullableOptionalProperty: Attribute? - var computedProperty: Attribute { - return enumProperty - } - - public static var sample: Attributes { - return Attributes(stringProperty: .init(value: "hello"), - enumProperty: .init(value: .one), - dateProperty: .init(value: Date()), - optionalProperty: nil, - nullableProperty: .init(value: nil), - nullableOptionalProperty: nil) - } - } - - public typealias Relationships = NoRelationships - } - - typealias TestType2 = BasicEntity - - enum TestType3Description: EntityDescription { - public static var jsonType: String { return "test3" } - - public typealias Attributes = NoAttributes - - public struct Relationships: JSONAPI.Relationships, Sampleable { - public let toOne: ToOneRelationship - public let optionalTooOne: ToOneRelationship? - public let nullableToOne: ToOneRelationship - public let nullableOptionalToOne: ToOneRelationship? - - public let toMany: ToManyRelationship - public let optionalToMany: ToManyRelationship? - // Note there is no such thing as nullable to-many relationships (Just use - // an empty array) - - public static var sample: Relationships { - return Relationships(toOne: .init(id: .init(rawValue: "1")), - optionalTooOne: nil, - nullableToOne: .init(id: nil), - nullableOptionalToOne: nil, - toMany: .init(ids: [.init(rawValue: "1")]), - optionalToMany: nil) - } - } - } - - typealias TestType3 = BasicEntity -} diff --git a/Tests/JSONAPIOpenAPITests/JSONAPIRelationshipsOpenAPITests.swift b/Tests/JSONAPIOpenAPITests/JSONAPIRelationshipsOpenAPITests.swift deleted file mode 100644 index ca51f8d..0000000 --- a/Tests/JSONAPIOpenAPITests/JSONAPIRelationshipsOpenAPITests.swift +++ /dev/null @@ -1,257 +0,0 @@ -// -// JSONAPIRelationshipsOpenAPITests.swift -// JSONAPI -// -// Created by Mathew Polzin on 1/14/19. -// - -import Foundation -import XCTest -import JSONAPI -import JSONAPITesting -import JSONAPIOpenAPI - -class JSONAPIRelationshipsOpenAPITests: XCTestCase { - - func test_ToOne() { - let node = try! ToOneRelationship.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .object(let contextB, let objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected object node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } - - func test_OptionalToOne() { - let node = try! ToOneRelationship?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .object(let contextB, let objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected object node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } - - func test_NullableToOne() { - let node = try! ToOneRelationship.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .object(let contextB, let objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected object node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } - - func test_OptionalNullableToOne() { - let node = try! ToOneRelationship?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .object(let contextB, let objectContext2)? = objectContext1.properties["data"] else { - XCTFail("Expected object node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } - - func test_ToMany() { - let node = try! ToManyRelationship.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .array(let contextB, let arrayContext)? = objectContext1.properties["data"] else { - XCTFail("Expected array node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - guard case .object(let contextC, let objectContext2) = arrayContext.items else { - XCTFail("Expected object node within items") - return - } - - XCTAssertEqual(contextC, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } - - func test_OptionalToMany() { - let node = try! ToManyRelationship?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .object(.generic)) - - guard case .object(let contextA, let objectContext1) = node else { - XCTFail("Expected object Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext1.additionalProperties) - XCTAssertEqual(Array(objectContext1.properties.keys), ["data"]) - - guard case .array(let contextB, let arrayContext)? = objectContext1.properties["data"] else { - XCTFail("Expected array node within properties") - return - } - - XCTAssertEqual(contextB, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - guard case .object(let contextC, let objectContext2) = arrayContext.items else { - XCTFail("Expected object node within items") - return - } - - XCTAssertEqual(contextC, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertNil(objectContext2.additionalProperties) - XCTAssertEqual(Set(objectContext2.properties.keys), Set(["id", "type"])) - } -} - -// MARK: Test Types -extension JSONAPIRelationshipsOpenAPITests { - enum TestEntityType1: EntityDescription { - static var jsonType: String { return "test_entities"} - - typealias Attributes = NoAttributes - typealias Relationships = NoRelationships - } - - typealias TestEntity1 = BasicEntity - - enum TestEntityType2: EntityDescription { - static var jsonType: String { return "second_test_entities"} - - typealias Attributes = NoAttributes - - struct Relationships: JSONAPI.Relationships { - let other: ToOneRelationship - } - } - - typealias TestEntity2 = BasicEntity -} diff --git a/Tests/JSONAPIOpenAPITests/JSONAPITransformedAttributeOpenAPITests.swift b/Tests/JSONAPIOpenAPITests/JSONAPITransformedAttributeOpenAPITests.swift deleted file mode 100644 index b92890f..0000000 --- a/Tests/JSONAPIOpenAPITests/JSONAPITransformedAttributeOpenAPITests.swift +++ /dev/null @@ -1,889 +0,0 @@ -// -// JSONAPITransformedAttributeOpenAPITests.swift -// JSONAPIOpenAPITests -// -// Created by Mathew Polzin on 1/28/19. -// - -import XCTest -import JSONAPI -import JSONAPIOpenAPI -import SwiftCheck -import AnyCodable - -class JSONAPITransformedAttributeOpenAPITests: XCTestCase { -} - -private typealias IdentityAttribute = TransformedAttribute> - -// MARK: - Boolean -extension JSONAPITransformedAttributeOpenAPITests { - func test_BooleanAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - } - - func test_NullableBooleanAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - } - - func test_OptionalBooleanAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - } - - func test_OptionalNullableBooleanAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .boolean(.generic)) - - guard case .boolean(let contextA) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - } -} - -// MARK: - Array of Strings -extension JSONAPITransformedAttributeOpenAPITests { - func test_Arrayttribute() { - let node = try! IdentityAttribute<[String]>.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_NullableArrayAttribute() { - let node = try! IdentityAttribute<[String]?>.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_OptionalArrayAttribute() { - let node = try! IdentityAttribute<[String]>?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } - - func test_OptionalNullableArrayAttribute() { - let node = try! IdentityAttribute<[String]?>?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .array(.generic)) - - guard case .array(let contextA, let arrayContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - let stringNode = JSONNode.string(.init(format: .generic, - required: true), - .init()) - - XCTAssertEqual(arrayContext, .init(items: stringNode)) - } -} - -// MARK: - Number -extension JSONAPITransformedAttributeOpenAPITests { - func test_NumberAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_NullableNumberAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNumberAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNullableNumberAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_FloatNumberAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertEqual(node.jsonTypeFormat, .number(.float)) - } -} - -// MARK: - Integer -extension JSONAPITransformedAttributeOpenAPITests { - func test_IntegerAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_NullableIntegerAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_OptionalIntegerAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } - - func test_OptionalNullableIntegerAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .integer(.generic)) - - guard case .integer(let contextA, let intContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(intContext, .init()) - } -} - -// MARK: - String -extension JSONAPITransformedAttributeOpenAPITests { - func test_StringAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_NullableStringAttribute() { - let node = try! IdentityAttribute.openAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalStringAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalNullableStringAttribute() { - let node = try! IdentityAttribute?.openAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } -} - -// MARK: - Enum -// NOTE: `enum` Attributes only gain the automatic support for allowed values -// (`enum` property in the OpenAPI Spec) at the Entity scope. These attributes -// will all still have `allowedValues: nil` at the attribute scope. -extension JSONAPITransformedAttributeOpenAPITests { - func test_EnumAttribute() { - let node = try! IdentityAttribute.rawOpenAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_NullableEnumAttribute() { - let node = try! IdentityAttribute.wrappedOpenAPINode() - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalEnumAttribute() { - let node = try! IdentityAttribute?.wrappedOpenAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_OptionalNullableEnumAttribute() { - let node = try! IdentityAttribute?.wrappedOpenAPINode() - - XCTAssertFalse(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.generic)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .generic, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } -} - -// MARK: - Date -extension JSONAPITransformedAttributeOpenAPITests { - func test_DateStringAttribute() { - // TEST: - // Encoder is set to use - // formatter with date - // with no time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.date)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .date, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateStringAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // formatter with date - // with no time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! IdentityAttribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.date)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .date, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateTimeStringAttribute() { - // TEST: - // Encoder is set to use - // formatter with date - // with time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_DateTimeStringAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // formatter with date - // with time. - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .short - dateFormatter.locale = Locale(identifier: "en_US") - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .formatted(dateFormatter) - - let node = try! IdentityAttribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - - func test_8601DateStringAttribute() { - if #available(OSX 10.12, *) { - // TEST: - // Encoder is set to use - // iso8601 date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .iso8601 - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - } - - func test_8601DateStringAttribute_Sampleable() { - if #available(OSX 10.12, *) { - // TEST: - // Encoder is set to use - // iso8601 date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .iso8601 - - let node = try! IdentityAttribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .string(.dateTime)) - - guard case .string(let contextA, let stringContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .dateTime, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(stringContext, .init()) - } - } - - func test_DateNumberAttribute() { - // TEST: - // Encoder is set to use - // seconds since 1970 as - // date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_DateNumberAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // seconds since 1970 as - // date format - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = try! IdentityAttribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_DateDeferredAttribute() { - // TEST: - // Encoder is set to use - // Date default encoding - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .deferredToDate - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNil(node) - } - - func test_DateDeferredAttribute_Sampleable() { - // TEST: - // Encoder is set to use - // Date default encoding - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .deferredToDate - - let node = try! IdentityAttribute.genericOpenAPINode(using: encoder) - - XCTAssertTrue(node.required) - XCTAssertEqual(node.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext) = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_NullableDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = IdentityAttribute.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertTrue(node?.required ?? false) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: true, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = IdentityAttribute?.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertFalse(node?.required ?? true) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: false, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } - - func test_OptionalNullableDateAttribute() { - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - encoder.dateEncodingStrategy = .secondsSince1970 - - let node = IdentityAttribute?.dateOpenAPINodeGuess(using: encoder) - - XCTAssertNotNil(node) - - XCTAssertFalse(node?.required ?? true) - XCTAssertEqual(node?.jsonTypeFormat, .number(.double)) - - guard case .number(let contextA, let numberContext)? = node else { - XCTFail("Expected string Node") - return - } - - XCTAssertEqual(contextA, .init(format: .double, - required: false, - nullable: true, - allowedValues: nil)) - - XCTAssertEqual(numberContext, .init()) - } -} - -// MARK: - Test Types -extension JSONAPITransformedAttributeOpenAPITests { - enum EnumAttribute: String, Codable, CaseIterable { - case one - case two - } -} diff --git a/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift b/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift deleted file mode 100644 index 62faad8..0000000 --- a/Tests/JSONAPIOpenAPITests/OpenAPI/OpenAPITests.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// OpenAPITests.swift -// JSONAPIOpenAPITests -// -// Created by Mathew Polzin on 1/25/19. -// - -import XCTest -import JSONAPI -import JSONAPIOpenAPI - -class OpenAPITests: XCTestCase { - - func test_placeholder() { - - let schemaInfo = OpenAPISchema.Info(title: "Cool API", version: "0.1.0") - - let personResponse = OpenAPIResponse(description: "Successfully created a Person", - content: [ - .json: .init(schema: .init(JSONReference.node(.init(type: \.schemas, selector: "person")))) - ]) - - let schemaPaths: [OpenAPISchema.PathComponents: OpenAPIPathItem] = [ - .init(["api","people"]): - .operations( - .init(parameters: [], - post: OpenAPIPathItem.PathProperties.Operation( - summary: "", - operationId: "createPerson", - parameters: [], - responses: [ - .status(code: 200): .init(personResponse) - ] - ) - ) - ) - ] - - let schemaComponents = OpenAPIComponents(schemas: ["person": .reference(.file("person.json"))], - parameters: [:]) - - let openAPISchema = OpenAPISchema(info: schemaInfo, - paths: schemaPaths, - components: schemaComponents) - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - - print(String(data: try! encoder.encode(openAPISchema), encoding: .utf8)!) - } - -} diff --git a/Tests/JSONAPIOpenAPITests/Test Helpers/EntityTestTypes.swift b/Tests/JSONAPIOpenAPITests/Test Helpers/EntityTestTypes.swift deleted file mode 100644 index 23e6b7d..0000000 --- a/Tests/JSONAPIOpenAPITests/Test Helpers/EntityTestTypes.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// EntityTestTypes.swift -// JSONAPITests -// -// Created by Mathew Polzin on 11/15/18. -// - -import JSONAPI - -public typealias Entity = JSONAPI.Entity - -public typealias BasicEntity = Entity - -public typealias NewEntity = JSONAPI.Entity diff --git a/Tests/JSONAPIOpenAPITests/Test Helpers/String+CreatableRawIdType.swift b/Tests/JSONAPIOpenAPITests/Test Helpers/String+CreatableRawIdType.swift deleted file mode 100644 index dd3c8f7..0000000 --- a/Tests/JSONAPIOpenAPITests/Test Helpers/String+CreatableRawIdType.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// String+CreatableRawIdType.swift -// JSONAPITests -// -// Created by Mathew Polzin on 11/12/18. -// - -import JSONAPI - -private var uniqueStringCounter = 0 - -extension String: CreatableRawIdType { - public static func unique() -> String { - uniqueStringCounter += 1 - return String(uniqueStringCounter) - } -} diff --git a/Tests/JSONAPIOpenAPITests/XCTestManifests.swift b/Tests/JSONAPIOpenAPITests/XCTestManifests.swift deleted file mode 100644 index b0e381a..0000000 --- a/Tests/JSONAPIOpenAPITests/XCTestManifests.swift +++ /dev/null @@ -1,136 +0,0 @@ -import XCTest - -extension JSONAPIAttributeOpenAPITests { - static let __allTests = [ - ("test_8601DateStringAttribute", test_8601DateStringAttribute), - ("test_8601DateStringAttribute_Sampleable", test_8601DateStringAttribute_Sampleable), - ("test_Arrayttribute", test_Arrayttribute), - ("test_BooleanAttribute", test_BooleanAttribute), - ("test_DateDeferredAttribute", test_DateDeferredAttribute), - ("test_DateDeferredAttribute_Sampleable", test_DateDeferredAttribute_Sampleable), - ("test_DateNumberAttribute", test_DateNumberAttribute), - ("test_DateNumberAttribute_Sampleable", test_DateNumberAttribute_Sampleable), - ("test_DateStringAttribute", test_DateStringAttribute), - ("test_DateStringAttribute_Sampleable", test_DateStringAttribute_Sampleable), - ("test_DateTimeStringAttribute", test_DateTimeStringAttribute), - ("test_DateTimeStringAttribute_Sampleable", test_DateTimeStringAttribute_Sampleable), - ("test_EnumAttribute", test_EnumAttribute), - ("test_FloatNumberAttribute", test_FloatNumberAttribute), - ("test_IntegerAttribute", test_IntegerAttribute), - ("test_NullableArrayAttribute", test_NullableArrayAttribute), - ("test_NullableBooleanAttribute", test_NullableBooleanAttribute), - ("test_NullableDateAttribute", test_NullableDateAttribute), - ("test_NullableEnumAttribute", test_NullableEnumAttribute), - ("test_NullableIntegerAttribute", test_NullableIntegerAttribute), - ("test_NullableNumberAttribute", test_NullableNumberAttribute), - ("test_NullableStringAttribute", test_NullableStringAttribute), - ("test_NumberAttribute", test_NumberAttribute), - ("test_OptionalArrayAttribute", test_OptionalArrayAttribute), - ("test_OptionalBooleanAttribute", test_OptionalBooleanAttribute), - ("test_OptionalDateAttribute", test_OptionalDateAttribute), - ("test_OptionalEnumAttribute", test_OptionalEnumAttribute), - ("test_OptionalIntegerAttribute", test_OptionalIntegerAttribute), - ("test_OptionalNullableArrayAttribute", test_OptionalNullableArrayAttribute), - ("test_OptionalNullableBooleanAttribute", test_OptionalNullableBooleanAttribute), - ("test_OptionalNullableDateAttribute", test_OptionalNullableDateAttribute), - ("test_OptionalNullableEnumAttribute", test_OptionalNullableEnumAttribute), - ("test_OptionalNullableIntegerAttribute", test_OptionalNullableIntegerAttribute), - ("test_OptionalNullableNumberAttribute", test_OptionalNullableNumberAttribute), - ("test_OptionalNullableStringAttribute", test_OptionalNullableStringAttribute), - ("test_OptionalNumberAttribute", test_OptionalNumberAttribute), - ("test_OptionalStringAttribute", test_OptionalStringAttribute), - ("test_StringAttribute", test_StringAttribute), - ] -} - -extension JSONAPIDocumentOpenAPITests { - static let __allTests = [ - ("test_DocumentWithOneIncludeType", test_DocumentWithOneIncludeType), - ("test_DocumentWithTwoIncludeTypes", test_DocumentWithTwoIncludeTypes), - ("test_ManyResourceDocument", test_ManyResourceDocument), - ("test_SingleResourceDocument", test_SingleResourceDocument), - ] -} - -extension JSONAPIEntityOpenAPITests { - static let __allTests = [ - ("test_AttributesAndRelationshipsEntity", test_AttributesAndRelationshipsEntity), - ("test_AttributesEntity", test_AttributesEntity), - ("test_EmptyEntity", test_EmptyEntity), - ("test_RelationshipsEntity", test_RelationshipsEntity), - ("test_UnidentifiedEmptyEntity", test_UnidentifiedEmptyEntity), - ] -} - -extension JSONAPIRelationshipsOpenAPITests { - static let __allTests = [ - ("test_NullableToOne", test_NullableToOne), - ("test_OptionalNullableToOne", test_OptionalNullableToOne), - ("test_OptionalToMany", test_OptionalToMany), - ("test_OptionalToOne", test_OptionalToOne), - ("test_ToMany", test_ToMany), - ("test_ToOne", test_ToOne), - ] -} - -extension JSONAPITransformedAttributeOpenAPITests { - static let __allTests = [ - ("test_8601DateStringAttribute", test_8601DateStringAttribute), - ("test_8601DateStringAttribute_Sampleable", test_8601DateStringAttribute_Sampleable), - ("test_Arrayttribute", test_Arrayttribute), - ("test_BooleanAttribute", test_BooleanAttribute), - ("test_DateDeferredAttribute", test_DateDeferredAttribute), - ("test_DateDeferredAttribute_Sampleable", test_DateDeferredAttribute_Sampleable), - ("test_DateNumberAttribute", test_DateNumberAttribute), - ("test_DateNumberAttribute_Sampleable", test_DateNumberAttribute_Sampleable), - ("test_DateStringAttribute", test_DateStringAttribute), - ("test_DateStringAttribute_Sampleable", test_DateStringAttribute_Sampleable), - ("test_DateTimeStringAttribute", test_DateTimeStringAttribute), - ("test_DateTimeStringAttribute_Sampleable", test_DateTimeStringAttribute_Sampleable), - ("test_EnumAttribute", test_EnumAttribute), - ("test_FloatNumberAttribute", test_FloatNumberAttribute), - ("test_IntegerAttribute", test_IntegerAttribute), - ("test_NullableArrayAttribute", test_NullableArrayAttribute), - ("test_NullableBooleanAttribute", test_NullableBooleanAttribute), - ("test_NullableDateAttribute", test_NullableDateAttribute), - ("test_NullableEnumAttribute", test_NullableEnumAttribute), - ("test_NullableIntegerAttribute", test_NullableIntegerAttribute), - ("test_NullableNumberAttribute", test_NullableNumberAttribute), - ("test_NullableStringAttribute", test_NullableStringAttribute), - ("test_NumberAttribute", test_NumberAttribute), - ("test_OptionalArrayAttribute", test_OptionalArrayAttribute), - ("test_OptionalBooleanAttribute", test_OptionalBooleanAttribute), - ("test_OptionalDateAttribute", test_OptionalDateAttribute), - ("test_OptionalEnumAttribute", test_OptionalEnumAttribute), - ("test_OptionalIntegerAttribute", test_OptionalIntegerAttribute), - ("test_OptionalNullableArrayAttribute", test_OptionalNullableArrayAttribute), - ("test_OptionalNullableBooleanAttribute", test_OptionalNullableBooleanAttribute), - ("test_OptionalNullableDateAttribute", test_OptionalNullableDateAttribute), - ("test_OptionalNullableEnumAttribute", test_OptionalNullableEnumAttribute), - ("test_OptionalNullableIntegerAttribute", test_OptionalNullableIntegerAttribute), - ("test_OptionalNullableNumberAttribute", test_OptionalNullableNumberAttribute), - ("test_OptionalNullableStringAttribute", test_OptionalNullableStringAttribute), - ("test_OptionalNumberAttribute", test_OptionalNumberAttribute), - ("test_OptionalStringAttribute", test_OptionalStringAttribute), - ("test_StringAttribute", test_StringAttribute), - ] -} - -extension OpenAPITests { - static let __allTests = [ - ("test_placeholder", test_placeholder), - ] -} - -#if !os(macOS) -public func __allTests() -> [XCTestCaseEntry] { - return [ - testCase(JSONAPIAttributeOpenAPITests.__allTests), - testCase(JSONAPIDocumentOpenAPITests.__allTests), - testCase(JSONAPIEntityOpenAPITests.__allTests), - testCase(JSONAPIRelationshipsOpenAPITests.__allTests), - testCase(JSONAPITransformedAttributeOpenAPITests.__allTests), - testCase(OpenAPITests.__allTests), - ] -} -#endif