From 477dae0a73fd35ea279987a872a67c6e86a4425f Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Mon, 21 Jan 2019 13:13:09 -0800 Subject: [PATCH] Add Arbitrary support for the rest of JSONAPI's key types. --- README.md | 14 +- .../APIDescription+Arbitrary.swift | 24 +++ .../Attribute+Arbitrary.swift | 2 +- .../JSONAPIArbitrary/Document+Arbitrary.swift | 110 ++++++++++++ .../JSONAPIArbitrary/Includes+Arbitrary.swift | 166 ++++++++++++++++++ .../ResourceBody+Arbitrary.swift | 27 +++ 6 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift create mode 100644 Sources/JSONAPIArbitrary/Document+Arbitrary.swift create mode 100644 Sources/JSONAPIArbitrary/Includes+Arbitrary.swift create mode 100644 Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift diff --git a/README.md b/README.md index a27f196..ab22a21 100644 --- a/README.md +++ b/README.md @@ -99,27 +99,27 @@ Note that Playground support for importing non-system Frameworks is still a bit #### Document - `data` - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI - `included` - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI - `errors` - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI - `meta` - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI - `jsonapi` (i.e. API Information) - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI - `links` - [x] Encoding/Decoding - - [ ] Arbitrary + - [x] Arbitrary - [ ] OpenAPI #### Resource Object @@ -838,7 +838,7 @@ The `JSONAPI` framework is packaged with a test library to help you test your `J # JSONAPI+Arbitrary The `JSONAPIArbitrary` framework adds `Arbitrary` support via `SwiftCheck`. With a little extra work on your part, this framework will allow you to create "arbitrary" (i.e. randomly generated) instances of your JSONAPI entities, includes, documents, etc. -This library does not offer full support of all `JSONAPI` types yet. The documentation will grow as the framework becomes more complete. +This Framework is currently undocumented, but familiarity with `SwiftCheck` will likely afford the user enough information to use this library to aid in the generation of arbitrary JSONAPI Documents for testing purposes. # JSONAPI+OpenAPI The `JSONAPIOpenAPI` framework adds the ability to generate OpenAPI compliant JSON documentation of a JSONAPI Document. diff --git a/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift b/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift new file mode 100644 index 0000000..05aea1f --- /dev/null +++ b/Sources/JSONAPIArbitrary/APIDescription+Arbitrary.swift @@ -0,0 +1,24 @@ +// +// 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 index 5c3ddb5..90c6264 100644 --- a/Sources/JSONAPIArbitrary/Attribute+Arbitrary.swift +++ b/Sources/JSONAPIArbitrary/Attribute+Arbitrary.swift @@ -14,7 +14,7 @@ extension Attribute: Arbitrary where RawValue: Arbitrary { } } -// Cannot extend TransformedAttribute here +// 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 new file mode 100644 index 0000000..9920718 --- /dev/null +++ b/Sources/JSONAPIArbitrary/Document+Arbitrary.swift @@ -0,0 +1,110 @@ +// +// 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/Includes+Arbitrary.swift b/Sources/JSONAPIArbitrary/Includes+Arbitrary.swift new file mode 100644 index 0000000..e04ed04 --- /dev/null +++ b/Sources/JSONAPIArbitrary/Includes+Arbitrary.swift @@ -0,0 +1,166 @@ +// +// 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/ResourceBody+Arbitrary.swift b/Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift new file mode 100644 index 0000000..1c84939 --- /dev/null +++ b/Sources/JSONAPIArbitrary/ResourceBody+Arbitrary.swift @@ -0,0 +1,27 @@ +// +// 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) + } +}