From 5060bddc4daf70b67241af4d5b416437b7564230 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 19:13:07 -0600 Subject: [PATCH 001/460] Add inversion --- SwiftCheck/Property.swift | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 19065fe..f4ec0de 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -44,6 +44,21 @@ public func disjoin(ps : Testable...) -> Property { })) } +/// Inverts the result of a test. That is, tests cases that would pass now fail and vice versa. +/// +/// Discarded tests remain discarded under inversion. +public func invert(p : Testable) -> Property { + return mapResult({ res in + return TestResult(ok: res.ok.map({ !$0 }), + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks) + })(p: p) +} + /// Applies a function that modifies the property generator's inner `Prop`. public func mapProp(f : Prop -> Prop)(p : Testable) -> Property { return Property(p.property().unProperty.fmap(f)) From 0e2d8138c0aac3ffaa6c1791f60c74541e630a7a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 19:13:30 -0600 Subject: [PATCH 002/460] Add the literal definition of an existential. I doubt this will work correctly. --- SwiftCheck/Test.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 7eee990..6f184da 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -102,6 +102,18 @@ public func forAll(pf : A -> Testable) -> Property { + return invert(forAllShrink(A.arbitrary(), { A.shrink($0) }, { (invert • pf)($0) })) +} + +/// Given an explicit generator, converts a function to an existentially quantified property using +/// the default shrinker for that type. +public func exists(gen : Gen, pf : A -> Testable) -> Property { + return invert(forAllShrink(gen, { A.shrink($0) }, { (invert • pf)($0) })) +} + /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. public func forAllShrink(gen : Gen, shrinker: A -> [A], f : A -> Testable) -> Property { From aaf75f52fe5f738e1cd951bfce8182413d1f19c6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 19:14:23 -0600 Subject: [PATCH 003/460] a typo --- SwiftCheck/Property.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index f4ec0de..328ec8d 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -44,7 +44,7 @@ public func disjoin(ps : Testable...) -> Property { })) } -/// Inverts the result of a test. That is, tests cases that would pass now fail and vice versa. +/// Inverts the result of a test. That is, test cases that would pass now fail and vice versa. /// /// Discarded tests remain discarded under inversion. public func invert(p : Testable) -> Property { From 9892d2cd81558288687d0ca3df4d832eda047c5d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 20:48:46 -0600 Subject: [PATCH 004/460] Adopt abort in invert --- SwiftCheck/Property.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index e05f951..8152a81 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -49,13 +49,14 @@ public func disjoin(ps : Testable...) -> Property { /// Discarded tests remain discarded under inversion. public func invert(p : Testable) -> Property { return mapResult({ res in - return TestResult(ok: res.ok.map({ !$0 }), + return TestResult(ok: res.ok.map(!), expect: res.expect, reason: res.reason, theException: res.theException, labels: res.labels, stamp: res.stamp, - callbacks: res.callbacks) + callbacks: res.callbacks, + abort: res.abort) })(p: p) } From 938c8fc2e1e8df1d129ef90285474116f9a906de Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:23:01 -0600 Subject: [PATCH 005/460] Add Quantification enum --- SwiftCheck/Property.swift | 48 +++++++++++++++++++++++++++------------ SwiftCheck/State.swift | 7 +++--- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 8152a81..49a2835 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -56,7 +56,8 @@ public func invert(p : Testable) -> Property { labels: res.labels, stamp: res.stamp, callbacks: res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) })(p: p) } @@ -108,7 +109,8 @@ public func once(p : Testable) -> Property { labels: res.labels, stamp: res.stamp, callbacks: res.callbacks, - abort: true) + abort: true, + quantifier: res.quantifier) })(p: p) } @@ -133,7 +135,8 @@ public func withCallback(cb : Callback)(p : Testable) -> Property { labels: res.labels, stamp: res.stamp, callbacks: [cb] + res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) })(p: p) } @@ -199,7 +202,8 @@ public func verbose(p : Testable) -> Property { labels: res.labels, stamp: res.stamp, callbacks: res.callbacks + chattyCallbacks(res.callbacks), - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) })(p: p) } @@ -215,7 +219,8 @@ public func expectFailure(p : Testable) -> Property { labels: res.labels, stamp: res.stamp, callbacks: res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) })(p: p) } @@ -252,7 +257,8 @@ public func cover(b : Bool)(n : Int)(s : String)(p : Testable) -> Property { labels: insertWith(max, s, n, res.labels), stamp: res.stamp.union([s]), callbacks: res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) })(p: p) } return p.property() @@ -275,7 +281,13 @@ public enum CallbackKind { case NotCounterexample } -public enum TestResultMatcher { +public enum Quantification { + case Universal + case Existential + case Uniqueness +} + +internal enum TestResultMatcher { case MatchResult( ok : Optional , expect : Bool , reason : String @@ -284,6 +296,7 @@ public enum TestResultMatcher { , stamp : Set , callbacks : [Callback] , abort : Bool + , quantifier : Quantification ) } @@ -306,13 +319,15 @@ public struct TestResult { let callbacks : [Callback] /// Indicates that any further testing of the property should cease. let abort : Bool + /// + let quantifier : Quantification /// Destructures a test case into a matcher that can be used in switch statement. - public func match() -> TestResultMatcher { - return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort) + internal func match() -> TestResultMatcher { + return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } - public init(ok : Optional, expect : Bool, reason : String, theException : Optional, labels : Dictionary, stamp : Set, callbacks : [Callback], abort : Bool) { + internal init(ok : Optional, expect : Bool, reason : String, theException : Optional, labels : Dictionary, stamp : Set, callbacks : [Callback], abort : Bool, quantifier : Quantification) { self.ok = ok self.expect = expect self.reason = reason @@ -321,8 +336,10 @@ public struct TestResult { self.stamp = stamp self.callbacks = callbacks self.abort = abort + self.quantifier = quantifier } } + /// public func succeeded() -> TestResult { return result(Optional.Some(true)) @@ -356,7 +373,7 @@ private func props(shrinker : A -> [A], #original : A, #pf: A -> Testable) -> } private func result(ok : Bool?, reason : String = "") -> TestResult { - return TestResult(ok: ok, expect: true, reason: reason, theException: .None, labels: [:], stamp: Set(), callbacks: [], abort: false) + return TestResult(ok: ok, expect: true, reason: reason, theException: .None, labels: [:], stamp: Set(), callbacks: [], abort: false, quantifier: .Universal) } private func id(x : A) -> A { @@ -397,7 +414,8 @@ private func addCallbacks(result : TestResult) -> TestResult -> TestResult { labels: res.labels, stamp: res.stamp, callbacks: result.callbacks + res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) } } @@ -410,7 +428,8 @@ private func addLabels(result : TestResult) -> TestResult -> TestResult { labels: unionWith(max, res.labels, result.labels), stamp: res.stamp.union(result.stamp), callbacks: res.callbacks, - abort: res.abort) + abort: res.abort, + quantifier: res.quantifier) } } @@ -508,7 +527,8 @@ private func disj(p : Rose, q : Rose) -> Rose Int -> Int, numSuccessTests : Int, numDiscardedTests : Int, labels : Dictionary, collected : [Set], expectedFailure : Bool, randomSeed : StdGen, numSuccessShrinks : Int, numTryShrinks : Int, numTotTryShrinks : Int, shouldAbort : Bool) { + public init(name : String, maxSuccessTests : Int, maxDiscardedTests : Int, computeSize : Int -> Int -> Int, numSuccessTests : Int, numDiscardedTests : Int, labels : Dictionary, collected : [Set], expectedFailure : Bool, randomSeed : StdGen, numSuccessShrinks : Int, numTryShrinks : Int, numTotTryShrinks : Int, shouldAbort : Bool, quantifier : Quantification) { self.name = name self.maxSuccessTests = maxSuccessTests self.maxDiscardedTests = maxDiscardedTests @@ -40,5 +38,6 @@ public struct State { self.numTryShrinks = numTryShrinks self.numTotTryShrinks = numTotTryShrinks self.shouldAbort = shouldAbort + self.quantifier = quantifier } } From ab7802e8bc34904b41847be976ede9b522c7c108 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:23:19 -0600 Subject: [PATCH 006/460] Express exists in terms of its generator-explicit counterpart --- SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index d2ef68e..50bed28 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -105,7 +105,7 @@ public func forAll(pf : A -> Testable) -> Property { - return invert(forAllShrink(A.arbitrary(), { A.shrink($0) }, { (invert • pf)($0) })) + return exists(A.arbitrary(), pf) } /// Given an explicit generator, converts a function to an existentially quantified property using From 91015d40c768a584750bbab12f3f7f282dcb033e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:23:51 -0600 Subject: [PATCH 007/460] Explicitly convert to .Existential --- SwiftCheck/Test.swift | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 50bed28..b1e8b3a 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -111,7 +111,17 @@ public func exists(pf : A -> Testable) -> Property { /// Given an explicit generator, converts a function to an existentially quantified property using /// the default shrinker for that type. public func exists(gen : Gen, pf : A -> Testable) -> Property { - return invert(forAllShrink(gen, { A.shrink($0) }, { (invert • pf)($0) })) + return mapResult({ res in + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: .Existential) + })(p: invert(forAllShrink(A.arbitrary(), { A.shrink($0) }, { (invert • pf)($0) }))) } /// Given an explicit generator and shrinker, converts a function to a universally quantified From 275f8aa776b7daf14016df1b2bc30e82c4d6f5cd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:24:09 -0600 Subject: [PATCH 008/460] Add ExistentialFailure case --- SwiftCheck/Test.swift | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index b1e8b3a..8fe9ddc 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -148,24 +148,32 @@ public func quickCheck(prop : Testable, name : String = "") { internal enum Result { case Success(numTests: Int - , labels: [(String, Int)] - , output: String + , labels : [(String, Int)] + , output : String ) case GaveUp(numTests: Int - , labels: [(String,Int)] - , output: String + , labels : [(String,Int)] + , output : String ) case Failure(numTests: Int - , numShrinks: Int - , usedSeed: StdGen - , usedSize: Int - , reason: String - , labels: [(String,Int)] - , output: String + , numShrinks : Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String ) - case NoExpectedFailure(numTests: Int - , labels: [(String,Int)] - , output: String + case ExistentialFailure(numTests: Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String + , lastResult : TestResult + ) + case NoExpectedFailure(numTests: Int + , labels : [(String,Int)] + , output : String ) } @@ -246,7 +254,8 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { , numSuccessShrinks: 0 , numTryShrinks: 0 , numTotTryShrinks: 0 - , shouldAbort: false) + , shouldAbort: false + , quantifier: .Universal) let modP : Property = (p.exhaustive ? once(p.property()) : p.property()) return test(state, modP.unProperty.unGen) } From 2ffe7f4077c684413f1291bc0aca8d7fe21eb056 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:24:26 -0600 Subject: [PATCH 009/460] Alter testing loop to accept existential failure --- SwiftCheck/Test.swift | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 8fe9ddc..11d7523 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -274,13 +274,28 @@ internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { while true { switch runATest(state)(f: f) { case let .Left(fail): - switch (fail.value.0, doneTesting(fail.value.1)(f: f)) { - case let (.Success(_, _, _), _): - return fail.value.0 - case let (_, .NoExpectedFailure(numTests, labels, output)): - return .NoExpectedFailure(numTests: numTests, labels: labels, output: output) - default: - return fail.value.0 + switch fail.value { + // Success and Failure simply fallthrough to doneTesting which will catch them + // and finish reporting for the test. + case let (.Success(_, _, _), _): + fallthrough + case let (.NoExpectedFailure(_, _, _), _): + return doneTesting(fail.value.1) + // Existential Failures need explicit propagation. Existentials increment the + // discard count so we check if it has been surpassed. If it has with any kind + // of success we're done. If no successes are found we've failed checking the + // existential and report it as such. Otherwise turn the testing loop. + case let (.ExistentialFailure(_, _, _, _, _, _, _), lsta): + if lsta.numDiscardedTests >= lsta.maxDiscardedTests && lsta.numSuccessTests == 0 { + return reportExistentialFailure(fail.value.1, fail.value.0) + } else if lsta.numDiscardedTests >= lsta.maxDiscardedTests { + return doneTesting(lsta) + } else { + state = lsta + break + } + default: + return fail.value.0 } case let .Right(sta): let lsta = sta.value // Local copy so I don't have to keep unwrapping. From 258d706b878e2b712f35be38f0b72bd30169006a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:24:55 -0600 Subject: [PATCH 010/460] reportExistentialFailure --- SwiftCheck/Test.swift | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 11d7523..ea16d72 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -300,10 +300,10 @@ internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { case let .Right(sta): let lsta = sta.value // Local copy so I don't have to keep unwrapping. if lsta.numSuccessTests >= lsta.maxSuccessTests || lsta.shouldAbort { - return doneTesting(lsta)(f: f) + return doneTesting(lsta) } if lsta.numDiscardedTests >= lsta.maxDiscardedTests || lsta.shouldAbort { - return giveUp(lsta)(f: f) + return giveUp(lsta) } state = lsta } @@ -418,7 +418,7 @@ internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { } } -internal func giveUp(st: State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func giveUp(st : State) -> Result { printDistributionGraph(st) return Result.GaveUp(numTests: st.numSuccessTests, labels: summary(st), output: "") } @@ -518,6 +518,21 @@ internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) } +internal func reportExistentialFailure(st : State, res : Result) -> Result { + switch res { + case let .ExistentialFailure(_, _, _, reason, _, _, lastTest): + let testMsg = " (after \(st.numDiscardedTests) test" + + print("*** Failed! ") + println("Proposition: " + st.name) + println(reason + pluralize(testMsg, st.numDiscardedTests) + "):") + dispatchAfterFinalFailureCallbacks(st, lastTest) + return res + default: + fatalError("Cannot report existential failure on non-failure type \(res)") + } +} + internal func dispatchAfterTestCallbacks(st : State, res : TestResult) { for c in res.callbacks { switch c { From e9209073bccf640a737966a2aca72d8235ea9a04 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:25:24 -0600 Subject: [PATCH 011/460] Fix pluralization for 0 tests ENGLIIIIIIIISH --- SwiftCheck/Test.swift | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index ea16d72..4274a0c 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -407,9 +407,10 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul } } -internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func doneTesting(st : State) -> Result { if st.expectedFailure { println("*** Passed " + "\(st.numSuccessTests)" + " tests") + println("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", st.numSuccessTests)) printDistributionGraph(st) return .Success(numTests: st.numSuccessTests, labels: summary(st), output: "") } else { @@ -505,13 +506,6 @@ internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, let testMsg = " (after \(st.numSuccessTests + 1) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" - func pluralize(s : String, i : Int) -> String { - if i > 1 { - return s + "s" - } - return s - } - println("Proposition: " + st.name) println(res.reason + pluralize(testMsg, st.numSuccessTests + 1) + pluralize(shrinkMsg, st.numSuccessShrinks) + "):") dispatchAfterFinalFailureCallbacks(st, res) @@ -629,3 +623,10 @@ internal func groupBy(list : [A], p : (A , A) -> Bool) -> [[A]] { } fatalError("groupBy reached a non-empty list that could not produce a first element") } + +private func pluralize(s : String, i : Int) -> String { + if i == 1 { + return s + } + return s + "s" +} From 7e856b90ef262a7fcac0faf53b59f67982476746 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:25:36 -0600 Subject: [PATCH 012/460] Fix testing loop for existentials --- SwiftCheck/Test.swift | 65 ++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 4274a0c..6ea027e 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -325,7 +325,7 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul switch res.match() { // Success - case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): + case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): let state = State(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests @@ -339,10 +339,12 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , numSuccessShrinks: st.numSuccessShrinks , numTryShrinks: st.numTryShrinks , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + // Existentials break on success + , shouldAbort: abort || (quantifier == .Existential) + , quantifier: quantifier) return .Right(Box(state)) // Discard - case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): + case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort, let quantifier): let state = State(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests @@ -356,16 +358,48 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , numSuccessShrinks: st.numSuccessShrinks , numTryShrinks: st.numTryShrinks , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + , shouldAbort: abort + , quantifier: quantifier) return .Right(Box(state)) // Fail - case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): - if !expect { + case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): + if quantifier == .Existential { + print("") + } else if !expect { print("+++ OK, failed as expected. ") } else { print("*** Failed! ") } + let state = State(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + 1 + , labels: st.labels + , collected: st.collected + , expectedFailure: res.expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort + , quantifier: quantifier) + + // Failure of an existential is not necessarily failure of the whole test case, + // so treat this like a discard. + if quantifier == .Existential { + let resul = Result.ExistentialFailure(numTests: st.numSuccessTests + 1 + , usedSeed: st.randomSeed + , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) + , reason: "Could not satisfy existential" + , labels: summary(st) + , output: "*** Failed! " + , lastResult: res) + return .Left(Box((resul, state))) + } + // Attempt a shrink. let (numShrinks, totFailed, lastFailed) = findMinimalFailingTestCase(st, res, ts()) @@ -382,21 +416,8 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , labels: summary(st) , output: "*** Failed! ") - let state = State(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 - , labels: st.labels - , collected: st.collected - , expectedFailure: res.expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) return .Left(Box((stat, state))) + default: fatalError("Pattern Match Failed: switch on a Result was inexhaustive.") break @@ -409,7 +430,6 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul internal func doneTesting(st : State) -> Result { if st.expectedFailure { - println("*** Passed " + "\(st.numSuccessTests)" + " tests") println("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", st.numSuccessTests)) printDistributionGraph(st) return .Success(numTests: st.numSuccessTests, labels: summary(st), output: "") @@ -498,7 +518,8 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros , numSuccessShrinks: numSuccessShrinks , numTryShrinks: numTryShrinks , numTotTryShrinks: numTotTryShrinks - , shouldAbort: st.shouldAbort) + , shouldAbort: st.shouldAbort + , quantifier: st.quantifier) return reportMinimumCaseFound(state, lastResult) } From 88cb1197f3f48bbf041da3e6ed756385061fdec3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 22:25:51 -0600 Subject: [PATCH 013/460] ExistentialFailure now fails in Xcode too --- SwiftCheck/Check.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 1d2140f..dc75ff0 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -27,7 +27,9 @@ public struct AssertiveQuickCheck { set(test) { let r = quickCheckWithResult(stdArgs(name: s), test) switch r { - case let .Failure(numTests, numShrinks, usedSeed, usedSize, reason, labels, output): + case let .Failure(_, _, _, _, reason, _, _): + XCTFail(reason) + case let .ExistentialFailure(_, _, _, reason, _, _, _): XCTFail(reason) case let .NoExpectedFailure(numTests, labels, output): XCTFail("Expected property to fail but it didn't.") From 3f95a4b3f5413dd2d7c39cffa3fe0a2254558fec Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:00:29 -0600 Subject: [PATCH 014/460] Succeed at all costs! --- SwiftCheck/Check.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index dc75ff0..fffb0a7 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -27,11 +27,13 @@ public struct AssertiveQuickCheck { set(test) { let r = quickCheckWithResult(stdArgs(name: s), test) switch r { + case .Success(_, _, _): + return case let .Failure(_, _, _, _, reason, _, _): XCTFail(reason) case let .ExistentialFailure(_, _, _, reason, _, _, _): XCTFail(reason) - case let .NoExpectedFailure(numTests, labels, output): + case let .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.") default: return From 47c0733b167f986d6b4b066d6e903afb432427f2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:00:58 -0600 Subject: [PATCH 015/460] Test existentials and inversion --- SwiftCheck/Test.swift | 6 +++--- SwiftCheckTests/PropertySpec.swift | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 6ea027e..20c5322 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -275,10 +275,10 @@ internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { switch runATest(state)(f: f) { case let .Left(fail): switch fail.value { - // Success and Failure simply fallthrough to doneTesting which will catch them - // and finish reporting for the test. + // Succeed at all costs! case let (.Success(_, _, _), _): - fallthrough + doneTesting(fail.value.1) + return fail.value.0 case let (.NoExpectedFailure(_, _, _), _): return doneTesting(fail.value.1) // Existential Failures need explicit propagation. Existentials increment the diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 17bd64f..4b0b86c 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -19,5 +19,21 @@ class PropertySpec : XCTestCase { return b == n }) } + + property["Invert turns passing properties to failing properties"] = expectFailure(invert(forAll { (n : Int) in + return n == n + })) + + property["Invert turns failing properties to passing properties"] = invert(forAll { (n : Int) in + return n != n + }) + + property["Invert does not affect discards"] = invert(forAll { (n : Int) in + return Discard() + }) + + property["Existential Quantification works"] = exists { (x : Int) in + return true + } } } From cf06c14abeefedc1b6af2c4cb8d98df77dcb5218 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:15:10 -0600 Subject: [PATCH 016/460] Caveats. Everything is caveats --- SwiftCheck/Test.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 20c5322..f38233f 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -103,7 +103,14 @@ public func forAll(pf : A -> Testable) -> Property { return exists(A.arbitrary(), pf) } From 383d63250a850a4a26149cce0977cc5779a93fd5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:15:15 -0600 Subject: [PATCH 017/460] No shrinks. --- SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index f38233f..6a5a27d 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -128,7 +128,7 @@ public func exists(gen : Gen, pf : A -> Testable) -> Property callbacks: res.callbacks, abort: res.abort, quantifier: .Existential) - })(p: invert(forAllShrink(A.arbitrary(), { A.shrink($0) }, { (invert • pf)($0) }))) + })(p: invert(forAllShrink(A.arbitrary(), shrinkNone, { (invert • pf)($0) }))) } /// Given an explicit generator and shrinker, converts a function to a universally quantified From 7b1afc4c8a9cd3dbab25af1c8f7c6cda0c9a1b3d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:26:41 -0600 Subject: [PATCH 018/460] Add note about Skolemization --- SwiftCheck/Test.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 6a5a27d..be868fb 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -111,6 +111,11 @@ public func forAll`_. `SNF` involves +/// turning every `exists` into a function returning the existential value, taking any other +/// parameters being quantified over as needed. public func exists(pf : A -> Testable) -> Property { return exists(A.arbitrary(), pf) } From 0a2cdb7a34d7de6f197e82eb2758fb1311536936 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:33:52 -0600 Subject: [PATCH 019/460] Really fix the pluralizer --- SwiftCheck/Test.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index be868fb..ac35c3c 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -537,10 +537,10 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, Int) { let testMsg = " (after \(st.numSuccessTests + 1) test" - let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" + let shrinkMsg = st.numSuccessShrinks > 1 ? pluralize(" and \(st.numSuccessShrinks) shrink", st.numSuccessShrinks) : "" println("Proposition: " + st.name) - println(res.reason + pluralize(testMsg, st.numSuccessTests + 1) + pluralize(shrinkMsg, st.numSuccessShrinks) + "):") + println(res.reason + pluralize(testMsg, st.numSuccessTests + 1) + shrinkMsg + "):") dispatchAfterFinalFailureCallbacks(st, res) return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) } From 4f62c4a03faf1c42aed189a3d5a186a1ebecf791 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jun 2015 23:35:56 -0600 Subject: [PATCH 020/460] Document quantification --- SwiftCheck/Property.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 49a2835..194f1c0 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -276,15 +276,22 @@ public enum Callback { /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { - /// + /// The callback is invoked after a counterexample is displayed. case Counterexample + /// The callback is invoked after every test. case NotCounterexample } +/// The types of quantification SwiftCheck can perform. public enum Quantification { + /// Universal Quantification ("for all"). case Universal + /// Existential Quanfication ("there exists"). case Existential - case Uniqueness + /// Uniqueness Quantification ("there exists one and only one") + // case Uniqueness + /// Counting Quantification ("there exist exactly k") + // case Counting } internal enum TestResultMatcher { @@ -340,7 +347,6 @@ public struct TestResult { } } -/// public func succeeded() -> TestResult { return result(Optional.Some(true)) } From bdb5045150abd6cfc7d045d8b2bc35d2e920ad7c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 23 Jun 2015 16:06:13 -0600 Subject: [PATCH 021/460] Add direct instances of Arbitrary Sort of --- SwiftCheck.xcodeproj/project.pbxproj | 6 + SwiftCheck/Arbitrary.swift | 207 ++++++++++++++++++++++----- SwiftCheck/Modifiers.swift | 86 +---------- SwiftCheck/Property.swift | 71 ++++----- 4 files changed, 215 insertions(+), 155 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 762f9e0..5521169 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -29,6 +29,8 @@ 8450D24A1AF8003800095EF6 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* Operators.swift */; }; 84572C251A6DBAA800241F68 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; + 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; + 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; 84DF76111B0BD58100C912B0 /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCA9198B323800EB242A /* Arbitrary.swift */; }; 84DF76121B0BD58100C912B0 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; @@ -107,6 +109,7 @@ 84572C2A1A6DBABA00241F68 /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; }; 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BooleanIdentitySpec.swift; sourceTree = ""; }; 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; }; + 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 84EA2C381B2287200001FB3F /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; }; @@ -208,6 +211,7 @@ 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, + 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); path = SwiftCheckTests; @@ -420,6 +424,7 @@ 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */, 8445C4AD1B17E48300280089 /* ShrinkSpec.swift in Sources */, 8445C4AA1B16D37800280089 /* GenSpec.swift in Sources */, + 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, @@ -454,6 +459,7 @@ 84DF761E1B0BD58900C912B0 /* SimpleSpec.swift in Sources */, 8445C4AE1B17E48300280089 /* ShrinkSpec.swift in Sources */, 8445C4AB1B16D37800280089 /* GenSpec.swift in Sources */, + 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index fbeb0d7..5bd30c1 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -233,7 +233,7 @@ extension String : Arbitrary { } public static func shrink(s : String) -> [String] { - return ArrayOf.shrink(ArrayOf([Character](s.characters))).map({ String($0.getArray) }) + return [Character].shrink([Character](s.characters)).map({ String($0) }) } } @@ -248,51 +248,83 @@ extension Character : Arbitrary { } } -//extension Array : Arbitrary where T : Arbitrary { -// public static func arbitrary() -> Gen> { -// return Gen.sized { n in -// return Gen.choose((0, n)).bind { k in -// if k == 0 { -// return Gen.pure([]) -// } -// -// return sequence(Array((0...k)).map { _ in T.arbitrary() }) -// } -// } -// } -// -// public static func shrink(bl : Array) -> [[T]] { -// return Array(Int.shrink(n).reverse()).flatMap({ k in removes(k + 1, n: bl.count, xs: bl) }) + shrinkOne(bl) -// } -//} +/// Generates an Optional of arbitrary values of type A. +extension Optional where T : Arbitrary { + public static func arbitrary() -> Gen> { + return Gen.frequency([ + (1, Gen.pure(.None)), + (3, liftM({ .Some($0) })(m1: T.arbitrary())), + ]) + } -private func bits(n : N) -> Int { - if n / 2 == 0 { - return 0 + public static func shrink(bl : Optional) -> [Optional] { + if let x = bl { + return [.None] + T.shrink(x).map { .Some($0) } + } + return [] } - return 1 + bits(n / 2) } -private func inBounds(fi : (Int -> A)) -> Gen -> Gen { - return { g in - return g.suchThat({ x in - return (fi(x) as! Int) == x - }).fmap(fi) +extension Array where T : Arbitrary { + public static func arbitrary() -> Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).bind { k in + if k == 0 { + return Gen.pure([]) + } + + return sequence((0...k).map { _ in T.arbitrary() }) + } + } + } + + public static func shrink(bl : Array) -> [[T]] { + return Int.shrink(bl.count).reverse().flatMap({ k in removes(k + 1, n: bl.count, xs: bl) }) + shrinkOne(bl) } } -private func nub(xs : [A]) -> [A] { - return [A](Set(xs)) +/// Generates an dictionary of arbitrary keys and values. +extension Dictionary where Key : Arbitrary, Value : Arbitrary { + public static func arbitrary() -> Gen> { + return [Key].arbitrary().bind { k in + return [Value].arbitrary().bind { v in + return Gen.pure(Dictionary(Zip2(k, v))) + } + } + } + + public static func shrink(d : Dictionary) -> [Dictionary] { + return d.map { Dictionary(Zip2(Key.shrink($0), Value.shrink($1))) } + } } -private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { - var acc = [A]() - var ini = initial - while let next = f(ini) { - acc.insert(next.0, atIndex: 0) - ini = next.1 + +extension Dictionary { + init(_ pairs : S) { + self.init() + var g = pairs.generate() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } +} + +extension Set where T : protocol { + public static func arbitrary() -> Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).bind { k in + if k == 0 { + return Gen.pure(Set([])) + } + + return sequence(Array((0...k)).map { _ in T.arbitrary() }).fmap({ Set($0) }) + } + } + } + + public static func shrink(s : Set) -> [Set] { + return [T].shrink([T](s)).map { Set($0) } } - return acc } @@ -422,3 +454,106 @@ extension Double : CoArbitrary { return coarbitraryIntegral(Int64(x)) } } + +extension Array : CoArbitrary { + public static func coarbitrary(a : [T]) -> (Gen -> Gen) { + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • [T].coarbitrary([T](a[1..(x : Dictionary) -> (Gen -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} + +extension Optional : CoArbitrary { + public static func coarbitrary(x : Optional) -> (Gen -> Gen) { + if let _ = x { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} + +extension Set : CoArbitrary { + public static func coarbitrary(x : Set) -> (Gen -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} + +/// MARK: Implementation Details + +private func bits(n : N) -> Int { + if n / 2 == 0 { + return 0 + } + return 1 + bits(n / 2) +} + +private func inBounds(fi : (Int -> A)) -> Gen -> Gen { + return { g in + return g.suchThat({ x in + return (fi(x) as! Int) == x + }).fmap(fi) + } +} + +private func nub(xs : [A]) -> [A] { + return [A](Set(xs)) +} + +private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { + var acc = [A]() + var ini = initial + while let next = f(ini) { + acc.insert(next.0, atIndex: 0) + ini = next.1 + } + return acc +} + +private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { + let xs1 = take(k, xs: xs) + let xs2 = drop(k, xs: xs) + + if k > n { + return [] + } else if xs2.isEmpty { + return [[]] + } else { + return [xs2] + removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + } +} + +private func take(num : Int, xs : [T]) -> [T] { + let n = (num < xs.count) ? num : xs.count + return [T](xs[0..(num : Int, xs : [T]) -> [T] { + let n = (num < xs.count) ? num : xs.count + return [T](xs[n..(xs : [A]) -> [[A]] { + if xs.isEmpty { + return [] + } else if let x = xs.first { + let xss = [A](xs[1.. : Arbitrary, CustomStringConvertible { } public static func arbitrary() -> Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).bind { k in - if k == 0 { - return Gen.pure(ArrayOf([])) - } - - return sequence(Array((0...k)).map { _ in A.arbitrary() }).fmap(ArrayOf.create) - } - } + return Array.arbitrary().fmap(ArrayOf.init) } public static func shrink(bl : ArrayOf) -> [ArrayOf] { - let n = bl.getArray.count - let xs = Array(Int.shrink(n).reverse()).flatMap({ k in removes(k + 1, n: n, xs: bl.getArray) }) + shrinkOne(bl.getArray) - return xs.map({ ArrayOf($0) }) + return Array.shrink(bl.getArray).map(ArrayOf.init) } } @@ -120,41 +110,6 @@ extension ArrayOf : CoArbitrary { } } -private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 = take(k, xs: xs) - let xs2 = drop(k, xs: xs) - - if k > n { - return [] - } else if xs2.isEmpty { - return [[]] - } else { - return [xs2] + removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) - } -} - -private func shrinkOne(xs : [A]) -> [[A]] { - if xs.isEmpty { - return [] - } else if let x = xs.first { - let xss = [A](xs[1..(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n.., V : Arbitrary> : Arbitrary, CustomStringConvertible { public let getDictionary : Dictionary @@ -172,38 +127,17 @@ public struct DictionaryOf, V : Arbitrary> : A } public static func arbitrary() -> Gen> { - return ArrayOf.arbitrary().bind { k in - return ArrayOf.arbitrary().bind { v in - return Gen.pure(DictionaryOf(Dictionary(Zip2(k.getArray, v.getArray)))) - } - } + return Dictionary.arbitrary().fmap(DictionaryOf.init) } public static func shrink(d : DictionaryOf) -> [DictionaryOf] { - var xs = [DictionaryOf]() - for (k, v) in d.getDictionary { - xs.append(DictionaryOf(Dictionary(Zip2(K.shrink(k), V.shrink(v))))) - } - return xs + return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } } extension DictionaryOf : CoArbitrary { public static func coarbitrary(x : DictionaryOf) -> (Gen -> Gen) { - if x.getDictionary.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - -extension Dictionary { - init(_ pairs : S) { - self.init() - var g = pairs.generate() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } + return Dictionary.coarbitrary(x.getDictionary) } } @@ -224,17 +158,11 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { } public static func arbitrary() -> Gen> { - return Gen.frequency([ - (1, Gen.pure(OptionalOf(Optional.None))), - (3, liftM({ OptionalOf(Optional.Some($0)) })(m1: A.arbitrary())) - ]) + return Optional.arbitrary().fmap(OptionalOf.init) } public static func shrink(bl : OptionalOf) -> [OptionalOf] { - if let x = bl.getOptional { - return [OptionalOf(Optional.None)] + A.shrink(x).map({ OptionalOf(Optional.Some($0)) }) - } - return [] + return Optional.shrink(bl.getOptional).map(OptionalOf.init) } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index db7a7f1..a254c1b 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -58,11 +58,11 @@ extension Testable { } /// Applies a function that modifies the result of a test case. -// public func mapTotalResult(f : TestResult -> TestResult) -> Property { -// return self.mapRoseResult({ rs in -// return protectResults(rs.fmap(f)) -// }) -// } + public func mapTotalResult(f : TestResult -> TestResult) -> Property { + return self.mapRoseResult({ rs in + return protectResults(rs.fmap(f)) + }) + } /// Applies a function that modifies the result of a test case. public func mapResult(f : TestResult -> TestResult) -> Property { @@ -187,8 +187,7 @@ extension Testable { /// /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { - // return self.mapTotalResult({ res in - return self.mapResult({ res in + return self.mapTotalResult({ res in return TestResult(ok: res.ok, expect: false, reason: res.reason, @@ -358,31 +357,31 @@ private func result(ok : Bool?, reason : String = "") -> TestResult { return TestResult(ok: ok, expect: true, reason: reason, theException: .None, labels: [:], stamp: Set(), callbacks: [], abort: false) } -//private func protectResults(rs : Rose) -> Rose { -// return onRose({ x in -// return { rs in -// return .IORose({ -// return .MkRose(protectResult({ x }), { rs.map(protectResults) }) -// }) -// } -// })(rs: rs) -//} -// -//internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { -// return { protect(Rose.pure • exception("Exception"))(x: f) } -//} -// -//internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { -// do { -// return try x() -// } catch let e { -// return f(e) -// } -//} -// -//private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { -// return { protect(exception("Exception"))(x: r) } -//} +private func protectResults(rs : Rose) -> Rose { + return onRose({ x in + return { rs in + return .IORose({ + return .MkRose(protectResult({ x }), { rs.map(protectResults) }) + }) + } + })(rs: rs) +} + +internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { + return { protect(Rose.pure • exception("Exception"))(x: f) } +} + +internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { + do { + return try x() + } catch let e { + return f(e) + } +} + +private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { + return { protect(exception("Exception"))(x: r) } +} private func id(x : A) -> A { return x @@ -467,14 +466,10 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose return rose2 case .None: return rose2 - default: - fatalError("Non-exhaustive switch performed") } default: fatalError("Rose should not have reduced to IORose") } - default: - fatalError("Non-exhaustive switch performed") } default: fatalError("Rose should not have reduced to IORose") @@ -536,8 +531,6 @@ private func disj(p : Rose, q : Rose) -> Rose, q : Rose) -> Rose Date: Tue, 23 Jun 2015 16:11:12 -0600 Subject: [PATCH 022/460] Test Direct instances --- SwiftCheck/Test.swift | 11 +---------- SwiftCheckTests/TestSpec.swift | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 SwiftCheckTests/TestSpec.swift diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 7ca8ca1..82428d0 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -104,7 +104,7 @@ public func forAll(gen : Gen, shrinker: A -> [A], f : A -> Testable) -> Property { +public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A -> Testable) -> Property { return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in return f(xs).counterexample(String(xs)) @@ -112,12 +112,6 @@ public func forAllShrink(gen : Gen, shrinker: A -> [A], f : A -> Testable) }) } -//public func forAll(pf : ([A] -> Testable)) -> Property { -// return forAllShrink(ArrayOf.arbitrary().fmap({ $0.getArray }), { (x : [A]) -> [[A]] in -// return ArrayOf.shrink(ArrayOf(x)).map({ $0.getArray }) -// }, pf) -//} - public func quickCheck(prop : Testable, name : String = "") { quickCheckWithResult(stdArgs(name), p: prop) } @@ -351,9 +345,6 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) return .Left(Box((stat, state))) - default: - fatalError("Pattern Match Failed: switch on a Result was inexhaustive.") - break } default: fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift new file mode 100644 index 0000000..b393659 --- /dev/null +++ b/SwiftCheckTests/TestSpec.swift @@ -0,0 +1,35 @@ +// +// TestSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 6/23/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +import XCTest +import SwiftCheck + +class TestSpec : XCTestCase { + func testAll() { + property("The reverse of the reverse of an array is that array") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + return + (xs.reverse().reverse() == xs) "Left identity" + ^&&^ + (xs == xs.reverse().reverse()) "Right identity" + } + + property("map behaves") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + return forAll { (f : ArrowOf) in + return xs.map(f.getArrow) == xs.map(f.getArrow) + } + } + + property("filter behaves") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + return forAll { (pred : ArrowOf) in + let f = pred.getArrow + return (xs.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) + } + } + } +} + From 8f067d6cf7bc397e7625167d51f5e4b4be46d81b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 23 Jun 2015 18:19:13 -0600 Subject: [PATCH 023/460] You get an instance, and you get an instance, and you get an instance, EVERYBODY GETS AN INSTANCE OF ARBITRARY (eventually). --- SwiftCheck/Arbitrary.swift | 216 +++++++++++++++++++++++++++++---- SwiftCheck/Gen.swift | 10 +- SwiftCheck/Lattice.swift | 21 ++++ SwiftCheck/Random.swift | 2 - SwiftCheckTests/TestSpec.swift | 12 ++ 5 files changed, 233 insertions(+), 28 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 5bd30c1..4c78ead 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -217,7 +217,7 @@ extension Double : Arbitrary { extension UnicodeScalar : Arbitrary { public static func arbitrary() -> Gen { - return UInt32.arbitrary().bind { Gen.pure(UnicodeScalar($0)) } + return UInt32.arbitrary().bind(Gen.pure • UnicodeScalar.init) } public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { @@ -233,35 +233,18 @@ extension String : Arbitrary { } public static func shrink(s : String) -> [String] { - return [Character].shrink([Character](s.characters)).map({ String($0) }) + return [Character].shrink([Character](s.characters)).map(String.init) } } extension Character : Arbitrary { public static func arbitrary() -> Gen { - return Gen.choose((32, 255)).bind { Gen.pure(Character(UnicodeScalar($0))) } + return Gen.choose((32, 255)).bind(Gen.pure • Character.init • UnicodeScalar.init) } public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars - return UnicodeScalar.shrink(ss[ss.startIndex]).map { Character($0) } - } -} - -/// Generates an Optional of arbitrary values of type A. -extension Optional where T : Arbitrary { - public static func arbitrary() -> Gen> { - return Gen.frequency([ - (1, Gen.pure(.None)), - (3, liftM({ .Some($0) })(m1: T.arbitrary())), - ]) - } - - public static func shrink(bl : Optional) -> [Optional] { - if let x = bl { - return [.None] + T.shrink(x).map { .Some($0) } - } - return [] + return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) } } @@ -283,6 +266,93 @@ extension Array where T : Arbitrary { } } +extension AnyBidirectionalCollection where Element : Arbitrary { + public static func arbitrary() -> Gen> { + return [Element].arbitrary().fmap(AnyBidirectionalCollection.init) + } + + public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) + } +} + +extension AnyForwardIndex : Arbitrary { + public static func arbitrary() -> Gen { + return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) + } + + public static func shrink(bl : AnyForwardIndex) -> [AnyForwardIndex] { + return [] + } +} + +extension AnyRandomAccessIndex : Arbitrary { + public static func arbitrary() -> Gen { + return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyRandomAccessIndex.init) + } + + public static func shrink(bl : AnyRandomAccessIndex) -> [AnyRandomAccessIndex] { + return [] + } +} + +extension AnySequence where T : Arbitrary { + public static func arbitrary() -> Gen> { + return [T].arbitrary().fmap(AnySequence.init) + } + + public static func shrink(bl : AnySequence) -> [AnySequence] { + return [T].shrink([Element](bl)).map(AnySequence.init) + } +} + +extension ArraySlice where T : Arbitrary { + public static func arbitrary() -> Gen> { + return [T].arbitrary().fmap(ArraySlice.init) + } + + public static func shrink(bl : ArraySlice) -> [ArraySlice] { + return [T].shrink([Element](bl)).map(ArraySlice.init) + } +} + +extension CollectionOfOne where T : Arbitrary { + public static func arbitrary() -> Gen> { + return T.arbitrary().fmap(CollectionOfOne.init) + } + + public static func shrink(bl : CollectionOfOne) -> [CollectionOfOne] { + return [] + } +} + +/// Generates an Optional of arbitrary values of type A. +extension Optional where T : Arbitrary { + public static func arbitrary() -> Gen> { + return Gen>.frequency([ + (1, Gen>.pure(.None)), + (3, liftM(Optional.Some)(m1: T.arbitrary())), + ]) + } + + public static func shrink(bl : Optional) -> [Optional] { + if let x = bl { + return [.None] + T.shrink(x).map(Optional.Some) + } + return [] + } +} + +extension ContiguousArray where T : Arbitrary { + public static func arbitrary() -> Gen> { + return [T].arbitrary().fmap(ContiguousArray.init) + } + + public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { + return [T].shrink([T](bl)).map(ContiguousArray.init) + } +} + /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { public static func arbitrary() -> Gen> { @@ -298,7 +368,6 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } - extension Dictionary { init(_ pairs : S) { self.init() @@ -309,6 +378,104 @@ extension Dictionary { } } +extension EmptyCollection : Arbitrary { + public static func arbitrary() -> Gen> { + return Gen.pure(EmptyCollection()) + } + + public static func shrink(bl : EmptyCollection) -> [EmptyCollection] { + return [] + } +} + +extension HalfOpenInterval where T : protocol { + public static func arbitrary() -> Gen> { + return T.arbitrary().bind { l in + return T.arbitrary().bind { r in + return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) + } + } + } + + public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { + return Zip2(T.shrink(bl.start), T.shrink(bl.end)).map(HalfOpenInterval.init) + } +} + +extension ImplicitlyUnwrappedOptional where T : Arbitrary { + public static func arbitrary() -> Gen> { + return Optional.arbitrary().fmap(ImplicitlyUnwrappedOptional.init) + } + + public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { + return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) + } +} + +extension LazyBidirectionalCollection where S : protocol, S.Index : BidirectionalIndexType { + public static func arbitrary() -> Gen> { + return S.arbitrary().fmap(lazy) + } + + public static func shrink(bl : LazyBidirectionalCollection) -> [LazyBidirectionalCollection] { + return [] + } +} + +extension LazyForwardCollection where S : protocol, S.Index : ForwardIndexType { + public static func arbitrary() -> Gen> { + return S.arbitrary().fmap(lazy) + } + + public static func shrink(bl : LazyForwardCollection) -> [LazyForwardCollection] { + return [] + } +} + +extension LazyRandomAccessCollection where S : protocol, S.Index : RandomAccessIndexType { + public static func arbitrary() -> Gen> { + return S.arbitrary().fmap(lazy) + } + + public static func shrink(bl : LazyRandomAccessCollection) -> [LazyRandomAccessCollection] { + return [] + } +} + +extension LazySequence where S : protocol { + public static func arbitrary() -> Gen> { + return S.arbitrary().fmap(lazy) + } + + public static func shrink(bl : LazySequence) -> [LazySequence] { + return [] + } +} + +extension Range where T : protocol { + public static func arbitrary() -> Gen> { + return T.arbitrary().bind { l in + return T.arbitrary().bind { r in + return Gen.pure(Range(start: min(l, r), end: max(l, r))) + } + } + } + + public static func shrink(bl : Range) -> [Range] { + return Zip2(T.shrink(bl.startIndex), T.shrink(bl.endIndex)).map(Range.init) + } +} + +extension Repeat where T : Arbitrary { + public static func arbitrary() -> Gen> { + return Gen.zip(Int.arbitrary(), T.arbitrary()).fmap(Repeat.init) + } + + public static func shrink(bl : Repeat) -> [Repeat] { + return [] + } +} + extension Set where T : protocol { public static func arbitrary() -> Gen> { return Gen.sized { n in @@ -317,17 +484,16 @@ extension Set where T : protocol { return Gen.pure(Set([])) } - return sequence(Array((0...k)).map { _ in T.arbitrary() }).fmap({ Set($0) }) + return sequence(Array((0...k)).map { _ in T.arbitrary() }).fmap(Set.init) } } } public static func shrink(s : Set) -> [Set] { - return [T].shrink([T](s)).map { Set($0) } + return [T].shrink([T](s)).map(Set.init) } } - /// Coarbitrary types must take an arbitrary value of their type and yield a function that /// transforms a given generator by returning a new generator that depends on the input value. Put /// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index d7364bb..0a7da80 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -23,6 +23,14 @@ public struct Gen { return unGen(r)(30) } + public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { + return gen1.bind { l in + return gen2.bind { r in + return Gen<(A, B)>.pure(l, r) + } + } + } + /// Constructs a Generator that selects a random value from the given list and produces only /// that value. /// @@ -70,7 +78,7 @@ public struct Gen { }) } - /// Constructs a random element in the range of two Integer Types. + /// Constructs a random element in the range of two `RandomType`s. /// /// When using this function, it is necessary to explicitly specialize the generic parameter /// `A`. For example: diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index eecb7c4..048fb95 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -69,6 +69,27 @@ extension Double : LatticeType { } } +extension AnyForwardIndex : LatticeType { + public static var min : AnyForwardIndex { + return AnyForwardIndex(Int64.min) + } + + public static var max : AnyForwardIndex { + return AnyForwardIndex(Int64.max) + } +} + +extension AnyRandomAccessIndex : LatticeType { + public static var min : AnyRandomAccessIndex { + return AnyRandomAccessIndex(Int64.min) + } + + public static var max : AnyRandomAccessIndex { + return AnyRandomAccessIndex(Int64.max) + } +} + + /// float.h does not export Float80's limits, nor does the Swift STL. // rdar://18404510 //extension Swift.Float80 : LatticeType { diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index cda4c9b..a894409 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -181,5 +181,3 @@ extension Double : RandomType { return (result, g); } } - - diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index b393659..18c62b4 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -11,6 +11,18 @@ import SwiftCheck class TestSpec : XCTestCase { func testAll() { + property("Dictionaries behave") <- forAllShrink(Dictionary.arbitrary(), shrinker: Dictionary.shrink) { (xs : Dictionary) in + return true + } + + property("Optionals behave") <- forAllShrink(Optional.arbitrary(), shrinker: Optional.shrink) { (xs : Int?) in + return true + } + + property("Sets behave") <- forAllShrink(Set.arbitrary(), shrinker: Set.shrink) { (xs : Set) in + return true + } + property("The reverse of the reverse of an array is that array") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in return (xs.reverse().reverse() == xs) "Left identity" From 8b6a99607cb71ca8783c7c56d386f8c8399175e9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 29 Jun 2015 23:59:57 -0600 Subject: [PATCH 024/460] Stop hogging the incredibly generic identifier "State" --- .../xcshareddata/SwiftCheck.xccheckout | 41 +++++++ SwiftCheck/Property.swift | 4 +- SwiftCheck/State.swift | 5 +- SwiftCheck/Test.swift | 112 +++++++++--------- 4 files changed, 100 insertions(+), 62 deletions(-) create mode 100644 SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout diff --git a/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout new file mode 100644 index 0000000..2206fb5 --- /dev/null +++ b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + E326D2CD-DAF2-4095-BEBC-E6E06316FA77 + IDESourceControlProjectName + SwiftCheck + IDESourceControlProjectOriginsDictionary + + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + https://github.com/CodaFi/SwiftCheck.git + + IDESourceControlProjectPath + SwiftCheck.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + ../.. + + IDESourceControlProjectURL + https://github.com/CodaFi/SwiftCheck.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + IDESourceControlWCCName + SwiftCheck + + + + diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index a254c1b..331f9f1 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -256,9 +256,9 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) /// with and the result of the test to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. - case AfterTest(kind : CallbackKind, f : (State, TestResult) -> ()) + case AfterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) /// The callback is posted after all cases in the test have failed. - case AfterFinalFailure(kind : CallbackKind, f : (State, TestResult) -> ()) + case AfterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index 530fe5f..d87dac1 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -6,10 +6,7 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - -public struct Terminal {} - -public struct State { +public struct CheckerState { let name : String let maxSuccessTests : Int let maxDiscardedTests : Int diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 82428d0..c72db9b 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -205,20 +205,20 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } - let state = State(name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard - , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 - , labels: [:] - , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 - , shouldAbort: false) + let state = CheckerState( name: args.name + , maxSuccessTests: args.maxSuccess + , maxDiscardedTests: args.maxDiscard + , computeSize: computeSize + , numSuccessTests: 0 + , numDiscardedTests: 0 + , labels: [:] + , collected: [] + , expectedFailure: false + , randomSeed: rnd() + , numSuccessShrinks: 0 + , numTryShrinks: 0 + , numTotTryShrinks: 0 + , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property().once : p.property()) return test(state, f: modP.unProperty.unGen) } @@ -232,7 +232,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { // - doneTesting: Invoked when testing the property fails or succeeds once and for all. // - giveUp: When the number of discarded tests exceeds the number given in the arguments we just // give up turning the run loop to prevent excessive generation. -internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { +internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { var state = st while true { switch runATest(state)(f: f) { @@ -261,7 +261,7 @@ internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { // Executes a single test of the property given an initial state and the generator function. // // On success the next state is returned. On failure the final result and state are returned. -internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Result, State), State> { +internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.numSuccessTests)(st.numDiscardedTests) let (rnd1, rnd2) = st.randomSeed.split() @@ -274,38 +274,38 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul switch res.match() { // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): - let state = State(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests + 1 - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + 1 + , numDiscardedTests: st.numDiscardedTests + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , expectedFailure: expect + , randomSeed: st.randomSeed + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) - return .Right(Box(state)) + return .Right(Box(nstate)) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): - let state = State(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) - return .Right(Box(state)) + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + 1 + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , expectedFailure: expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) + return .Right(Box(nstate)) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): if !expect { @@ -330,7 +330,7 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , labels: summary(st) , output: "*** Failed! ") - let state = State(name: st.name + let state = CheckerState(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize @@ -352,7 +352,7 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul } } -internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { if st.expectedFailure { print("*** Passed " + "\(st.numSuccessTests)" + " tests") printDistributionGraph(st) @@ -363,7 +363,7 @@ internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { } } -internal func giveUp(st: State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { printDistributionGraph(st) return Result.GaveUp(numTests: st.numSuccessTests, labels: summary(st), output: "") } @@ -377,7 +377,7 @@ internal func giveUp(st: State)(f : (StdGen -> Int -> Prop)) -> Result { // for complex shrinks (much like `split` in the Swift STL), and was slow as hell. This way we stay // in one stack frame no matter what and give ARC a chance to cleanup after us. Plus we get to // stay within a reasonable ~50-100 megabytes for truly horrendous tests that used to eat 8 gigs. -internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { +internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") } @@ -429,7 +429,7 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros numSuccessShrinks++ } - let state = State(name: st.name + let state = CheckerState(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize @@ -446,7 +446,7 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros return reportMinimumCaseFound(state, res: lastResult) } -internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, Int) { +internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { let testMsg = " (after \(st.numSuccessTests + 1) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" @@ -463,7 +463,7 @@ internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) } -internal func dispatchAfterTestCallbacks(st : State, res : TestResult) { +internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { for c in res.callbacks { switch c { case let .AfterTest(_, f): @@ -474,7 +474,7 @@ internal func dispatchAfterTestCallbacks(st : State, res : TestResult) { } } -internal func dispatchAfterFinalFailureCallbacks(st : State, res : TestResult) { +internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { for c in res.callbacks { switch c { case let .AfterFinalFailure(_, f): @@ -485,18 +485,18 @@ internal func dispatchAfterFinalFailureCallbacks(st : State, res : TestResult) { } } -internal func summary(s : State) -> [(String, Int)] { +internal func summary(s : CheckerState) -> [(String, Int)] { let strings = s.collected.flatMap({ l in Array(l).map({ "," + $0.0 }).filter({ !$0.isEmpty }) }) let l = strings.sort().groupBy(==) return l.map({ ss in (ss[0], ss.count * 100 / s.numSuccessTests) }) } -internal func labelPercentage(l : String, st : State) -> Int { +internal func labelPercentage(l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap({ Array($0) }).filter({ $0 == l }).count return (100 * occur) / st.maxSuccessTests } -internal func printDistributionGraph(st : State) { +internal func printDistributionGraph(st : CheckerState) { func showP(n : Int) -> String { return (n < 10 ? " " : "") + "\(n)" + "% " } From b0fed6f1bc83c65a5c3a599e40d7f5453015b6fe Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 30 Jun 2015 00:01:19 -0600 Subject: [PATCH 025/460] Stop hogging the incredibly generic identifier "State" --- .../xcshareddata/SwiftCheck.xccheckout | 41 +++++++ SwiftCheck/Property.swift | 4 +- SwiftCheck/State.swift | 5 +- SwiftCheck/Test.swift | 112 +++++++++--------- 4 files changed, 100 insertions(+), 62 deletions(-) create mode 100644 SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout diff --git a/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout new file mode 100644 index 0000000..2206fb5 --- /dev/null +++ b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + E326D2CD-DAF2-4095-BEBC-E6E06316FA77 + IDESourceControlProjectName + SwiftCheck + IDESourceControlProjectOriginsDictionary + + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + https://github.com/CodaFi/SwiftCheck.git + + IDESourceControlProjectPath + SwiftCheck.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + ../.. + + IDESourceControlProjectURL + https://github.com/CodaFi/SwiftCheck.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 53964F28C4CCA0826677C9F951DD3F64C20326C4 + IDESourceControlWCCName + SwiftCheck + + + + diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index a254c1b..331f9f1 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -256,9 +256,9 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) /// with and the result of the test to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. - case AfterTest(kind : CallbackKind, f : (State, TestResult) -> ()) + case AfterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) /// The callback is posted after all cases in the test have failed. - case AfterFinalFailure(kind : CallbackKind, f : (State, TestResult) -> ()) + case AfterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index 530fe5f..d87dac1 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -6,10 +6,7 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - -public struct Terminal {} - -public struct State { +public struct CheckerState { let name : String let maxSuccessTests : Int let maxDiscardedTests : Int diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 82428d0..c72db9b 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -205,20 +205,20 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } - let state = State(name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard - , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 - , labels: [:] - , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 - , shouldAbort: false) + let state = CheckerState( name: args.name + , maxSuccessTests: args.maxSuccess + , maxDiscardedTests: args.maxDiscard + , computeSize: computeSize + , numSuccessTests: 0 + , numDiscardedTests: 0 + , labels: [:] + , collected: [] + , expectedFailure: false + , randomSeed: rnd() + , numSuccessShrinks: 0 + , numTryShrinks: 0 + , numTotTryShrinks: 0 + , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property().once : p.property()) return test(state, f: modP.unProperty.unGen) } @@ -232,7 +232,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { // - doneTesting: Invoked when testing the property fails or succeeds once and for all. // - giveUp: When the number of discarded tests exceeds the number given in the arguments we just // give up turning the run loop to prevent excessive generation. -internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { +internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { var state = st while true { switch runATest(state)(f: f) { @@ -261,7 +261,7 @@ internal func test(st : State, f : (StdGen -> Int -> Prop)) -> Result { // Executes a single test of the property given an initial state and the generator function. // // On success the next state is returned. On failure the final result and state are returned. -internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Result, State), State> { +internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.numSuccessTests)(st.numDiscardedTests) let (rnd1, rnd2) = st.randomSeed.split() @@ -274,38 +274,38 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul switch res.match() { // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): - let state = State(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests + 1 - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + 1 + , numDiscardedTests: st.numDiscardedTests + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , expectedFailure: expect + , randomSeed: st.randomSeed + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) - return .Right(Box(state)) + return .Right(Box(nstate)) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): - let state = State(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) - return .Right(Box(state)) + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + 1 + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , expectedFailure: expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) + return .Right(Box(nstate)) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): if !expect { @@ -330,7 +330,7 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul , labels: summary(st) , output: "*** Failed! ") - let state = State(name: st.name + let state = CheckerState(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize @@ -352,7 +352,7 @@ internal func runATest(st : State)(f : (StdGen -> Int -> Prop)) -> Either<(Resul } } -internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { if st.expectedFailure { print("*** Passed " + "\(st.numSuccessTests)" + " tests") printDistributionGraph(st) @@ -363,7 +363,7 @@ internal func doneTesting(st : State)(f : (StdGen -> Int -> Prop)) -> Result { } } -internal func giveUp(st: State)(f : (StdGen -> Int -> Prop)) -> Result { +internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { printDistributionGraph(st) return Result.GaveUp(numTests: st.numSuccessTests, labels: summary(st), output: "") } @@ -377,7 +377,7 @@ internal func giveUp(st: State)(f : (StdGen -> Int -> Prop)) -> Result { // for complex shrinks (much like `split` in the Swift STL), and was slow as hell. This way we stay // in one stack frame no matter what and give ARC a chance to cleanup after us. Plus we get to // stay within a reasonable ~50-100 megabytes for truly horrendous tests that used to eat 8 gigs. -internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { +internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") } @@ -429,7 +429,7 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros numSuccessShrinks++ } - let state = State(name: st.name + let state = CheckerState(name: st.name , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize @@ -446,7 +446,7 @@ internal func findMinimalFailingTestCase(st : State, res : TestResult, ts : [Ros return reportMinimumCaseFound(state, res: lastResult) } -internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, Int) { +internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { let testMsg = " (after \(st.numSuccessTests + 1) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" @@ -463,7 +463,7 @@ internal func reportMinimumCaseFound(st : State, res : TestResult) -> (Int, Int, return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) } -internal func dispatchAfterTestCallbacks(st : State, res : TestResult) { +internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { for c in res.callbacks { switch c { case let .AfterTest(_, f): @@ -474,7 +474,7 @@ internal func dispatchAfterTestCallbacks(st : State, res : TestResult) { } } -internal func dispatchAfterFinalFailureCallbacks(st : State, res : TestResult) { +internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { for c in res.callbacks { switch c { case let .AfterFinalFailure(_, f): @@ -485,18 +485,18 @@ internal func dispatchAfterFinalFailureCallbacks(st : State, res : TestResult) { } } -internal func summary(s : State) -> [(String, Int)] { +internal func summary(s : CheckerState) -> [(String, Int)] { let strings = s.collected.flatMap({ l in Array(l).map({ "," + $0.0 }).filter({ !$0.isEmpty }) }) let l = strings.sort().groupBy(==) return l.map({ ss in (ss[0], ss.count * 100 / s.numSuccessTests) }) } -internal func labelPercentage(l : String, st : State) -> Int { +internal func labelPercentage(l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap({ Array($0) }).filter({ $0 == l }).count return (100 * occur) / st.maxSuccessTests } -internal func printDistributionGraph(st : State) { +internal func printDistributionGraph(st : CheckerState) { func showP(n : Int) -> String { return (n < 10 ? " " : "") + "\(n)" + "% " } From 4fcc7fffc736e2ebdce5f84045936cb6c9eb461b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 30 Jun 2015 00:05:37 -0600 Subject: [PATCH 026/460] GTFO --- .../xcshareddata/SwiftCheck.xccheckout | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout diff --git a/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout deleted file mode 100644 index 2206fb5..0000000 --- a/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/SwiftCheck.xccheckout +++ /dev/null @@ -1,41 +0,0 @@ - - - - - IDESourceControlProjectFavoriteDictionaryKey - - IDESourceControlProjectIdentifier - E326D2CD-DAF2-4095-BEBC-E6E06316FA77 - IDESourceControlProjectName - SwiftCheck - IDESourceControlProjectOriginsDictionary - - 53964F28C4CCA0826677C9F951DD3F64C20326C4 - https://github.com/CodaFi/SwiftCheck.git - - IDESourceControlProjectPath - SwiftCheck.xcodeproj - IDESourceControlProjectRelativeInstallPathDictionary - - 53964F28C4CCA0826677C9F951DD3F64C20326C4 - ../.. - - IDESourceControlProjectURL - https://github.com/CodaFi/SwiftCheck.git - IDESourceControlProjectVersion - 111 - IDESourceControlProjectWCCIdentifier - 53964F28C4CCA0826677C9F951DD3F64C20326C4 - IDESourceControlProjectWCConfigurations - - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - 53964F28C4CCA0826677C9F951DD3F64C20326C4 - IDESourceControlWCCName - SwiftCheck - - - - From 082be0514d1a9c73ffb89c58f648487d7bfd278a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 30 Jun 2015 00:05:48 -0600 Subject: [PATCH 027/460] Bye felicia --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1cc3218..a2298be 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ DerivedData *.hmap *.xcuserstate Carthage/ + +*.xccheckout From 1d51bac8ec9e24d2c28626b724545742d96efedd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 21:23:15 -0600 Subject: [PATCH 028/460] Add IsoOf to generate isomorphic functions --- SwiftCheck/Modifiers.swift | 76 ++++++++++++++++++++++++++++++ SwiftCheckTests/ModifierSpec.swift | 9 +++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index f02892b..6666fdd 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -273,6 +273,82 @@ public struct ArrowOf, U : Arbitrary> : Arbi } } +/// Generates two isomorphic Swift function from T to U and back again. +public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { + private var table : Dictionary + private var embed : T -> U + private var project : U -> T + + public var getTo : T -> U { + return embed + } + + public var getFrom : U -> T { + return project + } + + private init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { + self.table = table + self.embed = embed + self.project = project + } + + public init(_ embed : (T -> U), _ project : (U -> T)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + + self.embed = { t in + if let v = self.table[t] { + return v + } + let y = embed(t) + self.table[t] = y + return y + } + + self.project = { u in + let t = self.table.filter { $1.hashValue == u.hashValue }.map { $0.0 } + if let k = t.first, _ = self.table[k] { + return k + } + let y = project(u) + self.table[y] = u + return y + } + } + + public var description : String { + return "\(T.self) -> \(U.self)" + } + + public static func arbitrary() -> Gen> { + return Gen<(T -> U, U -> T)>.zip(promote({ a in + return T.coarbitrary(a)(U.arbitrary()) + }), promote({ a in + return U.coarbitrary(a)(T.arbitrary()) + })).fmap { IsoOf($0, $1) } + } + + public static func shrink(f : IsoOf) -> [IsoOf] { + var xxs : [IsoOf] = [] + for (x, y) in f.table { + xxs += Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in + return IsoOf({ (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) + }) + }) + } + return xxs + } +} + private func undefined() -> A { fatalError("") } diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index daf36f6..0e98f3f 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -34,7 +34,7 @@ class ModifierSpec : XCTestCase { property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in return true } - + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in return (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" @@ -45,6 +45,13 @@ class ModifierSpec : XCTestCase { property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) } + + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in + return + iso.getFrom(iso.getTo(x)) == x + ^&&^ + iso.getTo(iso.getFrom(y)) == y + } property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow From 07676b6709711c4316900e7c6d41cfdf2a7e5065 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 21:29:01 -0600 Subject: [PATCH 029/460] Add CustomReflectable instance for easier arrow debugging --- SwiftCheck/Modifiers.swift | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 6666fdd..c2183e9 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -273,6 +273,15 @@ public struct ArrowOf, U : Arbitrary> : Arbi } } +extension ArrowOf : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self.table, + ]) + } +} + /// Generates two isomorphic Swift function from T to U and back again. public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { private var table : Dictionary @@ -306,8 +315,8 @@ public struct IsoOf, U : protocol } self.project = { u in - let t = self.table.filter { $1.hashValue == u.hashValue }.map { $0.0 } - if let k = t.first, _ = self.table[k] { + let ts = self.table.filter { $1.hashValue == u.hashValue }.map { $0.0 } + if let k = ts.first, _ = self.table[k] { return k } let y = project(u) @@ -317,7 +326,7 @@ public struct IsoOf, U : protocol } public var description : String { - return "\(T.self) -> \(U.self)" + return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" } public static func arbitrary() -> Gen> { @@ -349,6 +358,16 @@ public struct IsoOf, U : protocol } } +extension IsoOf : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self.table, + ]) + } +} + private func undefined() -> A { fatalError("") } From c446ce178f9549bf9f4820f0d0689d5d6c08a34b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 21:33:27 -0600 Subject: [PATCH 030/460] Loops -> flatMap --- SwiftCheck/Modifiers.swift | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index c2183e9..a637b86 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -258,9 +258,8 @@ public struct ArrowOf, U : Arbitrary> : Arbi } public static func shrink(f : ArrowOf) -> [ArrowOf] { - var xxs : [ArrowOf] = [] - for (x, y) in f.table { - xxs += U.shrink(y).map({ (y2 : U) -> ArrowOf in + return f.table.flatMap { (x, y) in + return U.shrink(y).map({ (y2 : U) -> ArrowOf in return ArrowOf({ (z : T) -> U in if x == z { return y2 @@ -269,7 +268,6 @@ public struct ArrowOf, U : Arbitrary> : Arbi }) }) } - return xxs } } @@ -315,7 +313,7 @@ public struct IsoOf, U : protocol } self.project = { u in - let ts = self.table.filter { $1.hashValue == u.hashValue }.map { $0.0 } + let ts = self.table.filter { $1 == u }.map { $0.0 } if let k = ts.first, _ = self.table[k] { return k } @@ -338,9 +336,8 @@ public struct IsoOf, U : protocol } public static func shrink(f : IsoOf) -> [IsoOf] { - var xxs : [IsoOf] = [] - for (x, y) in f.table { - xxs += Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in + return f.table.flatMap { (x, y) in + return Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in return IsoOf({ (z : T) -> U in if x == z { return y2 @@ -354,7 +351,6 @@ public struct IsoOf, U : protocol }) }) } - return xxs } } From ef3a6ace82c4f9bb87c9b9780f1a0b6b9d752d29 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 21:51:18 -0600 Subject: [PATCH 031/460] Make `shrink` optional --- SwiftCheck/Arbitrary.swift | 185 +++++++++++++----------------- SwiftCheck/Modifiers.swift | 228 ++++++++++++++++++------------------- 2 files changed, 189 insertions(+), 224 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 4c78ead..f05fe26 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -11,7 +11,7 @@ import Darwin /// A type that implements random generation and shrinking of values. /// /// While testing, SwiftCheck will invoke `arbitrary()` a given amount of times (usually 100 if the -/// default settings are used). During that time, the receiver has an opportunity to call through +/// default settings are used). During that time, the receiver has an opportunity to call through /// to any data or sources of randomness it needs to return what it deems an "Arbitrary" value. /// /// Shrinking is reduction in the complexity of a tested value to remove noise and present a minimal @@ -36,28 +36,31 @@ public protocol Arbitrary { static func shrink(Self) -> [Self] } -/// The implementation of a shrink that returns no alternatives. -public func shrinkNone(_ : A) -> [A] { - return [] +extension Arbitrary { + /// The implementation of a shrink that returns no alternatives. + public static func shrink(Self) -> [Self] { + return [] + } } -/// Shrinks any IntegerType. -public func shrinkIntegral(x : A) -> [A] { - return unfoldr({ i in - if i <= 0 { - return .None - } - let n = i / 2 - return .Some((n, n)) - }, initial: x < 0 ? (x * -1) : x) +extension IntegerType { + /// Shrinks any IntegerType. + public var shrinkIntegral : [Self] { + return unfoldr({ i in + if i <= 0 { + return .None + } + let n = i / 2 + return .Some((n, n)) + }, initial: self < 0 ? (self * -1) : self) + } } - extension Bool : Arbitrary { public static func arbitrary() -> Gen { return Gen.pure((arc4random() % 2) == 1) } - + public static func shrink(x : Bool) -> [Bool] { if x { return [false] @@ -71,9 +74,9 @@ extension Int : Arbitrary { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int(arc4random_uniform(UInt32(n)))) } } - + public static func shrink(x : Int) -> [Int] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -82,9 +85,9 @@ extension Int8 : Arbitrary { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int8(arc4random_uniform(UInt32(n)))) } } - + public static func shrink(x : Int8) -> [Int8] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -93,9 +96,9 @@ extension Int16 : Arbitrary { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int16(arc4random_uniform(UInt32(n)))) } } - + public static func shrink(x : Int16) -> [Int16] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -104,9 +107,9 @@ extension Int32 : Arbitrary { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int32(arc4random_uniform(UInt32(n)))) } } - + public static func shrink(x : Int32) -> [Int32] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -115,9 +118,9 @@ extension Int64 : Arbitrary { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int64(arc4random_uniform(UInt32(n)))) } } - + public static func shrink(x : Int64) -> [Int64] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -125,9 +128,9 @@ extension UInt : Arbitrary { public static func arbitrary() -> Gen { return Gen.sized { n in Gen.pure(UInt(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt) -> [UInt] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -137,9 +140,9 @@ extension UInt8 : Arbitrary { return Gen.sized { n in Gen.pure(UInt8(arc4random_uniform(UInt32(abs(n))))) } }) } - + public static func shrink(x : UInt8) -> [UInt8] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -147,9 +150,9 @@ extension UInt16 : Arbitrary { public static func arbitrary() -> Gen { return Gen.sized { n in Gen.pure(UInt16(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt16) -> [UInt16] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -157,9 +160,9 @@ extension UInt32 : Arbitrary { public static func arbitrary() -> Gen { return Gen.sized { n in Gen.pure(arc4random_uniform(UInt32(abs(n)))) } } - + public static func shrink(x : UInt32) -> [UInt32] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -167,9 +170,9 @@ extension UInt64 : Arbitrary { public static func arbitrary() -> Gen { return Gen.sized { n in Gen.pure(UInt64(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt64) -> [UInt64] { - return shrinkIntegral(x) + return x.shrinkIntegral } } @@ -182,7 +185,7 @@ extension Float : Arbitrary { return Gen.pure(Float(-n) + Float(arc4random()) / Float(UINT32_MAX / UInt32((n)*2))) }) } - + public static func shrink(x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { @@ -203,7 +206,7 @@ extension Double : Arbitrary { return Gen.pure(Double(-n) + Double(arc4random()) / Double(UINT32_MAX / UInt32(n*2))) }) } - + public static func shrink(x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { @@ -219,7 +222,7 @@ extension UnicodeScalar : Arbitrary { public static func arbitrary() -> Gen { return UInt32.arbitrary().bind(Gen.pure • UnicodeScalar.init) } - + public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) return nub([ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ]).filter { $0 < x } @@ -231,7 +234,7 @@ extension String : Arbitrary { let chars = Gen.sized({ n in Character.arbitrary().proliferateSized(n) }) return chars.bind { ls in Gen.pure(String(ls)) } } - + public static func shrink(s : String) -> [String] { return [Character].shrink([Character](s.characters)).map(String.init) } @@ -241,7 +244,7 @@ extension Character : Arbitrary { public static func arbitrary() -> Gen { return Gen.choose((32, 255)).bind(Gen.pure • Character.init • UnicodeScalar.init) } - + public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) @@ -255,12 +258,12 @@ extension Array where T : Arbitrary { if k == 0 { return Gen.pure([]) } - + return sequence((0...k).map { _ in T.arbitrary() }) } } } - + public static func shrink(bl : Array) -> [[T]] { return Int.shrink(bl.count).reverse().flatMap({ k in removes(k + 1, n: bl.count, xs: bl) }) + shrinkOne(bl) } @@ -270,7 +273,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { public static func arbitrary() -> Gen> { return [Element].arbitrary().fmap(AnyBidirectionalCollection.init) } - + public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } @@ -280,27 +283,19 @@ extension AnyForwardIndex : Arbitrary { public static func arbitrary() -> Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) } - - public static func shrink(bl : AnyForwardIndex) -> [AnyForwardIndex] { - return [] - } } extension AnyRandomAccessIndex : Arbitrary { public static func arbitrary() -> Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyRandomAccessIndex.init) } - - public static func shrink(bl : AnyRandomAccessIndex) -> [AnyRandomAccessIndex] { - return [] - } } extension AnySequence where T : Arbitrary { public static func arbitrary() -> Gen> { return [T].arbitrary().fmap(AnySequence.init) } - + public static func shrink(bl : AnySequence) -> [AnySequence] { return [T].shrink([Element](bl)).map(AnySequence.init) } @@ -310,7 +305,7 @@ extension ArraySlice where T : Arbitrary { public static func arbitrary() -> Gen> { return [T].arbitrary().fmap(ArraySlice.init) } - + public static func shrink(bl : ArraySlice) -> [ArraySlice] { return [T].shrink([Element](bl)).map(ArraySlice.init) } @@ -320,10 +315,6 @@ extension CollectionOfOne where T : Arbitrary { public static func arbitrary() -> Gen> { return T.arbitrary().fmap(CollectionOfOne.init) } - - public static func shrink(bl : CollectionOfOne) -> [CollectionOfOne] { - return [] - } } /// Generates an Optional of arbitrary values of type A. @@ -332,9 +323,9 @@ extension Optional where T : Arbitrary { return Gen>.frequency([ (1, Gen>.pure(.None)), (3, liftM(Optional.Some)(m1: T.arbitrary())), - ]) + ]) } - + public static func shrink(bl : Optional) -> [Optional] { if let x = bl { return [.None] + T.shrink(x).map(Optional.Some) @@ -347,7 +338,7 @@ extension ContiguousArray where T : Arbitrary { public static func arbitrary() -> Gen> { return [T].arbitrary().fmap(ContiguousArray.init) } - + public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { return [T].shrink([T](bl)).map(ContiguousArray.init) } @@ -362,7 +353,7 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } } - + public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2(Key.shrink($0), Value.shrink($1))) } } @@ -382,10 +373,6 @@ extension EmptyCollection : Arbitrary { public static func arbitrary() -> Gen> { return Gen.pure(EmptyCollection()) } - - public static func shrink(bl : EmptyCollection) -> [EmptyCollection] { - return [] - } } extension HalfOpenInterval where T : protocol { @@ -396,7 +383,7 @@ extension HalfOpenInterval where T : protocol { } } } - + public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { return Zip2(T.shrink(bl.start), T.shrink(bl.end)).map(HalfOpenInterval.init) } @@ -406,7 +393,7 @@ extension ImplicitlyUnwrappedOptional where T : Arbitrary { public static func arbitrary() -> Gen> { return Optional.arbitrary().fmap(ImplicitlyUnwrappedOptional.init) } - + public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) } @@ -416,40 +403,24 @@ extension LazyBidirectionalCollection where S : protocol Gen> { return S.arbitrary().fmap(lazy) } - - public static func shrink(bl : LazyBidirectionalCollection) -> [LazyBidirectionalCollection] { - return [] - } } extension LazyForwardCollection where S : protocol, S.Index : ForwardIndexType { public static func arbitrary() -> Gen> { return S.arbitrary().fmap(lazy) } - - public static func shrink(bl : LazyForwardCollection) -> [LazyForwardCollection] { - return [] - } } extension LazyRandomAccessCollection where S : protocol, S.Index : RandomAccessIndexType { public static func arbitrary() -> Gen> { return S.arbitrary().fmap(lazy) } - - public static func shrink(bl : LazyRandomAccessCollection) -> [LazyRandomAccessCollection] { - return [] - } } extension LazySequence where S : protocol { public static func arbitrary() -> Gen> { return S.arbitrary().fmap(lazy) } - - public static func shrink(bl : LazySequence) -> [LazySequence] { - return [] - } } extension Range where T : protocol { @@ -460,7 +431,7 @@ extension Range where T : protocol { } } } - + public static func shrink(bl : Range) -> [Range] { return Zip2(T.shrink(bl.startIndex), T.shrink(bl.endIndex)).map(Range.init) } @@ -470,10 +441,6 @@ extension Repeat where T : Arbitrary { public static func arbitrary() -> Gen> { return Gen.zip(Int.arbitrary(), T.arbitrary()).fmap(Repeat.init) } - - public static func shrink(bl : Repeat) -> [Repeat] { - return [] - } } extension Set where T : protocol { @@ -483,18 +450,18 @@ extension Set where T : protocol { if k == 0 { return Gen.pure(Set([])) } - + return sequence(Array((0...k)).map { _ in T.arbitrary() }).fmap(Set.init) } } } - + public static func shrink(s : Set) -> [Set] { return [T].shrink([T](s)).map(Set.init) } } -/// Coarbitrary types must take an arbitrary value of their type and yield a function that +/// Coarbitrary types must take an arbitrary value of their type and yield a function that /// transforms a given generator by returning a new generator that depends on the input value. Put /// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. /// @@ -504,9 +471,11 @@ public protocol CoArbitrary { static func coarbitrary(x : Self) -> (Gen -> Gen) } -/// A corarbitrary implementation for any IntegerType -public func coarbitraryIntegral(x : A) -> Gen -> Gen { - return { $0.variant(x) } +extension IntegerType { + /// A corarbitrary implementation for any IntegerType + public func coarbitraryIntegral() -> Gen -> Gen { + return { $0.variant(self) } + } } /// A coarbitrary implementation for any Printable type. Avoid using this function if you can, it @@ -517,7 +486,7 @@ public func coarbitraryPrintable(x : A) -> Gen -> Gen { extension Bool : CoArbitrary { public static func coarbitrary(x : Bool) -> Gen -> Gen { - return { g in + return { g in if x { return g.variant(1) } @@ -550,74 +519,74 @@ extension String : CoArbitrary { extension Int : CoArbitrary { public static func coarbitrary(x : Int) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { public static func coarbitrary(x : Int8) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { public static func coarbitrary(x : Int16) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { public static func coarbitrary(x : Int32) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { public static func coarbitrary(x : Int64) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { public static func coarbitrary(x : UInt) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { public static func coarbitrary(x : UInt8) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { public static func coarbitrary(x : UInt16) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { public static func coarbitrary(x : UInt32) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { public static func coarbitrary(x : UInt64) -> Gen -> Gen { - return coarbitraryIntegral(x) + return x.coarbitraryIntegral() } } // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { public static func coarbitrary(x : Float) -> (Gen -> Gen) { - return coarbitraryIntegral(Int64(x)) + return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { public static func coarbitrary(x : Double) -> (Gen -> Gen) { - return coarbitraryIntegral(Int64(x)) + return Int64(x).coarbitraryIntegral() } } @@ -691,7 +660,7 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { let xs1 = take(k, xs: xs) let xs2 = drop(k, xs: xs) - + if k > n { return [] } else if xs2.isEmpty { diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index a637b86..9c4aacc 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -59,10 +59,6 @@ public struct Static : Arbitrary, CustomStringConvertible { public static func arbitrary() -> Gen> { return A.arbitrary().fmap(Static.create) } - - public static func shrink(bl : Static) -> [Static] { - return [] - } } extension Static : CoArbitrary { @@ -78,23 +74,23 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getArray) } - + public init(_ array : [A]) { self.getArray = array } - + public var description : String { return "\(self.getArray)" } - + private static func create(array : [A]) -> ArrayOf { return ArrayOf(array) } - + public static func arbitrary() -> Gen> { return Array.arbitrary().fmap(ArrayOf.init) } - + public static func shrink(bl : ArrayOf) -> [ArrayOf] { return Array.shrink(bl.getArray).map(ArrayOf.init) } @@ -113,23 +109,23 @@ extension ArrayOf : CoArbitrary { /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { public let getDictionary : Dictionary - + public init(_ dict : Dictionary) { self.getDictionary = dict } - + public var description : String { return "\(self.getDictionary)" } - + private static func create(dict : Dictionary) -> DictionaryOf { return DictionaryOf(dict) } - + public static func arbitrary() -> Gen> { return Dictionary.arbitrary().fmap(DictionaryOf.init) } - + public static func shrink(d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } @@ -144,23 +140,23 @@ extension DictionaryOf : CoArbitrary { /// Generates an Optional of arbitrary values of type A. public struct OptionalOf : Arbitrary, CustomStringConvertible { public let getOptional : A? - + public init(_ opt : A?) { self.getOptional = opt } - + public var description : String { return "\(self.getOptional)" } - + private static func create(opt : A?) -> OptionalOf { return OptionalOf(opt) } - + public static func arbitrary() -> Gen> { return Optional.arbitrary().fmap(OptionalOf.init) } - + public static func shrink(bl : OptionalOf) -> [OptionalOf] { return Optional.shrink(bl.getOptional).map(OptionalOf.init) } @@ -178,31 +174,31 @@ extension OptionalOf : CoArbitrary { /// Generates a set of arbitrary values of type A. public struct SetOf> : Arbitrary, CustomStringConvertible { public let getSet : Set - + public init(_ set : Set) { self.getSet = set } - + public var description : String { return "\(self.getSet)" } - + private static func create(set : Set) -> SetOf{ return SetOf(set) } - + public static func arbitrary() -> Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure(SetOf(Set([]))) } - + return sequence(Array((0...k)).map { _ in A.arbitrary() }).fmap({ SetOf.create(Set($0)) }) } } } - + public static func shrink(s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } @@ -224,12 +220,12 @@ public struct ArrowOf, U : Arbitrary> : Arbi public var getArrow : T -> U { return self.arr } - + private init (_ table : Dictionary, _ arr : (T -> U)) { self.table = table self.arr = arr } - + public init(_ arr : (T -> U)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) @@ -242,21 +238,21 @@ public struct ArrowOf, U : Arbitrary> : Arbi return y } } - + public var description : String { return "\(T.self) -> \(U.self)" } - + private static func create(arr : (T -> U)) -> ArrowOf { return ArrowOf(arr) } - + public static func arbitrary() -> Gen> { return promote({ a in return T.coarbitrary(a)(U.arbitrary()) }).fmap({ ArrowOf($0) }) } - + public static func shrink(f : ArrowOf) -> [ArrowOf] { return f.table.flatMap { (x, y) in return U.shrink(y).map({ (y2 : U) -> ArrowOf in @@ -272,96 +268,96 @@ public struct ArrowOf, U : Arbitrary> : Arbi } extension ArrowOf : CustomReflectable { - public func customMirror() -> Mirror { - return Mirror(self, children: [ - "types": "\(T.self) -> \(U.self)", - "currentMap": self.table, - ]) - } + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self.table, + ]) + } } /// Generates two isomorphic Swift function from T to U and back again. public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { - private var table : Dictionary - private var embed : T -> U - private var project : U -> T - - public var getTo : T -> U { - return embed - } - - public var getFrom : U -> T { - return project - } - - private init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { - self.table = table - self.embed = embed - self.project = project - } - - public init(_ embed : (T -> U), _ project : (U -> T)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - - self.embed = { t in - if let v = self.table[t] { - return v - } - let y = embed(t) - self.table[t] = y - return y - } - - self.project = { u in - let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self.table[k] { - return k - } - let y = project(u) - self.table[y] = u - return y - } - } - - public var description : String { - return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" - } - - public static func arbitrary() -> Gen> { - return Gen<(T -> U, U -> T)>.zip(promote({ a in - return T.coarbitrary(a)(U.arbitrary()) - }), promote({ a in - return U.coarbitrary(a)(T.arbitrary()) - })).fmap { IsoOf($0, $1) } - } - - public static func shrink(f : IsoOf) -> [IsoOf] { - return f.table.flatMap { (x, y) in - return Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in - return IsoOf({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) - }, { (z : U) -> T in - if y == z { - return y1 - } - return f.project(z) - }) - }) - } - } + private var table : Dictionary + private var embed : T -> U + private var project : U -> T + + public var getTo : T -> U { + return embed + } + + public var getFrom : U -> T { + return project + } + + private init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { + self.table = table + self.embed = embed + self.project = project + } + + public init(_ embed : (T -> U), _ project : (U -> T)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + + self.embed = { t in + if let v = self.table[t] { + return v + } + let y = embed(t) + self.table[t] = y + return y + } + + self.project = { u in + let ts = self.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, _ = self.table[k] { + return k + } + let y = project(u) + self.table[y] = u + return y + } + } + + public var description : String { + return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" + } + + public static func arbitrary() -> Gen> { + return Gen<(T -> U, U -> T)>.zip(promote({ a in + return T.coarbitrary(a)(U.arbitrary()) + }), promote({ a in + return U.coarbitrary(a)(T.arbitrary()) + })).fmap { IsoOf($0, $1) } + } + + public static func shrink(f : IsoOf) -> [IsoOf] { + return f.table.flatMap { (x, y) in + return Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in + return IsoOf({ (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) + }) + }) + } + } } extension IsoOf : CustomReflectable { - public func customMirror() -> Mirror { - return Mirror(self, children: [ - "embed": "\(T.self) -> \(U.self)", - "project": "\(U.self) -> \(T.self)", - "currentMap": self.table, - ]) - } + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self.table, + ]) + } } private func undefined() -> A { @@ -427,7 +423,7 @@ public struct NonZero> : Arbitrary, CustomS extension NonZero : CoArbitrary { public static func coarbitrary(x : NonZero) -> (Gen -> Gen) { - return coarbitraryIntegral(x.getNonZero) + return x.getNonZero.coarbitraryIntegral() } } @@ -458,6 +454,6 @@ public struct NonNegative> : Arbitrary, Cus extension NonNegative : CoArbitrary { public static func coarbitrary(x : NonNegative) -> (Gen -> Gen) { - return coarbitraryIntegral(x.getNonNegative) + return x.getNonNegative.coarbitraryIntegral() } } From 13942add8872d611f63d9c074cc0c282ee4790e6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 22:07:50 -0600 Subject: [PATCH 032/460] Make `arbitrary` a static var --- SwiftCheck/Arbitrary.swift | 124 ++++++++++++++++--------------- SwiftCheck/Modifiers.swift | 46 ++++++------ SwiftCheck/Test.swift | 2 +- SwiftCheckTests/GenSpec.swift | 10 +-- SwiftCheckTests/SimpleSpec.swift | 6 +- SwiftCheckTests/TestSpec.swift | 12 +-- 6 files changed, 101 insertions(+), 99 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index f05fe26..1cabe5c 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -19,20 +19,22 @@ import Darwin /// returning a list of all possible "smaller" values for SwiftCheck to run through. As long as /// each individual value in the returned list is less than or equal to the size of the input value, /// and is not a duplicate of the input value, a minimal case should be reached fairly efficiently. +/// Shrinking is an optional extension of normal testing. If no implementation of `shrink` is +/// provided, SwiftCheck will default to an empty one. /// /// As an example, take the `ArrayOf` implementation of shrink: /// /// shrink(ArrayOf([1, 2, 3])) /// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// -/// SwiftCheck will search each case 1 by one and continue shrinking until it has reached a case +/// SwiftCheck will search each case one-by-one and continue shrinking until it has reached a case /// it deems minimal enough to present. /// /// SwiftCheck implements a number of generators for common STL types for convenience. If more fine- /// grained testing is required see `Modifiers.swift` for an example of how to define a "Modifier" /// type to implement it. public protocol Arbitrary { - static func arbitrary() -> Gen + static var arbitrary : Gen { get } static func shrink(Self) -> [Self] } @@ -57,7 +59,7 @@ extension IntegerType { } extension Bool : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.pure((arc4random() % 2) == 1) } @@ -70,7 +72,7 @@ extension Bool : Arbitrary { } extension Int : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int(arc4random_uniform(UInt32(n)))) } } @@ -81,7 +83,7 @@ extension Int : Arbitrary { } extension Int8 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int8(arc4random_uniform(UInt32(n)))) } } @@ -92,7 +94,7 @@ extension Int8 : Arbitrary { } extension Int16 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int16(arc4random_uniform(UInt32(n)))) } } @@ -103,7 +105,7 @@ extension Int16 : Arbitrary { } extension Int32 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int32(arc4random_uniform(UInt32(n)))) } } @@ -114,7 +116,7 @@ extension Int32 : Arbitrary { } extension Int64 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { let sign = ((arc4random() % 2) == 1) return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int64(arc4random_uniform(UInt32(n)))) } } @@ -125,7 +127,7 @@ extension Int64 : Arbitrary { } extension UInt : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt(arc4random_uniform(UInt32(abs(n))))) } } @@ -135,7 +137,7 @@ extension UInt : Arbitrary { } extension UInt8 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized({ n in return Gen.sized { n in Gen.pure(UInt8(arc4random_uniform(UInt32(abs(n))))) } }) @@ -147,7 +149,7 @@ extension UInt8 : Arbitrary { } extension UInt16 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt16(arc4random_uniform(UInt32(abs(n))))) } } @@ -157,7 +159,7 @@ extension UInt16 : Arbitrary { } extension UInt32 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(arc4random_uniform(UInt32(abs(n)))) } } @@ -167,7 +169,7 @@ extension UInt32 : Arbitrary { } extension UInt64 : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt64(arc4random_uniform(UInt32(abs(n))))) } } @@ -177,7 +179,7 @@ extension UInt64 : Arbitrary { } extension Float : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized({ n in if n == 0 { return Gen.pure(0.0) @@ -198,7 +200,7 @@ extension Float : Arbitrary { } extension Double : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.sized({ n in if n == 0 { return Gen.pure(0.0) @@ -219,8 +221,8 @@ extension Double : Arbitrary { } extension UnicodeScalar : Arbitrary { - public static func arbitrary() -> Gen { - return UInt32.arbitrary().bind(Gen.pure • UnicodeScalar.init) + public static var arbitrary : Gen { + return UInt32.arbitrary.bind(Gen.pure • UnicodeScalar.init) } public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { @@ -230,8 +232,8 @@ extension UnicodeScalar : Arbitrary { } extension String : Arbitrary { - public static func arbitrary() -> Gen { - let chars = Gen.sized({ n in Character.arbitrary().proliferateSized(n) }) + public static var arbitrary : Gen { + let chars = Gen.sized({ n in Character.arbitrary.proliferateSized(n) }) return chars.bind { ls in Gen.pure(String(ls)) } } @@ -241,7 +243,7 @@ extension String : Arbitrary { } extension Character : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.choose((32, 255)).bind(Gen.pure • Character.init • UnicodeScalar.init) } @@ -252,14 +254,14 @@ extension Character : Arbitrary { } extension Array where T : Arbitrary { - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure([]) } - return sequence((0...k).map { _ in T.arbitrary() }) + return sequence((0...k).map { _ in T.arbitrary }) } } } @@ -270,8 +272,8 @@ extension Array where T : Arbitrary { } extension AnyBidirectionalCollection where Element : Arbitrary { - public static func arbitrary() -> Gen> { - return [Element].arbitrary().fmap(AnyBidirectionalCollection.init) + public static var arbitrary : Gen> { + return [Element].arbitrary.fmap(AnyBidirectionalCollection.init) } public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { @@ -280,20 +282,20 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } extension AnyForwardIndex : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) } } extension AnyRandomAccessIndex : Arbitrary { - public static func arbitrary() -> Gen { + public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyRandomAccessIndex.init) } } extension AnySequence where T : Arbitrary { - public static func arbitrary() -> Gen> { - return [T].arbitrary().fmap(AnySequence.init) + public static var arbitrary : Gen> { + return [T].arbitrary.fmap(AnySequence.init) } public static func shrink(bl : AnySequence) -> [AnySequence] { @@ -302,8 +304,8 @@ extension AnySequence where T : Arbitrary { } extension ArraySlice where T : Arbitrary { - public static func arbitrary() -> Gen> { - return [T].arbitrary().fmap(ArraySlice.init) + public static var arbitrary : Gen> { + return [T].arbitrary.fmap(ArraySlice.init) } public static func shrink(bl : ArraySlice) -> [ArraySlice] { @@ -312,17 +314,17 @@ extension ArraySlice where T : Arbitrary { } extension CollectionOfOne where T : Arbitrary { - public static func arbitrary() -> Gen> { - return T.arbitrary().fmap(CollectionOfOne.init) + public static var arbitrary : Gen> { + return T.arbitrary.fmap(CollectionOfOne.init) } } /// Generates an Optional of arbitrary values of type A. extension Optional where T : Arbitrary { - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen>.frequency([ (1, Gen>.pure(.None)), - (3, liftM(Optional.Some)(m1: T.arbitrary())), + (3, liftM(Optional.Some)(m1: T.arbitrary)), ]) } @@ -335,8 +337,8 @@ extension Optional where T : Arbitrary { } extension ContiguousArray where T : Arbitrary { - public static func arbitrary() -> Gen> { - return [T].arbitrary().fmap(ContiguousArray.init) + public static var arbitrary : Gen> { + return [T].arbitrary.fmap(ContiguousArray.init) } public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { @@ -346,9 +348,9 @@ extension ContiguousArray where T : Arbitrary { /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { - public static func arbitrary() -> Gen> { - return [Key].arbitrary().bind { k in - return [Value].arbitrary().bind { v in + public static var arbitrary : Gen> { + return [Key].arbitrary.bind { k in + return [Value].arbitrary.bind { v in return Gen.pure(Dictionary(Zip2(k, v))) } } @@ -370,15 +372,15 @@ extension Dictionary { } extension EmptyCollection : Arbitrary { - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen.pure(EmptyCollection()) } } extension HalfOpenInterval where T : protocol { - public static func arbitrary() -> Gen> { - return T.arbitrary().bind { l in - return T.arbitrary().bind { r in + public static var arbitrary : Gen> { + return T.arbitrary.bind { l in + return T.arbitrary.bind { r in return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) } } @@ -390,8 +392,8 @@ extension HalfOpenInterval where T : protocol { } extension ImplicitlyUnwrappedOptional where T : Arbitrary { - public static func arbitrary() -> Gen> { - return Optional.arbitrary().fmap(ImplicitlyUnwrappedOptional.init) + public static var arbitrary : Gen> { + return Optional.arbitrary.fmap(ImplicitlyUnwrappedOptional.init) } public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { @@ -400,33 +402,33 @@ extension ImplicitlyUnwrappedOptional where T : Arbitrary { } extension LazyBidirectionalCollection where S : protocol, S.Index : BidirectionalIndexType { - public static func arbitrary() -> Gen> { - return S.arbitrary().fmap(lazy) + public static var arbitrary : Gen> { + return S.arbitrary.fmap(lazy) } } extension LazyForwardCollection where S : protocol, S.Index : ForwardIndexType { - public static func arbitrary() -> Gen> { - return S.arbitrary().fmap(lazy) + public static var arbitrary : Gen> { + return S.arbitrary.fmap(lazy) } } extension LazyRandomAccessCollection where S : protocol, S.Index : RandomAccessIndexType { - public static func arbitrary() -> Gen> { - return S.arbitrary().fmap(lazy) + public static var arbitrary : Gen> { + return S.arbitrary.fmap(lazy) } } extension LazySequence where S : protocol { - public static func arbitrary() -> Gen> { - return S.arbitrary().fmap(lazy) + public static var arbitrary : Gen> { + return S.arbitrary.fmap(lazy) } } extension Range where T : protocol { - public static func arbitrary() -> Gen> { - return T.arbitrary().bind { l in - return T.arbitrary().bind { r in + public static var arbitrary : Gen> { + return T.arbitrary.bind { l in + return T.arbitrary.bind { r in return Gen.pure(Range(start: min(l, r), end: max(l, r))) } } @@ -438,20 +440,20 @@ extension Range where T : protocol { } extension Repeat where T : Arbitrary { - public static func arbitrary() -> Gen> { - return Gen.zip(Int.arbitrary(), T.arbitrary()).fmap(Repeat.init) + public static var arbitrary : Gen> { + return Gen.zip(Int.arbitrary, T.arbitrary).fmap(Repeat.init) } } extension Set where T : protocol { - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure(Set([])) } - return sequence(Array((0...k)).map { _ in T.arbitrary() }).fmap(Set.init) + return sequence(Array((0...k)).map { _ in T.arbitrary }).fmap(Set.init) } } } @@ -472,7 +474,7 @@ public protocol CoArbitrary { } extension IntegerType { - /// A corarbitrary implementation for any IntegerType + /// A coarbitrary implementation for any IntegerType public func coarbitraryIntegral() -> Gen -> Gen { return { $0.variant(self) } } diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 9c4aacc..b83d00b 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -24,8 +24,8 @@ public struct Blind : Arbitrary, CustomStringConvertible { return Blind(blind) } - public static func arbitrary() -> Gen> { - return A.arbitrary().fmap(Blind.create) + public static var arbitrary : Gen> { + return A.arbitrary.fmap(Blind.create) } public static func shrink(bl : Blind) -> [Blind] { @@ -56,8 +56,8 @@ public struct Static : Arbitrary, CustomStringConvertible { return Static(blind) } - public static func arbitrary() -> Gen> { - return A.arbitrary().fmap(Static.create) + public static var arbitrary : Gen> { + return A.arbitrary.fmap(Static.create) } } @@ -87,8 +87,8 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { return ArrayOf(array) } - public static func arbitrary() -> Gen> { - return Array.arbitrary().fmap(ArrayOf.init) + public static var arbitrary : Gen> { + return Array.arbitrary.fmap(ArrayOf.init) } public static func shrink(bl : ArrayOf) -> [ArrayOf] { @@ -122,8 +122,8 @@ public struct DictionaryOf, V : Arbitrary> : A return DictionaryOf(dict) } - public static func arbitrary() -> Gen> { - return Dictionary.arbitrary().fmap(DictionaryOf.init) + public static var arbitrary : Gen> { + return Dictionary.arbitrary.fmap(DictionaryOf.init) } public static func shrink(d : DictionaryOf) -> [DictionaryOf] { @@ -153,8 +153,8 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { return OptionalOf(opt) } - public static func arbitrary() -> Gen> { - return Optional.arbitrary().fmap(OptionalOf.init) + public static var arbitrary : Gen> { + return Optional.arbitrary.fmap(OptionalOf.init) } public static func shrink(bl : OptionalOf) -> [OptionalOf] { @@ -187,14 +187,14 @@ public struct SetOf> : Arbitrary, CustomString return SetOf(set) } - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure(SetOf(Set([]))) } - return sequence(Array((0...k)).map { _ in A.arbitrary() }).fmap({ SetOf.create(Set($0)) }) + return sequence(Array((0...k)).map { _ in A.arbitrary }).fmap({ SetOf.create(Set($0)) }) } } } @@ -247,9 +247,9 @@ public struct ArrowOf, U : Arbitrary> : Arbi return ArrowOf(arr) } - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return promote({ a in - return T.coarbitrary(a)(U.arbitrary()) + return T.coarbitrary(a)(U.arbitrary) }).fmap({ ArrowOf($0) }) } @@ -323,11 +323,11 @@ public struct IsoOf, U : protocol return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" } - public static func arbitrary() -> Gen> { + public static var arbitrary : Gen> { return Gen<(T -> U, U -> T)>.zip(promote({ a in - return T.coarbitrary(a)(U.arbitrary()) + return T.coarbitrary(a)(U.arbitrary) }), promote({ a in - return U.coarbitrary(a)(T.arbitrary()) + return U.coarbitrary(a)(T.arbitrary) })).fmap { IsoOf($0, $1) } } @@ -380,8 +380,8 @@ public struct Positive> : Arbitrary, C return Positive(blind) } - public static func arbitrary() -> Gen> { - return A.arbitrary().fmap({ Positive.create(abs($0)) }).suchThat({ $0.getPositive > 0 }) + public static var arbitrary : Gen> { + return A.arbitrary.fmap({ Positive.create(abs($0)) }).suchThat({ $0.getPositive > 0 }) } public static func shrink(bl : Positive) -> [Positive] { @@ -412,8 +412,8 @@ public struct NonZero> : Arbitrary, CustomS return NonZero(blind) } - public static func arbitrary() -> Gen> { - return A.arbitrary().suchThat({ $0 != 0 }).fmap(NonZero.create) + public static var arbitrary : Gen> { + return A.arbitrary.suchThat({ $0 != 0 }).fmap(NonZero.create) } public static func shrink(bl : NonZero) -> [NonZero] { @@ -443,8 +443,8 @@ public struct NonNegative> : Arbitrary, Cus return NonNegative(blind) } - public static func arbitrary() -> Gen> { - return A.arbitrary().suchThat({ $0 >= 0 }).fmap(NonNegative.create) + public static var arbitrary : Gen> { + return A.arbitrary.suchThat({ $0 >= 0 }).fmap(NonNegative.create) } public static func shrink(bl : NonNegative) -> [NonNegative] { diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index c72db9b..1efde51 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -9,7 +9,7 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. public func forAll(pf : (A -> Testable)) -> Property { - return forAllShrink(A.arbitrary(), shrinker: { A.shrink($0) }, f: pf) + return forAllShrink(A.arbitrary, shrinker: { A.shrink($0) }, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 81db89a..0ab689c 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -73,30 +73,30 @@ class GenSpec : XCTestCase { } property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = Int.arbitrary().proliferateSized(n).fmap({ ArrayOf($0) }) + let g = Int.arbitrary.proliferateSized(n).fmap({ ArrayOf($0) }) return forAll(g) { $0.getArray.count == n } } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary().proliferateSized(0).fmap({ ArrayOf($0) })) { + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferateSized(0).fmap({ ArrayOf($0) })) { return $0.getArray.isEmpty } property("Gen.suchThat in series obeys both predicates.") <- { - let g = String.arbitrary().suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) return forAll(g) { str in return !(str.isEmpty || str.rangeOfString(",") != nil) } } property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary().suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) return forAll(g) { str in return !str.isEmpty } } property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary().suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) return forAll(g) { str in return str.rangeOfString(",") == nil } diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index ea3159a..d798863 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -23,9 +23,9 @@ public struct ArbitraryFoo { } extension ArbitraryFoo : Arbitrary { - public static func arbitrary() -> Gen { - return Int.arbitrary().bind { i in - return Int.arbitrary().bind { j in + public static var arbitrary : Gen { + return Int.arbitrary.bind { i in + return Int.arbitrary.bind { j in return Gen.pure(ArbitraryFoo(x: i, y: j)) } } diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index 18c62b4..123a804 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -11,32 +11,32 @@ import SwiftCheck class TestSpec : XCTestCase { func testAll() { - property("Dictionaries behave") <- forAllShrink(Dictionary.arbitrary(), shrinker: Dictionary.shrink) { (xs : Dictionary) in + property("Dictionaries behave") <- forAllShrink(Dictionary.arbitrary, shrinker: Dictionary.shrink) { (xs : Dictionary) in return true } - property("Optionals behave") <- forAllShrink(Optional.arbitrary(), shrinker: Optional.shrink) { (xs : Int?) in + property("Optionals behave") <- forAllShrink(Optional.arbitrary, shrinker: Optional.shrink) { (xs : Int?) in return true } - property("Sets behave") <- forAllShrink(Set.arbitrary(), shrinker: Set.shrink) { (xs : Set) in + property("Sets behave") <- forAllShrink(Set.arbitrary, shrinker: Set.shrink) { (xs : Set) in return true } - property("The reverse of the reverse of an array is that array") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + property("The reverse of the reverse of an array is that array") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in return (xs.reverse().reverse() == xs) "Left identity" ^&&^ (xs == xs.reverse().reverse()) "Right identity" } - property("map behaves") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + property("map behaves") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in return forAll { (f : ArrowOf) in return xs.map(f.getArrow) == xs.map(f.getArrow) } } - property("filter behaves") <- forAllShrink(Array.arbitrary(), shrinker: Array.shrink) { (xs : Array) in + property("filter behaves") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in return forAll { (pred : ArrowOf) in let f = pred.getArrow return (xs.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) From a1cbe0a6a441d1eedb54701ed3756cba33b535a9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 22:13:29 -0600 Subject: [PATCH 033/460] Document the fields of Arbitrary and CoArbitrary --- SwiftCheck/Arbitrary.swift | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 1cabe5c..df32529 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -34,7 +34,20 @@ import Darwin /// grained testing is required see `Modifiers.swift` for an example of how to define a "Modifier" /// type to implement it. public protocol Arbitrary { + /// The generator for this particular type. + /// + /// This function should call out to any sources of randomness or state necessary to generate + /// values. It should not, however, be written as a deterministic function. If such a + /// generator is needed, combinators are provided in `Gen.swift`. static var arbitrary : Gen { get } + + /// An optional shrinking function. If this function goes unimplemented, it is the same as + /// returning the empty list. + /// + /// Shrunken values must be less than or equal to the "size" of the original type but never the + /// same as the value provided to this function (or a loop will form in the shrinker). It is + /// recommended that they be presented smallest to largest to speed up the overall shrinking + /// process. static func shrink(Self) -> [Self] } @@ -466,10 +479,8 @@ extension Set where T : protocol { /// Coarbitrary types must take an arbitrary value of their type and yield a function that /// transforms a given generator by returning a new generator that depends on the input value. Put /// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. -/// -/// Using Coarbitrary types it is possible to write an Arbitrary instance for `->` (a type that -/// generates functions). public protocol CoArbitrary { + /// Uses an instance of the receiver to return a function that perturbs a generator. static func coarbitrary(x : Self) -> (Gen -> Gen) } From 34e23b2635890dc5bf11a695be51df5cee4c3701 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 6 Jul 2015 22:14:59 -0600 Subject: [PATCH 034/460] Update README to new syntax --- README.md | 12 ++++-------- SwiftCheckTests/SimpleSpec.swift | 4 ---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7671685..d952fe1 100644 --- a/README.md +++ b/README.md @@ -211,12 +211,8 @@ public struct ArbitraryFoo { } extension ArbitraryFoo : Arbitrary { - public static func arbitrary() -> Gen { - return ArbitraryFoo.create <^> Int.arbitrary() <*> Int.arbitrary() - } - - public static func shrink(x : ArbitraryFoo) -> [ArbitraryFoo] { - return shrinkNone(x) + public static var arbitrary : Gen { + return ArbitraryFoo.create <^> Int.arbitrary <*> Int.arbitrary } } @@ -233,7 +229,7 @@ For everything else, SwiftCheck defines a number of combinators to make working with custom generators as simple as possible: ```swift -let onlyEven = Int.arbitrary().suchThat { $0 % 2 == 0 } +let onlyEven = Int.arbitrary.suchThat { $0 % 2 == 0 } let vowels = Gen.elements(["A", "E", "I", "O", "U" ]) @@ -243,7 +239,7 @@ let randomHexValue = Gen.choose((0, 15)) /// `.Some` 3/4 of the time let weightedOptionals = Gen.frequency([ (1, Gen.pure(OptionalOf(Optional.None))), - (3, liftM({ OptionalOf(Optional.Some($0)) })(m1: Int.arbitrary())) + (3, liftM({ OptionalOf(Optional.Some($0)) })(m1: Int.arbitrary)) ]) ``` diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index d798863..e7b867e 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -30,10 +30,6 @@ extension ArbitraryFoo : Arbitrary { } } } - - public static func shrink(x : ArbitraryFoo) -> [ArbitraryFoo] { - return shrinkNone(x) - } } From 1a09494d9fa7c8699a08bdfe99b577e8adf2ce39 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 20:54:25 -0600 Subject: [PATCH 035/460] Rename our operators file --- SwiftCheck.xcodeproj/project.pbxproj | 12 ++++++------ SwiftCheck/{Operators.swift => TestOperators.swift} | 0 2 files changed, 6 insertions(+), 6 deletions(-) rename SwiftCheck/{Operators.swift => TestOperators.swift} (100%) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 5521169..7390d1f 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -26,7 +26,7 @@ 844FCCC3198EC4F000EB242A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; - 8450D24A1AF8003800095EF6 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* Operators.swift */; }; + 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; 84572C251A6DBAA800241F68 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; @@ -37,7 +37,7 @@ 84DF76141B0BD58100C912B0 /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAB198B32DC00EB242A /* Gen.swift */; }; 84DF76151B0BD58100C912B0 /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; 84DF76161B0BD58100C912B0 /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; - 84DF76171B0BD58100C912B0 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* Operators.swift */; }; + 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; 84DF76181B0BD58100C912B0 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAD198B367000EB242A /* Property.swift */; }; 84DF76191B0BD58100C912B0 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; @@ -103,7 +103,7 @@ 844FCCC2198EC4F000EB242A /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; 844FCCC6198EFB4700EB242A /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rose.swift; sourceTree = ""; }; 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; }; - 8450D2491AF8003700095EF6 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; + 8450D2491AF8003700095EF6 /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestOperators.swift; sourceTree = ""; }; 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; }; 84572C241A6DBAA800241F68 /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Check.swift; sourceTree = ""; }; 84572C2A1A6DBABA00241F68 /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; }; @@ -180,7 +180,7 @@ 844FCCAB198B32DC00EB242A /* Gen.swift */, 842015101AF5C91C00F1F3CD /* Lattice.swift */, 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */, - 8450D2491AF8003700095EF6 /* Operators.swift */, + 8450D2491AF8003700095EF6 /* TestOperators.swift */, 844FCCAD198B367000EB242A /* Property.swift */, 844FCCC2198EC4F000EB242A /* Random.swift */, 844FCCC6198EFB4700EB242A /* Rose.swift */, @@ -410,7 +410,7 @@ 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */, 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */, 844FCCAA198B323800EB242A /* Arbitrary.swift in Sources */, - 8450D24A1AF8003800095EF6 /* Operators.swift in Sources */, + 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */, 844FCCB4198B39F300EB242A /* State.swift in Sources */, 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */, ); @@ -441,7 +441,7 @@ 84DF76151B0BD58100C912B0 /* Lattice.swift in Sources */, 84DF76161B0BD58100C912B0 /* Modifiers.swift in Sources */, D46395B71B1A94D200AA1B65 /* Equatable.swift in Sources */, - 84DF76171B0BD58100C912B0 /* Operators.swift in Sources */, + 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */, 84DF76181B0BD58100C912B0 /* Property.swift in Sources */, 84DF76191B0BD58100C912B0 /* Random.swift in Sources */, 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */, diff --git a/SwiftCheck/Operators.swift b/SwiftCheck/TestOperators.swift similarity index 100% rename from SwiftCheck/Operators.swift rename to SwiftCheck/TestOperators.swift From 022a25753ab822900c8c21fcbbee7d85777b99b0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:01:23 -0600 Subject: [PATCH 036/460] Depend on Operadics --- Cartfile.private | 1 + Cartfile.resolved | 1 + Carthage/Checkouts/Operadics/Operators.swift | 167 +++++++++++++++++++ README.md | 4 +- SwiftCheck.xcodeproj/project.pbxproj | 6 + SwiftCheck/Gen.swift | 47 ++++-- SwiftCheck/Property.swift | 5 - 7 files changed, 205 insertions(+), 26 deletions(-) create mode 100644 Carthage/Checkouts/Operadics/Operators.swift diff --git a/Cartfile.private b/Cartfile.private index e69de29..077b243 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -0,0 +1 @@ +github "typelift/Operadics" diff --git a/Cartfile.resolved b/Cartfile.resolved index e69de29..105d648 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "typelift/Operadics" "v0.1.0" diff --git a/Carthage/Checkouts/Operadics/Operators.swift b/Carthage/Checkouts/Operadics/Operators.swift new file mode 100644 index 0000000..1adf084 --- /dev/null +++ b/Carthage/Checkouts/Operadics/Operators.swift @@ -0,0 +1,167 @@ +// +// Operators.swift +// Operadics +// +// Created by Robert Widmann on 07/07/2015. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + +/// MARK: Combinators + +/// Compose | Applies one function to the result of another function to produce a third function. +infix operator • { + associativity right + precedence 190 +} + +/// Apply | Applies an argument to a function. +infix operator § { + associativity right + precedence 0 +} + +/// Pipe Backward | Applies the function to its left to an argument on its right. +infix operator <| { + associativity right + precedence 0 +} + +/// Pipe forward | Applies an argument on the left to a function on the right. +infix operator |> { + associativity left + precedence 0 +} + +/// MARK: Control.* + +/// Fmap | Maps a function over the value encapsulated by a functor. +infix operator <^> { + associativity left + precedence 140 +} + +/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. +infix operator <*> { + associativity left + precedence 140 +} + +/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the +/// left to a function on the right yielding a new monad. +infix operator >>- { + associativity left + precedence 110 +} + +/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the +/// original context. +infix operator ->> { + associativity left + precedence 110 +} + +/// MARK: Data.Result + +/// From | Creates a Result given a function that can possibly fail with an error. +infix operator !! { + associativity none + precedence 120 +} + +/// MARK: Data.Monoid + +/// Append | Alias for a Semigroup's operation. +infix operator <> { + associativity right + precedence 160 +} + +/// MARK: Control.Category + +/// Right-to-Left Composition | Composes two categories to form a new category with the source of +/// the second category and the target of the first category. +/// +/// This function is literally `•`, but for Categories. +infix operator <<< { + precedence 110 + associativity right +} + +/// Left-to-Right Composition | Composes two categories to form a new category with the source of +/// the first category and the target of the second category. +/// +/// Function composition with the arguments flipped. +infix operator >>> { + precedence 110 + associativity right +} + +/// MARK: Control.Arrow + +/// Split | Splits two computations and combines the result into one Arrow yielding a tuple of +/// the result of each side. +infix operator *** { + precedence 130 + associativity right +} + +/// Fanout | Given two functions with the same source but different targets, this function +/// splits the computation and combines the result of each Arrow into a tuple of the result of +/// each side. +infix operator &&& { + precedence 130 + associativity right +} + +/// MARK: Control.Arrow.Choice + +/// Splat | Splits two computations and combines the results into Eithers on the left and right. +infix operator +++ { + precedence 120 + associativity right +} + +/// Fanin | Given two functions with the same target but different sources, this function splits +/// the input between the two and merges the output. +infix operator ||| { + precedence 120 + associativity right +} + +/// MARK: Control.Arrow.Plus + +/// Op | Combines two ArrowZero monoids. +infix operator <+> { + precedence 150 + associativity right +} + +/// MARK: Data.JSON + +/// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. +/// +/// If the given keypath is not present or the retrieved value is not of the appropriate type, this +/// function returns `.None`. +infix operator -import func Swiftz.<*> - + public struct ArbitraryFoo { let x : Int let y : Int diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 7390d1f..8bb0b94 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; + 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; @@ -87,6 +89,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; }; 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; }; @@ -180,6 +183,7 @@ 844FCCAB198B32DC00EB242A /* Gen.swift */, 842015101AF5C91C00F1F3CD /* Lattice.swift */, 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */, + 82DD8EEB1B4CC88C00B66551 /* Operators.swift */, 8450D2491AF8003700095EF6 /* TestOperators.swift */, 844FCCAD198B367000EB242A /* Property.swift */, 844FCCC2198EC4F000EB242A /* Random.swift */, @@ -409,6 +413,7 @@ D46395B61B1A94D200AA1B65 /* Equatable.swift in Sources */, 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */, 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */, + 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */, 844FCCAA198B323800EB242A /* Arbitrary.swift in Sources */, 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */, 844FCCB4198B39F300EB242A /* State.swift in Sources */, @@ -444,6 +449,7 @@ 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */, 84DF76181B0BD58100C912B0 /* Property.swift in Sources */, 84DF76191B0BD58100C912B0 /* Random.swift in Sources */, + 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */, 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */, 84DF761B1B0BD58100C912B0 /* State.swift in Sources */, 84DF761C1B0BD58100C912B0 /* Test.swift in Sources */, diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 0a7da80..07b5e7b 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -202,14 +202,18 @@ extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the receiver creates. public func fmap(f : (A -> B)) -> Gen { - return Gen(unGen: { r in - return { n in - return f(self.unGen(r)(n)) - } - }) + return f <^> self } } +public func <^> (f : A -> B, g : Gen) -> Gen { + return Gen(unGen: { r in + return { n in + return f(g.unGen(r)(n)) + } + }) +} + extension Gen /*: Applicative*/ { typealias FAB = Gen B> @@ -225,14 +229,18 @@ extension Gen /*: Applicative*/ { /// Given a generator of functions, applies any generated function to any outputs the receiver /// creates. public func ap(fn : Gen B>) -> Gen { - return Gen(unGen: { r in - return { n in - return fn.unGen(r)(n)(self.unGen(r)(n)) - } - }) + return fn <*> self } } +public func <*> (fn : Gen B>, g : Gen) -> Gen { + return Gen(unGen: { r in + return { n in + return fn.unGen(r)(n)(g.unGen(r)(n)) + } + }) +} + extension Gen /*: Monad*/ { /// Applies the function to any generated values to yield a new generator. This generator is /// then given a new random seed and returned. @@ -241,16 +249,20 @@ extension Gen /*: Monad*/ { /// example, use a Generator of integers to control the length of a Generator of strings, or use /// it to choose a random index into a Generator of arrays. public func bind(fn : A -> Gen) -> Gen { - return Gen(unGen: { r in - return { n in - let (r1, r2) = r.split() - let m = fn(self.unGen(r1)(n)) - return m.unGen(r2)(n) - } - }) + return self >>- fn } } +public func >>- (m : Gen, fn : A -> Gen) -> Gen { + return Gen(unGen: { r in + return { n in + let (r1, r2) = r.split() + let m2 = fn(m.unGen(r1)(n)) + return m2.unGen(r2)(n) + } + }) +} + /// Reduces an array of generators to a generator that returns arrays of the original generators /// values in the order given. public func sequence(ms : [Gen]) -> Gen<[A]> { @@ -277,7 +289,6 @@ public func liftM(f : A -> R)(m1 : Gen) -> Gen { } } - /// Promotes a rose of generators to a generator of rose values. public func promote(x : Rose>) -> Gen> { return delay().bind { (let eval : Gen -> A) in diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 331f9f1..b4623df 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -6,11 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -infix operator • { - precedence 190 - associativity right -} - /// Takes the conjunction of multiple properties and reports all successes and failures as one /// combined property. That is, this property holds when all sub-properties hold and fails when one /// or more sub-properties fail. From 9b1773558b80d3bfd2492da5f5f4a421249d9f8b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:04:04 -0600 Subject: [PATCH 037/460] Add rose operators --- SwiftCheck/Rose.swift | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 56a41df..21ec91d 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -27,12 +27,16 @@ extension Rose /*: Functor*/ { /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` branches the map is suspended. public func fmap(f : (A -> B)) -> Rose { - switch self { - case .MkRose(let root, let children): - return .MkRose({ f(root()) }, { children().map() { $0.fmap(f) } }) - case .IORose(let rs): - return .IORose({ rs().fmap(f) }) - } + return f <^> self + } +} + +public func <^> (f : A -> B, g : Rose) -> Rose { + switch g { + case .MkRose(let root, let children): + return .MkRose({ f(root()) }, { children().map() { $0.fmap(f) } }) + case .IORose(let rs): + return .IORose({ rs().fmap(f) }) } } @@ -50,22 +54,30 @@ extension Rose /*: Applicative*/ { /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and /// applied, executing all side-effects along the way. public func ap(fn : Rose B>) -> Rose { - switch fn { - case .MkRose(let f, _): - return self.fmap(f()) - case .IORose(let rs): - return self.ap(rs()) ///EEWW, EW, EW, EW, EW, EW - } + return fn <*> self + } +} + +public func <*> (fn : Rose B>, g : Rose) -> Rose { + switch fn { + case .MkRose(let f, _): + return g.fmap(f()) + case .IORose(let rs): + return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW } } extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all together. public func bind(fn : A -> Rose) -> Rose { - return joinRose(self.fmap(fn)) + return self >>- fn } } +public func >>- (m : Rose, fn : A -> Rose) -> Rose { + return joinRose(m.fmap(fn)) +} + /// Lifts functions to functions over Rose Trees. public func liftM(f : A -> R)(m1 : Rose) -> Rose { return m1.bind { x1 in From 69679f3709b4571d77f7ffedd612cbe11170ff32 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:11:48 -0600 Subject: [PATCH 038/460] Remove create functions --- SwiftCheck/Modifiers.swift | 64 +++++++------------------------------- 1 file changed, 12 insertions(+), 52 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index b83d00b..dab17a5 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -20,16 +20,12 @@ public struct Blind : Arbitrary, CustomStringConvertible { return "(*)" } - private static func create(blind : A) -> Blind { - return Blind(blind) - } - public static var arbitrary : Gen> { - return A.arbitrary.fmap(Blind.create) + return Blind.init <^> A.arbitrary } public static func shrink(bl : Blind) -> [Blind] { - return A.shrink(bl.getBlind).map(Blind.create) + return A.shrink(bl.getBlind).map(Blind.init) } } @@ -52,12 +48,8 @@ public struct Static : Arbitrary, CustomStringConvertible { return "Static( \(self.getStatic) )" } - private static func create(blind : A) -> Static { - return Static(blind) - } - public static var arbitrary : Gen> { - return A.arbitrary.fmap(Static.create) + return Static.init <^> A.arbitrary } } @@ -83,12 +75,8 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { return "\(self.getArray)" } - private static func create(array : [A]) -> ArrayOf { - return ArrayOf(array) - } - public static var arbitrary : Gen> { - return Array.arbitrary.fmap(ArrayOf.init) + return ArrayOf.init <^> Array.arbitrary } public static func shrink(bl : ArrayOf) -> [ArrayOf] { @@ -118,12 +106,8 @@ public struct DictionaryOf, V : Arbitrary> : A return "\(self.getDictionary)" } - private static func create(dict : Dictionary) -> DictionaryOf { - return DictionaryOf(dict) - } - public static var arbitrary : Gen> { - return Dictionary.arbitrary.fmap(DictionaryOf.init) + return DictionaryOf.init <^> Dictionary.arbitrary } public static func shrink(d : DictionaryOf) -> [DictionaryOf] { @@ -149,12 +133,8 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { return "\(self.getOptional)" } - private static func create(opt : A?) -> OptionalOf { - return OptionalOf(opt) - } - public static var arbitrary : Gen> { - return Optional.arbitrary.fmap(OptionalOf.init) + return OptionalOf.init <^> Optional.arbitrary } public static func shrink(bl : OptionalOf) -> [OptionalOf] { @@ -183,10 +163,6 @@ public struct SetOf> : Arbitrary, CustomString return "\(self.getSet)" } - private static func create(set : Set) -> SetOf{ - return SetOf(set) - } - public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in @@ -194,7 +170,7 @@ public struct SetOf> : Arbitrary, CustomString return Gen.pure(SetOf(Set([]))) } - return sequence(Array((0...k)).map { _ in A.arbitrary }).fmap({ SetOf.create(Set($0)) }) + return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) } } } @@ -243,10 +219,6 @@ public struct ArrowOf, U : Arbitrary> : Arbi return "\(T.self) -> \(U.self)" } - private static func create(arr : (T -> U)) -> ArrowOf { - return ArrowOf(arr) - } - public static var arbitrary : Gen> { return promote({ a in return T.coarbitrary(a)(U.arbitrary) @@ -376,16 +348,12 @@ public struct Positive> : Arbitrary, C return "Positive( \(self.getPositive) )" } - private static func create(blind : A) -> Positive { - return Positive(blind) - } - public static var arbitrary : Gen> { - return A.arbitrary.fmap({ Positive.create(abs($0)) }).suchThat({ $0.getPositive > 0 }) + return A.arbitrary.fmap(Positive.init • abs).suchThat { $0.getPositive > 0 } } public static func shrink(bl : Positive) -> [Positive] { - return A.shrink(bl.getPositive).filter({ $0 > 0 }).map({ Positive($0) }) + return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) } } @@ -408,12 +376,8 @@ public struct NonZero> : Arbitrary, CustomS return "NonZero( \(self.getNonZero) )" } - private static func create(blind : A) -> NonZero { - return NonZero(blind) - } - public static var arbitrary : Gen> { - return A.arbitrary.suchThat({ $0 != 0 }).fmap(NonZero.create) + return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } } public static func shrink(bl : NonZero) -> [NonZero] { @@ -439,16 +403,12 @@ public struct NonNegative> : Arbitrary, Cus return "NonNegative( \(self.getNonNegative) )" } - private static func create(blind : A) -> NonNegative { - return NonNegative(blind) - } - public static var arbitrary : Gen> { - return A.arbitrary.suchThat({ $0 >= 0 }).fmap(NonNegative.create) + return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } } public static func shrink(bl : NonNegative) -> [NonNegative] { - return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map({ NonNegative($0) }) + return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) } } From e7712fdd5115abedb3a70539524417431b227f63 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:21:43 -0600 Subject: [PATCH 039/460] =?UTF-8?q?=CE=BB=20Golfing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SwiftCheck/Arbitrary.swift | 4 ++-- SwiftCheck/Gen.swift | 14 +++++--------- SwiftCheck/Modifiers.swift | 6 +++--- SwiftCheck/Test.swift | 8 ++++---- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index df32529..886daaa 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -247,7 +247,7 @@ extension UnicodeScalar : Arbitrary { extension String : Arbitrary { public static var arbitrary : Gen { let chars = Gen.sized({ n in Character.arbitrary.proliferateSized(n) }) - return chars.bind { ls in Gen.pure(String(ls)) } + return chars >>- (Gen.pure • String.init) } public static func shrink(s : String) -> [String] { @@ -257,7 +257,7 @@ extension String : Arbitrary { extension Character : Arbitrary { public static var arbitrary : Gen { - return Gen.choose((32, 255)).bind(Gen.pure • Character.init • UnicodeScalar.init) + return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) } public static func shrink(x : Character) -> [Character] { diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 07b5e7b..d30d726 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -65,7 +65,7 @@ public struct Gen { } return Gen<(A, [A])>.fromElementsOf(selectOne(xs)).bind { (y, ys) in - return Gen.fromShufflingElementsOf(ys).fmap({ [y] + $0 }) + return Gen.fromShufflingElementsOf(ys).fmap { [y] + $0 } } } @@ -83,7 +83,7 @@ public struct Gen { /// When using this function, it is necessary to explicitly specialize the generic parameter /// `A`. For example: /// - /// Gen.choose((32, 255)).bind { Gen.pure(Character(UnicodeScalar($0))) } + /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) public static func choose(rng : (A, A)) -> Gen { return Gen(unGen: { s in return { (_) in @@ -97,7 +97,7 @@ public struct Gen { public static func oneOf(gs : [Gen]) -> Gen { assert(gs.count != 0, "oneOf used with empty list") - return choose((0, gs.count - 1)).bind { x in + return choose((0, gs.count - 1)) >>- { x in return gs[x] } } @@ -173,9 +173,7 @@ extension Gen { /// size parameter. public func proliferate() -> Gen<[A]> { return Gen<[A]>.sized({ n in - return Gen.choose((0, n)).bind { k in - return self.proliferateSized(k) - } + return Gen.choose((0, n)) >>- self.proliferateSized }) } @@ -183,9 +181,7 @@ extension Gen { /// receiver's size parameter. public func proliferateNonEmpty() -> Gen<[A]> { return Gen<[A]>.sized({ n in - return Gen.choose((1, max(1, n))).bind { k in - return self.proliferateSized(k) - } + return Gen.choose((1, max(1, n))) >>- self.proliferateSized }) } diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index dab17a5..3ca71c0 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -220,9 +220,9 @@ public struct ArrowOf, U : Arbitrary> : Arbi } public static var arbitrary : Gen> { - return promote({ a in + return ArrowOf.init <^> promote({ a in return T.coarbitrary(a)(U.arbitrary) - }).fmap({ ArrowOf($0) }) + }) } public static func shrink(f : ArrowOf) -> [ArrowOf] { @@ -381,7 +381,7 @@ public struct NonZero> : Arbitrary, CustomS } public static func shrink(bl : NonZero) -> [NonZero] { - return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map({ NonZero($0) }) + return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 1efde51..4470140 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -9,7 +9,7 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. public func forAll(pf : (A -> Testable)) -> Property { - return forAllShrink(A.arbitrary, shrinker: { A.shrink($0) }, f: pf) + return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and @@ -57,7 +57,7 @@ public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { - return forAllShrink(gen, shrinker: { A.shrink($0) }, f: pf) + return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified property using the @@ -492,8 +492,8 @@ internal func summary(s : CheckerState) -> [(String, Int)] { } internal func labelPercentage(l : String, st : CheckerState) -> Int { - let occur = st.collected.flatMap({ Array($0) }).filter({ $0 == l }).count - return (100 * occur) / st.maxSuccessTests + let occur = st.collected.flatMap(Array.init).filter { $0 == l } + return (100 * occur.count) / st.maxSuccessTests } internal func printDistributionGraph(st : CheckerState) { From 30ebaadba1f0106e93c0db80d19c11476cfd030a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:24:15 -0600 Subject: [PATCH 040/460] Golf tests --- SwiftCheckTests/SimpleSpec.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index e7b867e..5fd405c 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -24,11 +24,7 @@ public struct ArbitraryFoo { extension ArbitraryFoo : Arbitrary { public static var arbitrary : Gen { - return Int.arbitrary.bind { i in - return Int.arbitrary.bind { j in - return Gen.pure(ArbitraryFoo(x: i, y: j)) - } - } + return ArbitraryFoo.create <^> Int.arbitrary <*> Int.arbitrary } } From 103b328f209da4cffe3d61fbbfcbce9a8c7d19f1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:49:14 -0600 Subject: [PATCH 041/460] Ignore Operadics checkout files --- .gitignore | 5 +- Carthage/Checkouts/Operadics/Operators.swift | 167 ------------------- 2 files changed, 3 insertions(+), 169 deletions(-) delete mode 100644 Carthage/Checkouts/Operadics/Operators.swift diff --git a/.gitignore b/.gitignore index a2298be..a167343 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ DerivedData .idea/ *.hmap *.xcuserstate -Carthage/ - *.xccheckout +Carthage/Build +Carthage/Checkouts + diff --git a/Carthage/Checkouts/Operadics/Operators.swift b/Carthage/Checkouts/Operadics/Operators.swift deleted file mode 100644 index 1adf084..0000000 --- a/Carthage/Checkouts/Operadics/Operators.swift +++ /dev/null @@ -1,167 +0,0 @@ -// -// Operators.swift -// Operadics -// -// Created by Robert Widmann on 07/07/2015. -// Copyright (c) 2015 TypeLift. All rights reserved. -// - -/// MARK: Combinators - -/// Compose | Applies one function to the result of another function to produce a third function. -infix operator • { - associativity right - precedence 190 -} - -/// Apply | Applies an argument to a function. -infix operator § { - associativity right - precedence 0 -} - -/// Pipe Backward | Applies the function to its left to an argument on its right. -infix operator <| { - associativity right - precedence 0 -} - -/// Pipe forward | Applies an argument on the left to a function on the right. -infix operator |> { - associativity left - precedence 0 -} - -/// MARK: Control.* - -/// Fmap | Maps a function over the value encapsulated by a functor. -infix operator <^> { - associativity left - precedence 140 -} - -/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. -infix operator <*> { - associativity left - precedence 140 -} - -/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the -/// left to a function on the right yielding a new monad. -infix operator >>- { - associativity left - precedence 110 -} - -/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the -/// original context. -infix operator ->> { - associativity left - precedence 110 -} - -/// MARK: Data.Result - -/// From | Creates a Result given a function that can possibly fail with an error. -infix operator !! { - associativity none - precedence 120 -} - -/// MARK: Data.Monoid - -/// Append | Alias for a Semigroup's operation. -infix operator <> { - associativity right - precedence 160 -} - -/// MARK: Control.Category - -/// Right-to-Left Composition | Composes two categories to form a new category with the source of -/// the second category and the target of the first category. -/// -/// This function is literally `•`, but for Categories. -infix operator <<< { - precedence 110 - associativity right -} - -/// Left-to-Right Composition | Composes two categories to form a new category with the source of -/// the first category and the target of the second category. -/// -/// Function composition with the arguments flipped. -infix operator >>> { - precedence 110 - associativity right -} - -/// MARK: Control.Arrow - -/// Split | Splits two computations and combines the result into one Arrow yielding a tuple of -/// the result of each side. -infix operator *** { - precedence 130 - associativity right -} - -/// Fanout | Given two functions with the same source but different targets, this function -/// splits the computation and combines the result of each Arrow into a tuple of the result of -/// each side. -infix operator &&& { - precedence 130 - associativity right -} - -/// MARK: Control.Arrow.Choice - -/// Splat | Splits two computations and combines the results into Eithers on the left and right. -infix operator +++ { - precedence 120 - associativity right -} - -/// Fanin | Given two functions with the same target but different sources, this function splits -/// the input between the two and merges the output. -infix operator ||| { - precedence 120 - associativity right -} - -/// MARK: Control.Arrow.Plus - -/// Op | Combines two ArrowZero monoids. -infix operator <+> { - precedence 150 - associativity right -} - -/// MARK: Data.JSON - -/// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. -/// -/// If the given keypath is not present or the retrieved value is not of the appropriate type, this -/// function returns `.None`. -infix operator Date: Tue, 7 Jul 2015 21:52:35 -0600 Subject: [PATCH 042/460] Prepare for Testable instance of Gen --- SwiftCheck/Testable.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index e9e5490..6c1da4d 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -16,7 +16,6 @@ public protocol Testable { var exhaustive : Bool { get } - func property() -> Property } @@ -73,3 +72,11 @@ extension Bool : Testable { return TestResult.liftBool(self).property() } } + +extension Gen where A : Testable { + public var exhaustive : Bool { return false } + + public func property() -> Property { + return Property(self >>- { $0.property().unProperty }) + } +} From 612640578e6387bfe622534afedb1b10539bc77f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 21:56:13 -0600 Subject: [PATCH 043/460] Make property a var --- SwiftCheck/Property.swift | 12 ++++++------ SwiftCheck/Test.swift | 2 +- SwiftCheck/TestOperators.swift | 12 ++++++------ SwiftCheck/Testable.swift | 31 ++++++++++++++++--------------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index b4623df..f2375b7 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -17,7 +17,7 @@ /// When conjoining properties all calls to `expectFailure` will fail. public func conjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property().unProperty.fmap({ $0.unProp }) + return p.property.unProperty.fmap({ $0.unProp }) })).bind({ roses in return Gen.pure(Prop(unProp: conj(id, xs: roses))) })) @@ -33,7 +33,7 @@ public func conjoin(ps : Testable...) -> Property { /// When disjoining properties all calls to `expectFailure` will fail. public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property().unProperty.fmap({ $0.unProp }) + return p.property.unProperty.fmap({ $0.unProp }) })).bind({ roses in return Gen.pure(Prop(unProp: roses.reduce(.MkRose({ TestResult.failed() }, { [] }), combine: disj))) })) @@ -42,13 +42,13 @@ public func disjoin(ps : Testable...) -> Property { extension Testable { /// Applies a function that modifies the property generator's inner `Prop`. public func mapProp(f : Prop -> Prop) -> Property { - return Property(self.property().unProperty.fmap(f)) + return Property(self.property.unProperty.fmap(f)) } /// Applies a function that modifies the property generator's size. public func mapSize(f : Int -> Int) -> Property { return Property(Gen.sized({ n in - return self.property().unProperty.resize(f(n)) + return self.property.unProperty.resize(f(n)) })) } @@ -230,7 +230,7 @@ extension Testable { abort: res.abort) }) } - return self.property() + return self.property } } @@ -343,7 +343,7 @@ private func exception(msg : String) -> ErrorType -> TestResult { } private func props(shrinker : A -> [A], original : A, pf: A -> Testable) -> Rose> { - return .MkRose({ pf(original).property().unProperty }, { shrinker(original).map { x1 in + return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 4470140..84d09f5 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -219,7 +219,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { , numTryShrinks: 0 , numTotTryShrinks: 0 , shouldAbort: false) - let modP : Property = (p.exhaustive ? p.property().once : p.property()) + let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(state, f: modP.unProperty.unGen) } diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 1053b5f..fb9ac2b 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -51,18 +51,18 @@ infix operator ==> { /// (in which case the test case is discarded), or if the given property holds. public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { if b { - return p().property() + return p().property } - return Discard().property() + return Discard().property } /// Models implication for properties. That is, the property holds if the first argument is false /// (in which case the test case is discarded), or if the given property holds. public func ==>(b : Bool, p : () -> Testable) -> Property { if b { - return p().property() + return p().property } - return Discard().property() + return Discard().property } infix operator ==== { @@ -100,7 +100,7 @@ infix operator ^&&^ { /// Conjoined properties succeed only when both sub-properties succeed and fail when one or more /// sub-properties fail. public func ^&&^(p1 : Testable, p2 : Testable) -> Property { - return conjoin(p1.property(), p2.property()) + return conjoin(p1.property, p2.property) } @@ -114,7 +114,7 @@ infix operator ^||^ { /// Disjoined properties succeed only when one or more sub-properties succeed and fail when both /// sub-properties fail. public func ^||^(p1 : Testable, p2 : Testable) -> Property { - return disjoin(p1.property(), p2.property()) + return disjoin(p1.property, p2.property) } import func XCTest.XCTFail diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index 6c1da4d..adcb94c 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -15,21 +15,24 @@ /// An exhaustiveness property is also required. If true, the property will only be tested once. public protocol Testable { var exhaustive : Bool { get } + var property : Property { get } +} - func property() -> Property +extension Testable { + public var exhaustive : Bool { + return false + } } /// A property is anything that generates propositions. public struct Property : Testable { let unProperty : Gen - public var exhaustive : Bool { return false } - public init(_ val : Gen) { self.unProperty = val; } - public func property() -> Property { + public var property : Property { return Property(self.unProperty) } } @@ -40,7 +43,7 @@ public struct Prop : Testable { public var exhaustive : Bool { return true } - public func property() -> Property { + public var property : Property { // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) } @@ -52,15 +55,15 @@ public struct Discard : Testable { public init() { } - public func property() -> Property { - return TestResult.rejected.property() + public var property : Property { + return TestResult.rejected.property } } extension TestResult : Testable { public var exhaustive : Bool { return true } - public func property() -> Property { + public var property : Property { return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) } } @@ -68,15 +71,13 @@ extension TestResult : Testable { extension Bool : Testable { public var exhaustive : Bool { return true } - public func property() -> Property { - return TestResult.liftBool(self).property() + public var property : Property { + return TestResult.liftBool(self).property } } -extension Gen where A : Testable { - public var exhaustive : Bool { return false } - - public func property() -> Property { - return Property(self >>- { $0.property().unProperty }) +extension Gen where A : Testable { + public var property : Property { + return Property(self >>- { $0.property.unProperty }) } } From fdfee3800f930c7441dca5a2c0a9406178a9ef35 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 22:04:05 -0600 Subject: [PATCH 044/460] Redo Testable Documentation --- SwiftCheck/Testable.swift | 20 +++++++++++++------- SwiftCheckTests/GenSpec.swift | 6 +++--- SwiftCheckTests/ShrinkSpec.swift | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index adcb94c..d65d747 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -7,14 +7,20 @@ // -/// The type of things that can be tested. +/// The type of things that can be tested. Consequently, the type of things that can be returned +/// from a `forAll` block. /// -/// A testable type must be able to convert itself to a Property. That entails being able to create -/// a Generator for elements of its encapsulated type. -/// -/// An exhaustiveness property is also required. If true, the property will only be tested once. +/// `Testable` values must be able to produce a `Rose`, that is a rose tree of test +/// cases that terminates in a passing or failing `TestResult`. SwiftCheck provides instances for +/// `Bool`, `Discard`, `Prop`, and `Property`. The last of these enables `forAll`s to return +/// further `forAll`s that can depend on previously generated values. public protocol Testable { + /// Returns true iff a single test case is exhaustive i.e. adequately covers the search space. + /// + /// If true, the property will only be tested once. Defaults to false. var exhaustive : Bool { get } + + /// Returns a `Property`, which SwiftCheck uses to perform test case generation. var property : Property { get } } @@ -33,7 +39,7 @@ public struct Property : Testable { } public var property : Property { - return Property(self.unProperty) + return self } } @@ -76,7 +82,7 @@ extension Bool : Testable { } } -extension Gen where A : Testable { +extension Gen /*: Testable*/ where A : Testable { public var property : Property { return Property(self >>- { $0.property.unProperty }) } diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 0ab689c..b1e0e12 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -63,7 +63,7 @@ class GenSpec : XCTestCase { return Discard() } let l = Set(xss.getArray) - return forAll(Gen.oneOf(xss.getArray.map({ Gen.pure($0) }))) { l.contains($0) } + return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } } property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in @@ -73,11 +73,11 @@ class GenSpec : XCTestCase { } property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = Int.arbitrary.proliferateSized(n).fmap({ ArrayOf($0) }) + let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) return forAll(g) { $0.getArray.count == n } } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferateSized(0).fmap({ ArrayOf($0) })) { + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { return $0.getArray.isEmpty } diff --git a/SwiftCheckTests/ShrinkSpec.swift b/SwiftCheckTests/ShrinkSpec.swift index 2eb42a7..3b119b8 100644 --- a/SwiftCheckTests/ShrinkSpec.swift +++ b/SwiftCheckTests/ShrinkSpec.swift @@ -13,7 +13,7 @@ class ShrinkSpec : XCTestCase { func shrinkArbitrary(x : A) -> [A] { let xs = A.shrink(x) if let x = xs.first { - return xs + [x].flatMap({ self.shrinkArbitrary($0) }) + return xs + [x].flatMap(self.shrinkArbitrary) } return xs } From 8da0ffbfe536a5e7306676ca3adb8242b0b8b5a1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Jul 2015 22:11:26 -0600 Subject: [PATCH 045/460] Add Operadics as submodule --- .gitmodules | 3 +++ Carthage/Checkouts/Operadics | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 Carthage/Checkouts/Operadics diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bf0c263 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Carthage/Checkouts/Operadics"] + path = Carthage/Checkouts/Operadics + url = https://github.com/typelift/Operadics.git diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics new file mode 160000 index 0000000..1e54027 --- /dev/null +++ b/Carthage/Checkouts/Operadics @@ -0,0 +1 @@ +Subproject commit 1e54027cccb0c29e28900c3fc241d2617364d33d From 82fc666f298a25ee1f3f35bdd64c20198015cb25 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 14:50:57 -0600 Subject: [PATCH 046/460] Update to beta 3 --- SwiftCheck.xcodeproj/project.pbxproj | 8 +- SwiftCheck/Arbitrary.swift | 126 +++++++++++++-------------- SwiftCheck/Gen.swift | 2 +- SwiftCheck/Modifiers.swift | 2 +- SwiftCheck/Test.swift | 8 +- 5 files changed, 73 insertions(+), 73 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 8bb0b94..c13dd85 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -593,7 +593,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = "-Xfrontend -gnone"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -626,7 +626,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = "-Xfrontend -gnone"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -688,7 +688,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -gnone"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftCheck; SDKROOT = iphoneos; @@ -714,7 +714,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-Xfrontend -gnone"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftCheck; SDKROOT = iphoneos; diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 886daaa..457f716 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -48,12 +48,12 @@ public protocol Arbitrary { /// same as the value provided to this function (or a loop will form in the shrinker). It is /// recommended that they be presented smallest to largest to speed up the overall shrinking /// process. - static func shrink(Self) -> [Self] + static func shrink(_ : Self) -> [Self] } extension Arbitrary { /// The implementation of a shrink that returns no alternatives. - public static func shrink(Self) -> [Self] { + public static func shrink(_ : Self) -> [Self] { return [] } } @@ -266,20 +266,20 @@ extension Character : Arbitrary { } } -extension Array where T : Arbitrary { - public static var arbitrary : Gen> { +extension Array where Element : Arbitrary { + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure([]) } - return sequence((0...k).map { _ in T.arbitrary }) + return sequence((0...k).map { _ in Element.arbitrary }) } } } - public static func shrink(bl : Array) -> [[T]] { + public static func shrink(bl : Array) -> [[Element]] { return Int.shrink(bl.count).reverse().flatMap({ k in removes(k + 1, n: bl.count, xs: bl) }) + shrinkOne(bl) } } @@ -306,29 +306,29 @@ extension AnyRandomAccessIndex : Arbitrary { } } -extension AnySequence where T : Arbitrary { - public static var arbitrary : Gen> { - return [T].arbitrary.fmap(AnySequence.init) +extension AnySequence where Element : Arbitrary { + public static var arbitrary : Gen> { + return [Element].arbitrary.fmap(AnySequence.init) } - public static func shrink(bl : AnySequence) -> [AnySequence] { - return [T].shrink([Element](bl)).map(AnySequence.init) + public static func shrink(bl : AnySequence) -> [AnySequence] { + return [Element].shrink([Element](bl)).map(AnySequence.init) } } -extension ArraySlice where T : Arbitrary { - public static var arbitrary : Gen> { - return [T].arbitrary.fmap(ArraySlice.init) +extension ArraySlice where Element : Arbitrary { + public static var arbitrary : Gen> { + return [Element].arbitrary.fmap(ArraySlice.init) } - public static func shrink(bl : ArraySlice) -> [ArraySlice] { - return [T].shrink([Element](bl)).map(ArraySlice.init) + public static func shrink(bl : ArraySlice) -> [ArraySlice] { + return [Element].shrink([Element](bl)).map(ArraySlice.init) } } -extension CollectionOfOne where T : Arbitrary { - public static var arbitrary : Gen> { - return T.arbitrary.fmap(CollectionOfOne.init) +extension CollectionOfOne where Element : Arbitrary { + public static var arbitrary : Gen> { + return Element.arbitrary.fmap(CollectionOfOne.init) } } @@ -338,7 +338,7 @@ extension Optional where T : Arbitrary { return Gen>.frequency([ (1, Gen>.pure(.None)), (3, liftM(Optional.Some)(m1: T.arbitrary)), - ]) + ]) } public static func shrink(bl : Optional) -> [Optional] { @@ -349,13 +349,13 @@ extension Optional where T : Arbitrary { } } -extension ContiguousArray where T : Arbitrary { - public static var arbitrary : Gen> { - return [T].arbitrary.fmap(ContiguousArray.init) +extension ContiguousArray where Element : Arbitrary { + public static var arbitrary : Gen> { + return [Element].arbitrary.fmap(ContiguousArray.init) } - public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { - return [T].shrink([T](bl)).map(ContiguousArray.init) + public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { + return [Element].shrink([Element](bl)).map(ContiguousArray.init) } } @@ -364,13 +364,13 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { public static var arbitrary : Gen> { return [Key].arbitrary.bind { k in return [Value].arbitrary.bind { v in - return Gen.pure(Dictionary(Zip2(k, v))) + return Gen.pure(Dictionary(Zip2Sequence(k, v))) } } } public static func shrink(d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(Zip2(Key.shrink($0), Value.shrink($1))) } + return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } } @@ -385,22 +385,22 @@ extension Dictionary { } extension EmptyCollection : Arbitrary { - public static var arbitrary : Gen> { + public static var arbitrary : Gen> { return Gen.pure(EmptyCollection()) } } -extension HalfOpenInterval where T : protocol { - public static var arbitrary : Gen> { - return T.arbitrary.bind { l in - return T.arbitrary.bind { r in +extension HalfOpenInterval where Bound : protocol { + public static var arbitrary : Gen> { + return Bound.arbitrary.bind { l in + return Bound.arbitrary.bind { r in return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) } } } - public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { - return Zip2(T.shrink(bl.start), T.shrink(bl.end)).map(HalfOpenInterval.init) + public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { + return Zip2Sequence(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } } @@ -414,65 +414,65 @@ extension ImplicitlyUnwrappedOptional where T : Arbitrary { } } -extension LazyBidirectionalCollection where S : protocol, S.Index : BidirectionalIndexType { - public static var arbitrary : Gen> { - return S.arbitrary.fmap(lazy) +extension LazyBidirectionalCollection where Base : protocol, Base.Index : BidirectionalIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(lazy) } } -extension LazyForwardCollection where S : protocol, S.Index : ForwardIndexType { - public static var arbitrary : Gen> { - return S.arbitrary.fmap(lazy) +extension LazyForwardCollection where Base : protocol, Base.Index : ForwardIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(lazy) } } -extension LazyRandomAccessCollection where S : protocol, S.Index : RandomAccessIndexType { - public static var arbitrary : Gen> { - return S.arbitrary.fmap(lazy) +extension LazyRandomAccessCollection where Base : protocol, Base.Index : RandomAccessIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(lazy) } } -extension LazySequence where S : protocol { - public static var arbitrary : Gen> { - return S.arbitrary.fmap(lazy) +extension LazySequence where Base : protocol { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(lazy) } } -extension Range where T : protocol { - public static var arbitrary : Gen> { - return T.arbitrary.bind { l in - return T.arbitrary.bind { r in +extension Range where Element : protocol { + public static var arbitrary : Gen> { + return Element.arbitrary.bind { l in + return Element.arbitrary.bind { r in return Gen.pure(Range(start: min(l, r), end: max(l, r))) } } } - public static func shrink(bl : Range) -> [Range] { - return Zip2(T.shrink(bl.startIndex), T.shrink(bl.endIndex)).map(Range.init) + public static func shrink(bl : Range) -> [Range] { + return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) } } -extension Repeat where T : Arbitrary { - public static var arbitrary : Gen> { - return Gen.zip(Int.arbitrary, T.arbitrary).fmap(Repeat.init) +extension Repeat where Element : Arbitrary { + public static var arbitrary : Gen> { + return Gen.zip(Int.arbitrary, Element.arbitrary).fmap(Repeat.init) } } -extension Set where T : protocol { - public static var arbitrary : Gen> { +extension Set where Element : protocol { + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure(Set([])) } - return sequence(Array((0...k)).map { _ in T.arbitrary }).fmap(Set.init) + return sequence(Array((0...k)).map { _ in Element.arbitrary }).fmap(Set.init) } } } - public static func shrink(s : Set) -> [Set] { - return [T].shrink([T](s)).map(Set.init) + public static func shrink(s : Set) -> [Set] { + return [Element].shrink([Element](s)).map(Set.init) } } @@ -604,11 +604,11 @@ extension Double : CoArbitrary { } extension Array : CoArbitrary { - public static func coarbitrary(a : [T]) -> (Gen -> Gen) { + public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { if a.isEmpty { return { $0.variant(0) } } - return { $0.variant(1) } • [T].coarbitrary([T](a[1..(x : Set) -> (Gen -> Gen) { + public static func coarbitrary(x : Set) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index d30d726..db7b6ec 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -26,7 +26,7 @@ public struct Gen { public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return gen1.bind { l in return gen2.bind { r in - return Gen<(A, B)>.pure(l, r) + return Gen<(A, B)>.pure((l, r)) } } } diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 3ca71c0..978dbc7 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -305,7 +305,7 @@ public struct IsoOf, U : protocol public static func shrink(f : IsoOf) -> [IsoOf] { return f.table.flatMap { (x, y) in - return Zip2(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in + return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in return IsoOf({ (z : T) -> U in if x == z { return y2 diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 84d09f5..27dcbe5 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -535,13 +535,13 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { } extension Array { - internal func groupBy(p : (T , T) -> Bool) -> [[T]] { - func span(list : [T], p : (T -> Bool)) -> ([T], [T]) { + internal func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { + func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { if list.isEmpty { return ([], []) } else if let x = list.first { if p (x) { - let (ys, zs) = span([T](list[1.. Date: Wed, 8 Jul 2015 14:56:14 -0600 Subject: [PATCH 047/460] =?UTF-8?q?=CE=BB=20Golfing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SwiftCheck/Arbitrary.swift | 20 ++++++++++---------- SwiftCheck/Property.swift | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 457f716..ca99b0c 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -286,7 +286,7 @@ extension Array where Element : Arbitrary { extension AnyBidirectionalCollection where Element : Arbitrary { public static var arbitrary : Gen> { - return [Element].arbitrary.fmap(AnyBidirectionalCollection.init) + return AnyBidirectionalCollection.init <^> [Element].arbitrary } public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { @@ -308,7 +308,7 @@ extension AnyRandomAccessIndex : Arbitrary { extension AnySequence where Element : Arbitrary { public static var arbitrary : Gen> { - return [Element].arbitrary.fmap(AnySequence.init) + return AnySequence.init <^> [Element].arbitrary } public static func shrink(bl : AnySequence) -> [AnySequence] { @@ -318,7 +318,7 @@ extension AnySequence where Element : Arbitrary { extension ArraySlice where Element : Arbitrary { public static var arbitrary : Gen> { - return [Element].arbitrary.fmap(ArraySlice.init) + return ArraySlice.init <^> [Element].arbitrary } public static func shrink(bl : ArraySlice) -> [ArraySlice] { @@ -328,7 +328,7 @@ extension ArraySlice where Element : Arbitrary { extension CollectionOfOne where Element : Arbitrary { public static var arbitrary : Gen> { - return Element.arbitrary.fmap(CollectionOfOne.init) + return CollectionOfOne.init <^> Element.arbitrary } } @@ -351,7 +351,7 @@ extension Optional where T : Arbitrary { extension ContiguousArray where Element : Arbitrary { public static var arbitrary : Gen> { - return [Element].arbitrary.fmap(ContiguousArray.init) + return ContiguousArray.init <^> [Element].arbitrary } public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { @@ -406,7 +406,7 @@ extension HalfOpenInterval where Bound : protocol { extension ImplicitlyUnwrappedOptional where T : Arbitrary { public static var arbitrary : Gen> { - return Optional.arbitrary.fmap(ImplicitlyUnwrappedOptional.init) + return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary } public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { @@ -454,7 +454,7 @@ extension Range where Element : protocol> { - return Gen.zip(Int.arbitrary, Element.arbitrary).fmap(Repeat.init) + return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) } } @@ -466,7 +466,7 @@ extension Set where Element : protocol { return Gen.pure(Set([])) } - return sequence(Array((0...k)).map { _ in Element.arbitrary }).fmap(Set.init) + return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) } } } @@ -650,9 +650,9 @@ private func bits(n : N) -> Int { private func inBounds(fi : (Int -> A)) -> Gen -> Gen { return { g in - return g.suchThat({ x in + return fi <^> g.suchThat { x in return (fi(x) as! Int) == x - }).fmap(fi) + } } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index f2375b7..979fe41 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -17,7 +17,7 @@ /// When conjoining properties all calls to `expectFailure` will fail. public func conjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.fmap({ $0.unProp }) + return p.property.unProperty.fmap { $0.unProp } })).bind({ roses in return Gen.pure(Prop(unProp: conj(id, xs: roses))) })) @@ -33,7 +33,7 @@ public func conjoin(ps : Testable...) -> Property { /// When disjoining properties all calls to `expectFailure` will fail. public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.fmap({ $0.unProp }) + return p.property.unProperty.fmap { $0.unProp } })).bind({ roses in return Gen.pure(Prop(unProp: roses.reduce(.MkRose({ TestResult.failed() }, { [] }), combine: disj))) })) @@ -42,7 +42,7 @@ public func disjoin(ps : Testable...) -> Property { extension Testable { /// Applies a function that modifies the property generator's inner `Prop`. public func mapProp(f : Prop -> Prop) -> Property { - return Property(self.property.unProperty.fmap(f)) + return Property(f <^> self.property.unProperty) } /// Applies a function that modifies the property generator's size. @@ -54,16 +54,16 @@ extension Testable { /// Applies a function that modifies the result of a test case. public func mapTotalResult(f : TestResult -> TestResult) -> Property { - return self.mapRoseResult({ rs in - return protectResults(rs.fmap(f)) - }) + return self.mapRoseResult { rs in + return protectResults(f <^> rs) + } } /// Applies a function that modifies the result of a test case. public func mapResult(f : TestResult -> TestResult) -> Property { - return self.mapRoseResult({ rs in - return rs.fmap(f) - }) + return self.mapRoseResult { rs in + return f <^> rs + } } /// Applies a function that modifies the underlying Rose Tree that a test case has generated. From 71ecd03e76b71e7e05f68fdabbccf3b134edf16a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 22:20:36 -0600 Subject: [PATCH 048/460] Relax Hashable constraint to Equatable --- SwiftCheck/Modifiers.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 978dbc7..2b151fc 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -249,7 +249,7 @@ extension ArrowOf : CustomReflectable { } /// Generates two isomorphic Swift function from T to U and back again. -public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { +public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { private var table : Dictionary private var embed : T -> U private var project : U -> T From 961d13b843972346f8f243d440c4cf57e7398141 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 22:20:45 -0600 Subject: [PATCH 049/460] Cleanup --- .gitignore | 1 + SwiftCheck/Test.swift | 76 +++++++++++++++--------------- SwiftCheckTests/ModifierSpec.swift | 16 +++---- 3 files changed, 47 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index a167343..bae65ef 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ DerivedData *.hmap *.xcuserstate *.xccheckout +*.xcscmblueprint Carthage/Build Carthage/Checkouts diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 27dcbe5..b81c808 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -206,19 +206,19 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { let state = CheckerState( name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard - , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 - , labels: [:] - , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 - , shouldAbort: false) + , maxSuccessTests: args.maxSuccess + , maxDiscardedTests: args.maxDiscard + , computeSize: computeSize + , numSuccessTests: 0 + , numDiscardedTests: 0 + , labels: [:] + , collected: [] + , expectedFailure: false + , randomSeed: rnd() + , numSuccessShrinks: 0 + , numTryShrinks: 0 + , numTotTryShrinks: 0 + , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(state, f: modP.unProperty.unGen) } @@ -275,36 +275,36 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests + 1 - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + 1 + , numDiscardedTests: st.numDiscardedTests + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , expectedFailure: expect + , randomSeed: st.randomSeed + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) return .Right(Box(nstate)) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + 1 + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , expectedFailure: expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) return .Right(Box(nstate)) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index 0e98f3f..337fa50 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -34,7 +34,7 @@ class ModifierSpec : XCTestCase { property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in return true } - + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in return (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" @@ -45,13 +45,13 @@ class ModifierSpec : XCTestCase { property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) } - - property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in - return - iso.getFrom(iso.getTo(x)) == x - ^&&^ - iso.getTo(iso.getFrom(y)) == y - } + + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in + return + iso.getFrom(iso.getTo(x)) == x + ^&&^ + iso.getTo(iso.getFrom(y)) == y + } property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow From 21536184712e578125ddd9df86758d833a5743c0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 22:39:09 -0600 Subject: [PATCH 050/460] Generalize oneOf --- SwiftCheck/Gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index db7b6ec..194d71d 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -94,10 +94,10 @@ public struct Gen { } /// Constructs a Generator that randomly selects and uses one of a number of given Generators. - public static func oneOf(gs : [Gen]) -> Gen { + public static func oneOf, S.Index : RandomType>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") - return choose((0, gs.count - 1)) >>- { x in + return choose((gs.indices.startIndex, advance(gs.indices.endIndex, -1))) >>- { x in return gs[x] } } From ce3d506682017dbe05009d393cf8e92c8a964db5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 22:39:24 -0600 Subject: [PATCH 051/460] Add conjamb --- SwiftCheck/Property.swift | 11 +++++++++++ SwiftCheckTests/PropertySpec.swift | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 979fe41..0b84475 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -39,6 +39,17 @@ public func disjoin(ps : Testable...) -> Property { })) } +/// Takes the nondeterministic conjunction of multiple properties and treats them as a single large +/// property. +/// +/// The resulting property makes 100 random choices to test any of the given properties. Thus, +/// running multiple test cases will result in distinct arbitrary sequences of each property being +/// tested. +public func conjamb(ps : () -> Testable...) -> Property { + let ls = lazy(ps).map { $0().property.unProperty } + return Property(Gen.oneOf(ls)) +} + extension Testable { /// Applies a function that modifies the property generator's inner `Prop`. public func mapProp(f : Prop -> Prop) -> Property { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index bf70449..db735a9 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -19,5 +19,18 @@ class PropertySpec : XCTestCase { return b == n }.once } + + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in + return conjamb({ + print("picked 1") + return true + }, { + print("picked 2") + return true + }, { + print("picked 3") + return true + }) + } } } From ea199b66c91ac6eb3e8d3b2046b6779fe871a785 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Jul 2015 22:43:52 -0600 Subject: [PATCH 052/460] Remove disgusting hack --- SwiftCheck/Gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 194d71d..33ed54d 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -94,10 +94,10 @@ public struct Gen { } /// Constructs a Generator that randomly selects and uses one of a number of given Generators. - public static func oneOf, S.Index : RandomType>(gs : S) -> Gen { + public static func oneOf, S.Index : protocol>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.indices.startIndex, advance(gs.indices.endIndex, -1))) >>- { x in + return choose((gs.indices.startIndex, gs.indices.endIndex.predecessor())) >>- { x in return gs[x] } } From 6a03411622062b736232a78c1e483edb06b9cf42 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 10 Jul 2015 18:38:59 -0600 Subject: [PATCH 053/460] Realign and remove print --- SwiftCheckTests/PropertySpec.swift | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index db735a9..e052d21 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -22,15 +22,12 @@ class PropertySpec : XCTestCase { property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in return conjamb({ - print("picked 1") - return true - }, { - print("picked 2") - return true - }, { - print("picked 3") - return true - }) + return true "picked 1" + }, { + return true "picked 2" + }, { + return true "picked 3" + }) } } } From 495a989723041439805d6af1e91144bce0251c03 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 22 Jul 2015 15:36:27 -0600 Subject: [PATCH 054/460] Fix compiler error --- SwiftCheck/Test.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index b81c808..cf98e08 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -486,9 +486,11 @@ internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestRe } internal func summary(s : CheckerState) -> [(String, Int)] { - let strings = s.collected.flatMap({ l in Array(l).map({ "," + $0.0 }).filter({ !$0.isEmpty }) }) - let l = strings.sort().groupBy(==) - return l.map({ ss in (ss[0], ss.count * 100 / s.numSuccessTests) }) + let l = s.collected + .flatMap({ l in l.map({ "," + $0 }).filter({ !$0.isEmpty }) }) + .sort() + .groupBy(==) + return l.map({ ss in (ss.first!, ss.count * 100 / s.numSuccessTests) }) } internal func labelPercentage(l : String, st : CheckerState) -> Int { @@ -498,7 +500,7 @@ internal func labelPercentage(l : String, st : CheckerState) -> Int { internal func printDistributionGraph(st : CheckerState) { func showP(n : Int) -> String { - return (n < 10 ? " " : "") + "\(n)" + "% " + return (n < 10 ? " " : "") + "\(n)" + "%" } let gAllLabels = st.collected.map({ (s : Set) in From b881537073ffab9b0a84b38a8e7adf70837010b1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 26 Jul 2015 19:08:31 -0600 Subject: [PATCH 055/460] Add WitnessedArbitrary protocol for [functor-like] Arbitrary types that must bear witness to 1 parameter. --- SwiftCheck/Witness.swift | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 SwiftCheck/Witness.swift diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift new file mode 100644 index 0000000..a3dd0d7 --- /dev/null +++ b/SwiftCheck/Witness.swift @@ -0,0 +1,61 @@ +// +// Witness.swift +// SwiftCheck +// +// Created by Robert Widmann on 7/26/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +public protocol WitnessedArbitrary { + typealias Param + + static func forAllWitnessed(wit : A -> Param)(pf : (Self -> Testable)) -> Property +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for that type. +public func forAll(pf : (A -> Testable)) -> Property { + return A.forAllWitnessed(id)(pf: pf) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 2 types. +public func forAll(pf : (A, B) -> Testable) -> Property { + return forAll({ t in forAll({ b in pf(t, b) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 3 types. +public func forAll(pf : (A, B, C) -> Testable) -> Property { + return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 4 types. +public func forAll(pf : (A, B, C, D) -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 5 types. +public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 6 types. +public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 7 types. +public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +} + +/// Converts a function into a universally quantified property using the default shrinker and +/// generator for 8 types. +public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +} From 0907339f33a4cb5ca927c16d2ae16d0d7931a41c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 26 Jul 2015 19:08:57 -0600 Subject: [PATCH 056/460] Add obvious WitnessedArbitrary instances --- SwiftCheck.xcodeproj/project.pbxproj | 10 ++- SwiftCheck/Arbitrary.swift | 103 ++++++++++++++++++++++++++- SwiftCheck/Property.swift | 2 +- 3 files changed, 111 insertions(+), 4 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index c13dd85..3dd7615 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; + 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -89,6 +91,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; }; @@ -191,6 +194,7 @@ 844FCCB3198B39F300EB242A /* State.swift */, 844FCCAF198B36BE00EB242A /* Test.swift */, 84572C2A1A6DBABA00241F68 /* Testable.swift */, + 827749F71B65ABCC00A7965F /* Witness.swift */, D46395B51B1A94D200AA1B65 /* Equatable.swift */, 844FCC90198B320500EB242A /* Supporting Files */, ); @@ -417,6 +421,7 @@ 844FCCAA198B323800EB242A /* Arbitrary.swift in Sources */, 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */, 844FCCB4198B39F300EB242A /* State.swift in Sources */, + 827749F81B65ABCC00A7965F /* Witness.swift in Sources */, 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -453,6 +458,7 @@ 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */, 84DF761B1B0BD58100C912B0 /* State.swift in Sources */, 84DF761C1B0BD58100C912B0 /* Test.swift in Sources */, + 827749F91B65ABCC00A7965F /* Witness.swift in Sources */, 84DF761D1B0BD58100C912B0 /* Testable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -686,7 +692,7 @@ ); INFOPLIST_FILE = SwiftCheck/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; @@ -712,7 +718,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SwiftCheck/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index ca99b0c..8b673d6 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -284,6 +284,16 @@ extension Array where Element : Arbitrary { } } +extension Array : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : ([Element] -> Testable)) -> Property { + return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + extension AnyBidirectionalCollection where Element : Arbitrary { public static var arbitrary : Gen> { return AnyBidirectionalCollection.init <^> [Element].arbitrary @@ -294,6 +304,16 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } } +extension AnyBidirectionalCollection : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (AnyBidirectionalCollection -> Testable)) -> Property { + return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in + return pf(AnyBidirectionalCollection(bl.map(wit))) + }) + } +} + extension AnyForwardIndex : Arbitrary { public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) @@ -316,6 +336,16 @@ extension AnySequence where Element : Arbitrary { } } +extension AnySequence : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (AnySequence -> Testable)) -> Property { + return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in + return pf(AnySequence(bl.map(wit))) + }) + } +} + extension ArraySlice where Element : Arbitrary { public static var arbitrary : Gen> { return ArraySlice.init <^> [Element].arbitrary @@ -326,12 +356,32 @@ extension ArraySlice where Element : Arbitrary { } } +extension ArraySlice : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (ArraySlice -> Testable)) -> Property { + return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in + return pf(ArraySlice(bl.map(wit))) + }) + } +} + extension CollectionOfOne where Element : Arbitrary { public static var arbitrary : Gen> { return CollectionOfOne.init <^> Element.arbitrary } } +extension CollectionOfOne : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (CollectionOfOne -> Testable)) -> Property { + return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in + return pf(CollectionOfOne(wit(bl[.Zero]))) + }) + } +} + /// Generates an Optional of arbitrary values of type A. extension Optional where T : Arbitrary { public static var arbitrary : Gen> { @@ -349,6 +399,16 @@ extension Optional where T : Arbitrary { } } +extension Optional : WitnessedArbitrary { + public typealias Param = T + + public static func forAllWitnessed(wit : A -> T)(pf : (Optional -> Testable)) -> Property { + return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + extension ContiguousArray where Element : Arbitrary { public static var arbitrary : Gen> { return ContiguousArray.init <^> [Element].arbitrary @@ -359,6 +419,16 @@ extension ContiguousArray where Element : Arbitrary { } } +extension ContiguousArray : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (ContiguousArray -> Testable)) -> Property { + return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in + return pf(ContiguousArray(bl.map(wit))) + }) + } +} + /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { public static var arbitrary : Gen> { @@ -400,7 +470,7 @@ extension HalfOpenInterval where Bound : protocol { } public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { - return Zip2Sequence(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) + return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } } @@ -414,6 +484,16 @@ extension ImplicitlyUnwrappedOptional where T : Arbitrary { } } +extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { + public typealias Param = T + + public static func forAllWitnessed(wit : A -> T)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { + return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + extension LazyBidirectionalCollection where Base : protocol, Base.Index : BidirectionalIndexType { public static var arbitrary : Gen> { return Base.arbitrary.fmap(lazy) @@ -458,6 +538,17 @@ extension Repeat where Element : Arbitrary { } } +extension Repeat : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { + return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in + let xs = bl.map(wit) + return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) + }) + } +} + extension Set where Element : protocol { public static var arbitrary : Gen> { return Gen.sized { n in @@ -476,6 +567,16 @@ extension Set where Element : protocol { } } +extension Set : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (Set -> Testable)) -> Property { + return forAll { (xs : [A]) in + return pf(Set(xs.map(wit))) + } + } +} + /// Coarbitrary types must take an arbitrary value of their type and yield a function that /// transforms a given generator by returning a new generator that depends on the input value. Put /// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 0b84475..960bc63 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -389,7 +389,7 @@ private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"))(x: r) } } -private func id(x : A) -> A { +internal func id(x : A) -> A { return x } From c965fbe8f3c0d100f542eb2c4d61cf9e1502e13f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 26 Jul 2015 19:09:06 -0600 Subject: [PATCH 057/460] Use them in spec. --- SwiftCheckTests/TestSpec.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index 123a804..b7a2caf 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -15,28 +15,28 @@ class TestSpec : XCTestCase { return true } - property("Optionals behave") <- forAllShrink(Optional.arbitrary, shrinker: Optional.shrink) { (xs : Int?) in + property("Optionals behave") <- forAll { (xs : Int?) in return true } - property("Sets behave") <- forAllShrink(Set.arbitrary, shrinker: Set.shrink) { (xs : Set) in + property("Sets behave") <- forAll { (xs : Set) in return true } - property("The reverse of the reverse of an array is that array") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in + property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in return (xs.reverse().reverse() == xs) "Left identity" ^&&^ (xs == xs.reverse().reverse()) "Right identity" } - property("map behaves") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in + property("map behaves") <- forAll { (xs : Array) in return forAll { (f : ArrowOf) in return xs.map(f.getArrow) == xs.map(f.getArrow) } } - property("filter behaves") <- forAllShrink(Array.arbitrary, shrinker: Array.shrink) { (xs : Array) in + property("filter behaves") <- forAll { (xs : Array) in return forAll { (pred : ArrowOf) in let f = pred.getArrow return (xs.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) From 5368d0f14d5464ec669cbb6c9e8d4fc3e8012559 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 26 Jul 2015 19:15:03 -0600 Subject: [PATCH 058/460] Me -> TypeLift --- SwiftCheck/Witness.swift | 2 +- SwiftCheckTests/PropertySpec.swift | 2 +- SwiftCheckTests/ShrinkSpec.swift | 2 +- SwiftCheckTests/TestSpec.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index a3dd0d7..a11427b 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 7/26/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2015 TypeLift. All rights reserved. // public protocol WitnessedArbitrary { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index e052d21..828a4e7 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 6/5/15. -// Copyright (c) 2015 Robert Widmann. All rights reserved. +// Copyright (c) 2015 TypeLift. All rights reserved. // import XCTest diff --git a/SwiftCheckTests/ShrinkSpec.swift b/SwiftCheckTests/ShrinkSpec.swift index 3b119b8..9f50c81 100644 --- a/SwiftCheckTests/ShrinkSpec.swift +++ b/SwiftCheckTests/ShrinkSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 5/28/15. -// Copyright (c) 2015 Robert Widmann. All rights reserved. +// Copyright (c) 2015 TypeLift. All rights reserved. // import XCTest diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index b7a2caf..29a60c6 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 6/23/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2015 TypeLift. All rights reserved. // import XCTest From 261f0a79b52bf2d9e28809e6643d7ca4185a4e5e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 7 Aug 2015 00:51:17 -0600 Subject: [PATCH 059/460] Update to that new swift thing --- SwiftCheck/Arbitrary.swift | 2 +- SwiftCheck/Gen.swift | 8 ++++---- SwiftCheck/Property.swift | 16 ++++++++-------- SwiftCheck/Test.swift | 30 +++++++++++++++--------------- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index ca99b0c..316711e 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -280,7 +280,7 @@ extension Array where Element : Arbitrary { } public static func shrink(bl : Array) -> [[Element]] { - return Int.shrink(bl.count).reverse().flatMap({ k in removes(k + 1, n: bl.count, xs: bl) }) + shrinkOne(bl) + return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) } } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 33ed54d..56bd646 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -154,7 +154,7 @@ extension Gen { return Gen.pure(x) case .None: return Gen.sized { n in - return self.suchThat(p).resize(n + 1) + return self.suchThat(p).resize(n.successor()) } } } @@ -313,13 +313,13 @@ internal func delay() -> Gen -> A> { import func Darwin.log -private func vary(k : S)(r: StdGen) -> StdGen { +private func vary(k : S)(r : StdGen) -> StdGen { let s = r.split() let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2)(r: r) } -private func attemptBoundedTry(gen: Gen, k: Int, n : Int, p: A -> Bool) -> Gen> { +private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) -> Gen> { if n == 0 { return Gen.pure(.None) } @@ -327,7 +327,7 @@ private func attemptBoundedTry(gen: Gen, k: Int, n : Int, p: A -> Bool) -> if p(x) { return Gen.pure(.Some(x)) } - return attemptBoundedTry(gen, k: k + 1, n: n - 1, p: p) + return attemptBoundedTry(gen, k: k.successor(), n: n - 1, p: p) } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 0b84475..f95d17f 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -409,10 +409,10 @@ internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l - for (k, v) in l { + l.forEach { (k, v) in map.updateValue(v, forKey: k) } - for (k, v) in r { + r.forEach { (k, v) in map.updateValue(v, forKey: k) } return map @@ -509,7 +509,7 @@ private func disj(p : Rose, q : Rose) -> Rose, q : Rose) -> Rose, q : Rose) -> Rose, q : Rose) -> Rose Int -> Prop)) -> Either , maxSuccessTests: st.maxSuccessTests , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests + 1 + , numSuccessTests: st.numSuccessTests.successor() , numDiscardedTests: st.numDiscardedTests , labels: unionWith(max, l: st.labels, r: labels) , collected: [stamp] + st.collected @@ -296,7 +296,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 + , numDiscardedTests: st.numDiscardedTests.successor() , labels: unionWith(max, l: st.labels, r: labels) , collected: st.collected , expectedFailure: expect @@ -318,11 +318,11 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) if !expect { - let s = Result.Success(numTests: st.numSuccessTests + 1, labels: summary(st), output: "+++ OK, failed as expected. ") + let s = Result.Success(numTests: st.numSuccessTests.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") return .Left(Box((s, st))) } - let stat = Result.Failure(numTests: st.numSuccessTests + 1 + let stat = Result.Failure(numTests: st.numSuccessTests.successor() , numShrinks: numShrinks , usedSeed: st.randomSeed , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) @@ -335,7 +335,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , maxDiscardedTests: st.maxDiscardedTests , computeSize: st.computeSize , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests + 1 + , numDiscardedTests: st.numDiscardedTests.successor() , labels: st.labels , collected: st.collected , expectedFailure: res.expect @@ -385,7 +385,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts var lastResult = res var branches = ts var numSuccessShrinks = st.numSuccessShrinks - var numTryShrinks = st.numTryShrinks + 1 + var numTryShrinks = st.numTryShrinks.successor() var numTotTryShrinks = st.numTotTryShrinks // cont is a sanity check so we don't fall into an infinite loop. It is set to false at each @@ -403,7 +403,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts numTryShrinks = 0 // Try all possible courses of action in this Rose Tree - for r in branches { + branches.forEach { r in switch reduce(r) { case .MkRose(let resC, let ts1): let res1 = resC() @@ -447,7 +447,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts } internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \(st.numSuccessTests + 1) test" + let testMsg = " (after \(st.numSuccessTests.successor()) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" func pluralize(s : String, i : Int) -> String { @@ -458,29 +458,29 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In } print("Proposition: " + st.name) - print(res.reason + pluralize(testMsg, i: st.numSuccessTests + 1) + pluralize(shrinkMsg, i: st.numSuccessShrinks) + "):") + print(res.reason + pluralize(testMsg, i: st.numSuccessTests.successor()) + pluralize(shrinkMsg, i: st.numSuccessShrinks) + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) } internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { - for c in res.callbacks { + res.callbacks.forEach { c in switch c { case let .AfterTest(_, f): f(st, res) default: - continue + break } } } internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { - for c in res.callbacks { + res.callbacks.forEach { c in switch c { case let .AfterFinalFailure(_, f): f(st, res) default: - continue + break } } } @@ -511,7 +511,7 @@ internal func printDistributionGraph(st : CheckerState) { let allLabels = Array(gPrint.sort().reverse()) var covers = [String]() - for (l, reqP) in st.labels { + st.labels.forEach { (l, reqP) in let p = labelPercentage(l, st: st) if p < reqP { covers += ["only \(p)% " + l + ", not \(reqP)%"] @@ -525,7 +525,7 @@ internal func printDistributionGraph(st : CheckerState) { print("(\(pt))") } else { print(":") - for pt in all { + all.forEach { pt in print(pt) } } From 644847e6b0fde56e718333f474550cb9d366dc37 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 7 Aug 2015 00:55:58 -0600 Subject: [PATCH 060/460] Tests uses less modifiers --- SwiftCheckTests/GenSpec.swift | 8 ++++---- SwiftCheckTests/ShrinkSpec.swift | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index b1e0e12..90429b9 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -46,12 +46,12 @@ class GenSpec : XCTestCase { return forAll(g) { $0 == 0 } } - property("Gen.elements only generates the elements of the given array") <- forAll { (xss : ArrayOf) in - if xss.getArray.isEmpty { + property("Gen.elements only generates the elements of the given array") <- forAll { (xss : Array) in + if xss.isEmpty { return Discard() } - let l = Set(xss.getArray) - return forAll(Gen.fromElementsOf(xss.getArray)) { l.contains($0) } + let l = Set(xss) + return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } } property("Gen.elements only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in diff --git a/SwiftCheckTests/ShrinkSpec.swift b/SwiftCheckTests/ShrinkSpec.swift index 9f50c81..e4b9b3f 100644 --- a/SwiftCheckTests/ShrinkSpec.swift +++ b/SwiftCheckTests/ShrinkSpec.swift @@ -27,11 +27,11 @@ class ShrinkSpec : XCTestCase { return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) } - property("Shrinking a list never gives back the original") <- forAll { (l : ArrayOf) in - return ArrayOf.shrink(l).map({ $0.getArray }).filter({ $0 == l.getArray }).isEmpty + property("Shrinking an array never gives back the original") <- forAll { (l : Array) in + return Array.shrink(l).filter({ $0 == l }).isEmpty } - property("Shrunken lists of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in + property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in return (!l.getArray.isEmpty && l.getArray != [0]) ==> { let ls = self.shrinkArbitrary(l).map { $0.getArray } return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) From 9be388f1cfdf5614984b1953547f80b969ec6c8a Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Sat, 8 Aug 2015 15:01:40 -0500 Subject: [PATCH 061/460] Fix random sign for numbers Sign being generated outside of Gen.sized was causing all of the values of a test to have the same sign. --- SwiftCheck/Arbitrary.swift | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 5469d72..cbadac7 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -68,8 +68,9 @@ extension Bool : Arbitrary { extension Int : Arbitrary { public static func arbitrary() -> Gen { - let sign = ((arc4random() % 2) == 1) - return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int(arc4random_uniform(UInt32(n)))) } + return Gen.sized { n in + return Bool.arbitrary().fmap { ($0 ? 1 : -1) * Int(arc4random_uniform(UInt32(n))) } + } } public static func shrink(x : Int) -> [Int] { @@ -79,8 +80,9 @@ extension Int : Arbitrary { extension Int8 : Arbitrary { public static func arbitrary() -> Gen { - let sign = ((arc4random() % 2) == 1) - return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int8(arc4random_uniform(UInt32(n)))) } + return Gen.sized { n in + return Bool.arbitrary().fmap { ($0 ? 1 : -1) * Int8(arc4random_uniform(UInt32(n))) } + } } public static func shrink(x : Int8) -> [Int8] { @@ -90,8 +92,9 @@ extension Int8 : Arbitrary { extension Int16 : Arbitrary { public static func arbitrary() -> Gen { - let sign = ((arc4random() % 2) == 1) - return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int16(arc4random_uniform(UInt32(n)))) } + return Gen.sized { n in + return Bool.arbitrary().fmap { ($0 ? 1 : -1) * Int16(arc4random_uniform(UInt32(n))) } + } } public static func shrink(x : Int16) -> [Int16] { @@ -101,8 +104,9 @@ extension Int16 : Arbitrary { extension Int32 : Arbitrary { public static func arbitrary() -> Gen { - let sign = ((arc4random() % 2) == 1) - return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int32(arc4random_uniform(UInt32(n)))) } + return Gen.sized { n in + return Bool.arbitrary().fmap { ($0 ? 1 : -1) * Int32(arc4random_uniform(UInt32(n))) } + } } public static func shrink(x : Int32) -> [Int32] { @@ -112,8 +116,9 @@ extension Int32 : Arbitrary { extension Int64 : Arbitrary { public static func arbitrary() -> Gen { - let sign = ((arc4random() % 2) == 1) - return Gen.sized { n in Gen.pure((sign ? 1 : -1) * Int64(arc4random_uniform(UInt32(n)))) } + return Gen.sized { n in + return Bool.arbitrary().fmap { ($0 ? 1 : -1) * Int64(arc4random_uniform(UInt32(n))) } + } } public static func shrink(x : Int64) -> [Int64] { From 4fd94cb31e6722a798d39905b254e67952a1fffd Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Sat, 8 Aug 2015 15:02:20 -0500 Subject: [PATCH 062/460] Fix Bool : Arbitrary Not using Gen.sized was causing every value to be the same in a test. --- SwiftCheck/Arbitrary.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index cbadac7..255364d 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -55,7 +55,7 @@ public func shrinkIntegral(x : A) -> [A] { extension Bool : Arbitrary { public static func arbitrary() -> Gen { - return Gen.pure((arc4random() % 2) == 1) + return Gen.sized { n in Gen.pure((arc4random() % 2) == 1) } } public static func shrink(x : Bool) -> [Bool] { From 48f1d6016299d2e5b031c51194cdf8b4d3db2009 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 8 Aug 2015 19:14:49 -0600 Subject: [PATCH 063/460] Fix pluralization in doneTesting --- SwiftCheck/Test.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 880aa85..43f5e4a 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -354,7 +354,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { if st.expectedFailure { - print("*** Passed " + "\(st.numSuccessTests)" + " tests") + print("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", i: st.numSuccessShrinks)) printDistributionGraph(st) return .Success(numTests: st.numSuccessTests, labels: summary(st), output: "") } else { @@ -450,13 +450,6 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In let testMsg = " (after \(st.numSuccessTests.successor()) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" - func pluralize(s : String, i : Int) -> String { - if i > 1 { - return s + "s" - } - return s - } - print("Proposition: " + st.name) print(res.reason + pluralize(testMsg, i: st.numSuccessTests.successor()) + pluralize(shrinkMsg, i: st.numSuccessShrinks) + "):") dispatchAfterFinalFailureCallbacks(st, res: res) @@ -536,6 +529,13 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { return rhs } +private func pluralize(s : String, i : Int) -> String { + if i > 1 { + return s + "s" + } + return s +} + extension Array { internal func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { From f4c6969b4cf6bbcb6a42d30fffb9dcb133fbdb46 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 8 Aug 2015 21:18:53 -0600 Subject: [PATCH 064/460] Print labels in verbose checks --- SwiftCheck/Property.swift | 9 ++++++--- SwiftCheck/Test.swift | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index b9d53cf..c7daf35 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -159,11 +159,14 @@ extension Testable { let c = Callback.AfterTest(kind: .Counterexample, f: { (st, res) in switch res.ok { case .Some(true): - print("Passed:") + print("Passed: ", appendNewline: false) + printLabels(res) case .Some(false): - print("Failed:") + print("Failed: ", appendNewline: false) + printLabels(res) default: - print("Discarded:") + print("Discarded: ", appendNewline: false) + printLabels(res) } }) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 43f5e4a..4ea18d9 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -491,6 +491,19 @@ internal func labelPercentage(l : String, st : CheckerState) -> Int { return (100 * occur.count) / st.maxSuccessTests } +internal func printLabels(st : TestResult) { + if st.labels.isEmpty { + print("(.)") + } else if st.labels.count == 1, let pt = st.labels.first { + print("(\(pt.0))") + } else { + let gAllLabels = st.labels.map({ (l, _) in + return l + ", " + }).reduce("", combine: +) + print("(" + gAllLabels[gAllLabels.startIndex.. String { return (n < 10 ? " " : "") + "\(n)" + "%" From 406808b9b0e5c35bb3cc9eaf6c7c9a5c70ccb34c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 8 Aug 2015 21:38:03 -0600 Subject: [PATCH 065/460] Test for failing in conjunctions --- SwiftCheck/Test.swift | 8 ++++---- SwiftCheckTests/TestSpec.swift | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 4ea18d9..adaa5e7 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -354,7 +354,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { if st.expectedFailure { - print("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", i: st.numSuccessShrinks)) + print("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", i: st.numSuccessTests)) printDistributionGraph(st) return .Success(numTests: st.numSuccessTests, labels: summary(st), output: "") } else { @@ -543,10 +543,10 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { } private func pluralize(s : String, i : Int) -> String { - if i > 1 { - return s + "s" + if i == 0 { + return s } - return s + return s + "s" } extension Array { diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index 29a60c6..cf5fe41 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -29,6 +29,13 @@ class TestSpec : XCTestCase { ^&&^ (xs == xs.reverse().reverse()) "Right identity" } + + property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in + return + (xs.sort().sort() == xs.sort()).verbose "Sort Left" + ^&&^ + ((xs.sort() != xs.sort().sort()).verbose "Bad Sort Right") + }.expectFailure property("map behaves") <- forAll { (xs : Array) in return forAll { (f : ArrowOf) in From 37faf3f7b270fb77896ad681ffbe92c0b1241fcc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 8 Aug 2015 21:45:58 -0600 Subject: [PATCH 066/460] Throw some newlines in the verbose printer --- SwiftCheck/Property.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index c7daf35..1a46dcf 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -159,13 +159,13 @@ extension Testable { let c = Callback.AfterTest(kind: .Counterexample, f: { (st, res) in switch res.ok { case .Some(true): - print("Passed: ", appendNewline: false) + print("\nPassed: ", appendNewline: false) printLabels(res) case .Some(false): - print("Failed: ", appendNewline: false) + print("\nFailed: ", appendNewline: false) printLabels(res) default: - print("Discarded: ", appendNewline: false) + print("\nDiscarded: ", appendNewline: false) printLabels(res) } }) From b1c18161f446c0bc3346a55b621ab7ef2ef281c2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 14 Aug 2015 23:29:52 -0600 Subject: [PATCH 067/460] Convert implementation to MARK --- SwiftCheck/Arbitrary.swift | 2 +- SwiftCheck/Gen.swift | 2 +- SwiftCheck/Property.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 12f1c1f..c7ed4bb 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -745,7 +745,7 @@ extension Set : CoArbitrary { } } -/// MARK: Implementation Details +/// MARK: - Implementation Details private func bits(n : N) -> Int { if n / 2 == 0 { diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 56bd646..d7ff706 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -309,7 +309,7 @@ internal func delay() -> Gen -> A> { }) } -/// Implementation Details Follow +/// MARK: - Implementation Details import func Darwin.log diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 1a46dcf..5b09431 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -350,7 +350,7 @@ public struct TestResult { } } -/// MARK: Implementation Details +/// MARK: - Implementation Details private func exception(msg : String) -> ErrorType -> TestResult { return { e in TestResult.failed(String(e)) } From ad8301a8ce640df40be82af4a5e6d4069209a044 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 14 Aug 2015 23:29:56 -0600 Subject: [PATCH 068/460] De-box --- SwiftCheck/Test.swift | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index adaa5e7..60792e1 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -116,7 +116,7 @@ public func quickCheck(prop : Testable, name : String = "") { quickCheckWithResult(stdArgs(name), p: prop) } -/// MARK: Implementation Details +/// MARK: - Implementation Details internal enum Result { case Success(numTests: Int @@ -141,14 +141,9 @@ internal enum Result { ) } -internal class Box { - let value : T - internal init(_ x : T) { self.value = x } -} - -internal enum Either { - case Left(Box) - case Right(Box) +internal indirect enum Either { + case Left(L) + case Right(R) } internal struct Arguments { @@ -237,16 +232,15 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { while true { switch runATest(state)(f: f) { case let .Left(fail): - switch (fail.value.0, doneTesting(fail.value.1)(f: f)) { + switch (fail.0, doneTesting(fail.1)(f: f)) { case (.Success(_, _, _), _): - return fail.value.0 + return fail.0 case let (_, .NoExpectedFailure(numTests, labels, output)): return .NoExpectedFailure(numTests: numTests, labels: labels, output: output) default: - return fail.value.0 + return fail.0 } - case let .Right(sta): - let lsta = sta.value // Local copy so I don't have to keep unwrapping. + case let .Right(lsta): if lsta.numSuccessTests >= lsta.maxSuccessTests || lsta.shouldAbort { return doneTesting(lsta)(f: f) } @@ -288,7 +282,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , numTryShrinks: st.numTryShrinks , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) - return .Right(Box(nstate)) + return .Right(nstate) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): let nstate = CheckerState(name: st.name @@ -305,7 +299,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , numTryShrinks: st.numTryShrinks , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) - return .Right(Box(nstate)) + return .Right(nstate) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): if !expect { @@ -319,7 +313,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either if !expect { let s = Result.Success(numTests: st.numSuccessTests.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") - return .Left(Box((s, st))) + return .Left((s, st)) } let stat = Result.Failure(numTests: st.numSuccessTests.successor() @@ -344,7 +338,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , numTryShrinks: st.numTryShrinks , numTotTryShrinks: st.numTotTryShrinks , shouldAbort: abort) - return .Left(Box((stat, nstate))) + return .Left((stat, nstate)) } default: fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") From 51f906806b2e34a056eacf9f6d3137e0fa1e25da Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Tue, 25 Aug 2015 14:19:33 -0400 Subject: [PATCH 069/460] Update for Xcode 7b6 Straightforward changes except for adding two private functions to emulate the old `lazy` functions. --- Cartfile.resolved | 2 +- Carthage/Checkouts/Operadics | 2 +- SwiftCheck/Arbitrary.swift | 64 ++++++++++++++++++++---------------- SwiftCheck/Property.swift | 8 ++--- SwiftCheck/Test.swift | 6 ++-- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 105d648..38c4267 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Operadics" "v0.1.0" +github "typelift/Operadics" "v0.1.2" diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics index 1e54027..0cf4ba9 160000 --- a/Carthage/Checkouts/Operadics +++ b/Carthage/Checkouts/Operadics @@ -1 +1 @@ -Subproject commit 1e54027cccb0c29e28900c3fc241d2617364d33d +Subproject commit 0cf4ba90af565214643542a1dc9a7193a3eb5720 diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index c7ed4bb..1c25d7b 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -388,26 +388,26 @@ extension CollectionOfOne : WitnessedArbitrary { } /// Generates an Optional of arbitrary values of type A. -extension Optional where T : Arbitrary { - public static var arbitrary : Gen> { - return Gen>.frequency([ - (1, Gen>.pure(.None)), - (3, liftM(Optional.Some)(m1: T.arbitrary)), +extension Optional where Wrapped : Arbitrary { + public static var arbitrary : Gen> { + return Gen>.frequency([ + (1, Gen>.pure(.None)), + (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), ]) } - public static func shrink(bl : Optional) -> [Optional] { + public static func shrink(bl : Optional) -> [Optional] { if let x = bl { - return [.None] + T.shrink(x).map(Optional.Some) + return [.None] + Wrapped.shrink(x).map(Optional.Some) } return [] } } extension Optional : WitnessedArbitrary { - public typealias Param = T + public typealias Param = Wrapped - public static func forAllWitnessed(wit : A -> T)(pf : (Optional -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (Optional -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -479,47 +479,55 @@ extension HalfOpenInterval where Bound : protocol { } } -extension ImplicitlyUnwrappedOptional where T : Arbitrary { - public static var arbitrary : Gen> { - return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary +extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { + public static var arbitrary : Gen> { + return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary } - public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { - return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) + public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { + return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) } } extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { - public typealias Param = T + public typealias Param = Wrapped - public static func forAllWitnessed(wit : A -> T)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in return pf(bl.map(wit)) }) } } -extension LazyBidirectionalCollection where Base : protocol, Base.Index : BidirectionalIndexType { - public static var arbitrary : Gen> { - return Base.arbitrary.fmap(lazy) +private func lazy(s: S) -> LazyCollection { + return s.lazy +} + +private func lazy(s: S) -> LazySequence { + return s.lazy +} + +extension LazyCollection where Base : protocol, Base.Index : BidirectionalIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(SwiftCheck.lazy) } } -extension LazyForwardCollection where Base : protocol, Base.Index : ForwardIndexType { - public static var arbitrary : Gen> { - return Base.arbitrary.fmap(lazy) +extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(SwiftCheck.lazy) } } -extension LazyRandomAccessCollection where Base : protocol, Base.Index : RandomAccessIndexType { - public static var arbitrary : Gen> { - return Base.arbitrary.fmap(lazy) +extension LazyCollection where Base : protocol, Base.Index : RandomAccessIndexType { + public static var arbitrary : Gen> { + return Base.arbitrary.fmap(SwiftCheck.lazy) } } extension LazySequence where Base : protocol { public static var arbitrary : Gen> { - return Base.arbitrary.fmap(lazy) + return Base.arbitrary.fmap(SwiftCheck.lazy) } } @@ -632,7 +640,7 @@ extension String : CoArbitrary { if x.isEmpty { return { $0.variant(0) } } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[advance(x.startIndex, 1)..(x : Optional) -> (Gen -> Gen) { + public static func coarbitrary(x : Optional) -> (Gen -> Gen) { if let _ = x { return { $0.variant(0) } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 5b09431..9bc7179 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -46,7 +46,7 @@ public func disjoin(ps : Testable...) -> Property { /// running multiple test cases will result in distinct arbitrary sequences of each property being /// tested. public func conjamb(ps : () -> Testable...) -> Property { - let ls = lazy(ps).map { $0().property.unProperty } + let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) } @@ -159,13 +159,13 @@ extension Testable { let c = Callback.AfterTest(kind: .Counterexample, f: { (st, res) in switch res.ok { case .Some(true): - print("\nPassed: ", appendNewline: false) + print("\nPassed: ", terminator: "") printLabels(res) case .Some(false): - print("\nFailed: ", appendNewline: false) + print("\nFailed: ", terminator: "") printLabels(res) default: - print("\nDiscarded: ", appendNewline: false) + print("\nDiscarded: ", terminator: "") printLabels(res) } }) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 60792e1..91377c0 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -303,9 +303,9 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): if !expect { - print("+++ OK, failed as expected. ", appendNewline: false) + print("+++ OK, failed as expected. ", terminator: "") } else { - print("*** Failed! ", appendNewline: false) + print("*** Failed! ", terminator: "") } // Attempt a shrink. @@ -494,7 +494,7 @@ internal func printLabels(st : TestResult) { let gAllLabels = st.labels.map({ (l, _) in return l + ", " }).reduce("", combine: +) - print("(" + gAllLabels[gAllLabels.startIndex.. Date: Tue, 25 Aug 2015 16:59:52 -0400 Subject: [PATCH 070/460] use successor instead of advancedBy --- SwiftCheck/Arbitrary.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 1c25d7b..d2b2cdd 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -640,7 +640,7 @@ extension String : CoArbitrary { if x.isEmpty { return { $0.variant(0) } } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.startIndex.advancedBy(1).. Date: Tue, 25 Aug 2015 17:18:17 -0400 Subject: [PATCH 071/460] remove overlapping `arbitrary` instances and `lazy` --- SwiftCheck/Arbitrary.swift | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index d2b2cdd..7b7f060 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -499,35 +499,15 @@ extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { } } -private func lazy(s: S) -> LazyCollection { - return s.lazy -} - -private func lazy(s: S) -> LazySequence { - return s.lazy -} - -extension LazyCollection where Base : protocol, Base.Index : BidirectionalIndexType { - public static var arbitrary : Gen> { - return Base.arbitrary.fmap(SwiftCheck.lazy) - } -} - extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { public static var arbitrary : Gen> { - return Base.arbitrary.fmap(SwiftCheck.lazy) - } -} - -extension LazyCollection where Base : protocol, Base.Index : RandomAccessIndexType { - public static var arbitrary : Gen> { - return Base.arbitrary.fmap(SwiftCheck.lazy) + return LazyCollection.arbitrary } } extension LazySequence where Base : protocol { public static var arbitrary : Gen> { - return Base.arbitrary.fmap(SwiftCheck.lazy) + return LazySequence.arbitrary } } From 7896f0d532ddb67303121d557db5b16a5f7e6d93 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 28 Aug 2015 16:17:33 -0400 Subject: [PATCH 072/460] Add installation instructions to the readme --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 8fc034b..8bcf862 100644 --- a/README.md +++ b/README.md @@ -241,4 +241,41 @@ let weightedOptionals = Gen.frequency([ ]) ``` +System Requirements +=================== + +SwiftCheck supports OS X 10.9+ and iOS 7.0+. + +Setup +===== + +SwiftCheck can be included one of two ways: + +**Using Carthage** + +- Add SwiftCheck to your Cartfile +- Run `carthage update` +- Drag the relevant copy of SwiftCheck into your project. +- Expand the Link Binary With Libraries phase +- Click the + and add SwiftCheck +- Click the + at the top left corner to add a Copy Files build phase +- Set the directory to `Frameworks` +- Click the + and add SwiftCheck + +**Framework** + +- Drag SwiftCheck.xcodeproj into your project tree + as a subproject +- Under your project's Build Phases, expand Target Dependencies +- Click the + and add SwiftCheck +- Expand the Link Binary With Libraries phase +- Click the + and add SwiftCheck +- Click the + at the top left corner to add a Copy Files build phase +- Set the directory to Frameworks +- Click the + and add SwiftCheck + +License +======= + +SwiftCheck is released under the MIT license. From bcf2ac9d06492cb4c7b98528b51df52fa88c0471 Mon Sep 17 00:00:00 2001 From: Alexander Altman Date: Fri, 28 Aug 2015 19:07:43 -0700 Subject: [PATCH 073/460] Tabs and formatting --- SwiftCheck.xcodeproj/project.pbxproj | 48 ++-- SwiftCheck/Arbitrary.swift | 82 +++---- SwiftCheck/Gen.swift | 6 +- SwiftCheck/Modifiers.swift | 120 +++++----- SwiftCheck/Property.swift | 137 ++++++----- SwiftCheck/Random.swift | 36 +-- SwiftCheck/Rose.swift | 27 ++- SwiftCheck/SwiftCheck.h | 10 - SwiftCheck/Test.swift | 336 +++++++++++++-------------- SwiftCheck/TestOperators.swift | 1 - SwiftCheck/Testable.swift | 8 +- SwiftCheck/Witness.swift | 2 +- SwiftCheckTests/ModifierSpec.swift | 10 +- SwiftCheckTests/PropertySpec.swift | 2 +- SwiftCheckTests/SimpleSpec.swift | 8 +- SwiftCheckTests/TestSpec.swift | 8 +- 16 files changed, 427 insertions(+), 414 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 3dd7615..536aca9 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -91,36 +91,36 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; }; - 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; }; - 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; }; - 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; }; - 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; }; + 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; + 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; + 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; + 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; + 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; usesTabs = 1; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC91198B320500EB242A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 844FCC92198B320500EB242A /* SwiftCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = SwiftCheck/SwiftCheck.h; sourceTree = ""; }; + 844FCC92198B320500EB242A /* SwiftCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = SwiftCheck/SwiftCheck.h; sourceTree = ""; usesTabs = 1; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC9E198B320500EB242A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 844FCCA9198B323800EB242A /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Arbitrary.swift; sourceTree = ""; }; - 844FCCAB198B32DC00EB242A /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gen.swift; sourceTree = ""; }; - 844FCCAD198B367000EB242A /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; }; - 844FCCAF198B36BE00EB242A /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; - 844FCCB3198B39F300EB242A /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; - 844FCCC2198EC4F000EB242A /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; - 844FCCC6198EFB4700EB242A /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rose.swift; sourceTree = ""; }; - 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; }; - 8450D2491AF8003700095EF6 /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestOperators.swift; sourceTree = ""; }; - 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; }; - 84572C241A6DBAA800241F68 /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Check.swift; sourceTree = ""; }; - 84572C2A1A6DBABA00241F68 /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; }; - 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BooleanIdentitySpec.swift; sourceTree = ""; }; - 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; }; - 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; }; + 844FCCA9198B323800EB242A /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Arbitrary.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCAB198B32DC00EB242A /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gen.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCAD198B367000EB242A /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCAF198B36BE00EB242A /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCB3198B39F300EB242A /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCC2198EC4F000EB242A /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCC6198EFB4700EB242A /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rose.swift; sourceTree = ""; usesTabs = 1; }; + 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; usesTabs = 1; }; + 8450D2491AF8003700095EF6 /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestOperators.swift; sourceTree = ""; usesTabs = 1; }; + 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; usesTabs = 1; }; + 84572C241A6DBAA800241F68 /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Check.swift; sourceTree = ""; usesTabs = 1; }; + 84572C2A1A6DBABA00241F68 /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; usesTabs = 1; }; + 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BooleanIdentitySpec.swift; sourceTree = ""; usesTabs = 1; }; + 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; usesTabs = 1; }; + 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; usesTabs = 1; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 84EA2C381B2287200001FB3F /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; }; - 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; }; - D46395B51B1A94D200AA1B65 /* Equatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Equatable.swift; sourceTree = ""; }; + 84EA2C381B2287200001FB3F /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; usesTabs = 1; }; + 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; usesTabs = 1; }; + D46395B51B1A94D200AA1B65 /* Equatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Equatable.swift; sourceTree = ""; usesTabs = 1; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 7b7f060..80fcb7a 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -40,7 +40,7 @@ public protocol Arbitrary { /// values. It should not, however, be written as a deterministic function. If such a /// generator is needed, combinators are provided in `Gen.swift`. static var arbitrary : Gen { get } - + /// An optional shrinking function. If this function goes unimplemented, it is the same as /// returning the empty list. /// @@ -75,7 +75,7 @@ extension Bool : Arbitrary { public static var arbitrary : Gen { return Gen.sized { _ in Gen.pure((arc4random() % 2) == 1) } } - + public static func shrink(x : Bool) -> [Bool] { if x { return [false] @@ -90,7 +90,7 @@ extension Int : Arbitrary { return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int(arc4random_uniform(UInt32(n))) } } } - + public static func shrink(x : Int) -> [Int] { return x.shrinkIntegral } @@ -102,7 +102,7 @@ extension Int8 : Arbitrary { return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int8(arc4random_uniform(UInt32(n))) } } } - + public static func shrink(x : Int8) -> [Int8] { return x.shrinkIntegral } @@ -114,7 +114,7 @@ extension Int16 : Arbitrary { return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int16(arc4random_uniform(UInt32(n))) } } } - + public static func shrink(x : Int16) -> [Int16] { return x.shrinkIntegral } @@ -126,7 +126,7 @@ extension Int32 : Arbitrary { return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int32(arc4random_uniform(UInt32(n))) } } } - + public static func shrink(x : Int32) -> [Int32] { return x.shrinkIntegral } @@ -138,7 +138,7 @@ extension Int64 : Arbitrary { return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int64(arc4random_uniform(UInt32(n))) } } } - + public static func shrink(x : Int64) -> [Int64] { return x.shrinkIntegral } @@ -148,7 +148,7 @@ extension UInt : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt) -> [UInt] { return x.shrinkIntegral } @@ -160,7 +160,7 @@ extension UInt8 : Arbitrary { return Gen.sized { n in Gen.pure(UInt8(arc4random_uniform(UInt32(abs(n))))) } }) } - + public static func shrink(x : UInt8) -> [UInt8] { return x.shrinkIntegral } @@ -170,7 +170,7 @@ extension UInt16 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt16(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt16) -> [UInt16] { return x.shrinkIntegral } @@ -180,7 +180,7 @@ extension UInt32 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(arc4random_uniform(UInt32(abs(n)))) } } - + public static func shrink(x : UInt32) -> [UInt32] { return x.shrinkIntegral } @@ -190,7 +190,7 @@ extension UInt64 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in Gen.pure(UInt64(arc4random_uniform(UInt32(abs(n))))) } } - + public static func shrink(x : UInt64) -> [UInt64] { return x.shrinkIntegral } @@ -205,7 +205,7 @@ extension Float : Arbitrary { return Gen.pure(Float(-n) + Float(arc4random()) / Float(UINT32_MAX / UInt32((n)*2))) }) } - + public static func shrink(x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { @@ -226,7 +226,7 @@ extension Double : Arbitrary { return Gen.pure(Double(-n) + Double(arc4random()) / Double(UINT32_MAX / UInt32(n*2))) }) } - + public static func shrink(x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { @@ -242,7 +242,7 @@ extension UnicodeScalar : Arbitrary { public static var arbitrary : Gen { return UInt32.arbitrary.bind(Gen.pure • UnicodeScalar.init) } - + public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) return nub([ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ]).filter { $0 < x } @@ -254,7 +254,7 @@ extension String : Arbitrary { let chars = Gen.sized({ n in Character.arbitrary.proliferateSized(n) }) return chars >>- (Gen.pure • String.init) } - + public static func shrink(s : String) -> [String] { return [Character].shrink([Character](s.characters)).map(String.init) } @@ -264,7 +264,7 @@ extension Character : Arbitrary { public static var arbitrary : Gen { return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) } - + public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) @@ -278,12 +278,12 @@ extension Array where Element : Arbitrary { if k == 0 { return Gen.pure([]) } - + return sequence((0...k).map { _ in Element.arbitrary }) } } } - + public static func shrink(bl : Array) -> [[Element]] { return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) } @@ -291,7 +291,7 @@ extension Array where Element : Arbitrary { extension Array : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : ([Element] -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) @@ -303,7 +303,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { public static var arbitrary : Gen> { return AnyBidirectionalCollection.init <^> [Element].arbitrary } - + public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } @@ -311,7 +311,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (AnyBidirectionalCollection -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) @@ -335,7 +335,7 @@ extension AnySequence where Element : Arbitrary { public static var arbitrary : Gen> { return AnySequence.init <^> [Element].arbitrary } - + public static func shrink(bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } @@ -343,7 +343,7 @@ extension AnySequence where Element : Arbitrary { extension AnySequence : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (AnySequence -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) @@ -355,7 +355,7 @@ extension ArraySlice where Element : Arbitrary { public static var arbitrary : Gen> { return ArraySlice.init <^> [Element].arbitrary } - + public static func shrink(bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } @@ -363,7 +363,7 @@ extension ArraySlice where Element : Arbitrary { extension ArraySlice : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (ArraySlice -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) @@ -379,7 +379,7 @@ extension CollectionOfOne where Element : Arbitrary { extension CollectionOfOne : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (CollectionOfOne -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[.Zero]))) @@ -395,7 +395,7 @@ extension Optional where Wrapped : Arbitrary { (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), ]) } - + public static func shrink(bl : Optional) -> [Optional] { if let x = bl { return [.None] + Wrapped.shrink(x).map(Optional.Some) @@ -406,7 +406,7 @@ extension Optional where Wrapped : Arbitrary { extension Optional : WitnessedArbitrary { public typealias Param = Wrapped - + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (Optional -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) @@ -418,7 +418,7 @@ extension ContiguousArray where Element : Arbitrary { public static var arbitrary : Gen> { return ContiguousArray.init <^> [Element].arbitrary } - + public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } @@ -426,7 +426,7 @@ extension ContiguousArray where Element : Arbitrary { extension ContiguousArray : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (ContiguousArray -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) @@ -443,7 +443,7 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } } - + public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } @@ -473,7 +473,7 @@ extension HalfOpenInterval where Bound : protocol { } } } - + public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } @@ -483,7 +483,7 @@ extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { public static var arbitrary : Gen> { return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary } - + public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) } @@ -491,7 +491,7 @@ extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { public typealias Param = Wrapped - + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in return pf(bl.map(wit)) @@ -519,7 +519,7 @@ extension Range where Element : protocol) -> [Range] { return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) } @@ -533,7 +533,7 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) @@ -549,12 +549,12 @@ extension Set where Element : protocol { if k == 0 { return Gen.pure(Set([])) } - + return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) } } } - + public static func shrink(s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } @@ -562,7 +562,7 @@ extension Set where Element : protocol { extension Set : WitnessedArbitrary { public typealias Param = Element - + public static func forAllWitnessed(wit : A -> Element)(pf : (Set -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) @@ -767,7 +767,7 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { let xs1 = take(k, xs: xs) let xs2 = drop(k, xs: xs) - + if k > n { return [] } else if xs2.isEmpty { diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index d7ff706..4d97f74 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -31,7 +31,7 @@ public struct Gen { } } - /// Constructs a Generator that selects a random value from the given list and produces only + /// Constructs a Generator that selects a random value from the given list and produces only /// that value. /// /// The input array is required to be non-empty. @@ -43,8 +43,8 @@ public struct Gen { } } - /// Constructs a Generator that uses a given array to produce smaller arrays composed of its - /// initial segments. The size of each initial segment increases with the receiver's size + /// Constructs a Generator that uses a given array to produce smaller arrays composed of its + /// initial segments. The size of each initial segment increases with the receiver's size /// parameter. /// /// The input array is required to be non-empty. diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 2b151fc..5211263 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -11,19 +11,19 @@ /// print, Blind will create a default description for them. public struct Blind : Arbitrary, CustomStringConvertible { public let getBlind : A - + public init(_ blind : A) { self.getBlind = blind } - + public var description : String { return "(*)" } - + public static var arbitrary : Gen> { return Blind.init <^> A.arbitrary } - + public static func shrink(bl : Blind) -> [Blind] { return A.shrink(bl.getBlind).map(Blind.init) } @@ -39,15 +39,15 @@ extension Blind : CoArbitrary { /// Guarantees test cases for its underlying type will not be shrunk. public struct Static : Arbitrary, CustomStringConvertible { public let getStatic : A - + public init(_ fixed : A) { self.getStatic = fixed } - + public var description : String { return "Static( \(self.getStatic) )" } - + public static var arbitrary : Gen> { return Static.init <^> A.arbitrary } @@ -66,19 +66,19 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getArray) } - + public init(_ array : [A]) { self.getArray = array } - + public var description : String { return "\(self.getArray)" } - + public static var arbitrary : Gen> { return ArrayOf.init <^> Array.arbitrary } - + public static func shrink(bl : ArrayOf) -> [ArrayOf] { return Array.shrink(bl.getArray).map(ArrayOf.init) } @@ -97,19 +97,19 @@ extension ArrayOf : CoArbitrary { /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { public let getDictionary : Dictionary - + public init(_ dict : Dictionary) { self.getDictionary = dict } - + public var description : String { return "\(self.getDictionary)" } - + public static var arbitrary : Gen> { return DictionaryOf.init <^> Dictionary.arbitrary } - + public static func shrink(d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } @@ -124,19 +124,19 @@ extension DictionaryOf : CoArbitrary { /// Generates an Optional of arbitrary values of type A. public struct OptionalOf : Arbitrary, CustomStringConvertible { public let getOptional : A? - + public init(_ opt : A?) { self.getOptional = opt } - + public var description : String { return "\(self.getOptional)" } - + public static var arbitrary : Gen> { return OptionalOf.init <^> Optional.arbitrary } - + public static func shrink(bl : OptionalOf) -> [OptionalOf] { return Optional.shrink(bl.getOptional).map(OptionalOf.init) } @@ -154,27 +154,27 @@ extension OptionalOf : CoArbitrary { /// Generates a set of arbitrary values of type A. public struct SetOf> : Arbitrary, CustomStringConvertible { public let getSet : Set - + public init(_ set : Set) { self.getSet = set } - + public var description : String { return "\(self.getSet)" } - + public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).bind { k in if k == 0 { return Gen.pure(SetOf(Set([]))) } - + return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) } } } - + public static func shrink(s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } @@ -196,15 +196,15 @@ public struct ArrowOf, U : Arbitrary> : Arbi public var getArrow : T -> U { return self.arr } - + private init (_ table : Dictionary, _ arr : (T -> U)) { self.table = table self.arr = arr } - + public init(_ arr : (T -> U)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - + self.arr = { x in if let v = self.table[x] { return v @@ -214,17 +214,17 @@ public struct ArrowOf, U : Arbitrary> : Arbi return y } } - + public var description : String { return "\(T.self) -> \(U.self)" } - + public static var arbitrary : Gen> { return ArrowOf.init <^> promote({ a in return T.coarbitrary(a)(U.arbitrary) }) } - + public static func shrink(f : ArrowOf) -> [ArrowOf] { return f.table.flatMap { (x, y) in return U.shrink(y).map({ (y2 : U) -> ArrowOf in @@ -253,24 +253,24 @@ public struct IsoOf, U : protocol private var table : Dictionary private var embed : T -> U private var project : U -> T - + public var getTo : T -> U { return embed } - + public var getFrom : U -> T { return project } - + private init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { self.table = table self.embed = embed self.project = project } - + public init(_ embed : (T -> U), _ project : (U -> T)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - + self.embed = { t in if let v = self.table[t] { return v @@ -279,7 +279,7 @@ public struct IsoOf, U : protocol self.table[t] = y return y } - + self.project = { u in let ts = self.table.filter { $1 == u }.map { $0.0 } if let k = ts.first, _ = self.table[k] { @@ -290,11 +290,11 @@ public struct IsoOf, U : protocol return y } } - + public var description : String { return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" } - + public static var arbitrary : Gen> { return Gen<(T -> U, U -> T)>.zip(promote({ a in return T.coarbitrary(a)(U.arbitrary) @@ -302,20 +302,20 @@ public struct IsoOf, U : protocol return U.coarbitrary(a)(T.arbitrary) })).fmap { IsoOf($0, $1) } } - + public static func shrink(f : IsoOf) -> [IsoOf] { return f.table.flatMap { (x, y) in return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in return IsoOf({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) - }, { (z : U) -> T in - if y == z { - return y1 - } - return f.project(z) + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) }) }) } @@ -339,19 +339,19 @@ private func undefined() -> A { /// Guarantees that every generated integer is greater than 0. public struct Positive> : Arbitrary, CustomStringConvertible { public let getPositive : A - + public init(_ pos : A) { self.getPositive = pos } - + public var description : String { return "Positive( \(self.getPositive) )" } - + public static var arbitrary : Gen> { return A.arbitrary.fmap(Positive.init • abs).suchThat { $0.getPositive > 0 } } - + public static func shrink(bl : Positive) -> [Positive] { return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) } @@ -367,19 +367,19 @@ extension Positive : CoArbitrary { /// Guarantees that every generated integer is never 0. public struct NonZero> : Arbitrary, CustomStringConvertible { public let getNonZero : A - + public init(_ non : A) { self.getNonZero = non } - + public var description : String { return "NonZero( \(self.getNonZero) )" } - + public static var arbitrary : Gen> { return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } } - + public static func shrink(bl : NonZero) -> [NonZero] { return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) } @@ -394,19 +394,19 @@ extension NonZero : CoArbitrary { /// Guarantees that every generated integer is greater than or equal to 0. public struct NonNegative> : Arbitrary, CustomStringConvertible { public let getNonNegative : A - + public init(_ non : A) { self.getNonNegative = non } - + public var description : String { return "NonNegative( \(self.getNonNegative) )" } - + public static var arbitrary : Gen> { return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } } - + public static func shrink(bl : NonNegative) -> [NonNegative] { return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 9bc7179..3797583 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -98,28 +98,32 @@ extension Testable { /// Modifies a property so that it only will be tested once. public var once : Property { return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: true) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: true + ) }) } /// Attaches a callback to a test case. public func withCallback(cb : Callback) -> Property { return self.mapResult({ (res) in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: [cb] + res.callbacks, - abort: res.abort) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: [cb] + res.callbacks, + abort: res.abort + ) }) } @@ -181,14 +185,16 @@ extension Testable { } return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks + chattyCallbacks(res.callbacks), - abort: res.abort) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks + chattyCallbacks(res.callbacks), + abort: res.abort + ) }) } @@ -197,14 +203,16 @@ extension Testable { /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { return self.mapTotalResult({ res in - return TestResult(ok: res.ok, - expect: false, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: res.abort) + return TestResult( + ok: res.ok, + expect: false, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort + ) }) } @@ -234,14 +242,16 @@ extension Testable { public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: insertWith(max, k: s, v: n, m: res.labels), - stamp: res.stamp.union([s]), - callbacks: res.callbacks, - abort: res.abort) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: insertWith(max, k: s, v: n, m: res.labels), + stamp: res.stamp.union([s]), + callbacks: res.callbacks, + abort: res.abort + ) }) } return self.property @@ -279,19 +289,19 @@ public enum CallbackKind { public enum TestResultMatcher { case MatchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - ) + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : [Callback] + , abort : Bool + ) } /// A `TestResult` represents the result of performing a single test. public struct TestResult { - /// The result of executing the test case. For Discarded test cases the value of this property + /// The result of executing the test case. For Discarded test cases the value of this property /// is .None. let ok : Optional /// Indicates what the expected result of the property is. @@ -363,7 +373,16 @@ private func props(shrinker : A -> [A], original : A, pf: A -> Testable) -> R } private func result(ok : Bool?, reason : String = "") -> TestResult { - return TestResult(ok: ok, expect: true, reason: reason, theException: .None, labels: [:], stamp: Set(), callbacks: [], abort: false) + return TestResult( + ok: ok, + expect: true, + reason: reason, + theException: .None, + labels: [:], + stamp: Set(), + callbacks: [], + abort: false + ) } private func protectResults(rs : Rose) -> Rose { @@ -423,27 +442,31 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult(ok: res.ok, + return TestResult( + ok: res.ok, expect: res.expect, reason: res.reason, theException: res.theException, labels: res.labels, stamp: res.stamp, callbacks: result.callbacks + res.callbacks, - abort: res.abort) + abort: res.abort + ) } } private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult(ok: res.ok, + return TestResult( + ok: res.ok, expect: res.expect, reason: res.reason, theException: res.theException, labels: unionWith(max, l: res.labels, r: result.labels), stamp: res.stamp.union(result.stamp), callbacks: res.callbacks, - abort: res.abort) + abort: res.abort + ) } } @@ -528,7 +551,8 @@ private func disj(p : Rose, q : Rose) -> Rose, q : Rose) -> Rose (Int, Self) - + func genRange() -> (Int, Int) func split() -> (Self, Self) } @@ -21,22 +21,22 @@ let standardRNG : StdGen = StdGen(time(nil)) public struct StdGen : RandomGen { let seed: Int - + init(_ seed : Int) { self.seed = seed } - + public func next() -> (Int, StdGen) { let s = Int(time(nil)) return (Int(rand()), StdGen(s)) } - + public func split() -> (StdGen, StdGen) { let (s1, g) = self.next() let (s2, _) = g.next() return (StdGen(s1), StdGen(s2)) } - + public func genRange() -> (Int, Int) { return (Int.min, Int.max) } @@ -50,7 +50,7 @@ private func mkStdRNG(seed : Int) -> StdGen { return StdGen(seed) } -/// Types that can generate random versions of themselves. +/// Types that can generate random versions of themselves. public protocol RandomType { static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) } @@ -65,7 +65,7 @@ extension Int : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (r % ((max + 1) - min)) + min; - + return (result, g); } } @@ -75,7 +75,7 @@ extension Int8 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (r % ((max + 1) - min)) + min; - + return (result, g); } } @@ -85,7 +85,7 @@ extension Int16 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (r % ((max + 1) - min)) + min; - + return (result, g); } } @@ -95,7 +95,7 @@ extension Int32 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (r % ((max + 1) - min)) + min; - + return (result, g); } } @@ -105,7 +105,7 @@ extension Int64 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (r % ((max + 1) - min)) + min; - + return (result, g); } } @@ -115,7 +115,7 @@ extension UInt : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (UInt(r) % ((max + 1) - min)) + min; - + return (result, g); } } @@ -125,7 +125,7 @@ extension UInt8 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (UInt8(r) % ((max + 1) - min)) + min; - + return (result, g); } } @@ -135,7 +135,7 @@ extension UInt16 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (UInt16(r) % ((max + 1) - min)) + min; - + return (result, g); } } @@ -145,7 +145,7 @@ extension UInt32 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (UInt32(r) % ((max + 1) - min)) + min; - + return (result, g); } } @@ -155,7 +155,7 @@ extension UInt64 : RandomType { let (min, max) = range let (r, g) = gen.next() let result = (UInt64(r) % ((max + 1) - min)) + min; - + return (result, g); } } @@ -166,7 +166,7 @@ extension Float : RandomType { let (r, g) = gen.next() let fr = Float(r) let result = (fr % ((max + 1) - min)) + min; - + return (result, g); } } @@ -177,7 +177,7 @@ extension Double : RandomType { let (r, g) = gen.next() let dr = Double(r) let result = (dr % ((max + 1) - min)) + min; - + return (result, g); } } diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 21ec91d..ceb47d8 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -6,9 +6,9 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the steps necessary for +/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the steps necessary for /// testing a property. The first case, .MkRose, consists of a value and a list of trees. The -/// second, case, .IORose, is a suspended IO action SwiftCheck must execute in order to produce +/// second, case, .IORose, is a suspended IO action SwiftCheck must execute in order to produce /// another Rose tree. All values in a `Rose` are lazy. /// /// In practice SwiftCheck will minimize the side-effects performed in a given `IORose` to printing @@ -33,10 +33,10 @@ extension Rose /*: Functor*/ { public func <^> (f : A -> B, g : Rose) -> Rose { switch g { - case .MkRose(let root, let children): - return .MkRose({ f(root()) }, { children().map() { $0.fmap(f) } }) - case .IORose(let rs): - return .IORose({ rs().fmap(f) }) + case .MkRose(let root, let children): + return .MkRose({ f(root()) }, { children().map() { $0.fmap(f) } }) + case .IORose(let rs): + return .IORose({ rs().fmap(f) }) } } @@ -51,7 +51,7 @@ extension Rose /*: Applicative*/ { /// Applies a Rose Tree of functions to the receiver to yield a new Rose Tree of values. /// /// For `.MkRose` branches the computation is applied to the node's value then application - /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and + /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and /// applied, executing all side-effects along the way. public func ap(fn : Rose B>) -> Rose { return fn <*> self @@ -60,10 +60,10 @@ extension Rose /*: Applicative*/ { public func <*> (fn : Rose B>, g : Rose) -> Rose { switch fn { - case .MkRose(let f, _): - return g.fmap(f()) - case .IORose(let rs): - return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + case .MkRose(let f, _): + return g.fmap(f()) + case .IORose(let rs): + return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW } } @@ -89,7 +89,7 @@ public func liftM(f : A -> R)(m1 : Rose) -> Rose { /// /// For `.IORose` branches the join is suspended. For `.MkRose` branches, the kind of subtree at /// the node dictates the behavior of the join. For `.IORose` sub-trees The join is suspended. For -/// `.MkRose` the result is the value at the sub-tree node and a recursive call to join the branch's +/// `.MkRose` the result is the value at the sub-tree node and a recursive call to join the branch's /// tree to its sub-trees. public func joinRose(rs : Rose>) -> Rose { switch rs { @@ -102,11 +102,10 @@ public func joinRose(rs : Rose>) -> Rose { case .MkRose(let x, let ts): return .MkRose(x, { rs().map(joinRose) + ts() }) } - } } -/// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is +/// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is /// encountered. That branch is then returned. public func reduce(rs : Rose) -> Rose { switch rs { diff --git a/SwiftCheck/SwiftCheck.h b/SwiftCheck/SwiftCheck.h index 7e5fada..1c17d82 100644 --- a/SwiftCheck/SwiftCheck.h +++ b/SwiftCheck/SwiftCheck.h @@ -6,14 +6,4 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -#import - -//! Project version number for SwiftCheck. -FOUNDATION_EXPORT double SwiftCheckVersionNumber; - -//! Project version string for SwiftCheck. -FOUNDATION_EXPORT const unsigned char SwiftCheckVersionString[]; - // In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 91377c0..819d65c 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -163,7 +163,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { func roundTo(n : Int)(m : Int) -> Int { return (m / m) * m } - + func rnd() -> StdGen { switch args.replay { case Optional.None: @@ -172,7 +172,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { return rnd } } - + let computeSize_ : Int -> Int -> Int = { x in return { y in if roundTo(x)(m: args.maxSize) + args.maxSize <= args.maxSuccess || @@ -184,7 +184,7 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } } } - + func at0(f : Int -> Int -> Int)(s : Int)(n : Int)(d : Int) -> Int { if n == 0 && d == 0 { return s @@ -192,28 +192,28 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { return f(n)(d) } } - + let computeSize : Int -> Int -> Int = { x in return { y in return (args.replay == nil) ? computeSize_(x)(y) : at0(computeSize_)(s: args.replay!.1)(n: x)(d: y) } } - - + + let istate = CheckerState(name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard - , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 - , labels: [:] - , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 - , shouldAbort: false) + , maxSuccessTests: args.maxSuccess + , maxDiscardedTests: args.maxDiscard + , computeSize: computeSize + , numSuccessTests: 0 + , numDiscardedTests: 0 + , labels: [:] + , collected: [] + , expectedFailure: false + , randomSeed: rnd() + , numSuccessShrinks: 0 + , numTryShrinks: 0 + , numTotTryShrinks: 0 + , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, f: modP.unProperty.unGen) } @@ -231,23 +231,23 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { var state = st while true { switch runATest(state)(f: f) { - case let .Left(fail): - switch (fail.0, doneTesting(fail.1)(f: f)) { - case (.Success(_, _, _), _): - return fail.0 - case let (_, .NoExpectedFailure(numTests, labels, output)): - return .NoExpectedFailure(numTests: numTests, labels: labels, output: output) - default: - return fail.0 - } - case let .Right(lsta): - if lsta.numSuccessTests >= lsta.maxSuccessTests || lsta.shouldAbort { - return doneTesting(lsta)(f: f) - } - if lsta.numDiscardedTests >= lsta.maxDiscardedTests || lsta.shouldAbort { - return giveUp(lsta)(f: f) - } - state = lsta + case let .Left(fail): + switch (fail.0, doneTesting(fail.1)(f: f)) { + case (.Success(_, _, _), _): + return fail.0 + case let (_, .NoExpectedFailure(numTests, labels, output)): + return .NoExpectedFailure(numTests: numTests, labels: labels, output: output) + default: + return fail.0 + } + case let .Right(lsta): + if lsta.numSuccessTests >= lsta.maxSuccessTests || lsta.shouldAbort { + return doneTesting(lsta)(f: f) + } + if lsta.numDiscardedTests >= lsta.maxDiscardedTests || lsta.shouldAbort { + return giveUp(lsta)(f: f) + } + state = lsta } } } @@ -258,91 +258,91 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.numSuccessTests)(st.numDiscardedTests) let (rnd1, rnd2) = st.randomSeed.split() - + // Execute the Rose Tree for the test and reduce to .MkRose. switch reduce(f(rnd1)(size).unProp) { - case .MkRose(let resC, let ts): - let res = resC() // Force the result only once. - dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks - - switch res.match() { - // Success - case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests.successor() - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) - return .Right(nstate) - // Discard - case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) - return .Right(nstate) - // Fail - case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): - if !expect { - print("+++ OK, failed as expected. ", terminator: "") - } else { - print("*** Failed! ", terminator: "") + case .MkRose(let resC, let ts): + let res = resC() // Force the result only once. + dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks + + switch res.match() { + // Success + case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests.successor() + , numDiscardedTests: st.numDiscardedTests + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , expectedFailure: expect + , randomSeed: st.randomSeed + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) + return .Right(nstate) + // Discard + case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests.successor() + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , expectedFailure: expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) + return .Right(nstate) + // Fail + case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): + if !expect { + print("+++ OK, failed as expected. ", terminator: "") + } else { + print("*** Failed! ", terminator: "") + } + + // Attempt a shrink. + let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) + + if !expect { + let s = Result.Success(numTests: st.numSuccessTests.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") + return .Left((s, st)) + } + + let stat = Result.Failure(numTests: st.numSuccessTests.successor() + , numShrinks: numShrinks + , usedSeed: st.randomSeed + , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) + , reason: res.reason + , labels: summary(st) + , output: "*** Failed! ") + + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests.successor() + , labels: st.labels + , collected: st.collected + , expectedFailure: res.expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) + return .Left((stat, nstate)) } - - // Attempt a shrink. - let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) - - if !expect { - let s = Result.Success(numTests: st.numSuccessTests.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") - return .Left((s, st)) - } - - let stat = Result.Failure(numTests: st.numSuccessTests.successor() - , numShrinks: numShrinks - , usedSeed: st.randomSeed - , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: st.labels - , collected: st.collected - , expectedFailure: res.expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) - return .Left((stat, nstate)) - } - default: - fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") - break + default: + fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") + break } } @@ -375,13 +375,13 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts if let e = res.theException { fatalError("Test failed due to exception: \(e)") } - + var lastResult = res var branches = ts var numSuccessShrinks = st.numSuccessShrinks var numTryShrinks = st.numTryShrinks.successor() var numTotTryShrinks = st.numTotTryShrinks - + // cont is a sanity check so we don't fall into an infinite loop. It is set to false at each // new iteration and true when we select a new set of branches to test. If the branch // selection doesn't change then we have exhausted our possibilities and so must have reached a @@ -392,58 +392,58 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts if branches.isEmpty { break; } - + cont = false numTryShrinks = 0 - + // Try all possible courses of action in this Rose Tree branches.forEach { r in switch reduce(r) { - case .MkRose(let resC, let ts1): - let res1 = resC() - dispatchAfterTestCallbacks(st, res: res1) - - // Did we fail? Good! Failure is healthy. - // Try the next set of branches. - if res1.ok == .Some(false) { - lastResult = res1 - branches = ts1() - cont = true - break; - } - - // Otherwise increment the tried shrink counter and the failed shrink counter. - numTryShrinks++ - numTotTryShrinks++ - default: - fatalError("Rose should not have reduced to IO") + case .MkRose(let resC, let ts1): + let res1 = resC() + dispatchAfterTestCallbacks(st, res: res1) + + // Did we fail? Good! Failure is healthy. + // Try the next set of branches. + if res1.ok == .Some(false) { + lastResult = res1 + branches = ts1() + cont = true + break; + } + + // Otherwise increment the tried shrink counter and the failed shrink counter. + numTryShrinks++ + numTotTryShrinks++ + default: + fatalError("Rose should not have reduced to IO") } } - + numSuccessShrinks++ } - + let state = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests - , labels: st.labels - , collected: st.collected - , expectedFailure: st.expectedFailure - , randomSeed: st.randomSeed - , numSuccessShrinks: numSuccessShrinks - , numTryShrinks: numTryShrinks - , numTotTryShrinks: numTotTryShrinks - , shouldAbort: st.shouldAbort) + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + , labels: st.labels + , collected: st.collected + , expectedFailure: st.expectedFailure + , randomSeed: st.randomSeed + , numSuccessShrinks: numSuccessShrinks + , numTryShrinks: numTryShrinks + , numTotTryShrinks: numTotTryShrinks + , shouldAbort: st.shouldAbort) return reportMinimumCaseFound(state, res: lastResult) } internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { let testMsg = " (after \(st.numSuccessTests.successor()) test" let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" - + print("Proposition: " + st.name) print(res.reason + pluralize(testMsg, i: st.numSuccessTests.successor()) + pluralize(shrinkMsg, i: st.numSuccessShrinks) + "):") dispatchAfterFinalFailureCallbacks(st, res: res) @@ -453,10 +453,10 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { res.callbacks.forEach { c in switch c { - case let .AfterTest(_, f): - f(st, res) - default: - break + case let .AfterTest(_, f): + f(st, res) + default: + break } } } @@ -464,10 +464,10 @@ internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { res.callbacks.forEach { c in switch c { - case let .AfterFinalFailure(_, f): - f(st, res) - default: - break + case let .AfterFinalFailure(_, f): + f(st, res) + default: + break } } } @@ -502,14 +502,14 @@ internal func printDistributionGraph(st : CheckerState) { func showP(n : Int) -> String { return (n < 10 ? " " : "") + "\(n)" + "%" } - + let gAllLabels = st.collected.map({ (s : Set) in return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) }) let gAll = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) let gPrint = gAll.map({ ss in showP((ss.count * 100) / st.numSuccessTests) + ss.first! }) let allLabels = Array(gPrint.sort().reverse()) - + var covers = [String]() st.labels.forEach { (l, reqP) in let p = labelPercentage(l, st: st) @@ -517,7 +517,7 @@ internal func printDistributionGraph(st : CheckerState) { covers += ["only \(p)% " + l + ", not \(reqP)%"] } } - + let all = covers + allLabels if all.isEmpty { print(".") @@ -557,7 +557,7 @@ extension Array { } fatalError("span reached a non-empty list that could not produce a first element") } - + if self.isEmpty { return [] } else if let x = self.first { diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index fb9ac2b..8922e5c 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -118,4 +118,3 @@ public func ^||^(p1 : Testable, p2 : Testable) -> Property { } import func XCTest.XCTFail - diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index d65d747..57a9f1a 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -19,7 +19,7 @@ public protocol Testable { /// /// If true, the property will only be tested once. Defaults to false. var exhaustive : Bool { get } - + /// Returns a `Property`, which SwiftCheck uses to perform test case generation. var property : Property { get } } @@ -33,7 +33,7 @@ extension Testable { /// A property is anything that generates propositions. public struct Property : Testable { let unProperty : Gen - + public init(_ val : Gen) { self.unProperty = val; } @@ -46,11 +46,11 @@ public struct Property : Testable { /// A proposition. public struct Prop : Testable { var unProp : Rose - + public var exhaustive : Bool { return true } public var property : Property { -// return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) + // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) } } diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index a11427b..eaa5fdc 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -8,7 +8,7 @@ public protocol WitnessedArbitrary { typealias Param - + static func forAllWitnessed(wit : A -> Param)(pf : (Self -> Testable)) -> Property } diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index 337fa50..cbb719b 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -14,7 +14,7 @@ class ModifierSpec : XCTestCase { property("All blind variables print '(*)'") <- forAll { (x : Blind) in return x.description == "(*)" } - + property("Static propositions never shrink") <- forAll { (x : Static) in return Static.shrink(x).isEmpty } @@ -22,11 +22,11 @@ class ModifierSpec : XCTestCase { property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in return x.getPositive > 0 } - + property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in return x.getNonZero != 0 } - + property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in return x.getNonNegative >= 0 } @@ -34,7 +34,7 @@ class ModifierSpec : XCTestCase { property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in return true } - + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in return (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" @@ -45,7 +45,7 @@ class ModifierSpec : XCTestCase { property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) } - + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in return iso.getFrom(iso.getTo(x)) == x diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 828a4e7..65b9254 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -19,7 +19,7 @@ class PropertySpec : XCTestCase { return b == n }.once } - + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in return conjamb({ return true "picked 1" diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index 5fd405c..ab96cb9 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -12,11 +12,11 @@ import SwiftCheck public struct ArbitraryFoo { let x : Int let y : Int - + public static func create(x : Int) -> Int -> ArbitraryFoo { return { y in ArbitraryFoo(x: x, y: y) } - } - + } + public var description : String { return "Arbitrary Foo!" } @@ -50,7 +50,7 @@ class SimpleSpec : XCTestCase { property("String Equality is Reflexive") <- forAll { (s : String) in return s == s } - + property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in return i.x == i.x && i.y == i.y } diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index cf5fe41..4fe4490 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -25,11 +25,11 @@ class TestSpec : XCTestCase { property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in return - (xs.reverse().reverse() == xs) "Left identity" - ^&&^ - (xs == xs.reverse().reverse()) "Right identity" + (xs.reverse().reverse() == xs) "Left identity" + ^&&^ + (xs == xs.reverse().reverse()) "Right identity" } - + property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in return (xs.sort().sort() == xs.sort()).verbose "Sort Left" From b22b790b966bc7072af298b2783c020080f1feec Mon Sep 17 00:00:00 2001 From: Alexander Altman Date: Fri, 28 Aug 2015 19:57:02 -0700 Subject: [PATCH 074/460] Line things up --- SwiftCheck/Property.swift | 183 +++++++++++++++++-------------------- SwiftCheck/Test.swift | 186 +++++++++++++++++++------------------- 2 files changed, 178 insertions(+), 191 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 3797583..9e77b99 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -98,32 +98,28 @@ extension Testable { /// Modifies a property so that it only will be tested once. public var once : Property { return self.mapResult({ res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: true - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: true) }) } /// Attaches a callback to a test case. public func withCallback(cb : Callback) -> Property { return self.mapResult({ (res) in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: [cb] + res.callbacks, - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: [cb] + res.callbacks, + abort: res.abort) }) } @@ -185,16 +181,14 @@ extension Testable { } return self.mapResult({ res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks + chattyCallbacks(res.callbacks), - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks + chattyCallbacks(res.callbacks), + abort: res.abort) }) } @@ -289,14 +283,14 @@ public enum CallbackKind { public enum TestResultMatcher { case MatchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - ) + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : [Callback] + , abort : Bool + ) } /// A `TestResult` represents the result of performing a single test. @@ -373,16 +367,14 @@ private func props(shrinker : A -> [A], original : A, pf: A -> Testable) -> R } private func result(ok : Bool?, reason : String = "") -> TestResult { - return TestResult( - ok: ok, - expect: true, - reason: reason, - theException: .None, - labels: [:], - stamp: Set(), - callbacks: [], - abort: false - ) + return TestResult(ok: ok, + expect: true, + reason: reason, + theException: .None, + labels: [:], + stamp: Set(), + callbacks: [], + abort: false) } private func protectResults(rs : Rose) -> Rose { @@ -442,31 +434,27 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: result.callbacks + res.callbacks, - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: result.callbacks + res.callbacks, + abort: res.abort) } } private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: unionWith(max, l: res.labels, r: result.labels), - stamp: res.stamp.union(result.stamp), - callbacks: res.callbacks, - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: unionWith(max, l: res.labels, r: result.labels), + stamp: res.stamp.union(result.stamp), + callbacks: res.callbacks, + abort: res.abort) } } @@ -540,32 +528,31 @@ private func disj(p : Rose, q : Rose) -> Rose, q : Rose) -> Rose { @@ -201,19 +201,19 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { let istate = CheckerState(name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard - , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 - , labels: [:] - , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 - , shouldAbort: false) + , maxSuccessTests: args.maxSuccess + , maxDiscardedTests: args.maxDiscard + , computeSize: computeSize + , numSuccessTests: 0 + , numDiscardedTests: 0 + , labels: [:] + , collected: [] + , expectedFailure: false + , randomSeed: rnd() + , numSuccessShrinks: 0 + , numTryShrinks: 0 + , numTotTryShrinks: 0 + , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, f: modP.unProperty.unGen) } @@ -268,37 +268,37 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either switch res.match() { // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests.successor() - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests.successor() + , numDiscardedTests: st.numDiscardedTests + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , expectedFailure: expect + , randomSeed: st.randomSeed + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) return .Right(nstate) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests.successor() + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , expectedFailure: expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) return .Right(nstate) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort): @@ -316,28 +316,28 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either return .Left((s, st)) } - let stat = Result.Failure(numTests: st.numSuccessTests.successor() - , numShrinks: numShrinks - , usedSeed: st.randomSeed - , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: st.labels - , collected: st.collected - , expectedFailure: res.expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks - , shouldAbort: abort) + let stat = Result.Failure(numTests: st.numSuccessTests.successor() + , numShrinks: numShrinks + , usedSeed: st.randomSeed + , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) + , reason: res.reason + , labels: summary(st) + , output: "*** Failed! ") + + let nstate = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests.successor() + , labels: st.labels + , collected: st.collected + , expectedFailure: res.expect + , randomSeed: rnd2 + , numSuccessShrinks: st.numSuccessShrinks + , numTryShrinks: st.numTryShrinks + , numTotTryShrinks: st.numTotTryShrinks + , shouldAbort: abort) return .Left((stat, nstate)) } default: @@ -423,20 +423,20 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts numSuccessShrinks++ } - let state = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests - , labels: st.labels - , collected: st.collected - , expectedFailure: st.expectedFailure - , randomSeed: st.randomSeed - , numSuccessShrinks: numSuccessShrinks - , numTryShrinks: numTryShrinks - , numTotTryShrinks: numTotTryShrinks - , shouldAbort: st.shouldAbort) + let state = CheckerState(name: st.name + , maxSuccessTests: st.maxSuccessTests + , maxDiscardedTests: st.maxDiscardedTests + , computeSize: st.computeSize + , numSuccessTests: st.numSuccessTests + , numDiscardedTests: st.numDiscardedTests + , labels: st.labels + , collected: st.collected + , expectedFailure: st.expectedFailure + , randomSeed: st.randomSeed + , numSuccessShrinks: numSuccessShrinks + , numTryShrinks: numTryShrinks + , numTotTryShrinks: numTotTryShrinks + , shouldAbort: st.shouldAbort) return reportMinimumCaseFound(state, res: lastResult) } From a585d57615229acefadbca99cbc50c21cd92b24c Mon Sep 17 00:00:00 2001 From: Alexander Altman Date: Fri, 28 Aug 2015 20:00:36 -0700 Subject: [PATCH 075/460] Whoops, missed a few! :P --- SwiftCheck/Property.swift | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 9e77b99..5ec659f 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -197,16 +197,14 @@ extension Testable { /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { return self.mapTotalResult({ res in - return TestResult( - ok: res.ok, - expect: false, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: false, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort) }) } @@ -236,16 +234,14 @@ extension Testable { public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { return self.mapResult({ res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: insertWith(max, k: s, v: n, m: res.labels), - stamp: res.stamp.union([s]), - callbacks: res.callbacks, - abort: res.abort - ) + return TestResult(ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: insertWith(max, k: s, v: n, m: res.labels), + stamp: res.stamp.union([s]), + callbacks: res.callbacks, + abort: res.abort) }) } return self.property From de864b9a5fe5892c9af24d677e5131b6f8b0c5e2 Mon Sep 17 00:00:00 2001 From: Alexander Altman Date: Fri, 28 Aug 2015 20:09:29 -0700 Subject: [PATCH 076/460] `return` to a proper place --- SwiftCheck/Testable.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index 57a9f1a..814a4c6 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -50,7 +50,7 @@ public struct Prop : Testable { public var exhaustive : Bool { return true } public var property : Property { - // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) +// return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) } } From 6cdccf913575db167906a59a694f3f69378438d5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 29 Aug 2015 02:33:03 -0400 Subject: [PATCH 077/460] Add podspec --- SwiftCheck.podspec | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 SwiftCheck.podspec diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec new file mode 100644 index 0000000..5d24985 --- /dev/null +++ b/SwiftCheck.podspec @@ -0,0 +1,39 @@ +Pod::Spec.new do |s| + s.name = "SwiftCheck" + s.version = "0.2.6" + s.summary = "QuickCheck for Swift." + s.homepage = "https://github.com/typelift/SwiftCheck" + s.license = { :type => "MIT", :text => <<-LICENSE + The MIT License (MIT) + + Copyright (c) 2015 TypeLift + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + LICENSE + } + s.authors = { "CodaFi" => "devteam.codafi@gmail.com", "pthariensflame" => "alexanderaltman@me.com" } + + s.requires_arc = true + s.osx.deployment_target = "10.9" + s.ios.deployment_target = "8.0" + s.framework = "XCTest" + s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } + s.source_files = "SwiftCheck/*.swift", "**/Operadics/*.swift" +end From eec755f95e7a08265f0b27f343cfd3a3faeeae17 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:32:01 -0400 Subject: [PATCH 078/460] Fix broken README examples --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8bcf862..7e0e49f 100644 --- a/README.md +++ b/README.md @@ -229,15 +229,15 @@ with custom generators as simple as possible: ```swift let onlyEven = Int.arbitrary.suchThat { $0 % 2 == 0 } -let vowels = Gen.elements(["A", "E", "I", "O", "U" ]) +let vowels = Gen.fromElementsOf(["A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) /// This generator will generate `.None` 1/4 of the time and an arbitrary /// `.Some` 3/4 of the time -let weightedOptionals = Gen.frequency([ - (1, Gen.pure(OptionalOf(Optional.None))), - (3, liftM({ OptionalOf(Optional.Some($0)) })(m1: Int.arbitrary)) +let weightedOptionals = Gen.frequency([ + (1, Gen.pure(nil)), + (3, Optional.Some <^> Int.arbitrary) ]) ``` From 68f997ef9816351e0b55afd562dc8b60697e72d9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:32:54 -0400 Subject: [PATCH 079/460] Generalize fromElementsOf to Indexables and Sequences --- SwiftCheck/Gen.swift | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 4d97f74..9c0d919 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -31,18 +31,28 @@ public struct Gen { } } - /// Constructs a Generator that selects a random value from the given list and produces only + /// Constructs a Generator that selects a random value from the given collection and produces only /// that value. /// /// The input array is required to be non-empty. - public static func fromElementsOf(xs : [A]) -> Gen { - assert(xs.count != 0, "Gen.fromElementsOf used with empty list") + public static func fromElementsOf>(xs : S) -> Gen { + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty list") - return choose((0, xs.count - 1)).fmap { i in + return choose((xs.startIndex, xs.endIndex.predecessor())).fmap { i in return xs[i] } } + /// Constructs a Generator that selects a random value from the given interval and produces only + /// that value. + /// + /// The input interval is required to be non-empty. + public static func fromElementsOf(xs : S) -> Gen { + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty list") + + return choose((xs.start, xs.end)) + } + /// Constructs a Generator that uses a given array to produce smaller arrays composed of its /// initial segments. The size of each initial segment increases with the receiver's size /// parameter. From b928b2e118c9451e65fdf1acaf3204381e673f23 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:33:07 -0400 Subject: [PATCH 080/460] Add Character and UnicodeScalar instances of RandomType --- SwiftCheck/Random.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index bf02ed9..8e87831 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -60,6 +60,24 @@ public func random, G : RandomGen>(gen : G return A.randomInRange((A.min, A.max), gen: gen) } +extension Character : RandomType { + public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { + let (min, max) = range + let minc = String(min).unicodeScalars.first! + let maxc = String(max).unicodeScalars.first! + + let (val, gg) = UnicodeScalar.randomInRange((minc, maxc), gen: gen) + return (Character(val), gg) + } +} + +extension UnicodeScalar : RandomType { + public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) + return (UnicodeScalar(val), gg) + } +} + extension Int : RandomType { public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (min, max) = range From 296771057245aadc745d137f5cf1331ed9a8e721 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:33:24 -0400 Subject: [PATCH 081/460] Index tests --- SwiftCheck.xcodeproj/project.pbxproj | 6 ++++++ SwiftCheckTests/GenSpec.swift | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 536aca9..61a2a48 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; settings = {ASSET_TAGS = (); }; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; @@ -91,6 +93,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; @@ -219,6 +222,7 @@ 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, + 8216BAB61B97775100A0D282 /* ComplexSpec.swift */, 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); @@ -434,6 +438,7 @@ 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */, 8445C4AD1B17E48300280089 /* ShrinkSpec.swift in Sources */, 8445C4AA1B16D37800280089 /* GenSpec.swift in Sources */, + 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, @@ -471,6 +476,7 @@ 84DF761E1B0BD58900C912B0 /* SimpleSpec.swift in Sources */, 8445C4AE1B17E48300280089 /* ShrinkSpec.swift in Sources */, 8445C4AB1B16D37800280089 /* GenSpec.swift in Sources */, + 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 90429b9..6918fc7 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -46,7 +46,7 @@ class GenSpec : XCTestCase { return forAll(g) { $0 == 0 } } - property("Gen.elements only generates the elements of the given array") <- forAll { (xss : Array) in + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in if xss.isEmpty { return Discard() } @@ -54,10 +54,17 @@ class GenSpec : XCTestCase { return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } } - property("Gen.elements only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } } + property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + return (n1 < n2) ==> { + let interval = n1...fromElementsOf(interval)) { interval.contains($0) } + } + } + property("oneOf n") <- forAll { (xss : ArrayOf) in if xss.getArray.isEmpty { return Discard() From 37caba872a11ce1b8460b916875421fff726fb54 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:33:55 -0400 Subject: [PATCH 082/460] Add a more complex spec --- SwiftCheckTests/ComplexSpec.swift | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 SwiftCheckTests/ComplexSpec.swift diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift new file mode 100644 index 0000000..da15cb7 --- /dev/null +++ b/SwiftCheckTests/ComplexSpec.swift @@ -0,0 +1,79 @@ +// +// ComplexSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 9/2/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +import XCTest +import SwiftCheck + +class ComplexSpec : XCTestCase { + func testProperties() { + let upper = Gen.fromElementsOf("A"..."Z" as ClosedInterval) + let lower = Gen.fromElementsOf("a"..."z" as ClosedInterval) + let numeric = Gen.fromElementsOf("0"..."9" as ClosedInterval) + let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) + + let localEmail = Gen.oneOf([ + upper, + lower, + numeric, + special, + ]).proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) + let hostname = Gen.oneOf([ + lower, + numeric, + Gen.pure("-"), + ]).proliferateNonEmpty().fmap(String.init) + let tld = Gen.oneOf([ + lower, + ]).proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) + + let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld + + property("Generated email addresses contain 1 @") <- forAll(emailGen) { (e : String) in + return e.characters.filter({ $0 == "@" }).count == 1 + } + + let hexDigits = Gen.oneOf([ + Gen.fromElementsOf("A"..."F"), + numeric, + ]) + + let ipHexDigits = Gen.oneOf([ + hexDigits.proliferateSized(1).fmap{ String.init($0) + ":" }, + hexDigits.proliferateSized(2).fmap{ String.init($0) + ":" }, + hexDigits.proliferateSized(3).fmap{ String.init($0) + ":" }, + hexDigits.proliferateSized(4).fmap{ String.init($0) + ":" }, + ]) + + let ipGen = { $0.initial() } <^> (wrap2 <^> ipHexDigits <*> ipHexDigits <*> ipHexDigits <*> ipHexDigits) + + property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in + return e.characters.filter({ $0 == ":" }).count == 3 + } + + } +} + +/// MARK: String Conveniences + +private func wrap(l : String) -> String -> String -> String { + return { m in { r in l + m + r } } +} + +private func wrap2(l : String) -> String -> String -> String -> String { + return { m in { m2 in { r in l + m + m2 + r } } } +} + +private func wrap3(l : String) -> String -> String -> String -> String -> String { + return { m in { m2 in { m3 in { r in l + m + m2 + m3 + r } } } } +} + +extension String { + func initial() -> String { + return self[self.startIndex.. Date: Wed, 2 Sep 2015 15:36:01 -0400 Subject: [PATCH 083/460] Make reference to new complex test suite --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7e0e49f..cb528c8 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,8 @@ let vowels = Gen.fromElementsOf(["A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) +let randomCharacter = Gen.choose("A"..."Z") + /// This generator will generate `.None` 1/4 of the time and an arbitrary /// `.Some` 3/4 of the time let weightedOptionals = Gen.frequency([ @@ -240,6 +242,9 @@ let weightedOptionals = Gen.frequency([ (3, Optional.Some <^> Int.arbitrary) ]) ``` + +For instances of many complex or "real world" generators, see +[`ComplexSpec.swift`](SwiftCheckTests/ComplexSpec.swift). System Requirements =================== From 55e6011240e60f029d1c16e49d2ca2a4b810fcd4 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:41:36 -0400 Subject: [PATCH 084/460] Reorganize --- SwiftCheckTests/ComplexSpec.swift | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index da15cb7..3ac40b4 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -15,6 +15,10 @@ class ComplexSpec : XCTestCase { let lower = Gen.fromElementsOf("a"..."z" as ClosedInterval) let numeric = Gen.fromElementsOf("0"..."9" as ClosedInterval) let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) + let hexDigits = Gen.oneOf([ + Gen.fromElementsOf("A"..."F"), + numeric, + ]) let localEmail = Gen.oneOf([ upper, @@ -27,9 +31,7 @@ class ComplexSpec : XCTestCase { numeric, Gen.pure("-"), ]).proliferateNonEmpty().fmap(String.init) - let tld = Gen.oneOf([ - lower, - ]).proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) + let tld = lower.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld @@ -37,11 +39,6 @@ class ComplexSpec : XCTestCase { return e.characters.filter({ $0 == "@" }).count == 1 } - let hexDigits = Gen.oneOf([ - Gen.fromElementsOf("A"..."F"), - numeric, - ]) - let ipHexDigits = Gen.oneOf([ hexDigits.proliferateSized(1).fmap{ String.init($0) + ":" }, hexDigits.proliferateSized(2).fmap{ String.init($0) + ":" }, From 7a1637369630456b20caea0dd37e334be534305f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:42:50 -0400 Subject: [PATCH 085/460] Another reorganization --- SwiftCheckTests/ComplexSpec.swift | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 3ac40b4..2a599b5 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -9,17 +9,17 @@ import XCTest import SwiftCheck -class ComplexSpec : XCTestCase { - func testProperties() { - let upper = Gen.fromElementsOf("A"..."Z" as ClosedInterval) - let lower = Gen.fromElementsOf("a"..."z" as ClosedInterval) - let numeric = Gen.fromElementsOf("0"..."9" as ClosedInterval) - let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) - let hexDigits = Gen.oneOf([ - Gen.fromElementsOf("A"..."F"), - numeric, - ]) +let upper = Gen.fromElementsOf("A"..."Z" as ClosedInterval) +let lower = Gen.fromElementsOf("a"..."z" as ClosedInterval) +let numeric = Gen.fromElementsOf("0"..."9" as ClosedInterval) +let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +let hexDigits = Gen.oneOf([ + Gen.fromElementsOf("A"..."F"), + numeric, +]) +class ComplexSpec : XCTestCase { + func testEmailAddressProperties() { let localEmail = Gen.oneOf([ upper, lower, @@ -38,7 +38,9 @@ class ComplexSpec : XCTestCase { property("Generated email addresses contain 1 @") <- forAll(emailGen) { (e : String) in return e.characters.filter({ $0 == "@" }).count == 1 } + } + func testIPv6Properties() { let ipHexDigits = Gen.oneOf([ hexDigits.proliferateSized(1).fmap{ String.init($0) + ":" }, hexDigits.proliferateSized(2).fmap{ String.init($0) + ":" }, @@ -51,7 +53,6 @@ class ComplexSpec : XCTestCase { property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 } - } } From fb55cdf7b66bb168d2ea322f9533a898ad8c7d47 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:46:45 -0400 Subject: [PATCH 086/460] Differentiate of and In --- README.md | 6 ++++-- SwiftCheck/Gen.swift | 2 +- SwiftCheckTests/ComplexSpec.swift | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cb528c8..1255091 100644 --- a/README.md +++ b/README.md @@ -233,8 +233,10 @@ let vowels = Gen.fromElementsOf(["A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) -let randomCharacter = Gen.choose("A"..."Z") - +let uppers : Gen= Gen.fromElementsIn("A"..."Z") +let lowers : Gen = Gen.fromElementsIn("a"..."z") +let numbers : Gen = Gen.fromElementsIn("0"..."9") + /// This generator will generate `.None` 1/4 of the time and an arbitrary /// `.Some` 3/4 of the time let weightedOptionals = Gen.frequency([ diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 9c0d919..a845563 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -47,7 +47,7 @@ public struct Gen { /// that value. /// /// The input interval is required to be non-empty. - public static func fromElementsOf(xs : S) -> Gen { + public static func fromElementsIn(xs : S) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty list") return choose((xs.start, xs.end)) diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 2a599b5..fb0e6df 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -9,12 +9,12 @@ import XCTest import SwiftCheck -let upper = Gen.fromElementsOf("A"..."Z" as ClosedInterval) -let lower = Gen.fromElementsOf("a"..."z" as ClosedInterval) -let numeric = Gen.fromElementsOf("0"..."9" as ClosedInterval) +let upper : Gen= Gen.fromElementsIn("A"..."Z") +let lower : Gen = Gen.fromElementsIn("a"..."z") +let numeric : Gen = Gen.fromElementsIn("0"..."9") let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) let hexDigits = Gen.oneOf([ - Gen.fromElementsOf("A"..."F"), + Gen.fromElementsIn("A"..."F"), numeric, ]) From 425faacb1c35d0abaebf575b1ae0faaf0b23cd8b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 2 Sep 2015 15:49:33 -0400 Subject: [PATCH 087/460] Fix asserts --- SwiftCheck/Gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index a845563..45c30c5 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -36,7 +36,7 @@ public struct Gen { /// /// The input array is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty list") + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty sequence") return choose((xs.startIndex, xs.endIndex.predecessor())).fmap { i in return xs[i] @@ -48,7 +48,7 @@ public struct Gen { /// /// The input interval is required to be non-empty. public static func fromElementsIn(xs : S) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty list") + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") return choose((xs.start, xs.end)) } From 4bf59cb0c1589d754f95936def59491578148c61 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 3 Sep 2015 16:02:02 -0400 Subject: [PATCH 088/460] Move and document zip --- SwiftCheck/Gen.swift | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 45c30c5..ddb9a99 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -6,12 +6,18 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A generator for values of type A. +/// `Gen` represents a generator for random arbitrary values of type `A`. /// /// `Gen` wraps a function that, when given a random number generator and a size, can be used to /// control the distribution of resultant values. A generator relies on its size to help control /// aspects like the length of generated arrays and the magnitude of integral values. public struct Gen { + /// The function underlying the receiver. + /// + /// +--- An RNG + /// | +--- The size of generated values. + /// | | + /// v v let unGen : StdGen -> Int -> A /// Generates a value. @@ -23,14 +29,6 @@ public struct Gen { return unGen(r)(30) } - public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return gen1.bind { l in - return gen2.bind { r in - return Gen<(A, B)>.pure((l, r)) - } - } - } - /// Constructs a Generator that selects a random value from the given collection and produces only /// that value. /// @@ -128,6 +126,15 @@ public struct Gen { public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } + + /// Zips together 2 generators of type `A` and `B` into a generator of pairs `(A, B)`. + public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { + return gen1.bind { l in + return gen2.bind { r in + return Gen<(A, B)>.pure((l, r)) + } + } + } } /// MARK: Generator Modifiers From 57c39a116498cee92a00a55f6ac01327855adf9c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 3 Sep 2015 18:58:53 -0400 Subject: [PATCH 089/460] More documentation everywhere --- SwiftCheck/Gen.swift | 68 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index ddb9a99..f93549a 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -29,10 +29,10 @@ public struct Gen { return unGen(r)(30) } - /// Constructs a Generator that selects a random value from the given collection and produces only - /// that value. + /// Constructs a Generator that selects a random value from the given collection and produces + /// only that value. /// - /// The input array is required to be non-empty. + /// The input collection is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty sequence") @@ -57,12 +57,12 @@ public struct Gen { /// /// The input array is required to be non-empty. public static func fromInitialSegmentsOf(xs : [A]) -> Gen { - assert(xs.count != 0, "Gen.fromInitialSegmentsOf used with empty list") + assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") let k = Double(xs.count) return sized({ n in let m = max(1, size(k)(m: n)) - return Gen.fromElementsOf(Array(xs[0 ..< m])) + return Gen.fromElementsOf(xs[0 ..< m]) }) } @@ -101,7 +101,11 @@ public struct Gen { }) } - /// Constructs a Generator that randomly selects and uses one of a number of given Generators. + /// Constructs a Generator that randomly selects and uses a particular generator from the given + /// sequence of Generators. + /// + /// If control over the distribution of generators is needed, see `Gen.frequency` or + /// `Gen.weighted`. public static func oneOf, S.Index : protocol>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") @@ -110,8 +114,11 @@ public struct Gen { } } - /// Given a list of Generators and weights associated with them, this function randomly selects and - /// uses a Generator. + /// Given a sequence of Generators and weights associated with them, this function randomly + /// selects and uses a Generator. + /// + /// Only use this function when you need to assign uneven "weights" to each generator. If all + /// generators need to have an equal chance of being selected, use `Gen.oneOf`. public static func frequency)>(xs : S) -> Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") @@ -123,6 +130,11 @@ public struct Gen { /// Given a list of values and weights associated with them, this function randomly selects and /// uses a Generator wrapping one of the values. + /// + /// This function operates in exactly the same manner as `Gen.frequency`, `Gen.fromElementsOf`, + /// and `Gen.fromElementsIn` but for any type rather than only Generators. It can help in cases + /// where your `Gen.from*` call contains only `Gen.pure` calls by allowing you to remove every + /// `.pure` in favor of a direct list of values. public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } @@ -219,6 +231,13 @@ extension Gen /*: Functor*/ { } } +/// Fmap | Returns a new generator that applies a given function to any outputs the given generator +/// creates. +/// +/// This function is most useful for converting between generators of inter-related types. For +/// example, you might have a Generator of `Character` values that you then `.proliferate()` into an +/// `Array` of `Character`s. You can then use `fmap` to convert that generator of `Array`s to a +/// generator of `String`s. public func <^> (f : A -> B, g : Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -246,6 +265,19 @@ extension Gen /*: Applicative*/ { } } +/// Ap | Returns a Generator that uses the first given Generator to produce functions and the second +/// given Generator to produce values that it applies to those functions. It can be used in +/// conjunction with <^> to simplify the application of "combining" functions to a large amount of +/// sub-generators. For example: +/// +/// struct Foo { let b : Int; let c : Int; let d : Int } +/// +/// let genFoo = curry(Foo.init) <^> Int.arbitrary <*> Int.arbitrary <*> Int.arbitrary +/// +/// This combinator acts like `zip`, but instead of creating pairs it creates values after applying +/// the zipped function to the zipped value. +/// +/// Promotes function application to a Generator of functions applied to a Generator of values. public func <*> (fn : Gen B>, g : Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -258,14 +290,20 @@ extension Gen /*: Monad*/ { /// Applies the function to any generated values to yield a new generator. This generator is /// then given a new random seed and returned. /// - /// Bind allows for the creation of Generators that depend on other generators. One might, for - /// example, use a Generator of integers to control the length of a Generator of strings, or use - /// it to choose a random index into a Generator of arrays. + /// `bind` allows for the creation of Generators that depend on other generators. One might, + /// for example, use a Generator of integers to control the length of a Generator of strings, or + /// use it to choose a random index into a Generator of arrays. public func bind(fn : A -> Gen) -> Gen { return self >>- fn } } +/// Applies the function to any generated values to yield a new generator. This generator is +/// then given a new random seed and returned. +/// +/// `bind` allows for the creation of Generators that depend on other generators. One might, +/// for example, use a Generator of integers to control the length of a Generator of strings, or +/// use it to choose a random index into a Generator of arrays. public func >>- (m : Gen, fn : A -> Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -276,8 +314,12 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { }) } -/// Reduces an array of generators to a generator that returns arrays of the original generators -/// values in the order given. +/// Creates and returns a Generator of arrays of values drawn from each generator in the given +/// array. +/// +/// The array that is created is guaranteed to use each of the given Generators in the order they +/// were given to the function exactly once. Thus all arrays generated are of the same rank as the +/// array that was given. public func sequence(ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in return x.bind { x1 in From 8878736bae2e92513f295a997f08cf890720bf22 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 3 Sep 2015 21:02:38 -0400 Subject: [PATCH 090/460] Remove extra type annotations --- SwiftCheck/Property.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 5ec659f..15a0c7e 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -253,8 +253,8 @@ extension Testable { /// Shrinking is handled automatically by SwiftCheck. Invoking this function is only necessary /// when you must override the default behavior. public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { - return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { (let rs : Rose) in - return Prop(unProp: joinRose(rs.fmap { (let x : Prop) in + return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { rs in + return Prop(unProp: joinRose(rs.fmap { x in return x.unProp })) }) @@ -356,7 +356,7 @@ private func exception(msg : String) -> ErrorType -> TestResult { return { e in TestResult.failed(String(e)) } } -private func props(shrinker : A -> [A], original : A, pf: A -> Testable) -> Rose> { +private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) From caf84d8163989ec89c1a48b1e38f893538511813 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 3 Sep 2015 22:07:39 -0400 Subject: [PATCH 091/460] Add meaningful documentation about property testing --- SwiftCheck/Test.swift | 104 +++++++++++++++++++++++++++++++++++------- 1 file changed, 88 insertions(+), 16 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index f5b7233..2740039 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -6,6 +6,78 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +// MARK: - Testing + +/// Property Testing is a more static and expressive form of Test-Driven Development that emphasizes +/// the testability of program properties - A statement or invariant that can be proven to hold when +/// fed any number of arguments of a particular kind. It is akin to Fuzz Testing but is made +/// significantly more power by the primitives in this framework. +/// +/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a value that is capable +/// of producing a framework type called `Prop`, which models individual test cases that themselves +/// are capable of passing or failing "in the small" with a `TestResult`. This ability is encoded +/// by a protocol called `Testable` that is adopted by Bool, Property, Prop, and several other +/// internal framework types. The thing to notice is the majority of user-facing functions and +/// combinators in this library return types that conform to `Testable`. This enables a high level +/// of composition and enables the testing of incredibly complex properties that would normally be +/// expressed by stateful, complected unit tests. +/// +/// Below is the method all SwiftCheck properties are based on, `forAll`. `forAll` acts as a +/// "Quantifier", i.e. a contract that serves as a guarantee that a property holds when the given +/// testing block returns `true` or truthy values, and fails when the testing block returns `false` +/// or falsy values. The testing block is usually used with Swift's abbreviated block syntax and +/// requires type annotations for all value positions being requested. For example, +/// +/// forAll { (anInteger : Int, aBoolean : Bool, someStrings : ArrayOf) in +/// return true // This test case always passes. +/// } +/// +/// Why require types? For one, Swift cannot infer the types of local variables because SwiftCheck +/// uses highly polymorphic testing primitives. But, more importantly, types are required because +/// SwiftCheck uses them to select the appropriate `Gen`erators and shrinkers for each data type +/// automagically by default. Those `Gen`erators and shrinkers are then used to create 100 random +/// test cases that are evaluated lazily to produce a final result. +/// +/// As mentioned before, SwiftCheck types do not exist in a bubble. They are highly compositional +/// and flexible enough to express unique combinations and permutations of test types. Below is a +/// purely illustrative example utilizing a significant portion of SwiftCheck's testing functions: +/// +/// /// This method comes out of SwiftCheck's test suite. +/// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in +/// +/// /// This part of the property uses `==>`, or the "implication" combinator. Implication +/// /// only executes the following block if the preceding statement returns true. It can +/// /// be used to discard test cases that contain data you don't want to test with. +/// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { +/// +/// /// shrinkArbitrary is a method call that invokes the shrinker +/// let ls = self.shrinkArbitrary(s).map { $0.getSet } +/// return forAll { (x : Int) in /// OMG, is that a `forAll` inside a `forAll`?! +/// +/// return x != x // Well that can't possibly hold. +/// +/// } +/// ^||^ /// <- `^||^` is like `||` in Swift, but lifted to work with properties. +/// (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).withCallback(.AfterTest(.NotCounterexample, { st, res in +/// /// For the seriously EXTREME tester, `withCallback` provides a look into +/// /// SwiftCheck's testing mechanism. You can request a variety of information +/// /// about the current state of the testing loop from inside this block. +/// /// +/// /// For the less crazed, SwiftCheck offers straight callbacks with `whenFail` and +/// /// `whenEachFail`. +/// print("This test is called: \(name)") +/// })) +/// } +/// }.expectFailure.verbose +/// ^ ^ +/// | | +/// | +--- The property will print EVERY generated test case to the console. +/// + --- We expect this property not to hold. +/// +/// Testing is not limited to just these listed combinators. New users should check out our test +/// suite and the files `Gen.swift`, `Property.swift`, `Modifiers.swift`, and the top half of this +/// very file to learn more about the various parts of the SwiftCheck testing mechanism. + /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. public func forAll(pf : (A -> Testable)) -> Property { @@ -119,25 +191,25 @@ public func quickCheck(prop : Testable, name : String = "") { /// MARK: - Implementation Details internal enum Result { - case Success(numTests: Int - , labels: [(String, Int)] - , output: String + case Success(numTests : Int + , labels : [(String, Int)] + , output : String ) - case GaveUp(numTests: Int - , labels: [(String,Int)] - , output: String + case GaveUp(numTests : Int + , labels : [(String,Int)] + , output : String ) - case Failure(numTests: Int - , numShrinks: Int - , usedSeed: StdGen - , usedSize: Int - , reason: String - , labels: [(String,Int)] - , output: String + case Failure(numTests : Int + , numShrinks : Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String ) - case NoExpectedFailure(numTests: Int - , labels: [(String,Int)] - , output: String + case NoExpectedFailure(numTests : Int + , labels : [(String,Int)] + , output : String ) } From 4ac9ac01dc9a33dbcd55f7d7be6eefc583b3c83a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 10:50:15 -0400 Subject: [PATCH 092/460] Remove cruft near the end of the introduction --- SwiftCheck/Test.swift | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 2740039..f2bfe08 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -15,13 +15,17 @@ /// /// A `Property` in SwiftCheck is more than just `true` and `false`, it is a value that is capable /// of producing a framework type called `Prop`, which models individual test cases that themselves -/// are capable of passing or failing "in the small" with a `TestResult`. This ability is encoded -/// by a protocol called `Testable` that is adopted by Bool, Property, Prop, and several other -/// internal framework types. The thing to notice is the majority of user-facing functions and -/// combinators in this library return types that conform to `Testable`. This enables a high level -/// of composition and enables the testing of incredibly complex properties that would normally be -/// expressed by stateful, complected unit tests. -/// +/// are capable of passing or failing "in the small" with a `TestResult`. For those familiar with +/// Protocol-Oriented Programming, lying at the heart of all of these types is a protocol called +/// `Testable` that provides any type a means of converting itself to a `Property`. SwiftCheck +/// uses `Testable` early and often in functions and operators to enable a high level of nesting +/// of framework primitives and an even higher level of genericity in the interface. By default +/// SwiftCheck provides `Testable` instances for `Bool`, `Property`, `Prop`, and several other +/// internal framework types. Practically, this means any assertions you could make in `XCTest` +/// will work immediately with the framework. + +// MARK: - Quantifiers + /// Below is the method all SwiftCheck properties are based on, `forAll`. `forAll` acts as a /// "Quantifier", i.e. a contract that serves as a guarantee that a property holds when the given /// testing block returns `true` or truthy values, and fails when the testing block returns `false` From 01260fd244bead56b126fae8cff05f41031ca813 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 10:58:39 -0400 Subject: [PATCH 093/460] Provide a better first example --- SwiftCheck/Test.swift | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index f2bfe08..366e46a 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -32,8 +32,15 @@ /// or falsy values. The testing block is usually used with Swift's abbreviated block syntax and /// requires type annotations for all value positions being requested. For example, /// -/// forAll { (anInteger : Int, aBoolean : Bool, someStrings : ArrayOf) in -/// return true // This test case always passes. +/// + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. +/// | + This backwards arrow binds a property name and a property to each other. +/// | | +/// v v +/// property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in +/// return +/// (xs.reverse().reverse() == xs) "Reverse on the left" +/// ^&&^ +/// (xs == xs.reverse().reverse()) "Reverse on the right" /// } /// /// Why require types? For one, Swift cannot infer the types of local variables because SwiftCheck @@ -41,7 +48,9 @@ /// SwiftCheck uses them to select the appropriate `Gen`erators and shrinkers for each data type /// automagically by default. Those `Gen`erators and shrinkers are then used to create 100 random /// test cases that are evaluated lazily to produce a final result. -/// + +// MARK: - Going Further + /// As mentioned before, SwiftCheck types do not exist in a bubble. They are highly compositional /// and flexible enough to express unique combinations and permutations of test types. Below is a /// purely illustrative example utilizing a significant portion of SwiftCheck's testing functions: @@ -84,102 +93,119 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. +@warn_unused_result public func forAll(pf : (A -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. +@warn_unused_result public func forAll(pf : (A, B) -> Testable) -> Property { return forAll({ t in forAll({ b in pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. +@warn_unused_result public func forAll(pf : (A, B, C) -> Testable) -> Property { return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. +@warn_unused_result public func forAll(pf : (A, B, C, D) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. +@warn_unused_result public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified property using the /// default shrinker for that type. +@warn_unused_result public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 2 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(pf : (A, B) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 3 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(pf : (A, B, C) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(pf: { b, c in pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 4 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(pf : (A, B, C, D) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(pf: { b, c, d in pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 5 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(pf: { b, c, d, e in pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 6 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 7 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(genG : Gen)(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(genF : genG)(pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 8 types. +@warn_unused_result public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(genG : Gen)(genH : Gen)(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(genF : genG)(genG : genH)(pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. +@warn_unused_result public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A -> Testable) -> Property { return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in From 3d664a53f78e1452736a8533b3b4ec1edaec36c8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 11:04:43 -0400 Subject: [PATCH 094/460] Provide a better ending example --- SwiftCheck/Test.swift | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 366e46a..74548aa 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -// MARK: - Testing +// MARK: - Property Testing with SwiftCheck /// Property Testing is a more static and expressive form of Test-Driven Development that emphasizes /// the testability of program properties - A statement or invariant that can be proven to hold when @@ -56,10 +56,14 @@ /// purely illustrative example utilizing a significant portion of SwiftCheck's testing functions: /// /// /// This method comes out of SwiftCheck's test suite. +/// +/// `SetOf` is called a "Modifier Type". To learn more about them see `Modifiers.swift`---+ +/// | +/// v /// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in /// /// /// This part of the property uses `==>`, or the "implication" combinator. Implication -/// /// only executes the following block if the preceding statement returns true. It can +/// /// only executes the following block if the preceding expression returns true. It can /// /// be used to discard test cases that contain data you don't want to test with. /// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { /// @@ -70,16 +74,10 @@ /// return x != x // Well that can't possibly hold. /// /// } -/// ^||^ /// <- `^||^` is like `||` in Swift, but lifted to work with properties. -/// (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).withCallback(.AfterTest(.NotCounterexample, { st, res in -/// /// For the seriously EXTREME tester, `withCallback` provides a look into -/// /// SwiftCheck's testing mechanism. You can request a variety of information -/// /// about the current state of the testing loop from inside this block. -/// /// -/// /// For the less crazed, SwiftCheck offers straight callbacks with `whenFail` and -/// /// `whenEachFail`. -/// print("This test is called: \(name)") -/// })) +/// ^||^ /// <- `^||^` is like `||` in Swift, but for properties. +/// (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).whenFail { +/// print("Oh noe!") +/// } /// } /// }.expectFailure.verbose /// ^ ^ @@ -87,7 +85,7 @@ /// | +--- The property will print EVERY generated test case to the console. /// + --- We expect this property not to hold. /// -/// Testing is not limited to just these listed combinators. New users should check out our test +/// Testing is not limited to just these listed functions. New users should check out our test /// suite and the files `Gen.swift`, `Property.swift`, `Modifiers.swift`, and the top half of this /// very file to learn more about the various parts of the SwiftCheck testing mechanism. From 38660349a65e1fe1d5afbbd9c7c0b4dbf5967843 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 11:40:20 -0400 Subject: [PATCH 095/460] Document modifiers --- SwiftCheck/Modifiers.swift | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 5211263..422c595 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -6,9 +6,34 @@ // Copyright (c) 2015 CodaFi. All rights reserved. // - -/// For types that either do not have a Printable instance or that wish to have no description to -/// print, Blind will create a default description for them. +// MARK: - Modifier Types + +/// A Modifier Type is a type that wraps another to provide special semantics or simply to generate +/// values of an underlying type that would be unusually difficult to express given the limitations +/// of Swift's type system. +/// +/// For an example of the former, take the `Blind` modifier. Because SwiftCheck's counterexamples +/// come from a description a particular object provides for itself, there are many cases where +/// console output can become unbearably long, or just simply isn't useful to your test suite. By +/// wrapping that type in `Blind` SwiftCheck ignore whatever description the property provides and +/// just print "(*)". +/// +/// For an example of the latter see the `ArrowOf` modifier. Because Swift's type system treats +/// arrows (`->`) as an opaque entity that you can't interact with or extend, SwiftCheck provides +/// `ArrowOf` to enable the generation of functions between 2 types. That's right, we can generate +/// arbitrary functions! +/// +/// Finally, modifiers nest to allow the generation of intricate structures that would not otherwise +/// be possible due to the limitations above. For example, to generate an Array of Arrays of +/// Dictionaries of Integers and Strings (a type that normally looks like +/// `Array>>`), would look like this: +/// +/// property("Generating monstrous data types is possible") <- forAll { (xs : ArrayOf>>) in +/// /// We're gonna need a bigger boat. +/// } + +/// For types that either do not have a `CustomStringConvertible` instance or that wish to have no +/// description to print, Blind will create a default description for them. public struct Blind : Arbitrary, CustomStringConvertible { public let getBlind : A From 27c2188444f448ea112b2ead47a97e85ab9bf5ec Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 12:00:58 -0400 Subject: [PATCH 096/460] Document State --- SwiftCheck/State.swift | 82 +++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index d87dac1..5a1f9c6 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -6,36 +6,70 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +/// The internal state of the testing system. public struct CheckerState { - let name : String - let maxSuccessTests : Int - let maxDiscardedTests : Int - let computeSize : Int -> Int -> Int - let numSuccessTests : Int - let numDiscardedTests : Int - let labels : Dictionary - let collected : [Set] - let expectedFailure : Bool - let randomSeed : StdGen - let numSuccessShrinks : Int - let numTryShrinks : Int - let numTotTryShrinks : Int - let shouldAbort : Bool + /// The name bound to the current property (not labels). + let name : String + /// The maximum number of successful tests before SwiftCheck gives up. Defaults to 100. + let maxAllowableSuccessfulTests : Int + /// The maximum number of discarded tests before SwiftCheck gives up. + let maxAllowableDiscardedTests : Int + /// The function that generates the sizes fed to the generators for each test case. + let computeSize : Int -> Int -> Int + /// The count of the number of successful test cases seen so far. + let successfulTestCount : Int + /// The count of the number of discarded test cases seen so far. + let discardedTestCount : Int + /// A dictionary of labels collected inside the test case. Each maps to an integer describing + /// the number of passed tests. It is used in conjunction with the number of successful tests + /// to print a coverage percentage. + let labels : Dictionary + /// A uniqued collection of all the labels collected during the test case. + let collected : [Set] + /// Returns whether the test case has fulfilled its expected failure outcome. If the test case + /// fails and it was expected this property returns true. If the test case doesn't fail and it + /// was not expected to fail this property returns true. Only when the test case's outcome + /// and its failure fulfillment expectation do not match does this property return false. + let hasFulfilledExpectedFailure : Bool + /// The Random Number Generator backing the testing session. + let randomSeedGenerator : StdGen + /// Returns the number of successful shrinking steps performed so far. + let successfulShrinkCount : Int + /// Returns the number of failed shrinking steps since the last successful shrink. + let failedShrinkStepDistance : Int + /// Returns the number of failed shrink steps. + let failedShrinkStepCount : Int + /// Returns whether the testing system should cease testing altogether. + let shouldAbort : Bool - public init(name : String, maxSuccessTests : Int, maxDiscardedTests : Int, computeSize : Int -> Int -> Int, numSuccessTests : Int, numDiscardedTests : Int, labels : Dictionary, collected : [Set], expectedFailure : Bool, randomSeed : StdGen, numSuccessShrinks : Int, numTryShrinks : Int, numTotTryShrinks : Int, shouldAbort : Bool) { + public init( name : String + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , computeSize : Int -> Int -> Int + , successfulTestCount : Int + , discardedTestCount : Int + , labels : Dictionary + , collected : [Set] + , hasFulfilledExpectedFailure : Bool + , randomSeedGenerator : StdGen + , successfulShrinkCount : Int + , failedShrinkStepDistance : Int + , failedShrinkStepCount : Int + , shouldAbort : Bool) + { self.name = name - self.maxSuccessTests = maxSuccessTests - self.maxDiscardedTests = maxDiscardedTests + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests self.computeSize = computeSize - self.numSuccessTests = numSuccessTests - self.numDiscardedTests = numDiscardedTests + self.successfulTestCount = successfulTestCount + self.discardedTestCount = discardedTestCount self.labels = labels self.collected = collected - self.expectedFailure = expectedFailure - self.randomSeed = randomSeed - self.numSuccessShrinks = numSuccessShrinks - self.numTryShrinks = numTryShrinks - self.numTotTryShrinks = numTotTryShrinks + self.hasFulfilledExpectedFailure = hasFulfilledExpectedFailure + self.randomSeedGenerator = randomSeedGenerator + self.successfulShrinkCount = successfulShrinkCount + self.failedShrinkStepDistance = failedShrinkStepDistance + self.failedShrinkStepCount = failedShrinkStepCount self.shouldAbort = shouldAbort } } From 23c60f0e0098274b88970c3668e277dbc930b319 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 12:02:46 -0400 Subject: [PATCH 097/460] Realign --- SwiftCheck/Test.swift | 178 +++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 74548aa..575f560 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -301,18 +301,18 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { let istate = CheckerState(name: args.name - , maxSuccessTests: args.maxSuccess - , maxDiscardedTests: args.maxDiscard + , maxAllowableSuccessfulTests: args.maxSuccess + , maxAllowableDiscardedTests: args.maxDiscard , computeSize: computeSize - , numSuccessTests: 0 - , numDiscardedTests: 0 + , successfulTestCount: 0 + , discardedTestCount: 0 , labels: [:] , collected: [] - , expectedFailure: false - , randomSeed: rnd() - , numSuccessShrinks: 0 - , numTryShrinks: 0 - , numTotTryShrinks: 0 + , hasFulfilledExpectedFailure: false + , randomSeedGenerator: rnd() + , successfulShrinkCount: 0 + , failedShrinkStepDistance: 0 + , failedShrinkStepCount: 0 , shouldAbort: false) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, f: modP.unProperty.unGen) @@ -341,10 +341,10 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { return fail.0 } case let .Right(lsta): - if lsta.numSuccessTests >= lsta.maxSuccessTests || lsta.shouldAbort { + if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { return doneTesting(lsta)(f: f) } - if lsta.numDiscardedTests >= lsta.maxDiscardedTests || lsta.shouldAbort { + if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { return giveUp(lsta)(f: f) } state = lsta @@ -356,8 +356,8 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { // // On success the next state is returned. On failure the final result and state are returned. internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { - let size = st.computeSize(st.numSuccessTests)(st.numDiscardedTests) - let (rnd1, rnd2) = st.randomSeed.split() + let size = st.computeSize(st.successfulTestCount)(st.discardedTestCount) + let (rnd1, rnd2) = st.randomSeedGenerator.split() // Execute the Rose Tree for the test and reduce to .MkRose. switch reduce(f(rnd1)(size).unProp) { @@ -368,36 +368,36 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either switch res.match() { // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests.successor() - , numDiscardedTests: st.numDiscardedTests - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , expectedFailure: expect - , randomSeed: st.randomSeed - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount.successor() + , discardedTestCount: st.discardedTestCount + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: st.randomSeedGenerator + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort) return .Right(nstate) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort): - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , expectedFailure: expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: st.discardedTestCount.successor() + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort) return .Right(nstate) // Fail @@ -412,31 +412,31 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) if !expect { - let s = Result.Success(numTests: st.numSuccessTests.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") + let s = Result.Success(numTests: st.successfulTestCount.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") return .Left((s, st)) } - let stat = Result.Failure(numTests: st.numSuccessTests.successor() + let stat = Result.Failure(numTests: st.successfulTestCount.successor() , numShrinks: numShrinks - , usedSeed: st.randomSeed - , usedSize: st.computeSize(st.numSuccessTests)(st.numDiscardedTests) + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount)(st.discardedTestCount) , reason: res.reason , labels: summary(st) , output: "*** Failed! ") - let nstate = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests.successor() - , labels: st.labels - , collected: st.collected - , expectedFailure: res.expect - , randomSeed: rnd2 - , numSuccessShrinks: st.numSuccessShrinks - , numTryShrinks: st.numTryShrinks - , numTotTryShrinks: st.numTotTryShrinks + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: st.discardedTestCount.successor() + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: res.expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort) return .Left((stat, nstate)) } @@ -447,19 +447,19 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either } internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { - if st.expectedFailure { - print("*** Passed " + "\(st.numSuccessTests)" + pluralize(" test", i: st.numSuccessTests)) + if st.hasFulfilledExpectedFailure { + print("*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .Success(numTests: st.numSuccessTests, labels: summary(st), output: "") + return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") } else { printDistributionGraph(st) - return .NoExpectedFailure(numTests: st.numSuccessTests, labels: summary(st), output: "") + return .NoExpectedFailure(numTests: st.successfulTestCount, labels: summary(st), output: "") } } internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { printDistributionGraph(st) - return Result.GaveUp(numTests: st.numSuccessTests, labels: summary(st), output: "") + return Result.GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of failed shrinks, @@ -478,9 +478,9 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts var lastResult = res var branches = ts - var numSuccessShrinks = st.numSuccessShrinks - var numTryShrinks = st.numTryShrinks.successor() - var numTotTryShrinks = st.numTotTryShrinks + var successfulShrinkCount = st.successfulShrinkCount + var failedShrinkStepDistance = st.failedShrinkStepDistance.successor() + var failedShrinkStepCount = st.failedShrinkStepCount // cont is a sanity check so we don't fall into an infinite loop. It is set to false at each // new iteration and true when we select a new set of branches to test. If the branch @@ -494,7 +494,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts } cont = false - numTryShrinks = 0 + failedShrinkStepDistance = 0 // Try all possible courses of action in this Rose Tree branches.forEach { r in @@ -513,41 +513,41 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts } // Otherwise increment the tried shrink counter and the failed shrink counter. - numTryShrinks++ - numTotTryShrinks++ + failedShrinkStepDistance++ + failedShrinkStepCount++ default: fatalError("Rose should not have reduced to IO") } } - numSuccessShrinks++ + successfulShrinkCount++ } - let state = CheckerState(name: st.name - , maxSuccessTests: st.maxSuccessTests - , maxDiscardedTests: st.maxDiscardedTests - , computeSize: st.computeSize - , numSuccessTests: st.numSuccessTests - , numDiscardedTests: st.numDiscardedTests - , labels: st.labels - , collected: st.collected - , expectedFailure: st.expectedFailure - , randomSeed: st.randomSeed - , numSuccessShrinks: numSuccessShrinks - , numTryShrinks: numTryShrinks - , numTotTryShrinks: numTotTryShrinks - , shouldAbort: st.shouldAbort) + let state = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: st.discardedTestCount + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure + , randomSeedGenerator: st.randomSeedGenerator + , successfulShrinkCount: successfulShrinkCount + , failedShrinkStepDistance: failedShrinkStepDistance + , failedShrinkStepCount: failedShrinkStepCount + , shouldAbort: st.shouldAbort) return reportMinimumCaseFound(state, res: lastResult) } internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \(st.numSuccessTests.successor()) test" - let shrinkMsg = st.numSuccessShrinks > 1 ? (" and \(st.numSuccessShrinks) shrink") : "" + let testMsg = " (after \(st.successfulTestCount.successor()) test" + let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" print("Proposition: " + st.name) - print(res.reason + pluralize(testMsg, i: st.numSuccessTests.successor()) + pluralize(shrinkMsg, i: st.numSuccessShrinks) + "):") + print(res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + pluralize(shrinkMsg, i: st.successfulShrinkCount) + "):") dispatchAfterFinalFailureCallbacks(st, res: res) - return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) + return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { @@ -577,12 +577,12 @@ internal func summary(s : CheckerState) -> [(String, Int)] { .flatMap({ l in l.map({ "," + $0 }).filter({ !$0.isEmpty }) }) .sort() .groupBy(==) - return l.map { ss in (ss.first!, ss.count * 100 / s.numSuccessTests) } + return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } internal func labelPercentage(l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap(Array.init).filter { $0 == l } - return (100 * occur.count) / st.maxSuccessTests + return (100 * occur.count) / st.maxAllowableSuccessfulTests } internal func printLabels(st : TestResult) { @@ -607,7 +607,7 @@ internal func printDistributionGraph(st : CheckerState) { return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) }) let gAll = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) - let gPrint = gAll.map({ ss in showP((ss.count * 100) / st.numSuccessTests) + ss.first! }) + let gPrint = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) let allLabels = Array(gPrint.sort().reverse()) var covers = [String]() From b5865501b65f0bb0e11773c99e618b686ff72682 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 4 Sep 2015 12:16:43 -0400 Subject: [PATCH 098/460] Rename and document RandomGen --- SwiftCheck/Gen.swift | 4 +- SwiftCheck/Random.swift | 88 ++++++++++++++++++++++------------------- SwiftCheck/Test.swift | 2 +- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index f93549a..dbe8770 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -307,7 +307,7 @@ extension Gen /*: Monad*/ { public func >>- (m : Gen, fn : A -> Gen) -> Gen { return Gen(unGen: { r in return { n in - let (r1, r2) = r.split() + let (r1, r2) = r.split let m2 = fn(m.unGen(r1)(n)) return m2.unGen(r2)(n) } @@ -373,7 +373,7 @@ internal func delay() -> Gen -> A> { import func Darwin.log private func vary(k : S)(r : StdGen) -> StdGen { - let s = r.split() + let s = r.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2)(r: r) } diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 8e87831..a809d26 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -9,41 +9,49 @@ import func Darwin.time import func Darwin.rand -public protocol RandomGen { - func next() -> (Int, Self) - - func genRange() -> (Int, Int) - func split() -> (Self, Self) +/// Provides a standard interface to an underlying Random Value Generator of any type. It is +/// analogous to `GeneratorType`, but rather than consume a sequence it uses sources of randomness +/// to generate values indefinitely. +public protocol RandomGeneneratorType { + /// The next operation returns an Int that is uniformly distributed in the range returned by + /// `genRange` (including both end points), and a new generator. + var next : (Int, Self) { get } + /// The genRange operation yields the range of values returned by the generator. + /// + /// This property must return integers in ascending order. + var genRange : (Int, Int) { get } + /// Splits the receiver into two distinct random value generators. + var split : (Self, Self) { get } } /// A library-provided standard random number generator. let standardRNG : StdGen = StdGen(time(nil)) -public struct StdGen : RandomGen { +public struct StdGen : RandomGeneneratorType { let seed: Int init(_ seed : Int) { self.seed = seed } - public func next() -> (Int, StdGen) { + public var next : (Int, StdGen) { let s = Int(time(nil)) return (Int(rand()), StdGen(s)) } - public func split() -> (StdGen, StdGen) { - let (s1, g) = self.next() - let (s2, _) = g.next() + public var split : (StdGen, StdGen) { + let (s1, g) = self.next + let (s2, _) = g.next return (StdGen(s1), StdGen(s2)) } - public func genRange() -> (Int, Int) { + public var genRange : (Int, Int) { return (Int.min, Int.max) } } public func newStdGen() -> StdGen { - return standardRNG.split().1 + return standardRNG.split.1 } private func mkStdRNG(seed : Int) -> StdGen { @@ -52,16 +60,16 @@ private func mkStdRNG(seed : Int) -> StdGen { /// Types that can generate random versions of themselves. public protocol RandomType { - static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) + static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) } /// Generates a random value from a LatticeType random type. -public func random, G : RandomGen>(gen : G) -> (A, G) { +public func random, G : RandomGeneneratorType>(gen : G) -> (A, G) { return A.randomInRange((A.min, A.max), gen: gen) } extension Character : RandomType { - public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { + public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! let maxc = String(max).unicodeScalars.first! @@ -72,16 +80,16 @@ extension Character : RandomType { } extension UnicodeScalar : RandomType { - public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) return (UnicodeScalar(val), gg) } } extension Int : RandomType { - public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { + public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (r % ((max + 1) - min)) + min; return (result, g); @@ -89,9 +97,9 @@ extension Int : RandomType { } extension Int8 : RandomType { - public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { + public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (r % ((max + 1) - min)) + min; return (result, g); @@ -99,9 +107,9 @@ extension Int8 : RandomType { } extension Int16 : RandomType { - public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { + public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (r % ((max + 1) - min)) + min; return (result, g); @@ -109,9 +117,9 @@ extension Int16 : RandomType { } extension Int32 : RandomType { - public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { + public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (r % ((max + 1) - min)) + min; return (result, g); @@ -119,9 +127,9 @@ extension Int32 : RandomType { } extension Int64 : RandomType { - public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { + public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (r % ((max + 1) - min)) + min; return (result, g); @@ -129,9 +137,9 @@ extension Int64 : RandomType { } extension UInt : RandomType { - public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { + public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (UInt(r) % ((max + 1) - min)) + min; return (result, g); @@ -139,9 +147,9 @@ extension UInt : RandomType { } extension UInt8 : RandomType { - public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { + public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (UInt8(r) % ((max + 1) - min)) + min; return (result, g); @@ -149,9 +157,9 @@ extension UInt8 : RandomType { } extension UInt16 : RandomType { - public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { + public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (UInt16(r) % ((max + 1) - min)) + min; return (result, g); @@ -159,9 +167,9 @@ extension UInt16 : RandomType { } extension UInt32 : RandomType { - public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { + public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (UInt32(r) % ((max + 1) - min)) + min; return (result, g); @@ -169,9 +177,9 @@ extension UInt32 : RandomType { } extension UInt64 : RandomType { - public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { + public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let result = (UInt64(r) % ((max + 1) - min)) + min; return (result, g); @@ -179,9 +187,9 @@ extension UInt64 : RandomType { } extension Float : RandomType { - public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { + public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let fr = Float(r) let result = (fr % ((max + 1) - min)) + min; @@ -190,9 +198,9 @@ extension Float : RandomType { } extension Double : RandomType { - public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { + public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { let (min, max) = range - let (r, g) = gen.next() + let (r, g) = gen.next let dr = Double(r) let result = (dr % ((max + 1) - min)) + min; diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 575f560..ee638b6 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -357,7 +357,7 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { // On success the next state is returned. On failure the final result and state are returned. internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount)(st.discardedTestCount) - let (rnd1, rnd2) = st.randomSeedGenerator.split() + let (rnd1, rnd2) = st.randomSeedGenerator.split // Execute the Rose Tree for the test and reduce to .MkRose. switch reduce(f(rnd1)(size).unProp) { From 424bcb08bb8fdb4bd8731c4b22f350710e54d506 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:01:34 -0400 Subject: [PATCH 099/460] Collapse test.swift example --- SwiftCheck.xcodeproj/project.pbxproj | 2 +- SwiftCheck/Test.swift | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 61a2a48..a4360e7 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -190,13 +190,13 @@ 842015101AF5C91C00F1F3CD /* Lattice.swift */, 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */, 82DD8EEB1B4CC88C00B66551 /* Operators.swift */, - 8450D2491AF8003700095EF6 /* TestOperators.swift */, 844FCCAD198B367000EB242A /* Property.swift */, 844FCCC2198EC4F000EB242A /* Random.swift */, 844FCCC6198EFB4700EB242A /* Rose.swift */, 844FCCB3198B39F300EB242A /* State.swift */, 844FCCAF198B36BE00EB242A /* Test.swift */, 84572C2A1A6DBABA00241F68 /* Testable.swift */, + 8450D2491AF8003700095EF6 /* TestOperators.swift */, 827749F71B65ABCC00A7965F /* Witness.swift */, D46395B51B1A94D200AA1B65 /* Equatable.swift */, 844FCC90198B320500EB242A /* Supporting Files */, diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index ee638b6..06ca406 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -69,15 +69,9 @@ /// /// /// shrinkArbitrary is a method call that invokes the shrinker /// let ls = self.shrinkArbitrary(s).map { $0.getSet } -/// return forAll { (x : Int) in /// OMG, is that a `forAll` inside a `forAll`?! -/// -/// return x != x // Well that can't possibly hold. -/// -/// } -/// ^||^ /// <- `^||^` is like `||` in Swift, but for properties. -/// (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).whenFail { -/// print("Oh noe!") -/// } +/// return (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).whenFail { +/// print("Oh noe!") +/// } /// } /// }.expectFailure.verbose /// ^ ^ From 05b966f23d42f18c3d9581c5c7a96958ce0ba3d3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:02:04 -0400 Subject: [PATCH 100/460] re-sugar --- SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 06ca406..6719487 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -36,7 +36,7 @@ /// | + This backwards arrow binds a property name and a property to each other. /// | | /// v v -/// property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in +/// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in /// return /// (xs.reverse().reverse() == xs) "Reverse on the left" /// ^&&^ From 1b59a83fc19b7295e5ba26fd4e13eb819c793d7a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:22:12 -0400 Subject: [PATCH 101/460] Provide more examples in Modifiers file --- SwiftCheck/Modifiers.swift | 14 +++++++++++++- SwiftCheckTests/ComplexSpec.swift | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 422c595..a2498f6 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -15,14 +15,26 @@ /// For an example of the former, take the `Blind` modifier. Because SwiftCheck's counterexamples /// come from a description a particular object provides for itself, there are many cases where /// console output can become unbearably long, or just simply isn't useful to your test suite. By -/// wrapping that type in `Blind` SwiftCheck ignore whatever description the property provides and +/// wrapping that type in `Blind` SwiftCheck ignores whatever description the property provides and /// just print "(*)". /// +/// property("All blind variables print '(*)'") <- forAll { (x : Blind) in +/// return x.description == "(*)" +/// } +/// /// For an example of the latter see the `ArrowOf` modifier. Because Swift's type system treats /// arrows (`->`) as an opaque entity that you can't interact with or extend, SwiftCheck provides /// `ArrowOf` to enable the generation of functions between 2 types. That's right, we can generate /// arbitrary functions! /// +/// property("map accepts SwiftCheck arrows") <- forAll { (xs : [Int]) in +/// return forAll { (f : ArrowOf) in +/// /// Just to prove it really is a function (that is, every input always maps to the +/// /// same output), and not just a trick, we map twice and should get equal arrays. +/// return xs.map(f.getArrow) == xs.map(f.getArrow) +/// } +/// } +/// /// Finally, modifiers nest to allow the generation of intricate structures that would not otherwise /// be possible due to the limitations above. For example, to generate an Array of Arrays of /// Dictionaries of Integers and Strings (a type that normally looks like diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index fb0e6df..43714d6 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -26,11 +26,13 @@ class ComplexSpec : XCTestCase { numeric, special, ]).proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) + let hostname = Gen.oneOf([ lower, numeric, Gen.pure("-"), ]).proliferateNonEmpty().fmap(String.init) + let tld = lower.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld From 52f5ff3bf06766d53071c23fca9361b5c2defb2a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:35:15 -0400 Subject: [PATCH 102/460] Format TestResult constructors --- SwiftCheck/Property.swift | 96 +++++++++++++++++++-------------------- SwiftCheck/Test.swift | 2 +- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 15a0c7e..e1ce55b 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -97,30 +97,30 @@ extension Testable { /// Modifies a property so that it only will be tested once. public var once : Property { - return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: true) - }) + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: true) + } } /// Attaches a callback to a test case. public func withCallback(cb : Callback) -> Property { - return self.mapResult({ (res) in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: [cb] + res.callbacks, - abort: res.abort) - }) + return self.mapResult { (res) in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: [cb] + res.callbacks + , abort: res.abort) + } } /// Adds the given string to the counterexamples of a failing property. @@ -180,16 +180,16 @@ extension Testable { } } - return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks + chattyCallbacks(res.callbacks), - abort: res.abort) - }) + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + chattyCallbacks(res.callbacks) + , abort: res.abort) + } } /// Modifies a property to indicate that it is expected to fail. @@ -197,14 +197,14 @@ extension Testable { /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { return self.mapTotalResult({ res in - return TestResult(ok: res.ok, - expect: false, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: res.callbacks, - abort: res.abort) + return TestResult(ok: res.ok + , expect: false + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort) }) } @@ -233,16 +233,16 @@ extension Testable { /// Discarded tests (i.e. ones with a false precondition) do not affect coverage. public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { - return self.mapResult({ res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: insertWith(max, k: s, v: n, m: res.labels), - stamp: res.stamp.union([s]), - callbacks: res.callbacks, - abort: res.abort) - }) + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: insertWith(max, k: s, v: n, m: res.labels) + , stamp: res.stamp.union([s]) + , callbacks: res.callbacks + , abort: res.abort) + } } return self.property } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 6719487..67c8896 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -67,7 +67,7 @@ /// /// be used to discard test cases that contain data you don't want to test with. /// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { /// -/// /// shrinkArbitrary is a method call that invokes the shrinker +/// /// N.B. `shrinkArbitrary` is a internal method call that invokes the shrinker. /// let ls = self.shrinkArbitrary(s).map { $0.getSet } /// return (ls.filter({ $0 == [0] || $0 == [] }).count >= 1).whenFail { /// print("Oh noe!") From 626dbe6d8462a93c5da6ce2f8dddfd8bdf323789 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:41:02 -0400 Subject: [PATCH 103/460] More formatting --- SwiftCheck/Property.swift | 49 ++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index e1ce55b..a28b840 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -272,20 +272,21 @@ public enum Callback { /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { - /// + /// Affected by the verbose combinator. case Counterexample + /// Not affected by the verbose combinator case NotCounterexample } public enum TestResultMatcher { - case MatchResult( ok : Optional - , expect : Bool - , reason : String + case MatchResult( ok : Optional + , expect : Bool + , reason : String , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool + , labels : Dictionary + , stamp : Set + , callbacks : Array + , abort : Bool ) } @@ -430,27 +431,27 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: res.labels, - stamp: res.stamp, - callbacks: result.callbacks + res.callbacks, - abort: res.abort) + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: result.callbacks + res.callbacks + , abort: res.abort) } } private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in - return TestResult(ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: unionWith(max, l: res.labels, r: result.labels), - stamp: res.stamp.union(result.stamp), - callbacks: res.callbacks, - abort: res.abort) + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: unionWith(max, l: res.labels, r: result.labels) + , stamp: res.stamp.union(result.stamp) + , callbacks: res.callbacks + , abort: res.abort) } } From 6f20f232bf0bc435fceb276f0ca5f022b47f32f9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:47:28 -0400 Subject: [PATCH 104/460] More formatting --- SwiftCheck/Property.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index a28b840..d556dec 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -125,16 +125,16 @@ extension Testable { /// Adds the given string to the counterexamples of a failing property. public func counterexample(s : String) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample, f: { _ in + return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample) { _ in return print(s) - })) + }) } /// Executes an action after the last failure of the property. public func whenFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample, f: { _ in + return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { _ in return m() - })) + }) } /// Executes an action after the every failure of the property. @@ -142,11 +142,11 @@ extension Testable { /// Because the action is executed after every failing test it can be used to track the list of /// failures generated by the shrinking mechanism. public func whenEachFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample, f: { (st, res) in + return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in if res.ok == .Some(false) { m() } - })) + }) } /// Modifies a property so it prints out every generated test case and the result of the property From b3493f3b2588177a9c15b89d72d6c3140290acf1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:50:17 -0400 Subject: [PATCH 105/460] Final checks --- SwiftCheck/Arbitrary.swift | 2 +- SwiftCheck/Property.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 80fcb7a..fabe26b 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -24,7 +24,7 @@ import Darwin /// /// As an example, take the `ArrayOf` implementation of shrink: /// -/// shrink(ArrayOf([1, 2, 3])) +/// Arbitrary.shrink(ArrayOf([1, 2, 3])) /// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// /// SwiftCheck will search each case one-by-one and continue shrinking until it has reached a case diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index d556dec..ce87335 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -156,7 +156,7 @@ extension Testable { /// callbacks. public var verbose : Property { func chattyCallbacks(cbs : [Callback]) -> [Callback] { - let c = Callback.AfterTest(kind: .Counterexample, f: { (st, res) in + let c = Callback.AfterTest(kind: .Counterexample) { (st, res) in switch res.ok { case .Some(true): print("\nPassed: ", terminator: "") @@ -168,7 +168,7 @@ extension Testable { print("\nDiscarded: ", terminator: "") printLabels(res) } - }) + } return [c] + cbs.map { (c : Callback) -> Callback in switch c { From 34733e17e555ecb81e116f99f63d919a78ffe565 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 14:54:28 -0400 Subject: [PATCH 106/460] Boilerplate --- .../SwiftCheck.playground/Contents.swift | 122 ------------------ .../Sources/SupportCode.swift | 3 - Tutorial.playground/Contents.swift | 7 + .../contents.xcplayground | 2 +- .../contents.xcworkspacedata | 2 +- .../timeline.xctimeline | 0 Tutorial.xcworkspace/contents.xcworkspacedata | 10 ++ 7 files changed, 19 insertions(+), 127 deletions(-) delete mode 100644 SwiftCheck/SwiftCheck.playground/Contents.swift delete mode 100644 SwiftCheck/SwiftCheck.playground/Sources/SupportCode.swift create mode 100644 Tutorial.playground/Contents.swift rename {SwiftCheck/SwiftCheck.playground => Tutorial.playground}/contents.xcplayground (58%) rename {SwiftCheck/SwiftCheck.playground => Tutorial.playground}/playground.xcworkspace/contents.xcworkspacedata (56%) rename {SwiftCheck/SwiftCheck.playground => Tutorial.playground}/timeline.xctimeline (100%) create mode 100644 Tutorial.xcworkspace/contents.xcworkspacedata diff --git a/SwiftCheck/SwiftCheck.playground/Contents.swift b/SwiftCheck/SwiftCheck.playground/Contents.swift deleted file mode 100644 index 2983c14..0000000 --- a/SwiftCheck/SwiftCheck.playground/Contents.swift +++ /dev/null @@ -1,122 +0,0 @@ -//: ## SwiftCheck - noun: QuickCheck for Swift. -//: -//: SwiftCheck is a testing library that automatically generates random data for testing of program -//: properties. - -import SwiftCheck - -//: For example, if we wanted to test the property that every Integer is equal to itself, we would -//: express it as such and SwiftCheck will handle the rest: -property["Integer equality obeys reflexivity"] = forAll { (i : Int) in - return i == i -} - -//: ## Shrinking -//: What makes QuickCheck unique is the notion of shrinking test cases. When fuzz testing with -//: arbitrary data, rather than simply halt on a failing test, SwiftCheck will begin whittling the -//: data that causes the test to fail down to a minimal counterexample. -//: -//: For example, the following function uses the Sieve of Eratosthenes to generate a list of primes -//: less than some n: - -// The Sieve of Eratosthenes: -// -// To find all the prime numbers less than or equal to a given integer n: -// - let l = [2...n] -// - let p = 2 -// - for i in [(2 * p) through n by p] { -// mark l[i] -// } -// - Remaining indices of unmarked numbers are primes -func sieve(n : Int) -> [Int] { - if n <= 1 { - return [Int]() - } - - var marked : [Bool] = (0...n).map({ _ in false }) - marked[0] = true - marked[1] = true - - for p in 2.. Bool { - if n == 0 || n == 1 { - return false - } else if n == 2 { - return true - } - - let max = Int(ceil(sqrt(Double(n)))) - for i in 2...max { - if n % i == 0 { - return false - } - } - return true -} - -//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the -//: following property: - -property["All Prime"] = forAll { (n : Int) in - return sieve(n).filter(isPrime) == sieve(n) -} - -//: Which produces the following in our testing log: -//: -//: > Test Case '-[SwiftCheckTests.PrimeSpec testAll]' started. -//: > *** Failed! Falsifiable (after 10 tests): -//: > 4 -//: -//: Indicating that our sieve has failed on the input number 4. A quick look back at the comments -//: describing the sieve reveals the mistake immediately: -//: -//: > - for i in stride(from: 2 * p, to: n, by: p) { -//: > + for i in stride(from: 2 * p, through: n, by: p) { -//: -//: Running SwiftCheck again reports a successful sieve of all 100 random cases: - -func sieveProperly(n : Int) -> [Int] { - if n <= 1 { - return [Int]() - } - - var marked : [Bool] = (0...n).map({ _ in false }) - marked[0] = true - marked[1] = true - - for p in 2.. - + \ No newline at end of file diff --git a/SwiftCheck/SwiftCheck.playground/playground.xcworkspace/contents.xcworkspacedata b/Tutorial.playground/playground.xcworkspace/contents.xcworkspacedata similarity index 56% rename from SwiftCheck/SwiftCheck.playground/playground.xcworkspace/contents.xcworkspacedata rename to Tutorial.playground/playground.xcworkspace/contents.xcworkspacedata index a0002ce..919434a 100644 --- a/SwiftCheck/SwiftCheck.playground/playground.xcworkspace/contents.xcworkspacedata +++ b/Tutorial.playground/playground.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/SwiftCheck/SwiftCheck.playground/timeline.xctimeline b/Tutorial.playground/timeline.xctimeline similarity index 100% rename from SwiftCheck/SwiftCheck.playground/timeline.xctimeline rename to Tutorial.playground/timeline.xctimeline diff --git a/Tutorial.xcworkspace/contents.xcworkspacedata b/Tutorial.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1b980dd --- /dev/null +++ b/Tutorial.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + From bf016fe4e805175e57c9fa839a3dcc2e33fa38ed Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 15:05:39 -0400 Subject: [PATCH 107/460] Pre-requisites --- Tutorial.playground/Contents.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 0e08252..ce94635 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -3,5 +3,23 @@ import SwiftCheck import XCTest +//: # Prerequisites +//: This tutorial assumes that you have a fairly good grasp on Swift, its syntax, and terms like +//: +//: * [(Data) Type](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html) +//: * [Protocol-Oriented Programming](https://developer.apple.com/videos/wwdc/2015/?id=408) +//: * [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) +//: * [Polymorphism](https://en.wikipedia.org/wiki/Polymorphism) +//: * [Map/Filter/Reduce](https://medium.com/@ivicamil/higher-order-functions-in-swift-part-1-d8e75f963d13) +//: +//: What this tutorial does *not* require are that you know +//: +//: * [Abstract Nonsense](https://en.wikipedia.org/wiki/Abstract_nonsense) +//: * Functional Programming +//: * What that dumb 'M' word is/does/means + +//: # Introduction + +//: From cadc16503a2d89055d08e77a107414783b78cc1a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 15:07:23 -0400 Subject: [PATCH 108/460] grammarz --- Tutorial.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index ce94635..ea2742c 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -13,7 +13,7 @@ import XCTest //: * [Polymorphism](https://en.wikipedia.org/wiki/Polymorphism) //: * [Map/Filter/Reduce](https://medium.com/@ivicamil/higher-order-functions-in-swift-part-1-d8e75f963d13) //: -//: What this tutorial does *not* require are that you know +//: What this tutorial does *not* require is that you know about //: //: * [Abstract Nonsense](https://en.wikipedia.org/wiki/Abstract_nonsense) //: * Functional Programming From 429a9f30b900ea371a000711a52328438a3c74d6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 15:08:47 -0400 Subject: [PATCH 109/460] Link to the m word --- Tutorial.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index ea2742c..d8e1a18 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -17,7 +17,7 @@ import XCTest //: //: * [Abstract Nonsense](https://en.wikipedia.org/wiki/Abstract_nonsense) //: * Functional Programming -//: * What that dumb 'M' word is/does/means +//: * What that dumb ['M' word](https://wiki.haskell.org/Monad) is/does/means //: # Introduction From 556d9f0aad8f6f4f580dc81361136963297087be Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 17:39:38 -0400 Subject: [PATCH 110/460] Write an introduction --- Tutorial.playground/Contents.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index d8e1a18..4d3c5e0 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -5,7 +5,7 @@ import XCTest //: # Prerequisites -//: This tutorial assumes that you have a fairly good grasp on Swift, its syntax, and terms like +//: This tutorial assumes that you have a fairly good grasp of Swift, its syntax, and terms like //: //: * [(Data) Type](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html) //: * [Protocol-Oriented Programming](https://developer.apple.com/videos/wwdc/2015/?id=408) @@ -21,5 +21,15 @@ import XCTest //: # Introduction -//: +//: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick`, by giving them +//: the ability to automatically test program properties. A property is a particular facet of an +//: algorithm, method, data structure, or program that must *hold* (that is, remain valid) even when +//: fed random or pseudo-random data. If that all seems complicated, it may be simpler to think of +//: Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements rather than +//: break the program. Throughout this tutorial, simplifications like the above will be made to aid +//: your understanding. Towards the end of it, we will begin to remove much of these "training wheels" +//: and reveal the real types of the operations in the library, which are often much more powerful and +//: generic than previously presented. + + From 5c46f40b842e1e131733581555851cdf4abd1200 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 18:46:25 -0400 Subject: [PATCH 111/460] Add Generator sections --- SwiftCheck/Gen.swift | 6 +- Tutorial.playground/Contents.swift | 130 ++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index dbe8770..c3863ee 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -33,10 +33,8 @@ public struct Gen { /// only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf>(xs : S) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty sequence") - - return choose((xs.startIndex, xs.endIndex.predecessor())).fmap { i in + public static func fromElementsOf>(xs : S) -> Gen { + return Gen.fromElementsIn(xs.startIndex..`. In Swift, we also have Generators, but we spell them `Gen`erators, +//: as in the universal Generator type `Gen`. `Gen` is a struct defined generically over any kind of type +//: that looks like this: +// +// /// We're not defining this here; We'll be using SwiftCheck's `Gen` from here on out. +// struct Gen { } +// +//: `Gen`, unlike `GeneratorType`, is not backed by a concrete data structure like an array or dictionary, +//: but is instead constructed by invoking methods that refine the kind of data that gets generated. Below +//: are some examples of `Gen`erators that generate random instances of simple data types. + +// `Gen.pure` constructs a generator that *only* produces the given value. +let onlyFive = Gen.pure(5) + +onlyFive.generate +onlyFive.generate +onlyFive.generate +onlyFive.generate +onlyFive.generate + +// `Gen.fromElementsIn` constructs a generator that pulls values from inside the +// bounds of the given Range. Because generation is random, some values may be repeated. +let fromOnetoFive = Gen.fromElementsIn(1...5) + +fromOnetoFive.generate +fromOnetoFive.generate +fromOnetoFive.generate +fromOnetoFive.generate +fromOnetoFive.generate + +let lowerCaseLetters : Gen = Gen.fromElementsIn("a"..."z") + +lowerCaseLetters.generate +lowerCaseLetters.generate +lowerCaseLetters.generate + +let upperCaseLetters : Gen = Gen.fromElementsIn("A"..."Z") + +upperCaseLetters.generate +upperCaseLetters.generate +upperCaseLetters.generate + +// `Gen.fromElementsOf` works like `Gen.fromElementsIn` but over an Array, not just a Range. +let specialCharacters = Gen.fromElementsOf([ "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" ]) + +specialCharacters.generate +specialCharacters.generate +specialCharacters.generate +specialCharacters.generate + +//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in amazing +//: ways. + +// `Gen.oneOf` randomly picks one of the generators from the given list and draws element from it. +let uppersAndLowers = Gen.oneOf([ + lowerCaseLetters, + upperCaseLetters, +]) + +uppersAndLowers.generate +uppersAndLowers.generate +uppersAndLowers.generate +uppersAndLowers.generate +uppersAndLowers.generate + +// `Gen.zip` works like zip in Swift but with `Gen`erators. +let pairsOfNumbers = Gen<(Int, Int)>.zip(fromOnetoFive, fromOnetoFive) + +pairsOfNumbers.generate +pairsOfNumbers.generate +pairsOfNumbers.generate + +//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck includes a number +//: of functions for creating `Gen`erators with "weights" attached to their elements. + +// This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. +let weightedGen = Gen.weighted([ + (1, nil), + (3, .Some(5)), +]) + +weightedGen.generate +weightedGen.generate +weightedGen.generate +weightedGen.generate + +// `Gen.frequency` works like `Gen.weighted` and `Gen.oneOf` put together. +let biasedUppersAndLowers = Gen.frequency([ + (1, uppersAndLowers), + (3, lowerCaseLetters), +]) + +//: `Gen`erators can even filter, modify, or combine the elements they create to produce. + +let oneToFiveEven = fromOnetoFive.suchThat { $0 % 2 == 0 } + +oneToFiveEven.generate +oneToFiveEven.generate +oneToFiveEven.generate + +let characterArray = uppersAndLowers.proliferate() + +characterArray.generate +characterArray.generate +characterArray.generate + +let oddLengthArrays = fromOnetoFive.proliferateNonEmpty().suchThat { $0.count % 2 == 1 } + +oddLengthArrays.generate.count +oddLengthArrays.generate.count +oddLengthArrays.generate.count + + + + + + + From aba0b388cea96b7e91394a782275fefd0a12a1fe Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 18:50:08 -0400 Subject: [PATCH 112/460] Fix some typos --- Tutorial.playground/Contents.swift | 5 ++++- Tutorial.playground/contents.xcplayground | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 79b9cc1..4f75d56 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -103,7 +103,7 @@ uppersAndLowers.generate uppersAndLowers.generate uppersAndLowers.generate -// `Gen.zip` works like zip in Swift but with `Gen`erators. +// `Gen.zip` works like `zip` in Swift but with `Gen`erators. let pairsOfNumbers = Gen<(Int, Int)>.zip(fromOnetoFive, fromOnetoFive) pairsOfNumbers.generate @@ -132,18 +132,21 @@ let biasedUppersAndLowers = Gen.frequency([ //: `Gen`erators can even filter, modify, or combine the elements they create to produce. +// `suchThat` takes a predicate function that filters generated elements. let oneToFiveEven = fromOnetoFive.suchThat { $0 % 2 == 0 } oneToFiveEven.generate oneToFiveEven.generate oneToFiveEven.generate +// `proliferate` turns a generator of single elements into a generator of arrays of those elements. let characterArray = uppersAndLowers.proliferate() characterArray.generate characterArray.generate characterArray.generate +/// `proliferateNonEmpty` works like `proliferate` but guarantees the generated array is never empty. let oddLengthArrays = fromOnetoFive.proliferateNonEmpty().suchThat { $0.count % 2 == 1 } oddLengthArrays.generate.count diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index a204ba6..0b96219 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 899d36be41212e5a36f04aaa36a4060802a3a771 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 19:37:08 -0400 Subject: [PATCH 113/460] Finish email gen and Generator section --- SwiftCheckTests/ComplexSpec.swift | 2 +- Tutorial.playground/Contents.swift | 136 +++++++++++++++++++++- Tutorial.playground/contents.xcplayground | 2 +- 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 43714d6..9661910 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -12,7 +12,7 @@ import SwiftCheck let upper : Gen= Gen.fromElementsIn("A"..."Z") let lower : Gen = Gen.fromElementsIn("a"..."z") let numeric : Gen = Gen.fromElementsIn("0"..."9") -let special = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) let hexDigits = Gen.oneOf([ Gen.fromElementsIn("A"..."F"), numeric, diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 4f75d56..15915ed 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -39,8 +39,9 @@ import XCTest //: In Swift, when one thinks of a Generator, they usually think of the `GeneratorType` protocol or the //: many many individual structures the Swift Standard Library exposes to allow loops to work with data //: structures like `[T]` and `Set`. In Swift, we also have Generators, but we spell them `Gen`erators, -//: as in the universal Generator type `Gen`. `Gen` is a struct defined generically over any kind of type -//: that looks like this: +//: as in the universal Generator type `Gen`. +//: +//: `Gen` is a struct defined generically over any kind of type that looks like this: // // /// We're not defining this here; We'll be using SwiftCheck's `Gen` from here on out. // struct Gen { } @@ -153,8 +154,139 @@ oddLengthArrays.generate.count oddLengthArrays.generate.count oddLengthArrays.generate.count +//: Generators also admit functional methods like `map` and `flatMap`, but with different names than you might +//: be used to. + +// `fmap` (function map) works exactly like Array's `map` method; it applies the function to any +// values it generates. +let fromTwoToSix = fromOnetoFive.fmap { $0 + 1 } + +fromTwoToSix.generate +fromTwoToSix.generate +fromTwoToSix.generate +fromTwoToSix.generate +fromTwoToSix.generate + +// `bind` works exactly like Array's `flatMap`, but instead of concatenating the generated arrays it produces +// a new generator that picks values from among the newly created generators produced by the function. While +// That definition may *technically* be what occurs, it is better to think of `bind` as a way of making a generator +// depend on another. For example, you can use a generator of sizes to limit the length of generators of arrays: + +let generatorBoundedSizeArrays = fromOnetoFive.bind { len in + return characterArray.suchThat { xs in xs.count <= len } +} + +generatorBoundedSizeArrays.generate +generatorBoundedSizeArrays.generate +generatorBoundedSizeArrays.generate +generatorBoundedSizeArrays.generate +generatorBoundedSizeArrays.generate + +//: Because SwiftCheck is based on the functional concepts in our other library [Swiftz](https://github.com/typelift/Swiftz), +//: each of these functions has an operator alias: +//: +//: * `<^>` is an alias for `fmap` +//: * `<*>` is an alias for `ap` +//: * `>>-` is an alias for `bind` + +// <^> is backwards for aesthetic and historical purposes. Its true use will be revealled soon. +let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive + +fromTwoToSix_.generate +fromTwoToSix_.generate +fromTwoToSix_.generate + +let generatorBoundedSizeArrays_ = fromOnetoFive >>- { len in + return characterArray.suchThat { xs in xs.count <= len } +} + +generatorBoundedSizeArrays_.generate +generatorBoundedSizeArrays_.generate +generatorBoundedSizeArrays_.generate + +//: Now that you've seen what generators can do, we'll use all we've learned to create a generator that +//: produces email addresses. To do this, we'll need one more operator/method notated `<*>` or `ap`. +//: `ap` comes from [Applicative Functors](http://staff.city.ac.uk/~ross/papers/Applicative.html) and is +//: used to "zip together" `Gen`erators of functions with `Gen`erators of of values, applying each function +//: during the zipping phase. That definition is a little hand-wavey and technical, so for now we'll say that +//: `ap` works like "glue" that sticks special kinds of generators togethers. +//: +//: For our purposes, we will say that an email address consists of 3 parts: A local part, a hostname, and a +//: Top-Level Domain each separated by an `@`, and a `.` respectively. +//: +//: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, numbers, and +//: certain kinds of special characters. We already have generators for upper and lower cased letters, so all we +//: need are special characters and a more complete number generator: + +let numeric : Gen = Gen.fromElementsIn("0"..."9") +let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) + +//: Now for the actual generator + +let allowedLocalCharacters : Gen = Gen.oneOf([ + upperCaseLetters, + lowerCaseLetters, + numeric, + special, +]) + +//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` +//: to get a `String` back. + +let localEmail = allowedLocalCharacters.proliferateNonEmpty().fmap(String.init) + +//: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some +//: steps here and combine both steps above into one big generator. + +let hostname = Gen.oneOf([ + lowerCaseLetters, + numeric, + Gen.pure("-"), +]).proliferateNonEmpty().fmap(String.init) + +//: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. + +let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) + +//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how +//: about some glue? +// Concatenates 5 strings together in order. +func glue5(l : String) -> String -> String -> String -> String -> String { + return { m in { m2 in { m3 in { r in l + m + m2 + m3 + r } } } } +} +//: This big thing looks a bit complicated, let's go through it part by part: + +//: +--- Here's our glue function. +//: | +--- This says we're mapping that function over all these pieces. +//: | | +--- Here's our funtional "glue" from before. +//: | | | +//: v v v +let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld + +//: And we're done! + +// Yes, these are in fact, all valid email addresses. +emailGen.generate + +//: By now you may be asking "why do we need all of this in the first place? Can't we just apply the parts to the +//: function to get back a result?" Well, we do it because we aren't working with Characters or Strings or Arrays, +//: we're working with `Gen`. And we can't apply `Gen` to a function that expects `String`, that wouldn't +//: make any sense - and it would never compile! Instead we use these operators to "lift" our function over `String`s to +//: functions over `Gen`s. +//: +//: Complex cases like the above are rare in practice. Most of the time you won't even need to use generators at all! This +//: brings us to one of the most important parts of SwiftCheck: + +//: # Randomness + +//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were writing +//: SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on values that would ask them +//: to generate a "next" value. But that would have been incredibly boring! Instead, we wrote a protocol called `Arbitrary` +//: and let Types, not values, do all the work. +//: +//: The `Arbitrary` protocol looks like this: diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 0b96219..59b4af3 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From d5335dbfc4fae413769ec9d593b63aaa8e82c36a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 20:00:52 -0400 Subject: [PATCH 114/460] Start Modifier and Randomness section --- Tutorial.playground/Contents.swift | 71 ++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 15915ed..feded95 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -82,6 +82,8 @@ upperCaseLetters.generate upperCaseLetters.generate // `Gen.fromElementsOf` works like `Gen.fromElementsIn` but over an Array, not just a Range. +// +// mnemonic: Use `fromElementsIn` with an INdex. let specialCharacters = Gen.fromElementsOf([ "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" ]) specialCharacters.generate @@ -287,10 +289,79 @@ emailGen.generate //: and let Types, not values, do all the work. //: //: The `Arbitrary` protocol looks like this: +// +// public protocol Arbitrary { +// /// The generator for this particular type. +// /// +// /// This function should call out to any sources of randomness or state necessary to generate +// /// values. It should not, however, be written as a deterministic function. If such a +// /// generator is needed, combinators are provided in `Gen.swift`. +// static var arbitrary : Gen { get } +// } +// +//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can, well, give us a generator to create +//: `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of types in the Swift Standard +//: Library in the ways you might expect e.g. The `Arbitrary` instance for `Int` calls `arc4random_uniform`. +//: +//: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen to write yourself. But +//: before that, let's try to write an `Arbitrary` instance for `NSDate`. + +import class Foundation.NSDate + +//: Here's the obvious way to do it +// +// extension NSDate : Arbitrary { +// public static var arbitrary : Gen { +// return Gen.oneOf([ +// Gen.pure(NSDate()), +// Gen.pure(NSDate.distantFuture()), +// Gen.pure(NSDate.distantPast()), +// NSDate.init <^> NSTimeInterval.arbitrary, +// ]) +// } +// } +// +//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` in the wrong +//: position. What to do? +//: +//: Let's write a wrapper! + +struct ArbitraryDate : Arbitrary { + let getDate : NSDate + + init(date : NSDate) { self.getDate = date } + + static var arbitrary : Gen { + return Gen.oneOf([ + Gen.pure(NSDate()), + Gen.pure(NSDate.distantFuture()), + Gen.pure(NSDate.distantPast()), + NSDate.init <^> NSTimeInterval.arbitrary, + ]).fmap(ArbitraryDate.init) + } +} + +ArbitraryDate.arbitrary.generate.getDate +ArbitraryDate.arbitrary.generate.getDate +//: What we've just written is called a `Modifier Type`; a wrapper around another type that we can't generate with +//: one that we can. +//: +//: SwiftCheck also uses this strategy for a few of the more "difficult" types in the Swift STL, but we also use them +//: in more benign ways too. For example, we can write a modifier type that only generates positive numbers: +public struct ArbitraryPositive> : Arbitrary { + public let getPositive : A + public init(_ pos : A) { self.getPositive = pos } + public static var arbitrary : Gen> { + return A.arbitrary.fmap({ ArbitraryPositive.init(abs($0)) }) + } +} +ArbitraryPositive.arbitrary.generate.getPositive +ArbitraryPositive.arbitrary.generate.getPositive +ArbitraryPositive.arbitrary.generate.getPositive From 7bfed2f5a6b66c9725c21917e82a4f1510ee8ca7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 21:00:51 -0400 Subject: [PATCH 115/460] Start last section --- SwiftCheck/Test.swift | 4 +- SwiftCheckTests/GenSpec.swift | 8 +- Tutorial.playground/Contents.swift | 122 +++++++++++++++++++++- Tutorial.playground/contents.xcplayground | 2 +- 4 files changed, 124 insertions(+), 12 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 67c8896..2b37a16 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -539,7 +539,7 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" print("Proposition: " + st.name) - print(res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + pluralize(shrinkMsg, i: st.successfulShrinkCount) + "):") + print(res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } @@ -631,7 +631,7 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { } private func pluralize(s : String, i : Int) -> String { - if i == 0 { + if i == 1 { return s } return s + "s" diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 6918fc7..f7386f6 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -46,12 +46,12 @@ class GenSpec : XCTestCase { return forAll(g) { $0 == 0 } } - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in - if xss.isEmpty { + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : SetOf) in + if xss.getSet.isEmpty { return Discard() } - let l = Set(xss) - return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } + let ll = Gen.fromElementsOf(xss.getSet) + return forAll(ll) { xss.getSet.contains($0) } } property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index feded95..49dc6d5 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -317,7 +317,7 @@ import class Foundation.NSDate // Gen.pure(NSDate.distantFuture()), // Gen.pure(NSDate.distantPast()), // NSDate.init <^> NSTimeInterval.arbitrary, -// ]) +// ]) // } // } // @@ -332,7 +332,7 @@ struct ArbitraryDate : Arbitrary { init(date : NSDate) { self.getDate = date } static var arbitrary : Gen { - return Gen.oneOf([ + return Gen.oneOf([ Gen.pure(NSDate()), Gen.pure(NSDate.distantFuture()), Gen.pure(NSDate.distantPast()), @@ -344,8 +344,8 @@ struct ArbitraryDate : Arbitrary { ArbitraryDate.arbitrary.generate.getDate ArbitraryDate.arbitrary.generate.getDate -//: What we've just written is called a `Modifier Type`; a wrapper around another type that we can't generate with -//: one that we can. +//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't generate with +//: another that we can. //: //: SwiftCheck also uses this strategy for a few of the more "difficult" types in the Swift STL, but we also use them //: in more benign ways too. For example, we can write a modifier type that only generates positive numbers: @@ -356,7 +356,7 @@ public struct ArbitraryPositive> : Arb public init(_ pos : A) { self.getPositive = pos } public static var arbitrary : Gen> { - return A.arbitrary.fmap({ ArbitraryPositive.init(abs($0)) }) + return A.arbitrary.fmap { ArbitraryPositive.init(abs($0)) } } } @@ -364,4 +364,116 @@ ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive +//: # Quantifiers + +//: What we've seen so far are the building blocks we need to introduce the final part of the library: The actual testing +//: interface. The last concept we'll introduce is *Quantifiers*. +//: +//: A Quantifier is a contract that serves as a guarantee that a property holds when the given +//: testing block returns `true` or truthy values, and fails when the testing block returns `false` +//: or falsy values. The testing block is usually used with Swift's abbreviated block syntax and +//: requires type annotations for all value positions being requested. There is only one quantifier +//: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec must +//: pass "for all" of the values. Here's what it looks like: +// +// func forAll(_ : (A... -> Bool)) -> Property +// +//: The actual type of `forAll` is much more general and expressive than this, but for now this will do. +//: +//: Here is an example of a simple property + +// + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. +// | + This backwards arrow binds a property name and a property to each other. +// | | +// v v +property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in + return xs.reverse().reverse() == xs +} + +// From now on, all of our examples will take the form above. + +//: Because `forAll` is variadic it works for a large number and variety of types too: + +// +--- This Modifier Type produces Arrays of Integers. +// | +--- This Modifier Type generates functions. That's right, SwiftCheck +// | | can generate *functions*!! +// v v +property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in + let f = pred.getArrow + return xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) + // ^ This property says that if we filter an array then apply the predicate to all its elements, then they + // should all return true. +} + +// How about a little Boolean Algebra too? +property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r +} + +//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not once did we have to invoke +//: `.generate` or have to construct a generator. We simply told the `forAll` block how many variables we wanted and of what +//: type and SwiftCheck automagically went out and was able to produce random values. +//: +//: Our not-so-magic trick is enabled behind the scenes by the judicious combination of `Arbitrary` to construct default generators +//: for each type and a testing mechanism that invokes the testing block for the proper number of tests. For some real magic, let's +//: see what happens when we fail a test: + +// `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, still print all failures to +// the console. We use it here because XCTest does not like it when you assert outside of a test case. +reportProperty("Obviously wrong") <- forAll({ (x : Int) in + return x != x +}).whenFail { // `whenFail` attaches a callback to the test when we fail. + print("Oh noes!") +} + +//: If you open the console for the playground, you'll see output very similar to the following: +//: +//: *** Failed! Proposition: Obviously wrong +//: Falsifiable (after 1 test): +//: Oh noes! +//: 0 +//: +//: The first line tells you what failed, the next how long it took to fail, the next our message from the callback, and the +//: last the value of `x` the property failed with. If you keep running the test over and over again you'll notice that the +//: test keeps failing on the number 0 despite the integer supposedly being random. What's going on here? +//: +//: To find out, let's see the full definition of the `Arbitrary` protocol: +// +// public protocol Arbitrary { +// /// The generator for this particular type. +// /// +// /// This function should call out to any sources of randomness or state necessary to generate +// /// values. It should not, however, be written as a deterministic function. If such a +// /// generator is needed, combinators are provided in `Gen.swift`. +// static var arbitrary : Gen { get } +// +// /// An optional shrinking function. If this function goes unimplemented, it is the same as +// /// returning the empty list. +// /// +// /// Shrunken values must be less than or equal to the "size" of the original type but never the +// /// same as the value provided to this function (or a loop will form in the shrinker). It is +// /// recommended that they be presented smallest to largest to speed up the overall shrinking +// /// process. +// static func shrink(_ : Self) -> [Self] +// } +// +//: Here's where we one-up Fuzz Testing and show the real power of property testing. A "shrink" is a strategy for reducing +//: randomly generated values. To shrink a value, all you need to do is return an array of "smaller values", whether in +//: magnitude or value. For example, the shrinker for `Array` returns Arrays that have a size less than or equal to that of +//: the input array. + +Array.shrink([1, 2, 3]) + +//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes the shrinker, tries the +//: property again on the values of the array until it finds another failing case, then repeats the process until it runs +//: out of cases to try. In other words, it *shrinks* the value down to the least possible size then reports that to you +//: as the failing test case rather than the randomly generated value which could be unnecessarily large or complex. + +//: # All Together Now! + +//: + + diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 59b4af3..6767221 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From c856007d5faddcd16a17f474f6889816d62749c2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 21:06:14 -0400 Subject: [PATCH 116/460] Add a conclusion --- Tutorial.playground/Contents.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 49dc6d5..87ba8c9 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -473,7 +473,12 @@ Array.shrink([1, 2, 3]) //: # All Together Now! -//: - - +//: If you've made it this far, congratulations! That's it. Naturally, there are other combinators and fancy ways of creating +//: `Gen`erators and properties with the primitives in this framework, but they are all variations on the themes present in ths +//: tutorial. With the power of SwiftCheck and a sufficiently expressive testing suite, we can begin to check our programs not +//: for individual passing cases in a few scattershot unit tests, but declare and enforce immutable properties that better describe +//: the intent and invariants of our programs. If you would like further reading, see the files `Arbitrary.swift`, `Test.swift`, +//: `Modifiers.swift`, and `Property.swift`. +//: +//: Go forth and test. From 1872a23e029ae23185d0d40e2ad1e1d0b2154c88 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 21:11:15 -0400 Subject: [PATCH 117/460] We crash Swiftc for reasons now? --- SwiftCheck/Gen.swift | 2 +- SwiftCheckTests/GenSpec.swift | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index c3863ee..c7a1ea1 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -34,7 +34,7 @@ public struct Gen { /// /// The input collection is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { - return Gen.fromElementsIn(xs.startIndex..) in - if xss.getSet.isEmpty { - return Discard() - } - let ll = Gen.fromElementsOf(xss.getSet) - return forAll(ll) { xss.getSet.contains($0) } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } - } +// This crashes swiftc. +// property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in +// if xss.isEmpty { +// return Discard() +// } +// let l = Set(xss) +// return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } +// } +// +// property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in +// return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } +// } property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in return (n1 < n2) ==> { - let interval = n1...fromElementsOf(interval)) { interval.contains($0) } } } From 5f8bd4abe8dd6d021d7e86fa2a926ea996007373 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 21:24:35 -0400 Subject: [PATCH 118/460] typos --- Tutorial.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 87ba8c9..c4f39a0 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -262,7 +262,7 @@ func glue5(l : String) -> String -> String -> String -> String -> String { //: +--- Here's our glue function. //: | +--- This says we're mapping that function over all these pieces. -//: | | +--- Here's our funtional "glue" from before. +//: | | +--- Here's our functional "glue" from before. //: | | | //: v v v let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld @@ -299,7 +299,7 @@ emailGen.generate // static var arbitrary : Gen { get } // } // -//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can, well, give us a generator to create +//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator to create //: `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of types in the Swift Standard //: Library in the ways you might expect e.g. The `Arbitrary` instance for `Int` calls `arc4random_uniform`. //: From 7d0ecc2fed51fae6a017ae5d8fcbb5fdfb988402 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 5 Sep 2015 21:47:43 -0400 Subject: [PATCH 119/460] Redo the glue --- Tutorial.playground/Contents.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index c4f39a0..a82574e 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -254,8 +254,8 @@ let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0[$0.endIndex.prede //: about some glue? // Concatenates 5 strings together in order. -func glue5(l : String) -> String -> String -> String -> String -> String { - return { m in { m2 in { m3 in { r in l + m + m2 + m3 + r } } } } +func glue5(l: String)(m: String)(m2: String)(m3: String)(r: String) -> String { + return l + m + m2 + m3 + r } //: This big thing looks a bit complicated, let's go through it part by part: From 957d0e2bb9876850a72bdd4e5402edebfe552d21 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 11:54:33 -0400 Subject: [PATCH 120/460] Reflow --- Tutorial.playground/Contents.swift | 196 +++++++++++++++-------------- 1 file changed, 105 insertions(+), 91 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index a82574e..c05f9a7 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -21,34 +21,35 @@ import XCTest //: # Introduction -//: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick`, by giving them -//: the ability to automatically test program properties. A property is a particular facet of an -//: algorithm, method, data structure, or program that must *hold* (that is, remain valid) even when -//: fed random or pseudo-random data. If that all seems complicated, it may be simpler to think of -//: Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements rather than -//: break the program. Throughout this tutorial, simplifications like the above will be made to aid -//: your understanding. Towards the end of it, we will begin to remove much of these "training wheels" -//: and reveal the real concepts and types of the operations in the library, which are often much more -//: powerful and generic than previously presented. +//: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick`, by giving +//: them the ability to automatically test program properties. A property is a particular facet of +//: an algorithm, method, data structure, or program that must *hold* (that is, remain valid) even +//: when fed random or pseudo-random data. If that all seems complicated, it may be simpler to +//: think of Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements +//: rather than break the program. Throughout this tutorial, simplifications like the above will be +//: made to aid your understanding. Towards the end of it, we will begin to remove much of these +//: "training wheels" and reveal the real concepts and types of the operations in the library, which +//: are often much more powerful and generic than previously presented. //: -//: This tutorial is divided into 3 parts, each meant to espouse a different aspect of the SwiftCheck -//: library. +//: This tutorial is divided into 3 parts, each meant to espouse a different aspect of the +//: SwiftCheck library. //: # `Gen`erators -//: In Swift, when one thinks of a Generator, they usually think of the `GeneratorType` protocol or the -//: many many individual structures the Swift Standard Library exposes to allow loops to work with data -//: structures like `[T]` and `Set`. In Swift, we also have Generators, but we spell them `Gen`erators, -//: as in the universal Generator type `Gen`. +//: In Swift, when one thinks of a Generator, they usually think of the `GeneratorType` protocol or +//: the many many individual structures the Swift Standard Library exposes to allow loops to work +//: with data structures like `[T]` and `Set`. In Swift, we also have Generators, but we spell +//: them `Gen`erators, as in the universal Generator type `Gen`. //: //: `Gen` is a struct defined generically over any kind of type that looks like this: // // /// We're not defining this here; We'll be using SwiftCheck's `Gen` from here on out. // struct Gen { } // -//: `Gen`, unlike `GeneratorType`, is not backed by a concrete data structure like an array or dictionary, -//: but is instead constructed by invoking methods that refine the kind of data that gets generated. Below -//: are some examples of `Gen`erators that generate random instances of simple data types. +//: `Gen`, unlike `GeneratorType`, is not backed by a concrete data structure like an `Array` or +//: `Dictionary`, but is instead constructed by invoking methods that refine the kind of data that +//: gets generated. Below are some examples of `Gen`erators that generate random instances of +//: simple data types. // `Gen.pure` constructs a generator that *only* produces the given value. let onlyFive = Gen.pure(5) @@ -59,8 +60,8 @@ onlyFive.generate onlyFive.generate onlyFive.generate -// `Gen.fromElementsIn` constructs a generator that pulls values from inside the -// bounds of the given Range. Because generation is random, some values may be repeated. +// `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the +// given Range. Because generation is random, some values may be repeated. let fromOnetoFive = Gen.fromElementsIn(1...5) fromOnetoFive.generate @@ -91,8 +92,8 @@ specialCharacters.generate specialCharacters.generate specialCharacters.generate -//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in amazing -//: ways. +//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in +//: amazing ways. // `Gen.oneOf` randomly picks one of the generators from the given list and draws element from it. let uppersAndLowers = Gen.oneOf([ @@ -113,8 +114,9 @@ pairsOfNumbers.generate pairsOfNumbers.generate pairsOfNumbers.generate -//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck includes a number -//: of functions for creating `Gen`erators with "weights" attached to their elements. +//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck +//: includes a number of functions for creating `Gen`erators with "weights" attached to their +//: elements. // This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. let weightedGen = Gen.weighted([ @@ -156,8 +158,8 @@ oddLengthArrays.generate.count oddLengthArrays.generate.count oddLengthArrays.generate.count -//: Generators also admit functional methods like `map` and `flatMap`, but with different names than you might -//: be used to. +//: Generators also admit functional methods like `map` and `flatMap`, but with different names than +//: you might be used to. // `fmap` (function map) works exactly like Array's `map` method; it applies the function to any // values it generates. @@ -169,10 +171,11 @@ fromTwoToSix.generate fromTwoToSix.generate fromTwoToSix.generate -// `bind` works exactly like Array's `flatMap`, but instead of concatenating the generated arrays it produces -// a new generator that picks values from among the newly created generators produced by the function. While -// That definition may *technically* be what occurs, it is better to think of `bind` as a way of making a generator -// depend on another. For example, you can use a generator of sizes to limit the length of generators of arrays: +// `bind` works exactly like Array's `flatMap`, but instead of concatenating the generated arrays it +// produces a new generator that picks values from among the newly created generators produced by +// the function. While That definition may *technically* be what occurs, it is better to think of +// `bind` as a way of making a generator depend on another. For example, you can use a generator of +// sizes to limit the length of generators of arrays: let generatorBoundedSizeArrays = fromOnetoFive.bind { len in return characterArray.suchThat { xs in xs.count <= len } @@ -184,8 +187,8 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate -//: Because SwiftCheck is based on the functional concepts in our other library [Swiftz](https://github.com/typelift/Swiftz), -//: each of these functions has an operator alias: +//: Because SwiftCheck is based on the functional concepts in our other library +//: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: //: //: * `<^>` is an alias for `fmap` //: * `<*>` is an alias for `ap` @@ -206,19 +209,20 @@ generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate -//: Now that you've seen what generators can do, we'll use all we've learned to create a generator that -//: produces email addresses. To do this, we'll need one more operator/method notated `<*>` or `ap`. -//: `ap` comes from [Applicative Functors](http://staff.city.ac.uk/~ross/papers/Applicative.html) and is -//: used to "zip together" `Gen`erators of functions with `Gen`erators of of values, applying each function -//: during the zipping phase. That definition is a little hand-wavey and technical, so for now we'll say that -//: `ap` works like "glue" that sticks special kinds of generators togethers. +//: Now that you've seen what generators can do, we'll use all we've learned to create a generator +//: that produces email addresses. To do this, we'll need one more operator/method notated `<*>` or +//: `ap`. `ap` comes from +//: [Applicative Functors](http://staff.city.ac.uk/~ross/papers/Applicative.html) and is used to +//: "zip together" `Gen`erators of functions with `Gen`erators of of values, applying each function +//: during the zipping phase. That definition is a little hand-wavey and technical, so for now +//: we'll say that `ap` works like "glue" that sticks special kinds of generators togethers. //: -//: For our purposes, we will say that an email address consists of 3 parts: A local part, a hostname, and a -//: Top-Level Domain each separated by an `@`, and a `.` respectively. +//: For our purposes, we will say that an email address consists of 3 parts: A local part, a +//: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. //: -//: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, numbers, and -//: certain kinds of special characters. We already have generators for upper and lower cased letters, so all we -//: need are special characters and a more complete number generator: +//: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, +//: numbers, and certain kinds of special characters. We already have generators for upper and +//: lower cased letters, so all we need are special characters and a more complete number generator: let numeric : Gen = Gen.fromElementsIn("0"..."9") let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) @@ -272,21 +276,23 @@ let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure( // Yes, these are in fact, all valid email addresses. emailGen.generate -//: By now you may be asking "why do we need all of this in the first place? Can't we just apply the parts to the -//: function to get back a result?" Well, we do it because we aren't working with Characters or Strings or Arrays, -//: we're working with `Gen`. And we can't apply `Gen` to a function that expects `String`, that wouldn't -//: make any sense - and it would never compile! Instead we use these operators to "lift" our function over `String`s to +//: By now you may be asking "why do we need all of this in the first place? Can't we just apply +//: the parts to the function to get back a result?" Well, we do it because we aren't working with +//: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply +//: `Gen` to a function that expects `String`, that wouldn't make any sense - and it would +//: never compile! Instead we use these operators to "lift" our function over `String`s to //: functions over `Gen`s. //: -//: Complex cases like the above are rare in practice. Most of the time you won't even need to use generators at all! This -//: brings us to one of the most important parts of SwiftCheck: +//: Complex cases like the above are rare in practice. Most of the time you won't even need to use +//: generators at all! This brings us to one of the most important parts of SwiftCheck: //: # Randomness -//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were writing -//: SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on values that would ask them -//: to generate a "next" value. But that would have been incredibly boring! Instead, we wrote a protocol called `Arbitrary` -//: and let Types, not values, do all the work. +//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were +//: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on +//: values that would ask them to generate a "next" value. But that would have been incredibly +//: boring! Instead, we wrote a protocol called `Arbitrary` and let Types, not values, do all the +//: work. //: //: The `Arbitrary` protocol looks like this: // @@ -299,12 +305,13 @@ emailGen.generate // static var arbitrary : Gen { get } // } // -//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator to create -//: `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of types in the Swift Standard -//: Library in the ways you might expect e.g. The `Arbitrary` instance for `Int` calls `arc4random_uniform`. +//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator +//: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of +//: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance +//: for `Int` calls `arc4random_uniform`. //: -//: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen to write yourself. But -//: before that, let's try to write an `Arbitrary` instance for `NSDate`. +//: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen +//: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. import class Foundation.NSDate @@ -321,8 +328,8 @@ import class Foundation.NSDate // } // } // -//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` in the wrong -//: position. What to do? +//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` +//: in the wrong position. What to do? //: //: Let's write a wrapper! @@ -344,11 +351,12 @@ struct ArbitraryDate : Arbitrary { ArbitraryDate.arbitrary.generate.getDate ArbitraryDate.arbitrary.generate.getDate -//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't generate with -//: another that we can. +//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't +//: generate with another that we can. //: -//: SwiftCheck also uses this strategy for a few of the more "difficult" types in the Swift STL, but we also use them -//: in more benign ways too. For example, we can write a modifier type that only generates positive numbers: +//: SwiftCheck also uses this strategy for a few of the more "difficult" types in the Swift STL, but +//: we also use them in more benign ways too. For example, we can write a modifier type that only +//: generates positive numbers: public struct ArbitraryPositive> : Arbitrary { public let getPositive : A @@ -366,15 +374,15 @@ ArbitraryPositive.arbitrary.generate.getPositive //: # Quantifiers -//: What we've seen so far are the building blocks we need to introduce the final part of the library: The actual testing -//: interface. The last concept we'll introduce is *Quantifiers*. +//: What we've seen so far are the building blocks we need to introduce the final part of the +//; library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. //: //: A Quantifier is a contract that serves as a guarantee that a property holds when the given //: testing block returns `true` or truthy values, and fails when the testing block returns `false` //: or falsy values. The testing block is usually used with Swift's abbreviated block syntax and //: requires type annotations for all value positions being requested. There is only one quantifier -//: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec must -//: pass "for all" of the values. Here's what it looks like: +//: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec +//: must pass "for all" of the values. Here's what it looks like: // // func forAll(_ : (A... -> Bool)) -> Property // @@ -412,13 +420,15 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in return l && r } -//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not once did we have to invoke -//: `.generate` or have to construct a generator. We simply told the `forAll` block how many variables we wanted and of what -//: type and SwiftCheck automagically went out and was able to produce random values. +//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not +//: once did we have to invoke `.generate` or have to construct a generator. We simply told the +//: `forAll` block how many variables we wanted and of what type and SwiftCheck automagically went +//: out and was able to produce random values. //: -//: Our not-so-magic trick is enabled behind the scenes by the judicious combination of `Arbitrary` to construct default generators -//: for each type and a testing mechanism that invokes the testing block for the proper number of tests. For some real magic, let's -//: see what happens when we fail a test: +//: Our not-so-magic trick is enabled behind the scenes by the judicious combination of `Arbitrary` +//: to construct default generators for each type and a testing mechanism that invokes the testing +//: block for the proper number of tests. For some real magic, let's see what happens when we fail +//: a test: // `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, still print all failures to // the console. We use it here because XCTest does not like it when you assert outside of a test case. @@ -435,9 +445,10 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in //: Oh noes! //: 0 //: -//: The first line tells you what failed, the next how long it took to fail, the next our message from the callback, and the -//: last the value of `x` the property failed with. If you keep running the test over and over again you'll notice that the -//: test keeps failing on the number 0 despite the integer supposedly being random. What's going on here? +//: The first line tells you what failed, the next how long it took to fail, the next our message +//: from the callback, and the last the value of `x` the property failed with. If you keep running +//: the test over and over again you'll notice that the test keeps failing on the number 0 despite +//: the integer supposedly being random. What's going on here? //: //: To find out, let's see the full definition of the `Arbitrary` protocol: // @@ -459,26 +470,29 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in // static func shrink(_ : Self) -> [Self] // } // -//: Here's where we one-up Fuzz Testing and show the real power of property testing. A "shrink" is a strategy for reducing -//: randomly generated values. To shrink a value, all you need to do is return an array of "smaller values", whether in -//: magnitude or value. For example, the shrinker for `Array` returns Arrays that have a size less than or equal to that of -//: the input array. +//: Here's where we one-up Fuzz Testing and show the real power of property testing. A "shrink" is +//: a strategy for reducing randomly generated values. To shrink a value, all you need to do is +//: return an array of "smaller values", whether in magnitude or value. For example, the shrinker +//: for `Array` returns Arrays that have a size less than or equal to that of the input array. Array.shrink([1, 2, 3]) -//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes the shrinker, tries the -//: property again on the values of the array until it finds another failing case, then repeats the process until it runs -//: out of cases to try. In other words, it *shrinks* the value down to the least possible size then reports that to you -//: as the failing test case rather than the randomly generated value which could be unnecessarily large or complex. +//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes +//: the shrinker, tries the property again on the values of the array until it finds another failing +//: case, then repeats the process until it runs out of cases to try. In other words, it *shrinks* +//: the value down to the least possible size then reports that to you as the failing test case +//: rather than the randomly generated value which could be unnecessarily large or complex. //: # All Together Now! -//: If you've made it this far, congratulations! That's it. Naturally, there are other combinators and fancy ways of creating -//: `Gen`erators and properties with the primitives in this framework, but they are all variations on the themes present in ths -//: tutorial. With the power of SwiftCheck and a sufficiently expressive testing suite, we can begin to check our programs not -//: for individual passing cases in a few scattershot unit tests, but declare and enforce immutable properties that better describe -//: the intent and invariants of our programs. If you would like further reading, see the files `Arbitrary.swift`, `Test.swift`, -//: `Modifiers.swift`, and `Property.swift`. +//: If you've made it this far, congratulations! That's it. Naturally, there are other combinators +//: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, +//: but they are all variations on the themes present in ths tutorial. With the power of SwiftCheck +//: and a sufficiently expressive testing suite, we can begin to check our programs not for +//: individual passing cases in a few scattershot unit tests, but declare and enforce immutable +//: properties that better describe the intent and invariants of our programs. If you would like +//: further reading, see the files `Arbitrary.swift`, `Test.swift`, `Modifiers.swift`, and +//: `Property.swift`. //: //: Go forth and test. From 8178261bd16e5294a9053b4236b24a4a3b2a5a0b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 11:55:37 -0400 Subject: [PATCH 121/460] format --- Tutorial.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index c05f9a7..8df91b8 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -258,7 +258,7 @@ let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0[$0.endIndex.prede //: about some glue? // Concatenates 5 strings together in order. -func glue5(l: String)(m: String)(m2: String)(m3: String)(r: String) -> String { +func glue5(l : String)(m : String)(m2 : String)(m3 : String)(r : String) -> String { return l + m + m2 + m3 + r } From 9003a885e9ece4f47fde94c478a806493463398f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 19:53:47 -0400 Subject: [PATCH 122/460] a bit of cleanup --- Tutorial.playground/Contents.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 8df91b8..e837ccc 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -354,7 +354,7 @@ ArbitraryDate.arbitrary.generate.getDate //: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't //: generate with another that we can. //: -//: SwiftCheck also uses this strategy for a few of the more "difficult" types in the Swift STL, but +//: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: @@ -430,8 +430,9 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in //: block for the proper number of tests. For some real magic, let's see what happens when we fail //: a test: -// `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, still print all failures to -// the console. We use it here because XCTest does not like it when you assert outside of a test case. +// `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, +// still print all failures to the console. We use it here because XCTest does not like it when you +// assert outside of a test case. reportProperty("Obviously wrong") <- forAll({ (x : Int) in return x != x }).whenFail { // `whenFail` attaches a callback to the test when we fail. From 7c8eddfb03c0530d484ea71aff1fbad7df85113a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 21:18:30 -0400 Subject: [PATCH 123/460] Finish up. --- Tutorial.playground/Contents.swift | 153 ++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index e837ccc..7d8e105 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -286,7 +286,7 @@ emailGen.generate //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: -//: # Randomness +//: # Arbitrary //: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were //: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on @@ -486,6 +486,157 @@ Array.shrink([1, 2, 3]) //: # All Together Now! +//: Let's put all of our newfound understanding of this framework to use by writing a property that +//: tests an implementation of the Sieve of Eratosthenes: + +// The Sieve of Eratosthenes: +// +// To find all the prime numbers less than or equal to a given integer n: +// - let l = [2...n] +// - let p = 2 +// - for i in [(2 * p) through n by p] { +// mark l[i] +// } +// - Remaining indices of unmarked numbers are primes +func sieve(n : Int) -> [Int] { + if n <= 1 { + return [] + } + + var marked : [Bool] = (0...n).map({ _ in false }) + marked[0] = true + marked[1] = true + + for p in 2.. Bool { + if n == 0 || n == 1 { + return false + } else if n == 2 { + return true + } + + let max = Int(ceil(sqrt(Double(n)))) + for i in 2...max { + if n % i == 0 { + return false + } + } + return true +} + +//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the +//: following property: + +reportProperty("All Prime") <- forAll { (n : Positive) in + let primes = sieve(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElementsOf(primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } +} + +//: This test introduces several new concepts that we'll go through 1-by-1: +//: +//: * `Positive`: This is a Modifier Type defined by SwiftCheck that only produces +//: integers larger than zero - positive integers. SwiftCheck also has +//: modifiers for `NonZero` (all integers that aren't 0) and `NonNegative` +//: (all positive integers including 0). +//: +//: * `==>`: This operator is called "Implication". It is used to introduce tests that need to +//: reject certain kinds of data that gets generated. Here, because our prime number +//: generator can return empty lists (which throws an error when used with `Gen.fromElementsOf`) +//: we put a condition on the left-hand side that requires arrays have a size larger than 1. +//: +//: * `forAll` in `forAll`: The *actual* type that `forAll` expects is not `Bool`. It's a protocol +//: called `Testable`, Bool just happens to conform to it. It turns out that +//: `Property`, the thing `forAll` returns, does to. So you can nest `forAll`s +//: in `forAll`s to your heart's content! +//: +//: * `forAll` + `Gen`: The `forAll`s we've seen before have all been using `Arbitrary` to retrieve a +//: default `Gen`erator for each type. But SwiftCheck also includes a variant of +//: `forAll` that takes a user-supplied generator. For those times when you want +//: absolute control over generated values, like we do here, use that particular +//: series of overloads. + +//: If you check the console, you'll notice that this property doesn't hold! What's wrong here? +//: +//: Let's go back to the spec we had for the sieve: +// +// The Sieve of Eratosthenes: +// +// To find all the prime numbers less than or equal to a given integer n: +// - let l = [2...n] +// - let p = 2 +// - for i in [(2 * p) **through** n by p] { +// mark l[i] +// } +// - Remaining indices of unmarked numbers are primes +// +//: Looks like we used `to:` when we meant `through:`. Let's try again: + +func sieveProperly(n : Int) -> [Int] { + if n <= 1 { + return [] + } + + var marked : [Bool] = (0...n).map({ _ in false }) + marked[0] = true + marked[1] = true + + for p in 2..) in + let primes = sieveProperly(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElementsOf(primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } +} + +//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm +//: isn't handling the case presented. So you search through some specification to find the mistake in +//: logic and try again. Along the way, SwiftCheck will do its best help you by presenting minimal +//: cases at the least, and, with more advanced uses of the framework, the names of specific sub-parts of +//: cases and even percentages of failing vs. passing tests. + +//; # Conclusion + //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators //: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, //: but they are all variations on the themes present in ths tutorial. With the power of SwiftCheck From 2322a9940396fd69401536ecfb540c6e3e43f4ab Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 22:38:01 -0400 Subject: [PATCH 124/460] Simplify final example --- Tutorial.playground/Contents.swift | 26 +++++++++++++++++++---- Tutorial.playground/contents.xcplayground | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 7d8e105..aa27aeb 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -252,6 +252,8 @@ let hostname = Gen.oneOf([ //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. +// Email addresses ending in '.' are invalid. +// ------------------------------------ let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) //: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how @@ -275,6 +277,8 @@ let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure( // Yes, these are in fact, all valid email addresses. emailGen.generate +emailGen.generate +emailGen.generate //: By now you may be asking "why do we need all of this in the first place? Can't we just apply //: the parts to the function to get back a result?" Well, we do it because we aren't working with @@ -375,7 +379,7 @@ ArbitraryPositive.arbitrary.generate.getPositive //: # Quantifiers //: What we've seen so far are the building blocks we need to introduce the final part of the -//; library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. +//: library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. //: //: A Quantifier is a contract that serves as a guarantee that a property holds when the given //: testing block returns `true` or truthy values, and fails when the testing block returns `false` @@ -409,8 +413,8 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow return xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) - // ^ This property says that if we filter an array then apply the predicate to all its elements, then they - // should all return true. + // ^ This property says that if we filter an array then apply the predicate + // to all its elements, then they should all respond with `true`. } // How about a little Boolean Algebra too? @@ -578,8 +582,15 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: absolute control over generated values, like we do here, use that particular //: series of overloads. -//: If you check the console, you'll notice that this property doesn't hold! What's wrong here? +//: If you check the console, you'll notice that this property doesn't hold! //: +//: *** Failed! Proposition: All Prime +//: Falsifiable (after 11 tests and 2 shrinks): +//: Positive( 4 ) // or Positive( 10 ) +//: 0 +//: +//: What's wrong here? + //: Let's go back to the spec we had for the sieve: // // The Sieve of Eratosthenes: @@ -635,6 +646,13 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: cases at the least, and, with more advanced uses of the framework, the names of specific sub-parts of //: cases and even percentages of failing vs. passing tests. +//: Just for fun, let's try a simpler property that checks the same outcome: + +reportProperty("All Prime") <- forAll { (n : Positive) in + // Sieving Properly then filtering for primes is the same as just Sieving, right? + return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) +} + //; # Conclusion //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 6767221..504b66a 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 5333f51c4365464363085441a29819aa2cfb5b9c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 23:29:34 -0400 Subject: [PATCH 125/460] Try a better metaphor --- Tutorial.playground/Contents.swift | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index aa27aeb..7c6fd85 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -213,9 +213,11 @@ generatorBoundedSizeArrays_.generate //: that produces email addresses. To do this, we'll need one more operator/method notated `<*>` or //: `ap`. `ap` comes from //: [Applicative Functors](http://staff.city.ac.uk/~ross/papers/Applicative.html) and is used to -//: "zip together" `Gen`erators of functions with `Gen`erators of of values, applying each function -//: during the zipping phase. That definition is a little hand-wavey and technical, so for now -//: we'll say that `ap` works like "glue" that sticks special kinds of generators togethers. +//: "zip together" `Gen`erators of functions with `Gen`erators of of values. Unlike `zip`, when +//: a function gets paired with a value the latter is applied to the former to produce a new +//: value. For our purposes, we don't even need that definition. We can think of `ap` like +//: a platform that a lifted value can ride atop as a function is carried through. You'll +//: see what this means in detail shortly. //: //: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. @@ -267,8 +269,8 @@ func glue5(l : String)(m : String)(m2 : String)(m3 : String)(r : String) -> Stri //: This big thing looks a bit complicated, let's go through it part by part: //: +--- Here's our glue function. -//: | +--- This says we're mapping that function over all these pieces. -//: | | +--- Here's our functional "glue" from before. +//: | +--- This says we're "lifting" and mapping that function over all these pieces. +//: | | +--- Here's our "platforms" from before. //: | | | //: v v v let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld @@ -572,8 +574,8 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: we put a condition on the left-hand side that requires arrays have a size larger than 1. //: //: * `forAll` in `forAll`: The *actual* type that `forAll` expects is not `Bool`. It's a protocol -//: called `Testable`, Bool just happens to conform to it. It turns out that -//: `Property`, the thing `forAll` returns, does to. So you can nest `forAll`s +//: called `Testable`, `Bool` just happens to conform to it. It turns out that +//: `Property`, the thing `forAll` returns, does too. So you can nest `forAll`s //: in `forAll`s to your heart's content! //: //: * `forAll` + `Gen`: The `forAll`s we've seen before have all been using `Arbitrary` to retrieve a From 5aad0473d7b94b96289bbd13f7f250a5dbf555c9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 6 Sep 2015 23:30:33 -0400 Subject: [PATCH 126/460] Add tutorial link in README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 1255091..9ac55f4 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ SwiftCheck QuickCheck for Swift. +For those already familiar with the Haskell library, check out the source. For +everybody else, see the [Tutorial Playground](Tutorial.playground) for a +beginner-level introduction to the major concepts and use-cases of this library. + Introduction ============ From 8e87fe9c210d89fa405e5a89e084a15cc3deeba0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 7 Sep 2015 02:23:02 -0400 Subject: [PATCH 127/460] Property Testing Manifesto --- Tutorial.playground/Contents.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 7c6fd85..2bdb112 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -31,6 +31,17 @@ import XCTest //: "training wheels" and reveal the real concepts and types of the operations in the library, which //: are often much more powerful and generic than previously presented. //: +//: Unlike Unit Testing, Property Testing abhors the use of state and global variables. Property +//: Tests are local, atomic entities that ideally only use the data given to them to match a +//: user-defined specification for the behavior of a program or algorithm. While this may +//: seem draconian, the upshot of these [unwritten] rules is that produced tests become +//: "law-like", as in a [Mathematical or Scientific Law](https://en.wikipedia.org/wiki/Laws_of_science). +//: +//: When you approach your tests with a clear goal in mind, SwiftCheck allows you to turn +//: that goal into many smaller parts that are each much easier to reason about than +//: considering the whole problem at once and putting out spot fires as they arise. With that, +//: let's begin. +//: //: This tutorial is divided into 3 parts, each meant to espouse a different aspect of the //: SwiftCheck library. From 3718bca08bba4678fd867cdfaf67f05151cf3c77 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 7 Sep 2015 02:25:51 -0400 Subject: [PATCH 128/460] typos and such --- Tutorial.playground/Contents.swift | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 2bdb112..0a76f26 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -34,16 +34,14 @@ import XCTest //: Unlike Unit Testing, Property Testing abhors the use of state and global variables. Property //: Tests are local, atomic entities that ideally only use the data given to them to match a //: user-defined specification for the behavior of a program or algorithm. While this may -//: seem draconian, the upshot of these [unwritten] rules is that produced tests become +//: seem draconian, the upshot of following these [unwritten] rules is that the produced tests become //: "law-like", as in a [Mathematical or Scientific Law](https://en.wikipedia.org/wiki/Laws_of_science). //: //: When you approach your tests with a clear goal in mind, SwiftCheck allows you to turn //: that goal into many smaller parts that are each much easier to reason about than -//: considering the whole problem at once and putting out spot fires as they arise. With that, -//: let's begin. +//: considering the whole problem at once and putting out spot fires as they arise. //: -//: This tutorial is divided into 3 parts, each meant to espouse a different aspect of the -//: SwiftCheck library. +//: With that, let's begin. //: # `Gen`erators From afb450baef8db5fbc2f4ad4781a147a776dfca64 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 7 Sep 2015 02:48:37 -0400 Subject: [PATCH 129/460] it's the little things --- Tutorial.playground/Contents.swift | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 0a76f26..01cc310 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -182,10 +182,11 @@ fromTwoToSix.generate // `bind` works exactly like Array's `flatMap`, but instead of concatenating the generated arrays it // produces a new generator that picks values from among the newly created generators produced by -// the function. While That definition may *technically* be what occurs, it is better to think of -// `bind` as a way of making a generator depend on another. For example, you can use a generator of -// sizes to limit the length of generators of arrays: - +// the function. +// +// While that definition may *technically* be what occurs, it is better to think of `bind` as a way +// of making a generator depend on another. For example, you can use a generator of sizes to limit +// the length of generators of arrays: let generatorBoundedSizeArrays = fromOnetoFive.bind { len in return characterArray.suchThat { xs in xs.count <= len } } @@ -253,7 +254,7 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ let localEmail = allowedLocalCharacters.proliferateNonEmpty().fmap(String.init) //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some -//: steps here and combine both steps above into one big generator. +//: steps here and combine both steps into one big generator. let hostname = Gen.oneOf([ lowerCaseLetters, @@ -486,7 +487,7 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in // static func shrink(_ : Self) -> [Self] // } // -//: Here's where we one-up Fuzz Testing and show the real power of property testing. A "shrink" is +//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is //: a strategy for reducing randomly generated values. To shrink a value, all you need to do is //: return an array of "smaller values", whether in magnitude or value. For example, the shrinker //: for `Array` returns Arrays that have a size less than or equal to that of the input array. @@ -641,7 +642,7 @@ func sieveProperly(n : Int) -> [Int] { } // Fo' Real This Time. -reportProperty("All Prime") <- forAll { (n : Positive) in +property("All Prime") <- forAll { (n : Positive) in let primes = sieveProperly(n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) @@ -659,7 +660,7 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: Just for fun, let's try a simpler property that checks the same outcome: -reportProperty("All Prime") <- forAll { (n : Positive) in +property("All Prime") <- forAll { (n : Positive) in // Sieving Properly then filtering for primes is the same as just Sieving, right? return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } From ee59c450d618c1366b059341c7b7643e41fd5411 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 7 Sep 2015 03:14:56 -0400 Subject: [PATCH 130/460] Include arbitrary email modifier --- Tutorial.playground/Contents.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 01cc310..b64822f 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -500,6 +500,35 @@ Array.shrink([1, 2, 3]) //: the value down to the least possible size then reports that to you as the failing test case //: rather than the randomly generated value which could be unnecessarily large or complex. +//: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: + +// SwiftCheck defines default shrinkers for most of the types it gives Arbitrary instances. There +// will often be times when those default shrinkers don't cut it, or you need more control over +// what happens when you generate or shrink values. Modifier Types to the rescue! +struct ArbitraryEmail : Arbitrary { + let getEmail : String + + init(email : String) { self.getEmail = email } + + static var arbitrary : Gen { return emailGen.fmap(ArbitraryEmail.init) } + + // Here we use `emailGen` to generate our cases out of convenience, but there are much + // more efficient ways we could have done this. See `Modifiers.swift` for examples. + static func shrink(tt : ArbitraryEmail) -> [ArbitraryEmail] { + return emailGen.suchThat({ $0.unicodeScalars.count <= (tt.getEmail.unicodeScalars.count / 2) }) // Halve the size of the input address for efficient shrinking. + .proliferateNonEmpty() // Proliferate an array + .generate // Generate + .map(ArbitraryEmail.init) // Then wrap in our Modifier Type + } +} + +// Let's be wrong for the sake of example +property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in + return !email.getEmail.containsString(".") +}.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` + // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail + // and live up to your expectations, SwiftCheck treats that as a failure of the test case. + //: # All Together Now! //: Let's put all of our newfound understanding of this framework to use by writing a property that From 8cc065eff159681965c431af344375f411a1c8c0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 14:02:43 -0400 Subject: [PATCH 131/460] typos --- Tutorial.playground/Contents.swift | 10 ++++++++-- Tutorial.playground/contents.xcplayground | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index b64822f..a8e665c 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -694,7 +694,7 @@ property("All Prime") <- forAll { (n : Positive) in return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } -//; # Conclusion +//: # Conclusion //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators //: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, @@ -703,7 +703,13 @@ property("All Prime") <- forAll { (n : Positive) in //: individual passing cases in a few scattershot unit tests, but declare and enforce immutable //: properties that better describe the intent and invariants of our programs. If you would like //: further reading, see the files `Arbitrary.swift`, `Test.swift`, `Modifiers.swift`, and -//: `Property.swift`. +//: `Property.swift`. Beyond that, there are a number of resources built for the original framework +//: and its other derivatives whose concepts translate directly into SwiftCheck: +//: +//: * [FP Complete's Intro to QuickCheck](https://www.fpcomplete.com/user/pbv/an-introduction-to-quickcheck-testing) +//: * [Real World Haskell on QuickCheck for QA](http://book.realworldhaskell.org/read/testing-and-quality-assurance.html) +//: * [ScalaCheck](https://www.scalacheck.org) +//: * [The Original (slightly outdated) QuickCheck Tutorial](http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html) //: //: Go forth and test. diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 504b66a..6767221 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 82a5e9f591f0bb6bdc53fcd74c81137c1ad76959 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 14:23:26 -0400 Subject: [PATCH 132/460] Get the tests to not crash shit --- SwiftCheck/Gen.swift | 2 +- SwiftCheckTests/GenSpec.swift | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index c7a1ea1..9ff67dd 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -34,7 +34,7 @@ public struct Gen { /// /// The input collection is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { - return Gen.fromElementsIn(xs.startIndex.. { - let interval = n1...n2 - return forAll(Gen.fromElementsOf(interval)) { interval.contains($0) } - } - } +// +// property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in +// return (n1 < n2) ==> { +// let interval = n1...n2 +// return forAll(Gen.fromElementsOf(interval)) { interval.contains($0) } +// } +// } property("oneOf n") <- forAll { (xss : ArrayOf) in if xss.getArray.isEmpty { From 7cde84d3af28224ea3d0cae63c89a939ab6228b2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 14:38:51 -0400 Subject: [PATCH 133/460] Final typos --- Tutorial.playground/Contents.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index a8e665c..e539a07 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -21,17 +21,17 @@ import XCTest //: # Introduction -//: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick`, by giving +//: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick` by giving //: them the ability to automatically test program properties. A property is a particular facet of //: an algorithm, method, data structure, or program that must *hold* (that is, remain valid) even //: when fed random or pseudo-random data. If that all seems complicated, it may be simpler to //: think of Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements //: rather than break the program. Throughout this tutorial, simplifications like the above will be -//: made to aid your understanding. Towards the end of it, we will begin to remove much of these +//: made to aid your understanding. Towards the end of it, we will begin to remove many of these //: "training wheels" and reveal the real concepts and types of the operations in the library, which //: are often much more powerful and generic than previously presented. //: -//: Unlike Unit Testing, Property Testing abhors the use of state and global variables. Property +//: Unlike Unit Testing, Property Testing is antithetical to the use of state and global variables. Property //: Tests are local, atomic entities that ideally only use the data given to them to match a //: user-defined specification for the behavior of a program or algorithm. While this may //: seem draconian, the upshot of following these [unwritten] rules is that the produced tests become @@ -39,7 +39,7 @@ import XCTest //: //: When you approach your tests with a clear goal in mind, SwiftCheck allows you to turn //: that goal into many smaller parts that are each much easier to reason about than -//: considering the whole problem at once and putting out spot fires as they arise. +//: the whole problem at once. //: //: With that, let's begin. From 1b7bcedb6618b2be5899b36fa44c60943e8e279b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 18:18:53 -0400 Subject: [PATCH 134/460] Make Arguments public --- SwiftCheck/Test.swift | 48 +++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 2b37a16..e136c2a 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -212,6 +212,10 @@ public func quickCheck(prop : Testable, name : String = "") { /// MARK: - Implementation Details +internal func stdArgs(name : String = "") -> CheckerArguments { + return CheckerArguments(name: name, replay: .None, maxSuccess: 100, maxDiscard: 500, maxSize: 100, chatty: true) +} + internal enum Result { case Success(numTests : Int , labels : [(String, Int)] @@ -240,20 +244,7 @@ internal indirect enum Either { case Right(R) } -internal struct Arguments { - let name : String - let replay : Optional<(StdGen, Int)> - let maxSuccess : Int - let maxDiscard : Int - let maxSize : Int - let chatty : Bool -} - -internal func stdArgs(name : String = "") -> Arguments{ - return Arguments(name: name, replay: .None, maxSuccess: 100, maxDiscard: 500, maxSize: 100, chatty: true) -} - -internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { +internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Result { func roundTo(n : Int)(m : Int) -> Int { return (m / m) * m } @@ -267,18 +258,6 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } } - let computeSize_ : Int -> Int -> Int = { x in - return { y in - if roundTo(x)(m: args.maxSize) + args.maxSize <= args.maxSuccess || - x >= args.maxSuccess || - args.maxSuccess % args.maxSize == 0 { - return min(x % args.maxSize + (y / 10), args.maxSize) - } else { - return min((x % args.maxSize) * args.maxSize / (args.maxSuccess % args.maxSize) + y / 10, args.maxSize) - } - } - } - func at0(f : Int -> Int -> Int)(s : Int)(n : Int)(d : Int) -> Int { if n == 0 && d == 0 { return s @@ -288,8 +267,23 @@ internal func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } let computeSize : Int -> Int -> Int = { x in + let computeSize_ : Int -> Int -> Int = { x in + return { y in + if roundTo(x)(m: args.maxSize) + args.maxSize <= args.maxSuccess || + x >= args.maxSuccess || + args.maxSuccess % args.maxSize == 0 { + return min(x % args.maxSize + (y / 10), args.maxSize) + } else { + return min((x % args.maxSize) * args.maxSize / (args.maxSuccess % args.maxSize) + y / 10, args.maxSize) + } + } + } + return { y in - return (args.replay == nil) ? computeSize_(x)(y) : at0(computeSize_)(s: args.replay!.1)(n: x)(d: y) + if let (_, sz) = args.replay { + return at0(computeSize_)(s: sz)(n: x)(d: y) + } + return computeSize_(x)(y) } } From 2515834f7868ce2fc7b5da0b98e1c82a1a5b8f03 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 18:19:02 -0400 Subject: [PATCH 135/460] Give the checkers args --- SwiftCheck/Check.swift | 26 ++++++++++++++++++++------ SwiftCheck/TestOperators.swift | 8 ++++---- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 0fbfa96..9588b1f 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -16,36 +16,50 @@ /// /// SwiftCheck will report all failures through the XCTest mechanism like a normal testing assert, /// but with minimal failing case reported as well. -public func property(msg : String, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line) +public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? stdArgs(msg)) } public struct AssertiveQuickCheck { let msg : String let file : String let line : UInt + let args : CheckerArguments - private init(msg : String, file : String, line : UInt) { + private init(msg : String, file : String, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line + self.args = args } } /// The interface for properties to be run through SwiftCheck without an XCTest assert. The /// property will still generate console output during testing. -public func reportProperty(msg : String, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line) +public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? stdArgs(msg)) } public struct ReportiveQuickCheck { let msg : String let file : String let line : UInt + let args : CheckerArguments - private init(msg : String, file : String, line : UInt) { + private init(msg : String, file : String, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line + self.args = args } } + +public struct CheckerArguments { + let name : String + let replay : Optional<(StdGen, Int)> + let maxSuccess : Int + let maxDiscard : Int + let maxSize : Int + let chatty : Bool +} + diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 8922e5c..1bd17ea 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -10,7 +10,7 @@ infix operator <- {} /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - switch quickCheckWithResult(stdArgs(checker.msg), p: test()) { + switch quickCheckWithResult(checker.args, p: test()) { case let .Failure(_, _, _, _, reason, _, _): XCTFail(reason, file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): @@ -22,7 +22,7 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { - switch quickCheckWithResult(stdArgs(checker.msg), p: test()) { + switch quickCheckWithResult(checker.args, p: test()) { case let .Failure(_, _, _, _, reason, _, _): XCTFail(reason, file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): @@ -34,12 +34,12 @@ public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { /// Binds a Testable value to a property. public func <-(checker : ReportiveQuickCheck, test : () -> Testable) { - quickCheckWithResult(stdArgs(checker.msg), p: test()) + quickCheckWithResult(checker.args, p: test()) } /// Binds a Testable value to a property. public func <-(checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - quickCheckWithResult(stdArgs(checker.msg), p: test()) + quickCheckWithResult(checker.args, p: test()) } infix operator ==> { From eeaabdbba3f394275d35605750459faf45f6ae46 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 20:36:28 -0400 Subject: [PATCH 136/460] Document argument --- SwiftCheck/Check.swift | 55 ++++++++++++++++++++++++++++++++++++------ SwiftCheck/Test.swift | 16 ++++++------ 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 9588b1f..732590b 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -30,7 +30,7 @@ public struct AssertiveQuickCheck { self.msg = msg self.file = file self.line = line - self.args = args + self.args = { var chk = args; chk.name = msg; return chk }() } } @@ -50,16 +50,55 @@ public struct ReportiveQuickCheck { self.msg = msg self.file = file self.line = line - self.args = args + self.args = { var chk = args; chk.name = msg; return chk }() } } +/// Represents the arguments the test driver will use while performing testing, shrinking, and +/// printing results. public struct CheckerArguments { - let name : String - let replay : Optional<(StdGen, Int)> - let maxSuccess : Int - let maxDiscard : Int - let maxSize : Int - let chatty : Bool + /// Provides a way of re-doing the test at the given size with a new generator. + let replay : Optional<(StdGen, Int)> + /// The maximum number of test cases that must pass before the property itself passes. + /// + /// The default value of this property is 100. In general, some tests may require more than + /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// on the property instead. + let maxAllowableSuccessfulTests : Int + /// The maximum number of tests cases that can be discarded before testing gives up on the + /// property. + /// + /// The default value of this property is 500. In general, most tests will require less than + /// this amount. `Discard`ed test cases do not affect the passing or failing status of the + /// property as a whole. + let maxAllowableDiscardedTests : Int + /// The limit to the size of all generators in the test. + /// + /// The default value of this property is 100. If "large" values, in magnitude or + /// size, are necessary then increase this value, else keep it relatively near the default. If + /// it becomes too small the samples present in the test case will lose diversity. + let maxTestCaseSize : Int + + public init( replay : Optional<(StdGen, Int)> + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , maxTestCaseSize : Int) { + self = CheckerArguments(replay: replay, maxAllowableSuccessfulTests: maxAllowableSuccessfulTests, maxAllowableDiscardedTests: maxAllowableDiscardedTests, maxTestCaseSize: maxTestCaseSize, name: "") + } + + internal init( replay : Optional<(StdGen, Int)> + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , maxTestCaseSize : Int + , name : String) { + + self.replay = replay + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.maxTestCaseSize = maxTestCaseSize + self.name = name + } + + internal var name : String } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index e136c2a..a8a4d27 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -213,7 +213,7 @@ public func quickCheck(prop : Testable, name : String = "") { /// MARK: - Implementation Details internal func stdArgs(name : String = "") -> CheckerArguments { - return CheckerArguments(name: name, replay: .None, maxSuccess: 100, maxDiscard: 500, maxSize: 100, chatty: true) + return CheckerArguments(replay: .None, maxAllowableSuccessfulTests: 100, maxAllowableDiscardedTests: 500, maxTestCaseSize: 100, name: name) } internal enum Result { @@ -269,12 +269,12 @@ internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Res let computeSize : Int -> Int -> Int = { x in let computeSize_ : Int -> Int -> Int = { x in return { y in - if roundTo(x)(m: args.maxSize) + args.maxSize <= args.maxSuccess || - x >= args.maxSuccess || - args.maxSuccess % args.maxSize == 0 { - return min(x % args.maxSize + (y / 10), args.maxSize) + if roundTo(x)(m: args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests || + x >= args.maxAllowableSuccessfulTests || + args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { + return min(x % args.maxTestCaseSize + (y / 10), args.maxTestCaseSize) } else { - return min((x % args.maxSize) * args.maxSize / (args.maxSuccess % args.maxSize) + y / 10, args.maxSize) + return min((x % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + y / 10, args.maxTestCaseSize) } } } @@ -289,8 +289,8 @@ internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Res let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxSuccess - , maxAllowableDiscardedTests: args.maxDiscard + , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests , computeSize: computeSize , successfulTestCount: 0 , discardedTestCount: 0 From 8b29b4048bbce3be23ce6b88be029589d17d366e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Sep 2015 20:45:25 -0400 Subject: [PATCH 137/460] Test arguments --- SwiftCheck/Check.swift | 21 ++++++++++++++++++--- SwiftCheck/Random.swift | 2 +- SwiftCheckTests/DiscardSpec.swift | 10 ++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 732590b..6519dca 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -15,7 +15,22 @@ /// } /// /// SwiftCheck will report all failures through the XCTest mechanism like a normal testing assert, -/// but with minimal failing case reported as well. +/// but with the minimal failing case reported as well. +/// +/// If necessary, arguments can be provided to this function to change the behavior of the testing +/// mechanism: +/// +/// let args = CheckerArguments( replay: Optional.Some((standardRNG, 10)) // Replays all tests with a new generator of size 10 +/// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. +/// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. +/// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. +/// ) +/// +/// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in +/// return i == i +/// } +/// +/// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? stdArgs(msg)) } @@ -57,7 +72,7 @@ public struct ReportiveQuickCheck { /// Represents the arguments the test driver will use while performing testing, shrinking, and /// printing results. public struct CheckerArguments { - /// Provides a way of re-doing the test at the given size with a new generator. + /// Provides a way of re-doing a test at the given size with a new generator. let replay : Optional<(StdGen, Int)> /// The maximum number of test cases that must pass before the property itself passes. /// @@ -99,6 +114,6 @@ public struct CheckerArguments { self.name = name } - internal var name : String + internal var name : String } diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index a809d26..28d4c80 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -25,7 +25,7 @@ public protocol RandomGeneneratorType { } /// A library-provided standard random number generator. -let standardRNG : StdGen = StdGen(time(nil)) +public let standardRNG : StdGen = StdGen(time(nil)) public struct StdGen : RandomGeneneratorType { let seed: Int diff --git a/SwiftCheckTests/DiscardSpec.swift b/SwiftCheckTests/DiscardSpec.swift index c4903d9..8d0a117 100644 --- a/SwiftCheckTests/DiscardSpec.swift +++ b/SwiftCheckTests/DiscardSpec.swift @@ -13,5 +13,15 @@ class DiscardSpec : XCTestCase { func testDiscardFailure() { property("P != NP") <- Discard() property("P = NP") <- Discard().expectFailure + + let args = CheckerArguments( replay: Optional.Some((standardRNG, 10)) + , maxAllowableSuccessfulTests: 200 + , maxAllowableDiscardedTests: 0 + , maxTestCaseSize: 1000 + ) + + property("Discards forbidden", arguments: args) <- forAll { (x : UInt) in + return Discard() + }.expectFailure } } From e8a988d11e32885942d1ac276db4f5701fffdf8c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 9 Sep 2015 16:45:25 -0400 Subject: [PATCH 138/460] Add Large modifier --- SwiftCheck.xcodeproj/project.pbxproj | 5 +++-- SwiftCheck/Arbitrary.swift | 8 -------- SwiftCheck/Check.swift | 2 +- SwiftCheck/Modifiers.swift | 28 ++++++++++++++++++++++++++++ SwiftCheckTests/DiscardSpec.swift | 2 +- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index a4360e7..759bb0a 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,8 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; settings = {ASSET_TAGS = (); }; }; - 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; + 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; @@ -338,6 +338,7 @@ 844FCC84198B320500EB242A /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Robert Widmann"; TargetAttributes = { diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index fabe26b..6730dab 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -742,14 +742,6 @@ private func bits(n : N) -> Int { return 1 + bits(n / 2) } -private func inBounds(fi : (Int -> A)) -> Gen -> Gen { - return { g in - return fi <^> g.suchThat { x in - return (fi(x) as! Int) == x - } - } -} - private func nub(xs : [A]) -> [A] { return [A](Set(xs)) } diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 6519dca..7509b42 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -20,7 +20,7 @@ /// If necessary, arguments can be provided to this function to change the behavior of the testing /// mechanism: /// -/// let args = CheckerArguments( replay: Optional.Some((standardRNG, 10)) // Replays all tests with a new generator of size 10 +/// let args = CheckerArguments( replay: Optional.Some((newStdGen(), 10)) // Replays all tests with a new generator of size 10 /// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. /// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. /// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index a2498f6..8e47270 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -373,6 +373,26 @@ private func undefined() -> A { fatalError("") } +public struct Large> : Arbitrary { + public let getLarge : A + + public init(_ lrg : A) { + self.getLarge = lrg + } + + public var description : String { + return "Large( \(self.getLarge) )" + } + + public static var arbitrary : Gen> { + return Gen.choose((A.min, A.max)).fmap(Large.init) + } + + public static func shrink(bl : Large) -> [Large] { + return bl.getLarge.shrinkIntegral.map(Large.init) + } +} + /// Guarantees that every generated integer is greater than 0. public struct Positive> : Arbitrary, CustomStringConvertible { public let getPositive : A @@ -454,3 +474,11 @@ extension NonNegative : CoArbitrary { return x.getNonNegative.coarbitraryIntegral() } } + +private func inBounds(fi : (Int -> A)) -> Gen -> Gen { + return { g in + return fi <^> g.suchThat { x in + return (fi(x) as! Int) == x + } + } +} diff --git a/SwiftCheckTests/DiscardSpec.swift b/SwiftCheckTests/DiscardSpec.swift index 8d0a117..10e867b 100644 --- a/SwiftCheckTests/DiscardSpec.swift +++ b/SwiftCheckTests/DiscardSpec.swift @@ -14,7 +14,7 @@ class DiscardSpec : XCTestCase { property("P != NP") <- Discard() property("P = NP") <- Discard().expectFailure - let args = CheckerArguments( replay: Optional.Some((standardRNG, 10)) + let args = CheckerArguments( replay: Optional.Some((newStdGen(), 10)) , maxAllowableSuccessfulTests: 200 , maxAllowableDiscardedTests: 0 , maxTestCaseSize: 1000 From e5156cb7cb2056a5128cc2e7865e94c70b478558 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 9 Sep 2015 16:48:17 -0400 Subject: [PATCH 139/460] Try this new travis out --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b019c5..5cedc69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: beta-xcode6.3 +osx_image: xcode7 script: - xctool -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test From c09d1b8863d38225a7454979e7599a70f9f8b0e1 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Wed, 9 Sep 2015 23:37:57 -0500 Subject: [PATCH 140/460] Support tvOS in the iOS target --- SwiftCheck.xcodeproj/project.pbxproj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 759bb0a..117c8e5 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -706,9 +706,10 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,3"; }; name = Debug; }; @@ -732,9 +733,10 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = "1,2,3"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -759,6 +761,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; }; name = Debug; }; @@ -778,6 +781,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; VALIDATE_PRODUCT = YES; }; name = Release; From b5af8fb287d8384f41d8012543c6394ded22e6df Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Thu, 10 Sep 2015 09:54:18 -0500 Subject: [PATCH 141/460] Change Travis to xcpretty --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cedc69..e146035 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,6 @@ language: objective-c osx_image: xcode7 script: - - xctool -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test - - xctool -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test - + - set -o pipefail + - xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c + - xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c From 2297786c7af8e4b15ba422b240ecde5bfc7cac72 Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Thu, 10 Sep 2015 10:08:25 -0500 Subject: [PATCH 142/460] Use xcpretty-travis-formatter for Travis --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e146035..247b347 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ language: objective-c osx_image: xcode7 +before_install: + - gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet + script: - - set -o pipefail - - xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c - - xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c + - set -o pipefail && xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter` + - set -o pipefail && xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter` From 515890bd705eceedf195755745d12ebbac089e91 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 11 Sep 2015 12:03:32 -0400 Subject: [PATCH 143/460] ++Operadics --- Cartfile.resolved | 2 +- Carthage/Checkouts/Operadics | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 38c4267..dd030d0 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Operadics" "v0.1.2" +github "typelift/Operadics" "v0.1.3" diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics index 0cf4ba9..a5897e8 160000 --- a/Carthage/Checkouts/Operadics +++ b/Carthage/Checkouts/Operadics @@ -1 +1 @@ -Subproject commit 0cf4ba90af565214643542a1dc9a7193a3eb5720 +Subproject commit a5897e80a6054c1d4877348977185ec6264bb8fe From 7c44aecadbcf766743061562c9034d7af7fa4961 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 11 Sep 2015 12:13:43 -0400 Subject: [PATCH 144/460] Add a pod spec for 2.0 --- SwiftCheck.podspec | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 SwiftCheck.podspec diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec new file mode 100644 index 0000000..8f915fe --- /dev/null +++ b/SwiftCheck.podspec @@ -0,0 +1,40 @@ +Pod::Spec.new do |s| + s.name = "SwiftCheck" + s.version = "0.3.0" + s.summary = "QuickCheck for Swift." + s.homepage = "https://github.com/typelift/SwiftCheck" + s.license = { :type => "MIT", :text => <<-LICENSE + The MIT License (MIT) + + Copyright (c) 2015 TypeLift + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + LICENSE + } + s.authors = { "CodaFi" => "devteam.codafi@gmail.com", "pthariensflame" => "alexanderaltman@me.com" } + + s.requires_arc = true + s.osx.deployment_target = "10.9" + s.ios.deployment_target = "8.0" + s.framework = "XCTest" + s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } + s.source_files = "SwiftCheck/*.swift", "**/Operadics/*.swift" +end + From 8a7c0e4fc32682b5cafe7d53902dae52b78b6ed2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 13 Sep 2015 14:50:43 -0400 Subject: [PATCH 145/460] Temporarily update Operadics to work around resolver bugs --- Cartfile.resolved | 2 +- Carthage/Checkouts/Operadics | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index dd030d0..1dd0fd1 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Operadics" "v0.1.3" +github "typelift/Operadics" "0.1.4" diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics index a5897e8..c65e635 160000 --- a/Carthage/Checkouts/Operadics +++ b/Carthage/Checkouts/Operadics @@ -1 +1 @@ -Subproject commit a5897e80a6054c1d4877348977185ec6264bb8fe +Subproject commit c65e6355e22282a89d68a8a2d594a32c36c1e7b0 From cce8948966aa37cb5b22ffb991665f688f927cbc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Sep 2015 19:25:38 -0400 Subject: [PATCH 146/460] Fail hard and often --- SwiftCheck.xcodeproj/project.pbxproj | 6 +++++ SwiftCheckTests/FailureSpec.swift | 38 ++++++++++++++++++++++++++++ SwiftCheckTests/GenSpec.swift | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 SwiftCheckTests/FailureSpec.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 117c8e5..665e302 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; + 82AA258D1BACD10400F369A1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82AA258C1BACD10400F369A1 /* FailureSpec.swift */; }; + 82AA258E1BACD10400F369A1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82AA258C1BACD10400F369A1 /* FailureSpec.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -95,6 +97,7 @@ /* Begin PBXFileReference section */ 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; + 82AA258C1BACD10400F369A1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; @@ -217,6 +220,7 @@ children = ( 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */, 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, + 82AA258C1BACD10400F369A1 /* FailureSpec.swift */, 8445C4A91B16D37800280089 /* GenSpec.swift */, 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, @@ -442,6 +446,7 @@ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, + 82AA258D1BACD10400F369A1 /* FailureSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, ); @@ -480,6 +485,7 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, + 82AA258E1BACD10400F369A1 /* FailureSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, ); diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift new file mode 100644 index 0000000..2d59f79 --- /dev/null +++ b/SwiftCheckTests/FailureSpec.swift @@ -0,0 +1,38 @@ +// +// FailureSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 9/18/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +import SwiftCheck +import XCTest + +class FailureSpec : XCTestCase { + private var failCount : Int = 0 + private let tests : [Property] = [ + forAll { (_ : Int) in return false }, + forAll { (x : Int) in return x != x }, + forAll { (b : Bool) in return !(b || !b) }, + ] + + func testProperties() { + self.tests.forEach { t in + property("Fail") <- t + } + } + + override func recordFailureWithDescription(message : String, inFile file : String, atLine line : UInt, expected : Bool) { + if !expected { + assert(false, "Assertion should never throw."); + } else { +// super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) + failCount++; + } + } + + override func tearDown() { + XCTAssert(failCount == tests.count) + } +} \ No newline at end of file diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 5df609a..13388fd 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -37,7 +37,7 @@ class GenSpec : XCTestCase { } } - property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((0, 1000))) { n in + property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in return forAll(Gen.weighted(Array(count: n, repeatedValue: (1, 0)))) { $0 == 0 } } From 3266fe1e54e198fb9538b7a3f221156df26d4d06 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Sep 2015 19:28:14 -0400 Subject: [PATCH 147/460] Document contribution --- SwiftCheckTests/FailureSpec.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 2d59f79..8b41bb1 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -23,6 +23,8 @@ class FailureSpec : XCTestCase { } } + /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) + /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) override func recordFailureWithDescription(message : String, inFile file : String, atLine line : UInt, expected : Bool) { if !expected { assert(false, "Assertion should never throw."); @@ -35,4 +37,4 @@ class FailureSpec : XCTestCase { override func tearDown() { XCTAssert(failCount == tests.count) } -} \ No newline at end of file +} From 720cb8f5f1d7790f380cb3e72b8df4464091ca53 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Sep 2015 19:36:13 -0400 Subject: [PATCH 148/460] Fail on inequality properties --- SwiftCheckTests/FailureSpec.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 8b41bb1..0846704 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -12,9 +12,15 @@ import XCTest class FailureSpec : XCTestCase { private var failCount : Int = 0 private let tests : [Property] = [ - forAll { (_ : Int) in return false }, - forAll { (x : Int) in return x != x }, - forAll { (b : Bool) in return !(b || !b) }, + forAll { (_ : Int) in false }, + forAll { (x : Int) in x != x }, + forAll { (b : Bool) in !(b || !b) }, + forAll { (x : Int) in x > (x + 1) }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x + c < y + c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x - c < y - c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, ] func testProperties() { From 24b2b8f5de3a3866b88e147593ec3c3bb4e2b530 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Sep 2015 19:37:55 -0400 Subject: [PATCH 149/460] Add double negation assert --- SwiftCheckTests/FailureSpec.swift | 1 + SwiftCheckTests/GenSpec.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 0846704..c9fcafb 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -12,6 +12,7 @@ import XCTest class FailureSpec : XCTestCase { private var failCount : Int = 0 private let tests : [Property] = [ + forAll { (_ : Int) in false }.expectFailure.expectFailure, forAll { (_ : Int) in false }, forAll { (x : Int) in x != x }, forAll { (b : Bool) in !(b || !b) }, diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 13388fd..8413bd7 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -22,7 +22,7 @@ class GenSpec : XCTestCase { } } - property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((0, 1000))) { n in + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in return forAll(Gen.frequency(Array(count: n, repeatedValue: (1, Gen.pure(0))))) { $0 == 0 } } From 822b716ee889d55e1b40a6f1805606d1ed4d9241 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 19 Sep 2015 13:21:26 -0400 Subject: [PATCH 150/460] Better overload resolution for forAll --- SwiftCheck/Test.swift | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index a8a4d27..00cbc5e 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -149,50 +149,50 @@ public func forAll(gen : Gen, pf : (A -> Testable)) -> Propert /// Given 2 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 2 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(pf : (A, B) -> Testable) -> Property { +public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 3 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(pf : (A, B, C) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(pf: { b, c in pf(t, b, c) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 4 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(pf : (A, B, C, D) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(pf: { b, c, d in pf(t, b, c, d) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 5 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(pf : (A, B, C, D, E) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(pf: { b, c, d, e in pf(t, b, c, d, e) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 6 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(pf : (A, B, C, D, E, F) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 7 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(genG : Gen)(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(genF : genG)(pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 8 types. @warn_unused_result -public func forAll(genA : Gen)(genB : Gen)(genC : Gen)(genD : Gen)(genE : Gen)(genF : Gen)(genG : Gen)(genH : Gen)(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB)(genB: genC)(genC: genD)(genD: genE)(genE: genF)(genF : genG)(genG : genH)(pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a universally quantified From fe5b93a1294a2b74de993a620e3f57152300effc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 19 Sep 2015 13:49:28 -0400 Subject: [PATCH 151/460] Add forAllShrink --- SwiftCheck/Test.swift | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 00cbc5e..fad5a2d 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -195,6 +195,86 @@ public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { + return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) +} + +/// Given 2 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 2 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in pf(t, b) }) }) +} + +/// Given 3 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 3 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in pf(t, b, c) }) }) +} + +/// Given 4 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 4 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in pf(t, b, c, d) }) }) +} + +/// Given 5 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 5 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in pf(t, b, c, d, e) }) }) +} + +/// Given 6 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 6 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +} + +/// Given 7 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 7 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +} + +/// Given 8 explicit generators, converts a function to a universally quantified property using the +/// default shrinkers for those 8 types. +/// +/// This variant of `forAll` does not shrink its argument but allows generators of any type, not +/// just those that conform to `Arbitrary`. +@warn_unused_result +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +} + /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. @warn_unused_result From 94f844f7f73fe043ee2082caf9e89ef4fdca0995 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 19 Sep 2015 13:51:44 -0400 Subject: [PATCH 152/460] Fix docs --- SwiftCheck/Test.swift | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index fad5a2d..e5f9fdb 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -195,8 +195,8 @@ public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } -/// Given 2 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 2 types. +/// Given 2 explicit generators, converts a function to a universally quantified property for those +/// 2 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -215,8 +215,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) -> return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in pf(t, b) }) }) } -/// Given 3 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 3 types. +/// Given 3 explicit generators, converts a function to a universally quantified property for those +/// 3 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -225,8 +225,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in pf(t, b, c) }) }) } -/// Given 4 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 4 types. +/// Given 4 explicit generators, converts a function to a universally quantified property +/// for those 4 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -235,8 +235,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in pf(t, b, c, d) }) }) } -/// Given 5 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 5 types. +/// Given 5 explicit generators, converts a function to a universally quantified property for those +/// 5 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -245,8 +245,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in pf(t, b, c, d, e) }) }) } -/// Given 6 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 6 types. +/// Given 6 explicit generators, converts a function to a universally quantified property for those +/// 6 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -255,8 +255,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ g return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } -/// Given 7 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 7 types. +/// Given 7 explicit generators, converts a function to a universally quantified property for those +/// 7 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @@ -265,8 +265,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } -/// Given 8 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 8 types. +/// Given 8 explicit generators, converts a function to a universally quantified property for those +/// 8 types. /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. From 57b8bfeef969b2a016de85de2082eb008a343b1f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 19 Sep 2015 14:09:14 -0400 Subject: [PATCH 153/460] Test forAllNoShrink --- SwiftCheckTests/TestSpec.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index 4fe4490..ce5889c 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -9,9 +9,22 @@ import XCTest import SwiftCheck +extension Dictionary { + init(_ pairs : S) { + self.init() + var g = pairs.generate() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } +} + + class TestSpec : XCTestCase { func testAll() { - property("Dictionaries behave") <- forAllShrink(Dictionary.arbitrary, shrinker: Dictionary.shrink) { (xs : Dictionary) in + let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate().fmap(Dictionary.init) + + property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in return true } From 7213f260f7b810f39317e6584f5637100d977862 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 27 Sep 2015 00:37:54 -0400 Subject: [PATCH 154/460] whoops --- SwiftCheck/Property.swift | 2 +- SwiftCheck/Test.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 44a8e64..c24cbce 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -398,7 +398,7 @@ private func exception(msg : String) -> ErrorType -> TestResult { private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) - }}) + }}) } private func result(ok : Bool?, reason : String = "") -> TestResult { diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index d4626fc..a0d2471 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -11,7 +11,7 @@ /// Property Testing is a more static and expressive form of Test-Driven Development that emphasizes /// the testability of program properties - A statement or invariant that can be proven to hold when /// fed any number of arguments of a particular kind. It is akin to Fuzz Testing but is made -/// significantly more power by the primitives in this framework. +/// significantly more powerful by the primitives in this framework. /// /// A `Property` in SwiftCheck is more than just `true` and `false`, it is a value that is capable /// of producing a framework type called `Prop`, which models individual test cases that themselves From adbab9f612b2ee2c4ed7e73f8e6fd3cba406d5ca Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 27 Sep 2015 00:40:19 -0400 Subject: [PATCH 155/460] More whitespace stuff --- SwiftCheck/Check.swift | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 6d60e7a..4e22ed4 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -94,18 +94,22 @@ public struct CheckerArguments { /// it becomes too small the samples present in the test case will lose diversity. let maxTestCaseSize : Int - public init( replay : Optional<(StdGen, Int)> - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , maxTestCaseSize : Int) { + public init(replay : Optional<(StdGen, Int)> + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , maxTestCaseSize : Int + ) + { self = CheckerArguments(replay: replay, maxAllowableSuccessfulTests: maxAllowableSuccessfulTests, maxAllowableDiscardedTests: maxAllowableDiscardedTests, maxTestCaseSize: maxTestCaseSize, name: "") } - internal init( replay : Optional<(StdGen, Int)> - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , maxTestCaseSize : Int - , name : String) { + internal init(replay : Optional<(StdGen, Int)> + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , maxTestCaseSize : Int + , name : String + ) + { self.replay = replay self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests From d13f624a25d4c27ccba181e360f35df2b72d64b3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 27 Sep 2015 00:53:29 -0400 Subject: [PATCH 156/460] Give a reason to use Existential --- SwiftCheck/Property.swift | 104 +++++++++++++++++++------------------- SwiftCheck/Test.swift | 20 ++++---- 2 files changed, 63 insertions(+), 61 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index c24cbce..df324d3 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -201,14 +201,14 @@ extension Testable { return self.mapResult { res in return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks + chattyCallbacks(res.callbacks) - , abort: res.abort - , quantifier: res.quantifier) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + chattyCallbacks(res.callbacks) + , abort: res.abort + , quantifier: res.quantifier) } } @@ -218,14 +218,14 @@ extension Testable { public var expectFailure : Property { return self.mapTotalResult({ res in return TestResult(ok: res.ok - , expect: false - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + , expect: false + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) }) } @@ -256,14 +256,14 @@ extension Testable { if b { return self.mapResult { res in return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: insertWith(max, k: s, v: n, m: res.labels) - , stamp: res.stamp.union([s]) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: insertWith(max, k: s, v: n, m: res.labels) + , stamp: res.stamp.union([s]) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) } } return self.property @@ -278,8 +278,8 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { rs in return Prop(unProp: joinRose(rs.fmap { x in return x.unProp - })) - }) + })) + }) } /// A `Callback` is a block of code that can be run after a test case has finished. They consist @@ -301,16 +301,16 @@ public enum CallbackKind { } public enum TestResultMatcher { - case MatchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification - ) + case MatchResult( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : Array + , abort : Bool + , quantifier : Quantification + ) } /// The types of quantification SwiftCheck can perform. @@ -472,28 +472,28 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: result.callbacks + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: result.callbacks + res.callbacks + , abort: res.abort + , quantifier: res.quantifier) } } private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: unionWith(max, l: res.labels, r: result.labels) - , stamp: res.stamp.union(result.stamp) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: unionWith(max, l: res.labels, r: result.labels) + , stamp: res.stamp.union(result.stamp) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index a0d2471..3be26a6 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -290,16 +290,18 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A -> Testable /// generator for that type to search for a passing case. SwiftCheck only runs a limited number of /// trials before giving up and failing. /// -/// The nature of Existential Quantification means we have to enumerate over the entire domain of -/// `A` in order to return a proper value. Because such a traversal is both impractical and leads -/// to computationally questionable behavior (infinite loops and the like), SwiftCheck instead -/// interprets `exists` as a finite search over arbitrarily many values (around 500). No shrinking -/// is performed during the search. +/// The nature of Existential Quantification means SwiftCheck would have to enumerate over the +/// entire domain of the type `A` in order to return a proper value. Because such a traversal is +/// both impractical and leads to computationally questionable behavior (infinite loops and the +/// like), SwiftCheck instead interprets `exists` as a finite search over arbitrarily many values +/// (around 500). No shrinking is performed during the search. /// -/// It is recommended that you avoid existential quantification and instead reduce your property to -/// `Skolem Normal Form `_. `SNF` involves -/// turning every `exists` into a function returning the existential value, taking any other -/// parameters being quantified over as needed. +/// Existential Quantification should rarely be used, and in practice is usually used for *negative* +/// statements "there does not exist `foo` such that `bar`". It is recommended that you avoid +/// `exists` and instead reduce your property to +/// [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). `SNF` involves turning +/// every `exists` into a function returning the existential value, taking any other parameters +/// being quantified over as needed. public func exists(pf : A -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } From 4ef6c10d9cd130c6299fcfa3342d6e4099eb99ab Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 27 Sep 2015 01:12:40 -0400 Subject: [PATCH 157/460] Add existential to failure spec --- SwiftCheckTests/FailureSpec.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index c9fcafb..ba36259 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -14,6 +14,8 @@ class FailureSpec : XCTestCase { private let tests : [Property] = [ forAll { (_ : Int) in false }.expectFailure.expectFailure, forAll { (_ : Int) in false }, + exists { (x : Int) in x != x }, + exists { (x : Int) in x != 0 }, forAll { (x : Int) in x != x }, forAll { (b : Bool) in !(b || !b) }, forAll { (x : Int) in x > (x + 1) }, From df52d2f5856bbd35319f99e6e41ce4d5d93c1498 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 28 Sep 2015 13:01:33 -0400 Subject: [PATCH 158/460] Add fun inequality --- SwiftCheckTests/FailureSpec.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index ba36259..2a22065 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -24,6 +24,14 @@ class FailureSpec : XCTestCase { forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, + forAll { (a : Float, b : Float, c : Float) in + return exists { (x : Float) in + return exists { (y : Float) in + return (x != y) ==> { a * pow(x, 2) + b * x + c == a * pow(y, 2) + b * y + c } + } + } + }, + ] func testProperties() { From b89406023c1501e42adfc73d4948dd5224a77862 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 1 Oct 2015 15:30:08 -0400 Subject: [PATCH 159/460] Add carthage to matrix --- .travis.yml | 17 ++++++++++++++--- SwiftCheck.xcodeproj/project.pbxproj | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 247b347..059f800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,20 @@ language: objective-c osx_image: xcode7 +env: + - TEST_CONFIG="RELEASE" + - TEST_CONFIG="CARTHAGE" + before_install: - - gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet; fi + - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then brew install carthage; fi + +install: + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then git submodule update -i --recursive; fi script: - - set -o pipefail && xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter` - - set -o pipefail && xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter` + - set -o pipefail + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi + - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage update --verbose --no-use-binaries --configuration Debug && carthage build --no-skip-current; fi + diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 665e302..02e7099 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -691,7 +691,7 @@ 84DF760C1B0BD54600C912B0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; From bd4e405cbe24f3b4b380da33d667b1d91e064399 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 1 Oct 2015 15:43:34 -0400 Subject: [PATCH 160/460] Add Pods to matrix --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 059f800..3955800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ osx_image: xcode7 env: - TEST_CONFIG="RELEASE" - TEST_CONFIG="CARTHAGE" + - TEST_CONFIG="PODS" before_install: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet; fi @@ -16,5 +17,5 @@ script: - set -o pipefail - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage update --verbose --no-use-binaries --configuration Debug && carthage build --no-skip-current; fi - + - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage update --verbose --no-use-binaries && carthage build --no-skip-current --configuration Debug; fi + - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint && pod install; fi From f4f701273d7f7679306030808360f0004536c10c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 1 Oct 2015 15:52:03 -0400 Subject: [PATCH 161/460] No need to pod install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3955800..deb5138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,4 @@ script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage update --verbose --no-use-binaries && carthage build --no-skip-current --configuration Debug; fi - - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint && pod install; fi + - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi From bc3608ae0acae462596d4debaacc90955849d90a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 6 Oct 2015 13:47:33 -0400 Subject: [PATCH 162/460] Disable carthage build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index deb5138..cee15c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ osx_image: xcode7 env: - TEST_CONFIG="RELEASE" - - TEST_CONFIG="CARTHAGE" +# - TEST_CONFIG="CARTHAGE" - TEST_CONFIG="PODS" before_install: From 16702acea781ccc314242d1df26a983dd093d135 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 6 Oct 2015 13:53:54 -0400 Subject: [PATCH 163/460] Revert code signing changes --- SwiftCheck.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 02e7099..665e302 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -691,7 +691,7 @@ 84DF760C1B0BD54600C912B0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; From 13dbc40da152db83bf6943410bd9166ee6e0e2b4 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 6 Oct 2015 14:04:22 -0400 Subject: [PATCH 164/460] Fix bogus framework search paths --- SwiftCheck.xcodeproj/project.pbxproj | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 665e302..b3075ef 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -9,10 +9,10 @@ /* Begin PBXBuildFile section */ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; + 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; settings = {ASSET_TAGS = (); }; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; - 82AA258D1BACD10400F369A1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82AA258C1BACD10400F369A1 /* FailureSpec.swift */; }; - 82AA258E1BACD10400F369A1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82AA258C1BACD10400F369A1 /* FailureSpec.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -96,8 +96,8 @@ /* Begin PBXFileReference section */ 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; + 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; - 82AA258C1BACD10400F369A1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; @@ -220,7 +220,7 @@ children = ( 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */, 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, - 82AA258C1BACD10400F369A1 /* FailureSpec.swift */, + 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */, 8445C4A91B16D37800280089 /* GenSpec.swift */, 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, @@ -446,7 +446,7 @@ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, - 82AA258D1BACD10400F369A1 /* FailureSpec.swift in Sources */, + 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, ); @@ -485,7 +485,7 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, - 82AA258E1BACD10400F369A1 /* FailureSpec.swift in Sources */, + 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, ); @@ -601,8 +601,8 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = SwiftCheck/Info.plist; @@ -634,8 +634,8 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = SwiftCheck/Info.plist; @@ -697,7 +697,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(PLATFORM_DIR)/Developer/Library/Frameworks"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -728,7 +731,10 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = "$(PLATFORM_DIR)/Developer/Library/Frameworks"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SwiftCheck/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; From e8ea9678431ff4475bb4639a2b18723573738d17 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 14 Oct 2015 21:15:25 -0400 Subject: [PATCH 165/460] Welp, that was easier than I expected --- SwiftCheck/Test.swift | 105 +++++++++++++++-------------- SwiftCheckTests/FailureSpec.swift | 7 +- SwiftCheckTests/PropertySpec.swift | 4 ++ 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 3be26a6..b9b77fd 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -86,113 +86,113 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. @warn_unused_result -public func forAll(pf : (A -> Testable)) -> Property { +public func forAll(pf : (A throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. @warn_unused_result -public func forAll(pf : (A, B) -> Testable) -> Property { - return forAll({ t in forAll({ b in pf(t, b) }) }) +public func forAll(pf : (A, B) throws -> Testable) -> Property { + return forAll({ t in forAll({ b in try pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. @warn_unused_result -public func forAll(pf : (A, B, C) -> Testable) -> Property { - return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) +public func forAll(pf : (A, B, C) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c in try pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. @warn_unused_result -public func forAll(pf : (A, B, C, D) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) +public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d in try pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. @warn_unused_result -public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) +public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. @warn_unused_result -public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. @warn_unused_result -public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. @warn_unused_result -public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { + return forAll({ t in forAll({ b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified property using the /// default shrinker for that type. @warn_unused_result -public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { +public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 2 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, pf: { b in pf(t, b) }) }) +public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 3 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in pf(t, b, c) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 4 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in pf(t, b, c, d) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 5 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in pf(t, b, c, d, e) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 6 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 7 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 8 types. @warn_unused_result -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified property for that @@ -201,7 +201,7 @@ public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { +public func forAllNoShrink(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -211,8 +211,8 @@ public func forAllNoShrink(gen : Gen, pf : (A -> Testable)) -> Property { /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in pf(t, b) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property for those @@ -221,8 +221,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) -> /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in pf(t, b, c) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property @@ -231,8 +231,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in pf(t, b, c, d) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property for those @@ -241,8 +241,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in pf(t, b, c, d, e) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property for those @@ -251,8 +251,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in pf(t, b, c, d, e, f) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property for those @@ -261,8 +261,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ g /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property for those @@ -271,17 +271,22 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. @warn_unused_result -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) +public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. @warn_unused_result -public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A -> Testable) -> Property { +public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in - return f(xs).counterexample(String(xs)) + do { + let fs = try f(xs) + return fs.counterexample(String(xs)) + } catch let e { + return TestResult.failed("Test case threw an exception: \"" + String(e) + "\"") + } }).unProperty }) } @@ -302,14 +307,14 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A -> Testable /// [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). `SNF` involves turning /// every `exists` into a function returning the existential value, taking any other parameters /// being quantified over as needed. -public func exists(pf : A -> Testable) -> Property { +public func exists(pf : A throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially quantified property using /// the default shrinker for that type. -public func exists(gen : Gen, pf : A -> Testable) -> Property { - return forAllNoShrink(A.arbitrary, pf: { pf($0).invert }).invert.mapResult { res in +public func exists(gen : Gen, pf : A throws -> Testable) -> Property { + return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok , expect: res.expect , reason: res.reason diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 2a22065..d43b454 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -9,6 +9,10 @@ import SwiftCheck import XCTest +enum SwiftCheckError : ErrorType { + case Bogus +} + class FailureSpec : XCTestCase { private var failCount : Int = 0 private let tests : [Property] = [ @@ -31,7 +35,8 @@ class FailureSpec : XCTestCase { } } }, - + forAll { (_ : Int) in throw SwiftCheckError.Bogus }, + forAll { (_ : Int) in throw SwiftCheckError.Bogus }.expectFailure.expectFailure, ] func testProperties() { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index fe6b3c2..58e113b 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -38,6 +38,10 @@ class PropertySpec : XCTestCase { return n != n }.invert + property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in + throw SwiftCheckError.Bogus + }.invert + property("Invert does not affect discards") <- forAll { (n : Int) in return Discard() }.invert From 7c63577e385fda68a241cb4a794de2077814e96c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 14 Oct 2015 21:18:04 -0400 Subject: [PATCH 166/460] Test existential too --- SwiftCheckTests/FailureSpec.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index d43b454..1676fe5 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -36,7 +36,8 @@ class FailureSpec : XCTestCase { } }, forAll { (_ : Int) in throw SwiftCheckError.Bogus }, - forAll { (_ : Int) in throw SwiftCheckError.Bogus }.expectFailure.expectFailure, + forAll { (_ : Int, _ : Float, _ : Int) in throw SwiftCheckError.Bogus }.expectFailure.expectFailure, + exists { (_ : Int) in throw SwiftCheckError.Bogus }, ] func testProperties() { From a48463713892a10d45dcbed071b7b7e3d542c76b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 15 Oct 2015 16:23:32 -0400 Subject: [PATCH 167/460] Compact and document --- SwiftCheck/Test.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index b9b77fd..1442486 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -282,8 +282,7 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in do { - let fs = try f(xs) - return fs.counterexample(String(xs)) + return (try f(xs)).counterexample(String(xs)) } catch let e { return TestResult.failed("Test case threw an exception: \"" + String(e) + "\"") } @@ -327,7 +326,7 @@ public func exists(gen : Gen, pf : A throws -> Testable) -> Pr } } - +/// Tests a property and prints the results to stdout. public func quickCheck(prop : Testable, name : String = "") { quickCheckWithResult(stdArgs(name), p: prop) } From 8a597e940efbe4833378af0a6516d73e0e94788e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 15 Oct 2015 16:35:36 -0400 Subject: [PATCH 168/460] Bump Podspec Version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 5155d91..edca611 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.3.0" + s.version = "0.3.2" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 6604edb9e2f8d0b86991835ad87efa1a2a339fc3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 16:48:22 -0500 Subject: [PATCH 169/460] Export XCTest --- SwiftCheck/TestOperators.swift | 2 +- SwiftCheckTests/BooleanIdentitySpec.swift | 1 - SwiftCheckTests/ComplexSpec.swift | 1 - SwiftCheckTests/DiscardSpec.swift | 1 - SwiftCheckTests/FailureSpec.swift | 1 - SwiftCheckTests/GenSpec.swift | 1 - SwiftCheckTests/ModifierSpec.swift | 1 - SwiftCheckTests/PropertySpec.swift | 1 - SwiftCheckTests/ShrinkSpec.swift | 1 - SwiftCheckTests/SimpleSpec.swift | 1 - SwiftCheckTests/TestSpec.swift | 1 - Tutorial.playground/Contents.swift | 1 - Tutorial.playground/contents.xcplayground | 2 +- 13 files changed, 2 insertions(+), 13 deletions(-) diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 1bd17ea..b92f114 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -117,4 +117,4 @@ public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } -import func XCTest.XCTFail +@exported import XCTest diff --git a/SwiftCheckTests/BooleanIdentitySpec.swift b/SwiftCheckTests/BooleanIdentitySpec.swift index db4820d..31d0ef9 100644 --- a/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/SwiftCheckTests/BooleanIdentitySpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class BooleanIdentitySpec : XCTestCase { diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 9661910..7ed026c 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -6,7 +6,6 @@ // Copyright © 2015 Robert Widmann. All rights reserved. // -import XCTest import SwiftCheck let upper : Gen= Gen.fromElementsIn("A"..."Z") diff --git a/SwiftCheckTests/DiscardSpec.swift b/SwiftCheckTests/DiscardSpec.swift index 10e867b..0c9e6fe 100644 --- a/SwiftCheckTests/DiscardSpec.swift +++ b/SwiftCheckTests/DiscardSpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class DiscardSpec : XCTestCase { diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 1676fe5..825bc61 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -7,7 +7,6 @@ // import SwiftCheck -import XCTest enum SwiftCheckError : ErrorType { case Bogus diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 8413bd7..671190a 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class GenSpec : XCTestCase { diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index cbb719b..01df868 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class ModifierSpec : XCTestCase { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 58e113b..f67da76 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class PropertySpec : XCTestCase { diff --git a/SwiftCheckTests/ShrinkSpec.swift b/SwiftCheckTests/ShrinkSpec.swift index e4b9b3f..eb63207 100644 --- a/SwiftCheckTests/ShrinkSpec.swift +++ b/SwiftCheckTests/ShrinkSpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck class ShrinkSpec : XCTestCase { diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index ab96cb9..0245252 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck public struct ArbitraryFoo { diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index ce5889c..d8a3c4e 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -6,7 +6,6 @@ // Copyright © 2015 TypeLift. All rights reserved. // -import XCTest import SwiftCheck extension Dictionary { diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index e539a07..e872d53 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -1,7 +1,6 @@ //: Playground - noun: a place where people can play import SwiftCheck -import XCTest //: # Prerequisites diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 6767221..b85a947 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 8ba9a7a96a4a307911406c36406a583a4c6bdbda Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 16:54:26 -0500 Subject: [PATCH 170/460] Crash tests no longer crash --- SwiftCheckTests/GenSpec.swift | 37 ++++++++++++++++---------------- SwiftCheckTests/SimpleSpec.swift | 1 - 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 671190a..454d19e 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -45,25 +45,24 @@ class GenSpec : XCTestCase { return forAll(g) { $0 == 0 } } -// This crashes swiftc. -// property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in -// if xss.isEmpty { -// return Discard() -// } -// let l = Set(xss) -// return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } -// } -// -// property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in -// return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } -// } -// -// property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in -// return (n1 < n2) ==> { -// let interval = n1...n2 -// return forAll(Gen.fromElementsOf(interval)) { interval.contains($0) } -// } -// } + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in + if xss.isEmpty { + return Discard() + } + let l = Set(xss) + return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } + } + + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in + return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } + } + + property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + return (n1 < n2) ==> { + let interval = n1...n2 + return forAll(Gen.fromElementsOf(n1...n2)) { interval.contains($0) } + } + } property("oneOf n") <- forAll { (xss : ArrayOf) in if xss.getArray.isEmpty { diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index 0245252..cbae1f7 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -27,7 +27,6 @@ extension ArbitraryFoo : Arbitrary { } } - class SimpleSpec : XCTestCase { func testAll() { property("Integer Equality is Reflexive") <- forAll { (i : Int8) in From fd885a88eae6b6eddf42551ff4dbfe03e3625010 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 17:54:51 -0500 Subject: [PATCH 171/460] Fix types for Gen and test --- SwiftCheck/Gen.swift | 19 +++++++-------- SwiftCheckTests/GenSpec.swift | 44 +++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 9ff67dd..93d23dd 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -54,23 +54,22 @@ public struct Gen { /// parameter. /// /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(xs : [A]) -> Gen { + public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") - let k = Double(xs.count) - return sized({ n in - let m = max(1, size(k)(m: n)) - return Gen.fromElementsOf(xs[0 ..< m]) + return Gen<[S]>.sized({ n in + let ss = xs[xs.startIndex...pure([S](ss)) }) } /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(xs : [A]) -> Gen<[A]> { + public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { if xs.isEmpty { - return Gen<[A]>.pure([]) + return Gen<[S]>.pure([]) } - return Gen<(A, [A])>.fromElementsOf(selectOne(xs)).bind { (y, ys) in + return Gen<(S, [S])>.fromElementsOf(selectOne(xs)).bind { (y, ys) in return Gen.fromShufflingElementsOf(ys).fmap { [y] + $0 } } } @@ -388,9 +387,9 @@ private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) - } } -private func size(k : Double)(m : Int) -> Int { +private func size(k : S)(m : Int) -> Int { let n = Double(m) - return Int((log(n + 1)) * k / log(100)) + return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } private func selectOne(xs : [A]) -> [(A, [A])] { diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 454d19e..a2acbb8 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -50,17 +50,31 @@ class GenSpec : XCTestCase { return Discard() } let l = Set(xss) - return forAll(Gen.fromElementsOf(xss)) { l.contains($0) } + return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } } property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } + return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } } - property("Gen.fromElementsOf only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in return (n1 < n2) ==> { let interval = n1...n2 - return forAll(Gen.fromElementsOf(n1...n2)) { interval.contains($0) } + return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } + } + } + + property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in + return !xs.isEmpty ==> { + return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in + return xs.startsWith(ys) + } + } + } + + property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in + return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in + return (xs.count == ys.count) ^&&^ (xs.sort() == ys.sort()) } } @@ -87,7 +101,27 @@ class GenSpec : XCTestCase { return $0.getArray.isEmpty } - property("Gen.suchThat in series obeys both predicates.") <- { + property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in + var n : Int = 0 + return forAll(Gen.sized { xx in + n = xx + return Int.arbitrary + }) { (x : Int) in + return x <= n + } + } + + property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in + var n : Int = 0 + return forAllNoShrink(Gen<[Int]>.sized { xx in + n = xx + return [Int].arbitrary + }) { (xs : [Int]) in + return xs.count <= n + } + } + + property("Gen.suchThat in series obeys both predicates") <- { let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) return forAll(g) { str in return !(str.isEmpty || str.rangeOfString(",") != nil) From f55e9a933e37baff2577eabf7d24421265509d82 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 18:24:33 -0500 Subject: [PATCH 172/460] Test monad laws --- SwiftCheckTests/GenSpec.swift | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index a2acbb8..b9a6397 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -142,4 +142,69 @@ class GenSpec : XCTestCase { } } } + + func testLaws() { + /// Turns out Gen is a really sketchy monad because of the underlying randomness. + let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) + let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) + + property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.fmap(id)) == id(x) + } + + property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAllNoShrink(lawfulGen) { (x : Gen) in + return ((f.getArrow • g.getArrow) <^> x) == (x.fmap(g.getArrow).fmap(f.getArrow)) + } + } + + property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (Gen.pure(id) <*> x) == x + } + + property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.fmap({ $0.getArrow }) + let g = gl.fmap({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.fmap({ $0.getArrow }) + let g = gl.fmap({ $0.getArrow }) + return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in + let f : Int -> Gen = Gen.pure • fa.getArrow + return (Gen.pure(a) >>- f) == f(a) + } + + property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in + return (m >>- Gen.pure) == m + } + + property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in + let f : Int -> Gen = Gen.pure • fa.getArrow + let g : Int -> Gen = Gen.pure • ga.getArrow + return forAllNoShrink(lawfulGen) { (m : Gen) in + return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) + } + } + } +} + +private func curry(f : (A, B) -> C) -> A -> B -> C { + return { a in { b in f(a, b) } } +} + +private func id(x : A) -> A { + return x +} + +private func • (f : B -> C, g : A -> B) -> A -> C { + return { f(g($0)) } +} + +private func ==(l : Gen, r : Gen) -> Bool { + return l.proliferateSized(10).generate == r.proliferateSized(10).generate } From 854f8c11c6bdd36b73e5559237cd5e4bee99bfc4 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 18:24:39 -0500 Subject: [PATCH 173/460] Fix resize tests --- SwiftCheckTests/GenSpec.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index b9a6397..0d06fe4 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -106,17 +106,17 @@ class GenSpec : XCTestCase { return forAll(Gen.sized { xx in n = xx return Int.arbitrary - }) { (x : Int) in + }.resize(n)) { (x : Int) in return x <= n } } property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in var n : Int = 0 - return forAllNoShrink(Gen<[Int]>.sized { xx in + return forAllNoShrink(Gen<[Int]>.sized({ xx in n = xx return [Int].arbitrary - }) { (xs : [Int]) in + }).resize(n)) { (xs : [Int]) in return xs.count <= n } } From 05fc3fc84a3fa596e76552037c06e5b559ffe067 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Nov 2015 21:41:21 -0500 Subject: [PATCH 174/460] Undo rendering mode changes --- Tutorial.playground/contents.xcplayground | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index b85a947..6bcaa60 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From 31deebaf336c5d6b40854bfd2f79ca85e40a2ab3 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 11 Nov 2015 21:29:23 -0800 Subject: [PATCH 175/460] Print the counterexample when a test case throws an error --- SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 1442486..702acb1 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -284,7 +284,7 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T do { return (try f(xs)).counterexample(String(xs)) } catch let e { - return TestResult.failed("Test case threw an exception: \"" + String(e) + "\"") + return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(xs)) } }).unProperty }) From 299676836e8a1c030f2d26262ff254579c32d024 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 12 Nov 2015 01:08:14 -0500 Subject: [PATCH 176/460] Make existential tests more conservative --- SwiftCheck/Test.swift | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 702acb1..50c9d4d 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -460,10 +460,8 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { // of success we're done. If no successes are found we've failed checking the // existential and report it as such. Otherwise turn the testing loop. case (.ExistentialFailure(_, _, _, _, _, _, _), _): - if fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests && fail.1.successfulTestCount == 0 { + if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { return reportExistentialFailure(fail.1, res: fail.0) - } else if fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { - return doneTesting(fail.1)(f: f) } else { state = fail.1 break @@ -536,7 +534,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): if quantifier == .Existential { - print("") +// print("") } else if !expect { print("+++ OK, failed as expected. ", terminator: "") } else { @@ -562,14 +560,18 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , shouldAbort: abort , quantifier: quantifier) - let resul = Result.ExistentialFailure(numTests: st.successfulTestCount + 1 - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount)(st.discardedTestCount) - , reason: "Could not satisfy existential" - , labels: summary(st) - , output: "*** Failed! " - , lastResult: res) - return .Left((resul, nstate)) + /// However, some existentials outlive their usefulness + if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { + let resul = Result.ExistentialFailure(numTests: st.successfulTestCount.successor() + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount)(st.discardedTestCount) + , reason: "Could not satisfy existential" + , labels: summary(st) + , output: "*** Failed! " + , lastResult: res) + return .Left((resul, nstate)) + } + return .Right(nstate) } // Attempt a shrink. From 2cca29f8af664b33a0dc31ddbe75c987bc078e49 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 11 Nov 2015 21:49:11 -0800 Subject: [PATCH 177/460] Give CheckerArguments default values Instead of merely documenting the defaults, actually provide defaults for the init arguments. This way clients can just say something like `CheckerArguments(maxAllowableSuccessfulTests: 200)` and they'll get the defaults for everything else. --- SwiftCheck/Check.swift | 20 ++++++++++---------- SwiftCheck/Test.swift | 6 +----- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 4e22ed4..b05b451 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -32,7 +32,7 @@ /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? stdArgs(msg)) + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } public struct AssertiveQuickCheck { @@ -52,7 +52,7 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest assert. The /// property will still generate console output during testing. public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? stdArgs(msg)) + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } public struct ReportiveQuickCheck { @@ -94,19 +94,19 @@ public struct CheckerArguments { /// it becomes too small the samples present in the test case will lose diversity. let maxTestCaseSize : Int - public init(replay : Optional<(StdGen, Int)> - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , maxTestCaseSize : Int + public init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 ) { self = CheckerArguments(replay: replay, maxAllowableSuccessfulTests: maxAllowableSuccessfulTests, maxAllowableDiscardedTests: maxAllowableDiscardedTests, maxTestCaseSize: maxTestCaseSize, name: "") } - internal init(replay : Optional<(StdGen, Int)> - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , maxTestCaseSize : Int + internal init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 , name : String ) { diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 702acb1..8ed07ef 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -328,15 +328,11 @@ public func exists(gen : Gen, pf : A throws -> Testable) -> Pr /// Tests a property and prints the results to stdout. public func quickCheck(prop : Testable, name : String = "") { - quickCheckWithResult(stdArgs(name), p: prop) + quickCheckWithResult(CheckerArguments(name: name), p: prop) } /// MARK: - Implementation Details -internal func stdArgs(name : String = "") -> CheckerArguments { - return CheckerArguments(replay: .None, maxAllowableSuccessfulTests: 100, maxAllowableDiscardedTests: 500, maxTestCaseSize: 100, name: name) -} - internal enum Result { case Success(numTests : Int , labels : [(String, Int)] From d9a4e0e27f8dd12f1ffe7f8ff83651b20aad3f55 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 12 Nov 2015 01:35:09 -0500 Subject: [PATCH 178/460] One last thing --- SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 01aa15c..7707f48 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -622,7 +622,7 @@ internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Res internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { printDistributionGraph(st) - return Result.GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of failed shrinks, From b5e19bd58f3143d0a1fe49bc2f2cf9e81df06250 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:17:58 -0500 Subject: [PATCH 179/460] Upgrade project --- SwiftCheck.xcodeproj/project.pbxproj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index b3075ef..2b0ae5a 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -9,10 +9,12 @@ /* Begin PBXBuildFile section */ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; - 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; settings = {ASSET_TAGS = (); }; }; - 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; settings = {ASSET_TAGS = (); }; }; + 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; + 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; + 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; + 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -98,6 +100,7 @@ 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; + 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; @@ -224,6 +227,7 @@ 8445C4A91B16D37800280089 /* GenSpec.swift */, 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, + 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, 8216BAB61B97775100A0D282 /* ComplexSpec.swift */, @@ -448,6 +452,7 @@ 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, + 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -487,6 +492,7 @@ 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, + 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */, 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From c9805226a41551733a445d955f58ea7449d6c3aa Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:18:18 -0500 Subject: [PATCH 180/460] Blatantly steal haskell's random stuff --- SwiftCheck/Arbitrary.swift | 52 +++++++++++++-------- SwiftCheck/Modifiers.swift | 7 --- SwiftCheck/Random.swift | 93 +++++++++++++++++++++++++++++++------- SwiftCheck/Test.swift | 2 +- 4 files changed, 110 insertions(+), 44 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 6730dab..df93f80 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -6,8 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import Darwin - /// A type that implements random generation and shrinking of values. /// /// While testing, SwiftCheck will invoke `arbitrary()` a given amount of times (usually 100 if the @@ -73,7 +71,7 @@ extension IntegerType { extension Bool : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { _ in Gen.pure((arc4random() % 2) == 1) } + return Gen.choose((false, true)) } public static func shrink(x : Bool) -> [Bool] { @@ -87,7 +85,7 @@ extension Bool : Arbitrary { extension Int : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in - return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int(arc4random_uniform(UInt32(n))) } + return Gen.choose((-n, n)) } } @@ -96,10 +94,18 @@ extension Int : Arbitrary { } } +//private func inBounds(fi : (Int -> A)) -> Gen -> Gen { +// return { g in +// return fi <^> g.suchThat { x in +// return (fi(x) as! A.IntegerLiteralType) == x +// } +// } +//} + extension Int8 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in - return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int8(arc4random_uniform(UInt32(n))) } + return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) } } @@ -111,7 +117,7 @@ extension Int8 : Arbitrary { extension Int16 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in - return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int16(arc4random_uniform(UInt32(n))) } + return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) } } @@ -123,7 +129,7 @@ extension Int16 : Arbitrary { extension Int32 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in - return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int32(arc4random_uniform(UInt32(n))) } + return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) } } @@ -135,7 +141,7 @@ extension Int32 : Arbitrary { extension Int64 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in - return Bool.arbitrary.fmap { ($0 ? 1 : -1) * Int64(arc4random_uniform(UInt32(n))) } + return Gen.choose((Int64(-n), Int64(n))) } } @@ -146,7 +152,7 @@ extension Int64 : Arbitrary { extension UInt : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { n in Gen.pure(UInt(arc4random_uniform(UInt32(abs(n))))) } + return Gen.sized { n in Gen.choose((0, UInt(n))) } } public static func shrink(x : UInt) -> [UInt] { @@ -157,7 +163,7 @@ extension UInt : Arbitrary { extension UInt8 : Arbitrary { public static var arbitrary : Gen { return Gen.sized({ n in - return Gen.sized { n in Gen.pure(UInt8(arc4random_uniform(UInt32(abs(n))))) } + return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } }) } @@ -168,7 +174,7 @@ extension UInt8 : Arbitrary { extension UInt16 : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { n in Gen.pure(UInt16(arc4random_uniform(UInt32(abs(n))))) } + return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } } public static func shrink(x : UInt16) -> [UInt16] { @@ -178,7 +184,7 @@ extension UInt16 : Arbitrary { extension UInt32 : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { n in Gen.pure(arc4random_uniform(UInt32(abs(n)))) } + return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } } public static func shrink(x : UInt32) -> [UInt32] { @@ -188,7 +194,7 @@ extension UInt32 : Arbitrary { extension UInt64 : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { n in Gen.pure(UInt64(arc4random_uniform(UInt32(abs(n))))) } + return Gen.sized { n in Gen.choose((0, UInt64(n))) } } public static func shrink(x : UInt64) -> [UInt64] { @@ -198,12 +204,16 @@ extension UInt64 : Arbitrary { extension Float : Arbitrary { public static var arbitrary : Gen { - return Gen.sized({ n in + let precision = 9999999999999 + + return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen.pure(Float(-n) + Float(arc4random()) / Float(UINT32_MAX / UInt32((n)*2))) - }) + return Gen<(Int, Int)>.zip(Gen.choose(((-n) * precision, n * precision)), Gen.choose((1, precision))) >>- { (a, b) in + return Gen.pure(Float(a) / Float(b)) + } + } } public static func shrink(x : Float) -> [Float] { @@ -219,12 +229,16 @@ extension Float : Arbitrary { extension Double : Arbitrary { public static var arbitrary : Gen { - return Gen.sized({ n in + let precision = 9999999999999 + + return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen.pure(Double(-n) + Double(arc4random()) / Double(UINT32_MAX / UInt32(n*2))) - }) + return Gen<(Int, Int)>.zip(Gen.choose(((-n) * precision, n * precision)), Gen.choose((1, precision))) >>- { (a, b) in + return Gen.pure(Double(a) / Double(b)) + } + } } public static func shrink(x : Double) -> [Double] { diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 8e47270..74f06eb 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -475,10 +475,3 @@ extension NonNegative : CoArbitrary { } } -private func inBounds(fi : (Int -> A)) -> Gen -> Gen { - return { g in - return fi <^> g.suchThat { x in - return (fi(x) as! Int) == x - } - } -} diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 28d4c80..28c3824 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -7,7 +7,7 @@ // import func Darwin.time -import func Darwin.rand +import func Darwin.clock /// Provides a standard interface to an underlying Random Value Generator of any type. It is /// analogous to `GeneratorType`, but rather than consume a sequence it uses sources of randomness @@ -25,24 +25,51 @@ public protocol RandomGeneneratorType { } /// A library-provided standard random number generator. -public let standardRNG : StdGen = StdGen(time(nil)) +public let standardRNG : StdGen = mkStdRNG(time(nil)) +/// public struct StdGen : RandomGeneneratorType { - let seed: Int + let seed1 : Int + let seed2 : Int + + /// Creates a + public init(replaySeed : Int) { + func mkStdGen32(sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen((s1+1), (s2+1)) + } + self = mkStdGen32(replaySeed) + } - init(_ seed : Int) { - self.seed = seed + init(_ seed1 : Int, _ seed2 : Int) { + self.seed1 = seed1 + self.seed2 = seed2 } public var next : (Int, StdGen) { - let s = Int(time(nil)) - return (Int(rand()), StdGen(s)) + let s1 = self.seed1 + let s2 = self.seed2 + + let k = s1 / 53668 + let s1_ = 40014 * (s1 - k * 53668) - k * 12211 + let s1__ = s1_ < 0 ? s1_ + 2147483563 : s1_ + + let k_ = s2 / 52774 + let s2_ = 40692 * (s2 - k_ * 52774) - k_ * 3791 + let s2__ = s2_ < 0 ? s2_ + 2147483399 : s2_ + + let z = s1__ - s2__ + let z_ = z < 1 ? z + 2147483562 : z + return (z_, StdGen(s1__, s2__)) } public var split : (StdGen, StdGen) { - let (s1, g) = self.next - let (s2, _) = g.next - return (StdGen(s1), StdGen(s2)) + let s1 = self.seed1 + let s2 = self.seed2 + let std = self.next.1 + return (StdGen(s1 == 2147483562 ? 1 : s1 + 1, std.seed2), StdGen(std.seed1, s2 == 1 ? 2147483398 : s2 - 1)) } public var genRange : (Int, Int) { @@ -54,10 +81,6 @@ public func newStdGen() -> StdGen { return standardRNG.split.1 } -private func mkStdRNG(seed : Int) -> StdGen { - return StdGen(seed) -} - /// Types that can generate random versions of themselves. public protocol RandomType { static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) @@ -68,6 +91,13 @@ public func random, G : RandomGeneneratorT return A.randomInRange((A.min, A.max), gen: gen) } +extension Bool : RandomType { + public static func randomInRange(range: (Bool, Bool), gen: G) -> (Bool, G) { + let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) + return (x == 1, gg) + } +} + extension Character : RandomType { public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range @@ -150,7 +180,7 @@ extension UInt8 : RandomType { public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt8(r) % ((max + 1) - min)) + min; + let result = (UInt8(truncatingBitPattern: r) % ((max + 1) - min)) + min; return (result, g); } @@ -160,7 +190,7 @@ extension UInt16 : RandomType { public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt16(r) % ((max + 1) - min)) + min; + let result = (UInt16(truncatingBitPattern: r) % ((max + 1) - min)) + min; return (result, g); } @@ -170,7 +200,7 @@ extension UInt32 : RandomType { public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt32(r) % ((max + 1) - min)) + min; + let result = (UInt32(truncatingBitPattern: r) % ((max + 1) - min)) + min; return (result, g); } @@ -207,3 +237,32 @@ extension Double : RandomType { return (result, g); } } + +/// Implementation Details Follow + +private func mkStdRNG(o : Int) -> StdGen { + func mkStdGen32(sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen(s1+1, s2+1) + } + + let ct = Int(clock()) + var tt = timespec() + clock_gettime(0, &tt); + let (sec, psec) = (tt.tv_sec, tt.tv_nsec) + return mkStdGen32(Int(sec) * 12345 + psec + ct + o) +} + +private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { + var now : timeval = timeval() + let rv = gettimeofday(&now, nil) + if rv != 0 { + return Int(rv) + } + t.memory.tv_sec = now.tv_sec + t.memory.tv_nsec = Int(now.tv_usec) * 1000 + + return 0; +} diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 7707f48..146925b 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -358,7 +358,7 @@ internal enum Result { , output : String , lastResult : TestResult ) - case NoExpectedFailure(numTests : Int + case NoExpectedFailure(numTests : Int , labels : [(String,Int)] , output : String ) From 4ea988eb64d0470a9dae2d18de1b7e5bb742cbda Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:18:29 -0500 Subject: [PATCH 181/460] Test replays --- SwiftCheckTests/ReplaySpec.swift | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 SwiftCheckTests/ReplaySpec.swift diff --git a/SwiftCheckTests/ReplaySpec.swift b/SwiftCheckTests/ReplaySpec.swift new file mode 100644 index 0000000..fb8b962 --- /dev/null +++ b/SwiftCheckTests/ReplaySpec.swift @@ -0,0 +1,30 @@ +// +// ReplaySpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 11/18/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +import SwiftCheck + +class ReplaySpec : XCTestCase { + func testProperties() { + property("Test is replayed at specific args") <- forAll { (seed : Int, size : Int) in + let replayArgs = CheckerArguments(replay: .Some(StdGen(replaySeed: seed), size)) + var foundArgs : [Int] = [] + property("Replay at \(seed), \(size)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs.append(x) + return true + } + + var foundArgs2 : [Int] = [] + property("Replay at \(seed), \(size)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs2.append(x) + return foundArgs.contains(x) + } + + return foundArgs == foundArgs2 + } + } +} \ No newline at end of file From a58ca3dfe4b4254bd5d671c6739ec40105cc3b96 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:19:13 -0500 Subject: [PATCH 182/460] Remove extra copy of unneeded function --- SwiftCheck/Arbitrary.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index df93f80..298f9ed 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -94,14 +94,6 @@ extension Int : Arbitrary { } } -//private func inBounds(fi : (Int -> A)) -> Gen -> Gen { -// return { g in -// return fi <^> g.suchThat { x in -// return (fi(x) as! A.IntegerLiteralType) == x -// } -// } -//} - extension Int8 : Arbitrary { public static var arbitrary : Gen { return Gen.sized { n in From 3097cbef7408ac3022f82ac81579fa7a58dbf964 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:20:58 -0500 Subject: [PATCH 183/460] newline --- SwiftCheckTests/ReplaySpec.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheckTests/ReplaySpec.swift b/SwiftCheckTests/ReplaySpec.swift index fb8b962..520e173 100644 --- a/SwiftCheckTests/ReplaySpec.swift +++ b/SwiftCheckTests/ReplaySpec.swift @@ -27,4 +27,4 @@ class ReplaySpec : XCTestCase { return foundArgs == foundArgs2 } } -} \ No newline at end of file +} From 008a294791fd81ccc8cae1244aa9d6d69020ed04 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:24:54 -0500 Subject: [PATCH 184/460] Use diff fence in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ac55f4..0fac48f 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ Test Case '-[SwiftCheckTests.PrimeSpec testAll]' started. Indicating that our sieve has failed on the input number 4. A quick look back at the comments describing the sieve reveals the mistake immediately: -``` +```diff - for i in stride(from: 2 * p, to: n, by: p) { + for i in stride(from: 2 * p, through: n, by: p) { ``` From bf084c3ff8fabd481d18c5c5851cedd33d2e9742 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:38:02 -0500 Subject: [PATCH 185/460] Fix precision on 32-bit arches --- SwiftCheck/Arbitrary.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 298f9ed..174b8c9 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -196,7 +196,11 @@ extension UInt64 : Arbitrary { extension Float : Arbitrary { public static var arbitrary : Gen { - let precision = 9999999999999 + #if !(arch(x86_64) || arch(arm64)) + let precision : Int = 999999999 + #else + let precision : Int = 9999999999999 + #endif return Gen.sized { n in if n == 0 { @@ -221,7 +225,11 @@ extension Float : Arbitrary { extension Double : Arbitrary { public static var arbitrary : Gen { - let precision = 9999999999999 + #if !(arch(x86_64) || arch(arm64)) + let precision : Int = 999999999 + #else + let precision : Int = 9999999999999 + #endif return Gen.sized { n in if n == 0 { From b390d80cd8092a9db1323e0c43819759e95760a6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:38:32 -0500 Subject: [PATCH 186/460] Fix type annotation --- SwiftCheck/Arbitrary.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 174b8c9..3cdf03a 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -144,7 +144,7 @@ extension Int64 : Arbitrary { extension UInt : Arbitrary { public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt(n))) } + return Gen.sized { n in Gen.choose((0, UInt(n))) } } public static func shrink(x : UInt) -> [UInt] { From 512ad932de480952a3c9acdd64e9356eec545279 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:51:07 -0500 Subject: [PATCH 187/460] Golf --- SwiftCheck/Arbitrary.swift | 6 +++--- SwiftCheck/Property.swift | 8 ++++---- SwiftCheck/Test.swift | 4 ++-- SwiftCheck/Testable.swift | 2 +- SwiftCheckTests/FailureSpec.swift | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 3cdf03a..29994c7 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -154,9 +154,9 @@ extension UInt : Arbitrary { extension UInt8 : Arbitrary { public static var arbitrary : Gen { - return Gen.sized({ n in + return Gen.sized { n in return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } - }) + } } public static func shrink(x : UInt8) -> [UInt8] { @@ -265,7 +265,7 @@ extension UnicodeScalar : Arbitrary { extension String : Arbitrary { public static var arbitrary : Gen { - let chars = Gen.sized({ n in Character.arbitrary.proliferateSized(n) }) + let chars = Gen.sized(Character.arbitrary.proliferateSized) return chars >>- (Gen.pure • String.init) } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index df324d3..d9521d7 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -58,9 +58,9 @@ extension Testable { /// Applies a function that modifies the property generator's size. public func mapSize(f : Int -> Int) -> Property { - return Property(Gen.sized({ n in + return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) - })) + }) } /// Applies a function that modifies the result of a test case. @@ -79,9 +79,9 @@ extension Testable { /// Applies a function that modifies the underlying Rose Tree that a test case has generated. public func mapRoseResult(f : Rose -> Rose) -> Property { - return self.mapProp({ t in + return self.mapProp { t in return Prop(unProp: f(t.unProp)) - }) + } } /// Modifies a property so it will not shrink when it fails. diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 146925b..c79e94b 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -653,7 +653,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts while cont { /// If we're out of branches we're out of options. if branches.isEmpty { - break; + break } cont = false @@ -672,7 +672,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts lastResult = res1 branches = ts1() cont = true - break; + break } // Otherwise increment the tried shrink counter and the failed shrink counter. diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index 814a4c6..e36d0f7 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -35,7 +35,7 @@ public struct Property : Testable { let unProperty : Gen public init(_ val : Gen) { - self.unProperty = val; + self.unProperty = val } public var property : Property { diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 825bc61..1736928 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -49,10 +49,10 @@ class FailureSpec : XCTestCase { /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) override func recordFailureWithDescription(message : String, inFile file : String, atLine line : UInt, expected : Bool) { if !expected { - assert(false, "Assertion should never throw."); + assert(false, "Assertion should never throw.") } else { // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) - failCount++; + failCount++ } } From 658f0b4da5952ea66b87bba4f2a61f58f24647bd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 17:53:25 -0500 Subject: [PATCH 188/460] Remove semicolons --- SwiftCheck/Random.swift | 55 +++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 28c3824..61c253b 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -120,9 +120,9 @@ extension Int : RandomType { public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (min, max) = range let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min; + let result = (r % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -130,9 +130,9 @@ extension Int8 : RandomType { public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (min, max) = range let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min; + let result = (r % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -140,9 +140,9 @@ extension Int16 : RandomType { public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (min, max) = range let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min; + let result = (r % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -150,9 +150,9 @@ extension Int32 : RandomType { public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (min, max) = range let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min; + let result = (r % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -160,9 +160,9 @@ extension Int64 : RandomType { public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { let (min, max) = range let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min; + let result = (r % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -170,9 +170,9 @@ extension UInt : RandomType { public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt(r) % ((max + 1) - min)) + min; + let result = (UInt(r) % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -180,9 +180,9 @@ extension UInt8 : RandomType { public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt8(truncatingBitPattern: r) % ((max + 1) - min)) + min; + let result = (UInt8(truncatingBitPattern: r) % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -190,9 +190,9 @@ extension UInt16 : RandomType { public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt16(truncatingBitPattern: r) % ((max + 1) - min)) + min; + let result = (UInt16(truncatingBitPattern: r) % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -200,9 +200,9 @@ extension UInt32 : RandomType { public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt32(truncatingBitPattern: r) % ((max + 1) - min)) + min; + let result = (UInt32(truncatingBitPattern: r) % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -210,9 +210,9 @@ extension UInt64 : RandomType { public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { let (min, max) = range let (r, g) = gen.next - let result = (UInt64(r) % ((max + 1) - min)) + min; + let result = (UInt64(r) % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -221,9 +221,9 @@ extension Float : RandomType { let (min, max) = range let (r, g) = gen.next let fr = Float(r) - let result = (fr % ((max + 1) - min)) + min; + let result = (fr % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -232,9 +232,9 @@ extension Double : RandomType { let (min, max) = range let (r, g) = gen.next let dr = Double(r) - let result = (dr % ((max + 1) - min)) + min; + let result = (dr % ((max + 1) - min)) + min - return (result, g); + return (result, g) } } @@ -250,9 +250,10 @@ private func mkStdRNG(o : Int) -> StdGen { let ct = Int(clock()) var tt = timespec() - clock_gettime(0, &tt); + clock_gettime(0, &tt) let (sec, psec) = (tt.tv_sec, tt.tv_nsec) - return mkStdGen32(Int(sec) * 12345 + psec + ct + o) + let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) + return mkStdGen32(ll + psec + ct + o) } private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { @@ -264,5 +265,5 @@ private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int t.memory.tv_sec = now.tv_sec t.memory.tv_nsec = Int(now.tv_usec) * 1000 - return 0; + return 0 } From 514985299120ed2938bad52e74e13130ac4664d3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 18:05:13 -0500 Subject: [PATCH 189/460] Standardize around 64-bit values --- SwiftCheck/Arbitrary.swift | 16 ++++------------ SwiftCheck/Random.swift | 33 +++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 29994c7..96ebd4b 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -196,17 +196,13 @@ extension UInt64 : Arbitrary { extension Float : Arbitrary { public static var arbitrary : Gen { - #if !(arch(x86_64) || arch(arm64)) - let precision : Int = 999999999 - #else - let precision : Int = 9999999999999 - #endif + let precision : Int64 = 9999999999999 return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen<(Int, Int)>.zip(Gen.choose(((-n) * precision, n * precision)), Gen.choose((1, precision))) >>- { (a, b) in + return Gen<(Int64, Int64)>.zip(Gen.choose((Int64(-n) * precision, Int64(n) * precision)), Gen.choose((1, precision))) >>- { (a, b) in return Gen.pure(Float(a) / Float(b)) } } @@ -225,17 +221,13 @@ extension Float : Arbitrary { extension Double : Arbitrary { public static var arbitrary : Gen { - #if !(arch(x86_64) || arch(arm64)) - let precision : Int = 999999999 - #else - let precision : Int = 9999999999999 - #endif + let precision : Int64 = 9999999999999 return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen<(Int, Int)>.zip(Gen.choose(((-n) * precision, n * precision)), Gen.choose((1, precision))) >>- { (a, b) in + return Gen<(Int64, Int64)>.zip(Gen.choose((Int64(-n) * precision, Int64(n) * precision)), Gen.choose((1, precision))) >>- { (a, b) in return Gen.pure(Double(a) / Double(b)) } } diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 61c253b..302f88e 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -118,49 +118,54 @@ extension UnicodeScalar : RandomType { extension Int : RandomType { public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { - let (min, max) = range + let (minl, maxl) = range + let (min, max) = (Int64(minl), Int64(maxl)) let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min + let result = (Int64(r) % ((max + 1) - min)) + min - return (result, g) + return (Int(truncatingBitPattern: result), g) } } extension Int8 : RandomType { public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { - let (min, max) = range + let (minl, maxl) = range + let (min, max) = (Int64(minl), Int64(maxl)) let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min + let result = (Int64(r) % ((max + 1) - min)) + min - return (result, g) + return (Int8(truncatingBitPattern: result), g) } } extension Int16 : RandomType { public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { - let (min, max) = range + let (minl, maxl) = range + let (min, max) = (Int64(minl), Int64(maxl)) let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min + let result = (Int64(r) % ((max + 1) - min)) + min - return (result, g) + return (Int16(truncatingBitPattern: result), g) } } extension Int32 : RandomType { public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { - let (min, max) = range + let (minl, maxl) = range + let (min, max) = (Int64(minl), Int64(maxl)) let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min + let result = (Int64(r) % ((max + 1) - min)) + min - return (result, g) + return (Int32(truncatingBitPattern: result), g) } } extension Int64 : RandomType { public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { - let (min, max) = range + let (minl, maxl) = range + let (min, max) = (Int64(minl), Int64(maxl)) let (r, g) = gen.next - let result = (r % ((max + 1) - min)) + min + let result = (Int64(r) % ((max + 1) - min)) + min return (result, g) } From 8b1f13180220a76b50c357e9cfbaa66342752375 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 18:10:44 -0500 Subject: [PATCH 190/460] Document random --- SwiftCheck/Random.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 302f88e..06baad5 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -27,18 +27,21 @@ public protocol RandomGeneneratorType { /// A library-provided standard random number generator. public let standardRNG : StdGen = mkStdRNG(time(nil)) -/// +/// `StdGen` represents a pseudo-random number generator. The library makes it possible to generate +/// repeatable results, by starting with a specified initial random number generator, or to get +/// different results on each run by using the system-initialised generator or by supplying a seed +/// from some other source. public struct StdGen : RandomGeneneratorType { let seed1 : Int let seed2 : Int - /// Creates a + /// Creates a `StdGen` initialized at the given seed. public init(replaySeed : Int) { func mkStdGen32(sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 - return StdGen((s1+1), (s2+1)) + return StdGen((s1 + 1), (s2 + 1)) } self = mkStdGen32(replaySeed) } From 48a112204e94f6019abc0dea10482c2e5eba4c25 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 18:19:25 -0500 Subject: [PATCH 191/460] Print seeds in verbose mode --- SwiftCheck/Property.swift | 1 + SwiftCheck/Random.swift | 19 ++++++++++++------- SwiftCheckTests/ReplaySpec.swift | 8 ++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index d9521d7..b8d10a4 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -183,6 +183,7 @@ extension Testable { case .Some(false): print("\nFailed: ", terminator: "") printLabels(res) + print("Pass the seed values \(st.randomSeedGenerator) to replay the test.") default: print("\nDiscarded: ", terminator: "") printLabels(res) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 06baad5..7d4a69e 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -31,24 +31,29 @@ public let standardRNG : StdGen = mkStdRNG(time(nil)) /// repeatable results, by starting with a specified initial random number generator, or to get /// different results on each run by using the system-initialised generator or by supplying a seed /// from some other source. -public struct StdGen : RandomGeneneratorType { +public struct StdGen : RandomGeneneratorType, CustomStringConvertible { let seed1 : Int let seed2 : Int - /// Creates a `StdGen` initialized at the given seed. - public init(replaySeed : Int) { + /// Creates a `StdGen` initialized at the given seeds that is suitable for replaying of tests. + public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { + self.seed1 = replaySeed1 + self.seed2 = replaySeed2 + } + + /// Convenience to create a `StdGen` from a given integer. + public init(_ o : Int) { func mkStdGen32(sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 return StdGen((s1 + 1), (s2 + 1)) } - self = mkStdGen32(replaySeed) + self = mkStdGen32(o) } - init(_ seed1 : Int, _ seed2 : Int) { - self.seed1 = seed1 - self.seed2 = seed2 + public var description : String { + return "\(self.seed1) \(self.seed2)" } public var next : (Int, StdGen) { diff --git a/SwiftCheckTests/ReplaySpec.swift b/SwiftCheckTests/ReplaySpec.swift index 520e173..a711d61 100644 --- a/SwiftCheckTests/ReplaySpec.swift +++ b/SwiftCheckTests/ReplaySpec.swift @@ -10,16 +10,16 @@ import SwiftCheck class ReplaySpec : XCTestCase { func testProperties() { - property("Test is replayed at specific args") <- forAll { (seed : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .Some(StdGen(replaySeed: seed), size)) + property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in + let replayArgs = CheckerArguments(replay: .Some(StdGen(seedl, seedr), size)) var foundArgs : [Int] = [] - property("Replay at \(seed), \(size)", arguments: replayArgs) <- forAll { (x : Int) in + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in foundArgs.append(x) return true } var foundArgs2 : [Int] = [] - property("Replay at \(seed), \(size)", arguments: replayArgs) <- forAll { (x : Int) in + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in foundArgs2.append(x) return foundArgs.contains(x) } From bb7d4521f79c8b13be0b95db38937325f2141ac4 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 18:34:27 -0500 Subject: [PATCH 192/460] Add some newlines --- SwiftCheck/Property.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index b8d10a4..655d010 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -183,7 +183,7 @@ extension Testable { case .Some(false): print("\nFailed: ", terminator: "") printLabels(res) - print("Pass the seed values \(st.randomSeedGenerator) to replay the test.") + print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") default: print("\nDiscarded: ", terminator: "") printLabels(res) From 8de263ef060782e02d835ea82a720218f9116f8e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 19:18:01 -0500 Subject: [PATCH 193/460] Assert with replay tokens along with failing test. --- SwiftCheck/TestOperators.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index b92f114..c00b721 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -11,8 +11,8 @@ infix operator <- {} /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { switch quickCheckWithResult(checker.args, p: test()) { - case let .Failure(_, _, _, _, reason, _, _): - XCTFail(reason, file: checker.file, line: checker.line) + case let .Failure(_, sz, seed, _, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) default: @@ -23,8 +23,8 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { switch quickCheckWithResult(checker.args, p: test()) { - case let .Failure(_, _, _, _, reason, _, _): - XCTFail(reason, file: checker.file, line: checker.line) + case let .Failure(_, sz, seed, _, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) default: From fa7586af49453e6982dc8d37583bd2d8179d07fd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 18 Nov 2015 19:33:06 -0500 Subject: [PATCH 194/460] Bump pod spec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index edca611..743440e 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.3.2" + s.version = "0.4.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From b1d710f8c00750919a619f6098e7716690ce1ce4 Mon Sep 17 00:00:00 2001 From: Denis Fileev Date: Thu, 19 Nov 2015 20:32:47 +0300 Subject: [PATCH 195/460] Fixes email tld generator predicate --- Tutorial.playground/Contents.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index e872d53..f8c71e0 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -263,9 +263,7 @@ let hostname = Gen.oneOf([ //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. -// Email addresses ending in '.' are invalid. -// ------------------------------------ -let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) +let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) //: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how //: about some glue? From 0465b2b317a4309122ffd3622b62b86df26c05a5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:38:10 -0500 Subject: [PATCH 196/460] move undefined --- SwiftCheck/Modifiers.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 74f06eb..2c28b48 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -369,10 +369,6 @@ extension IsoOf : CustomReflectable { } } -private func undefined() -> A { - fatalError("") -} - public struct Large> : Arbitrary { public let getLarge : A @@ -475,3 +471,7 @@ extension NonNegative : CoArbitrary { } } +private func undefined() -> A { + fatalError("") +} + From c77d7b4355b10c46f89946b310f815c40856acdd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:38:22 -0500 Subject: [PATCH 197/460] Fix retain cycle in IsoOf --- SwiftCheck/Modifiers.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 2c28b48..ee40c54 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -286,7 +286,7 @@ extension ArrowOf : CustomReflectable { } /// Generates two isomorphic Swift function from T to U and back again. -public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { +public final class IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { private var table : Dictionary private var embed : T -> U private var project : U -> T @@ -305,25 +305,25 @@ public struct IsoOf, U : protocol self.project = project } - public init(_ embed : (T -> U), _ project : (U -> T)) { + public convenience init(_ embed : (T -> U), _ project : (U -> T)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - self.embed = { t in - if let v = self.table[t] { + self.embed = { [weak self] t in + if let v = self!.table[t] { return v } let y = embed(t) - self.table[t] = y + self!.table[t] = y return y } - self.project = { u in - let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self.table[k] { + self.project = { [weak self] u in + let ts = self!.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, _ = self!.table[k] { return k } let y = project(u) - self.table[y] = u + self!.table[y] = u return y } } From 6e2520ee927bee907403c386de34754552f5a822 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:38:35 -0500 Subject: [PATCH 198/460] Fix retain cycle in ArrowOf --- SwiftCheck/Modifiers.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index ee40c54..1b5f4e5 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -227,7 +227,7 @@ extension SetOf : CoArbitrary { } /// Generates a Swift function from T to U. -public struct ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { +public final class ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { private var table : Dictionary private var arr : T -> U public var getArrow : T -> U { @@ -239,15 +239,15 @@ public struct ArrowOf, U : Arbitrary> : Arbi self.arr = arr } - public init(_ arr : (T -> U)) { + public convenience init(_ arr : (T -> U)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - self.arr = { x in - if let v = self.table[x] { + self.arr = { [weak self] x in + if let v = self!.table[x] { return v } let y = arr(x) - self.table[x] = y + self!.table[x] = y return y } } @@ -257,9 +257,9 @@ public struct ArrowOf, U : Arbitrary> : Arbi } public static var arbitrary : Gen> { - return ArrowOf.init <^> promote({ a in + return ArrowOf.init <^> promote { a in return T.coarbitrary(a)(U.arbitrary) - }) + } } public static func shrink(f : ArrowOf) -> [ArrowOf] { From 0a44c3d43ea4e6c1dafb424762390dd7ad148fbb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:38:46 -0500 Subject: [PATCH 199/460] Implement PointerOf --- SwiftCheck/Modifiers.swift | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 1b5f4e5..5e75bd2 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -226,6 +226,43 @@ extension SetOf : CoArbitrary { } } +/// Generates pointers of varying size of random values of type T. +public final class PointerOf : Arbitrary { + private var ptr : UnsafeMutablePointer + public let size : Int + + public var getPointer : UnsafePointer { + return UnsafePointer(self.ptr) + } + + public var description : String { + return "\(self.ptr)" + } + + private init(_ ptr : UnsafeMutablePointer, _ size : Int) { + self.ptr = ptr + self.size = size + } + + deinit { + if self.size > 0 && self.ptr != nil { + self.ptr.dealloc(self.size) + self.ptr = nil + } + } + + public static var arbitrary : Gen> { + return Gen.sized { n in + if n <= 0 { + return Gen.pure(PointerOf(nil, 0)) + } + let pt = UnsafeMutablePointer.alloc(n) + let gt = pt.initializeFrom <^> sequence(Array((0.., U : Arbitrary> : Arbitrary, CustomStringConvertible { private var table : Dictionary From 4a25b601bf51e988e1a8200b7f76d31401b6b39c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:38:53 -0500 Subject: [PATCH 200/460] Add pointer test --- SwiftCheckTests/ModifierSpec.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index 01df868..d564cdb 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -18,6 +18,10 @@ class ModifierSpec : XCTestCase { return Static.shrink(x).isEmpty } + property("Pointers behave") <- forAll { (x : PointerOf) in + return x.getPointer == nil || x.size != 0 + } + property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in return x.getPositive > 0 } From 9678794c58a6e981661320b76ec77b63154b68c1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 14:43:47 -0500 Subject: [PATCH 201/460] Patch tutorial --- Tutorial.playground/Contents.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index f8c71e0..f78a473 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -250,8 +250,10 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ //: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` //: to get a `String` back. -let localEmail = allowedLocalCharacters.proliferateNonEmpty().fmap(String.init) - +let localEmail = allowedLocalCharacters + .proliferateNonEmpty() // Make a non-empty array of characters + .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. + .fmap(String.init) // Then make a string. //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine both steps into one big generator. From f0fac924850dfd100abc797e11a7c4be700a8f44 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 15:09:08 -0500 Subject: [PATCH 202/460] Return value semantics to arrow and iso of --- SwiftCheck/Modifiers.swift | 261 ++++++++++++++++++++----------------- 1 file changed, 144 insertions(+), 117 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 5e75bd2..3b1baa2 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -264,145 +264,40 @@ public final class PointerOf : Arbitrary { } /// Generates a Swift function from T to U. -public final class ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { - private var table : Dictionary - private var arr : T -> U - public var getArrow : T -> U { - return self.arr - } +public struct ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { + private let _impl : ArrowOfImpl - private init (_ table : Dictionary, _ arr : (T -> U)) { - self.table = table - self.arr = arr - } - - public convenience init(_ arr : (T -> U)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - - self.arr = { [weak self] x in - if let v = self!.table[x] { - return v - } - let y = arr(x) - self!.table[x] = y - return y - } + public var getArrow : T -> U { + return self._impl.arr } public var description : String { - return "\(T.self) -> \(U.self)" + return self._impl.description } public static var arbitrary : Gen> { - return ArrowOf.init <^> promote { a in - return T.coarbitrary(a)(U.arbitrary) - } - } - - public static func shrink(f : ArrowOf) -> [ArrowOf] { - return f.table.flatMap { (x, y) in - return U.shrink(y).map({ (y2 : U) -> ArrowOf in - return ArrowOf({ (z : T) -> U in - if x == z { - return y2 - } - return f.arr(z) - }) - }) - } - } -} - -extension ArrowOf : CustomReflectable { - public func customMirror() -> Mirror { - return Mirror(self, children: [ - "types": "\(T.self) -> \(U.self)", - "currentMap": self.table, - ]) + return ArrowOfImpl.arbitrary.fmap(ArrowOf.init) } } /// Generates two isomorphic Swift function from T to U and back again. -public final class IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { - private var table : Dictionary - private var embed : T -> U - private var project : U -> T +public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { + private let _impl : IsoOfImpl public var getTo : T -> U { - return embed + return self._impl.embed } public var getFrom : U -> T { - return project - } - - private init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { - self.table = table - self.embed = embed - self.project = project - } - - public convenience init(_ embed : (T -> U), _ project : (U -> T)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - - self.embed = { [weak self] t in - if let v = self!.table[t] { - return v - } - let y = embed(t) - self!.table[t] = y - return y - } - - self.project = { [weak self] u in - let ts = self!.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self!.table[k] { - return k - } - let y = project(u) - self!.table[y] = u - return y - } + return self._impl.project } public var description : String { - return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" + return self._impl.description } public static var arbitrary : Gen> { - return Gen<(T -> U, U -> T)>.zip(promote({ a in - return T.coarbitrary(a)(U.arbitrary) - }), promote({ a in - return U.coarbitrary(a)(T.arbitrary) - })).fmap { IsoOf($0, $1) } - } - - public static func shrink(f : IsoOf) -> [IsoOf] { - return f.table.flatMap { (x, y) in - return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOf in - return IsoOf({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) - }, { (z : U) -> T in - if y == z { - return y1 - } - return f.project(z) - }) - }) - } - } -} - -extension IsoOf : CustomReflectable { - public func customMirror() -> Mirror { - return Mirror(self, children: [ - "embed": "\(T.self) -> \(U.self)", - "project": "\(U.self) -> \(T.self)", - "currentMap": self.table, - ]) + return IsoOfImpl.arbitrary.fmap(IsoOf.init) } } @@ -508,7 +403,139 @@ extension NonNegative : CoArbitrary { } } +/// Implementation Details + private func undefined() -> A { fatalError("") } +private final class ArrowOfImpl, U : Arbitrary> : Arbitrary, CustomStringConvertible { + private var table : Dictionary + private var arr : T -> U + + init (_ table : Dictionary, _ arr : (T -> U)) { + self.table = table + self.arr = arr + } + + convenience init(_ arr : (T -> U)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }) + + self.arr = { [weak self] x in + if let v = self!.table[x] { + return v + } + let y = arr(x) + self!.table[x] = y + return y + } + } + + var description : String { + return "\(T.self) -> \(U.self)" + } + + static var arbitrary : Gen> { + return ArrowOfImpl.init <^> promote { a in + return T.coarbitrary(a)(U.arbitrary) + } + } + + static func shrink(f : ArrowOfImpl) -> [ArrowOfImpl] { + return f.table.flatMap { (x, y) in + return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in + return ArrowOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.arr(z) + }) + }) + } + } +} + +extension ArrowOfImpl : CustomReflectable { + func customMirror() -> Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self.table, + ]) + } +} + +private final class IsoOfImpl, U : protocol> : Arbitrary, CustomStringConvertible { + var table : Dictionary + var embed : T -> U + var project : U -> T + + init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { + self.table = table + self.embed = embed + self.project = project + } + + convenience init(_ embed : (T -> U), _ project : (U -> T)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + + self.embed = { [weak self] t in + if let v = self!.table[t] { + return v + } + let y = embed(t) + self!.table[t] = y + return y + } + + self.project = { [weak self] u in + let ts = self!.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, _ = self!.table[k] { + return k + } + let y = project(u) + self!.table[y] = u + return y + } + } + + var description : String { + return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" + } + + static var arbitrary : Gen> { + return Gen<(T -> U, U -> T)>.zip(promote({ a in + return T.coarbitrary(a)(U.arbitrary) + }), promote({ a in + return U.coarbitrary(a)(T.arbitrary) + })).fmap { IsoOfImpl($0, $1) } + } + + static func shrink(f : IsoOfImpl) -> [IsoOfImpl] { + return f.table.flatMap { (x, y) in + return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return IsoOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) + }) + }) + } + } +} + +extension IsoOfImpl : CustomReflectable { + func customMirror() -> Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self.table, + ]) + } +} + From ba017683238c49248bce4209b747f5eee23340f6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 15:42:42 -0500 Subject: [PATCH 203/460] use unowned, not weak --- SwiftCheck/Modifiers.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 3b1baa2..1d84b04 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -421,12 +421,12 @@ private final class ArrowOfImpl, U : Arbitra convenience init(_ arr : (T -> U)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - self.arr = { [weak self] x in - if let v = self!.table[x] { + self.arr = { [unowned self] x in + if let v = self.table[x] { return v } let y = arr(x) - self!.table[x] = y + self.table[x] = y return y } } @@ -478,22 +478,22 @@ private final class IsoOfImpl, U convenience init(_ embed : (T -> U), _ project : (U -> T)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - self.embed = { [weak self] t in - if let v = self!.table[t] { + self.embed = { [unowned self] t in + if let v = self.table[t] { return v } let y = embed(t) - self!.table[t] = y + self.table[t] = y return y } - self.project = { [weak self] u in - let ts = self!.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self!.table[k] { + self.project = { [unowned self] u in + let ts = self.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, _ = self.table[k] { return k } let y = project(u) - self!.table[y] = u + self.table[y] = u return y } } From 165e3fa2d373cf42ddf2926ff2d8fe1955516f86 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Nov 2015 16:31:11 -0500 Subject: [PATCH 204/460] Give PointerOf value semantics --- SwiftCheck/Modifiers.swift | 96 ++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 1d84b04..7633ebd 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -227,39 +227,23 @@ extension SetOf : CoArbitrary { } /// Generates pointers of varying size of random values of type T. -public final class PointerOf : Arbitrary { - private var ptr : UnsafeMutablePointer - public let size : Int +public struct PointerOf : Arbitrary, CustomStringConvertible { + private let _impl : PointerOfImpl public var getPointer : UnsafePointer { - return UnsafePointer(self.ptr) + return UnsafePointer(self._impl.ptr) } - public var description : String { - return "\(self.ptr)" - } - - private init(_ ptr : UnsafeMutablePointer, _ size : Int) { - self.ptr = ptr - self.size = size + public var size : Int { + return self._impl.size } - deinit { - if self.size > 0 && self.ptr != nil { - self.ptr.dealloc(self.size) - self.ptr = nil - } + public var description : String { + return self._impl.description } public static var arbitrary : Gen> { - return Gen.sized { n in - if n <= 0 { - return Gen.pure(PointerOf(nil, 0)) - } - let pt = UnsafeMutablePointer.alloc(n) - let gt = pt.initializeFrom <^> sequence(Array((0.., U : Arbitrary> : Arbi } } +extension ArrowOf : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self._impl.table, + ]) + } +} + /// Generates two isomorphic Swift function from T to U and back again. public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { private let _impl : IsoOfImpl @@ -301,6 +294,16 @@ public struct IsoOf, U : protocol } } +extension IsoOf : CustomReflectable { + public func customMirror() -> Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self._impl.table, + ]) + } +} + public struct Large> : Arbitrary { public let getLarge : A @@ -455,15 +458,6 @@ private final class ArrowOfImpl, U : Arbitra } } -extension ArrowOfImpl : CustomReflectable { - func customMirror() -> Mirror { - return Mirror(self, children: [ - "types": "\(T.self) -> \(U.self)", - "currentMap": self.table, - ]) - } -} - private final class IsoOfImpl, U : protocol> : Arbitrary, CustomStringConvertible { var table : Dictionary var embed : T -> U @@ -529,13 +523,35 @@ private final class IsoOfImpl, U } } -extension IsoOfImpl : CustomReflectable { - func customMirror() -> Mirror { - return Mirror(self, children: [ - "embed": "\(T.self) -> \(U.self)", - "project": "\(U.self) -> \(T.self)", - "currentMap": self.table, - ]) +private final class PointerOfImpl : Arbitrary { + var ptr : UnsafeMutablePointer + let size : Int + + var description : String { + return "\(self.ptr)" + } + + init(_ ptr : UnsafeMutablePointer, _ size : Int) { + self.ptr = ptr + self.size = size + } + + deinit { + if self.size > 0 && self.ptr != nil { + self.ptr.dealloc(self.size) + self.ptr = nil + } + } + + static var arbitrary : Gen> { + return Gen.sized { n in + if n <= 0 { + return Gen.pure(PointerOfImpl(nil, 0)) + } + let pt = UnsafeMutablePointer.alloc(n) + let gt = pt.initializeFrom <^> sequence(Array((0.. Date: Thu, 19 Nov 2015 16:52:58 -0500 Subject: [PATCH 205/460] Don't search frameworks in test bundle --- SwiftCheck.xcodeproj/project.pbxproj | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 2b0ae5a..476ee2c 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -764,10 +764,7 @@ buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -788,10 +785,7 @@ buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SwiftCheckTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; From b7757c2a42be89e2efefc13e56d1c0ba089a5a73 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Nov 2015 14:16:46 -0500 Subject: [PATCH 206/460] Adjust random gen to be more accurate with Double --- SwiftCheck/Arbitrary.swift | 14 ++-- SwiftCheck/Gen.swift | 12 ++-- SwiftCheck/Random.swift | 142 ++++++++++++++++++++----------------- 3 files changed, 92 insertions(+), 76 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 96ebd4b..e7eb5bc 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -202,9 +202,10 @@ extension Float : Arbitrary { if n == 0 { return Gen.pure(0.0) } - return Gen<(Int64, Int64)>.zip(Gen.choose((Int64(-n) * precision, Int64(n) * precision)), Gen.choose((1, precision))) >>- { (a, b) in - return Gen.pure(Float(a) / Float(b)) - } + + return Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + >>- { a in Gen.choose((1, precision)) + >>- { b in Gen.pure(Float(a) / Float(b)) } } } } @@ -227,9 +228,10 @@ extension Double : Arbitrary { if n == 0 { return Gen.pure(0.0) } - return Gen<(Int64, Int64)>.zip(Gen.choose((Int64(-n) * precision, Int64(n) * precision)), Gen.choose((1, precision))) >>- { (a, b) in - return Gen.pure(Double(a) / Double(b)) - } + + return Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + >>- { a in Gen.choose((1, precision)) + >>- { b in Gen.pure(Double(a) / Double(b)) } } } } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 93d23dd..e4f50dd 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -190,25 +190,25 @@ extension Gen { /// attempts are encoded in the form of an `Optional` where values satisfying the predicate are /// wrapped in `.Some` and failing values are `.None`. public func suchThatOptional(p : A -> Bool) -> Gen> { - return Gen>.sized({ n in + return Gen>.sized { n in return attemptBoundedTry(self, k: 0, n: max(n, 1), p: p) - }) + } } /// Modifies a Generator such that it produces arrays with a length determined by the receiver's /// size parameter. public func proliferate() -> Gen<[A]> { - return Gen<[A]>.sized({ n in + return Gen<[A]>.sized { n in return Gen.choose((0, n)) >>- self.proliferateSized - }) + } } /// Modifies a Generator such that it produces non-empty arrays with a length determined by the /// receiver's size parameter. public func proliferateNonEmpty() -> Gen<[A]> { - return Gen<[A]>.sized({ n in + return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))) >>- self.proliferateSized - }) + } } /// Modifies a Generator such that it only produces arrays of a given length. diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 7d4a69e..1009a2f 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -95,7 +95,7 @@ public protocol RandomType { } /// Generates a random value from a LatticeType random type. -public func random, G : RandomGeneneratorType>(gen : G) -> (A, G) { +public func randomBound, G : RandomGeneneratorType>(gen : G) -> (A, G) { return A.randomInRange((A.min, A.max), gen: gen) } @@ -127,127 +127,141 @@ extension UnicodeScalar : RandomType { extension Int : RandomType { public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range - let (min, max) = (Int64(minl), Int64(maxl)) - let (r, g) = gen.next - let result = (Int64(r) % ((max + 1) - min)) + min - - return (Int(truncatingBitPattern: result), g) + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int(truncatingBitPattern: bb), gg) } } extension Int8 : RandomType { public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range - let (min, max) = (Int64(minl), Int64(maxl)) - let (r, g) = gen.next - let result = (Int64(r) % ((max + 1) - min)) + min - - return (Int8(truncatingBitPattern: result), g) + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int8(truncatingBitPattern: bb), gg) } } extension Int16 : RandomType { public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range - let (min, max) = (Int64(minl), Int64(maxl)) - let (r, g) = gen.next - let result = (Int64(r) % ((max + 1) - min)) + min - - return (Int16(truncatingBitPattern: result), g) + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int16(truncatingBitPattern: bb), gg) } } extension Int32 : RandomType { public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range - let (min, max) = (Int64(minl), Int64(maxl)) - let (r, g) = gen.next - let result = (Int64(r) % ((max + 1) - min)) + min - - return (Int32(truncatingBitPattern: result), g) + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int32(truncatingBitPattern: bb), gg) } } extension Int64 : RandomType { public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { - let (minl, maxl) = range - let (min, max) = (Int64(minl), Int64(maxl)) - let (r, g) = gen.next - let result = (Int64(r) % ((max + 1) - min)) + min - - return (result, g) + let (l, h) = range + if l > h { + return Int64.randomInRange((h, l), gen: gen) + } else { + let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) + let b = genhi - genlo + 1 + + let q : Int64 = 1000 + let k = h - l + 1 + let magtgt = k * q + + func entropize(mag : Int64, _ v : Int64, _ g : G) -> (Int64, G) { + if mag >= magtgt { + return (v, g) + } else { + let (x, g_) = g.next + let v_ = (v * b + (Int64(x) - genlo)) + return entropize(mag * b, v_, g_) + } + } + + let (v, rng_) = entropize(1, 0, gen) + return (l + (v % k), rng_) + } } } extension UInt : RandomType { public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { - let (min, max) = range - let (r, g) = gen.next - let result = (UInt(r) % ((max + 1) - min)) + min - - return (result, g) + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt(truncatingBitPattern: bb), gg) } } extension UInt8 : RandomType { public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { - let (min, max) = range - let (r, g) = gen.next - let result = (UInt8(truncatingBitPattern: r) % ((max + 1) - min)) + min - - return (result, g) + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt8(truncatingBitPattern: bb), gg) } } extension UInt16 : RandomType { public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { - let (min, max) = range - let (r, g) = gen.next - let result = (UInt16(truncatingBitPattern: r) % ((max + 1) - min)) + min - - return (result, g) + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt16(truncatingBitPattern: bb), gg) } } extension UInt32 : RandomType { public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { - let (min, max) = range - let (r, g) = gen.next - let result = (UInt32(truncatingBitPattern: r) % ((max + 1) - min)) + min - - return (result, g) + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt32(truncatingBitPattern: bb), gg) } } extension UInt64 : RandomType { public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { - let (min, max) = range - let (r, g) = gen.next - let result = (UInt64(r) % ((max + 1) - min)) + min - - return (result, g) + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt64(bb), gg) } } extension Float : RandomType { - public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { - let (min, max) = range - let (r, g) = gen.next - let fr = Float(r) - let result = (fr % ((max + 1) - min)) + min + public static func random(rng : G) -> (Float, G) { + let (x, rng_) : (Int32, G) = randomBound(rng) + let twoto24 = Int32(2) ^ Int32(24) + let mask24 = twoto24 - 1 - return (result, g) + return (Float(mask24 & (x)) / Float(twoto24), rng_) + } + + public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { + let (l, h) = range + if l > h { + return Float.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Float.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } } } extension Double : RandomType { - public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { - let (min, max) = range - let (r, g) = gen.next - let dr = Double(r) - let result = (dr % ((max + 1) - min)) + min + public static func random(rng : G) -> (Double, G) { + let (x, rng_) : (Int64, G) = randomBound(rng) + let twoto53 = Int64(2) ^ Int64(53) + let mask53 = twoto53 - 1 - return (result, g) + return (Double(mask53 & (x)) / Double(twoto53), rng_) + } + + public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { + let (l, h) = range + if l > h { + return Double.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Double.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } } } From ee78464ce6548339385f7e872b3c8e0d441a334f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Nov 2015 15:12:25 -0500 Subject: [PATCH 207/460] Fix applicative instance --- SwiftCheck.xcodeproj/project.pbxproj | 4 +++- SwiftCheck/Gen.swift | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 476ee2c..716ca7b 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -222,6 +222,7 @@ isa = PBXGroup; children = ( 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */, + 8216BAB61B97775100A0D282 /* ComplexSpec.swift */, 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */, 8445C4A91B16D37800280089 /* GenSpec.swift */, @@ -230,7 +231,6 @@ 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, - 8216BAB61B97775100A0D282 /* ComplexSpec.swift */, 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); @@ -687,10 +687,12 @@ "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); + GCC_OPTIMIZATION_LEVEL = s; INFOPLIST_FILE = SwiftCheckTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index e4f50dd..a9131a0 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -57,10 +57,10 @@ public struct Gen { public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") - return Gen<[S]>.sized({ n in + return Gen<[S]>.sized { n in let ss = xs[xs.startIndex...pure([S](ss)) - }) + } } /// Constructs a Generator that produces permutations of a given array. @@ -76,7 +76,7 @@ public struct Gen { /// Constructs a generator that depends on a size parameter. public static func sized(f : Int -> Gen) -> Gen { - return Gen(unGen:{ r in + return Gen(unGen: { r in return { n in return f(n).unGen(r)(n) } @@ -276,11 +276,11 @@ extension Gen /*: Applicative*/ { /// /// Promotes function application to a Generator of functions applied to a Generator of values. public func <*> (fn : Gen B>, g : Gen) -> Gen { - return Gen(unGen: { r in - return { n in - return fn.unGen(r)(n)(g.unGen(r)(n)) + return fn >>- { x1 in + return g >>- { x2 in + return Gen.pure(x1(x2)) } - }) + } } extension Gen /*: Monad*/ { From 6a644f57e071d117e0a1c3e90fce7433881ea329 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Nov 2015 15:12:36 -0500 Subject: [PATCH 208/460] Propagate stdgens properly --- SwiftCheck/Random.swift | 10 ++++++---- SwiftCheck/Test.swift | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 1009a2f..faeb566 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -24,9 +24,6 @@ public protocol RandomGeneneratorType { var split : (Self, Self) { get } } -/// A library-provided standard random number generator. -public let standardRNG : StdGen = mkStdRNG(time(nil)) - /// `StdGen` represents a pseudo-random number generator. The library makes it possible to generate /// repeatable results, by starting with a specified initial random number generator, or to get /// different results on each run by using the system-initialised generator or by supplying a seed @@ -85,8 +82,13 @@ public struct StdGen : RandomGeneneratorType, CustomStringConvertible { } } +private var theStdGen : StdGen = mkStdRNG(0) + +/// A library-provided standard random number generator. public func newStdGen() -> StdGen { - return standardRNG.split.1 + let (left, right) = theStdGen.split + theStdGen = left + return right } /// Types that can generate random versions of themselves. diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index c79e94b..35b3cfd 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -371,7 +371,7 @@ internal indirect enum Either { internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Result { func roundTo(n : Int)(m : Int) -> Int { - return (m / m) * m + return (n / m) * m } func rnd() -> StdGen { @@ -414,20 +414,20 @@ internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Res let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests + , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: computeSize - , successfulTestCount: 0 - , discardedTestCount: 0 - , labels: [:] - , collected: [] - , hasFulfilledExpectedFailure: false + , computeSize: computeSize + , successfulTestCount: 0 + , discardedTestCount: 0 + , labels: [:] + , collected: [] + , hasFulfilledExpectedFailure: false , randomSeedGenerator: rnd() - , successfulShrinkCount: 0 + , successfulShrinkCount: 0 , failedShrinkStepDistance: 0 , failedShrinkStepCount: 0 - , shouldAbort: false - , quantifier: .Universal) + , shouldAbort: false + , quantifier: .Universal) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, f: modP.unProperty.unGen) } @@ -502,7 +502,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either , labels: unionWith(max, l: st.labels, r: labels) , collected: [stamp] + st.collected , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: st.randomSeedGenerator + , randomSeedGenerator: rnd2 , successfulShrinkCount: st.successfulShrinkCount , failedShrinkStepDistance: st.failedShrinkStepDistance , failedShrinkStepCount: st.failedShrinkStepCount From c03b79442a57cd278adc1ab8ecb2c6a026cf10ee Mon Sep 17 00:00:00 2001 From: Matthew Purland Date: Sat, 21 Nov 2015 12:51:26 -0800 Subject: [PATCH 209/460] Updated travis ci build to use objc-build-scripts to help make builds consistent. This should help issues related to stalling iOS tests. --- .travis.yml | 20 ++---- script/LICENSE.md | 18 +++++ script/README.md | 82 +++++++++++++++++++++ script/bootstrap | 47 ++++++++++++ script/cibuild | 173 +++++++++++++++++++++++++++++++++++++++++++++ script/schemes.awk | 10 +++ script/xctool.awk | 25 +++++++ 7 files changed, 360 insertions(+), 15 deletions(-) create mode 100644 script/LICENSE.md create mode 100644 script/README.md create mode 100755 script/bootstrap create mode 100755 script/cibuild create mode 100644 script/schemes.awk create mode 100644 script/xctool.awk diff --git a/.travis.yml b/.travis.yml index cee15c0..3f0f109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,11 @@ language: objective-c -osx_image: xcode7 - +osx_image: xcode7.1 env: - TEST_CONFIG="RELEASE" -# - TEST_CONFIG="CARTHAGE" - TEST_CONFIG="PODS" -before_install: - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet; fi - - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then brew install carthage; fi - -install: - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then git submodule update -i --recursive; fi - -script: - - set -o pipefail - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck -sdk macosx ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -project SwiftCheck.xcodeproj -scheme SwiftCheck-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO clean build test | xcpretty -c -f `xcpretty-travis-formatter`; fi - - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage update --verbose --no-use-binaries && carthage build --no-skip-current --configuration Debug; fi +before_install: true +install: true +script: + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi diff --git a/script/LICENSE.md b/script/LICENSE.md new file mode 100644 index 0000000..8d92384 --- /dev/null +++ b/script/LICENSE.md @@ -0,0 +1,18 @@ +**Copyright (c) 2013 Justin Spahr-Summers** + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/script/README.md b/script/README.md new file mode 100644 index 0000000..f66206f --- /dev/null +++ b/script/README.md @@ -0,0 +1,82 @@ +# objc-build-scripts + +This project is a collection of scripts created with two goals: + + 1. To standardize how Objective-C projects are bootstrapped after cloning + 1. To easily build Objective-C projects on continuous integration servers + +## Scripts + +Right now, there are two important scripts: [`bootstrap`](#bootstrap) and +[`cibuild`](#cibuild). Both are Bash scripts, to maximize compatibility and +eliminate pesky system configuration issues (like setting up a working Ruby +environment). + +The structure of the scripts on disk is meant to follow that of a typical Ruby +project: + +``` +script/ + bootstrap + cibuild +``` + +### bootstrap + +This script is responsible for bootstrapping (initializing) your project after +it's been checked out. Here, you should install or clone any dependencies that +are required for a working build and development environment. + +By default, the script will verify that [xctool][] is installed, then initialize +and update submodules recursively. If any submodules contain `script/bootstrap`, +that will be run as well. + +To check that other tools are installed, you can set the `REQUIRED_TOOLS` +environment variable before running `script/bootstrap`, or edit it within the +script directly. Note that no installation is performed automatically, though +this can always be added within your specific project. + +### cibuild + +This script is responsible for building the project, as you would want it built +for continuous integration. This is preferable to putting the logic on the CI +server itself, since it ensures that any changes are versioned along with the +source. + +By default, the script will run [`bootstrap`](#bootstrap), look for any Xcode +workspace or project in the working directory, then build all targets/schemes +(as found by `xcodebuild -list`) using [xctool][]. + +You can also specify the schemes to build by passing them into the script: + +```sh +script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS +``` + +As with the `bootstrap` script, there are several environment variables that can +be used to customize behavior. They can be set on the command line before +invoking the script, or the defaults changed within the script directly. + +## Getting Started + +To add the scripts to your project, read the contents of this repository into +a `script` folder: + +``` +$ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git +$ git fetch objc-build-scripts +$ git read-tree --prefix=script/ -u objc-build-scripts/master +``` + +Then commit the changes, to incorporate the scripts into your own repository's +history. You can also freely tweak the scripts for your specific project's +needs. + +To merge in upstream changes later: + +``` +$ git fetch -p objc-build-scripts +$ git merge --ff --squash -Xsubtree=script objc-build-scripts/master +``` + +[xctool]: https://github.com/facebook/xctool diff --git a/script/bootstrap b/script/bootstrap new file mode 100755 index 0000000..d61c863 --- /dev/null +++ b/script/bootstrap @@ -0,0 +1,47 @@ +#!/bin/bash + +export SCRIPT_DIR=$(dirname "$0") + +## +## Bootstrap Process +## + +main () +{ + local submodules=$(git submodule status) + local result=$? + + if [ "$result" -ne "0" ] + then + exit $result + fi + + if [ -n "$submodules" ] + then + echo "*** Updating submodules..." + update_submodules + fi +} + +bootstrap_submodule () +{ + local bootstrap="script/bootstrap" + + if [ -e "$bootstrap" ] + then + echo "*** Bootstrapping $name..." + "$bootstrap" >/dev/null + else + update_submodules + fi +} + +update_submodules () +{ + git submodule sync --quiet && git submodule update --init && git submodule foreach --quiet bootstrap_submodule +} + +export -f bootstrap_submodule +export -f update_submodules + +main diff --git a/script/cibuild b/script/cibuild new file mode 100755 index 0000000..33b5129 --- /dev/null +++ b/script/cibuild @@ -0,0 +1,173 @@ +#!/bin/bash + +export SCRIPT_DIR=$(dirname "$0") + +## +## Configuration Variables +## + +SCHEMES="$@" + +config () +{ + # The workspace to build. + # + # If not set and no workspace is found, the -workspace flag will not be passed + # to `xctool`. + # + # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will + # take precedence. + : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")} + + # The project to build. + # + # If not set and no project is found, the -project flag will not be passed + # to `xctool`. + # + # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will + # take precedence. + : ${XCODEPROJ=$(find_pattern "*.xcodeproj")} + + # A bootstrap script to run before building. + # + # If this file does not exist, it is not considered an error. + : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"} + + # Extra options to pass to xctool. + : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"} + + # A whitespace-separated list of default schemes to build. + # + # Individual names can be quoted to avoid word splitting. + : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")} + + # A whitespace-separated list of executables that must be present and locatable. + : ${REQUIRED_TOOLS="xctool"} + + export XCWORKSPACE + export XCODEPROJ + export BOOTSTRAP + export XCTOOL_OPTIONS + export SCHEMES + export REQUIRED_TOOLS +} + +## +## Build Process +## + +main () +{ + config + + if [ -n "$REQUIRED_TOOLS" ] + then + echo "*** Checking dependencies..." + check_deps + fi + + if [ -f "$BOOTSTRAP" ] + then + echo "*** Bootstrapping..." + "$BOOTSTRAP" || exit $? + fi + + echo "*** The following schemes will be built:" + echo "$SCHEMES" | xargs -n 1 echo " " + echo + + echo "$SCHEMES" | xargs -n 1 | ( + local status=0 + + while read scheme + do + build_scheme "$scheme" || status=1 + done + + exit $status + ) +} + +check_deps () +{ + for tool in $REQUIRED_TOOLS + do + which -s "$tool" + if [ "$?" -ne "0" ] + then + echo "*** Error: $tool not found. Please install it and cibuild again." + exit 1 + fi + done +} + +find_pattern () +{ + ls -d $1 2>/dev/null | head -n 1 +} + +run_xctool () +{ + if [ -n "$XCWORKSPACE" ] + then + xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 + elif [ -n "$XCODEPROJ" ] + then + xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 + else + echo "*** No workspace or project file found." + exit 1 + fi +} + +parse_build () +{ + awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null +} + +build_scheme () +{ + local scheme=$1 + + echo "*** Building and testing $scheme..." + echo + + local sdkflag= + local action=test + + # Determine whether we can run unit tests for this target. + run_xctool -scheme "$scheme" run-tests | parse_build + + local awkstatus=$? + + if [ "$awkstatus" -eq "1" ] + then + # SDK not found, try for iphonesimulator. + sdkflag="-sdk iphonesimulator" + + # Determine whether the unit tests will run with iphonesimulator + run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build + + awkstatus=$? + + if [ "$awkstatus" -ne "0" ] + then + # Unit tests will not run on iphonesimulator. + sdkflag="" + fi + fi + + if [ "$awkstatus" -ne "0" ] + then + # Unit tests aren't supported. + action=build + fi + + run_xctool $sdkflag -scheme "$scheme" $action +} + +export -f build_scheme +export -f run_xctool +export -f parse_build + +main diff --git a/script/schemes.awk b/script/schemes.awk new file mode 100644 index 0000000..4c94df9 --- /dev/null +++ b/script/schemes.awk @@ -0,0 +1,10 @@ +BEGIN { + FS = "\n"; +} + +/Schemes:/ { + while (getline && $0 != "") { + sub(/^ +/, ""); + print "'" $0 "'"; + } +} diff --git a/script/xctool.awk b/script/xctool.awk new file mode 100644 index 0000000..f613258 --- /dev/null +++ b/script/xctool.awk @@ -0,0 +1,25 @@ +# Exit statuses: +# +# 0 - No errors found. +# 1 - Wrong SDK. Retry with SDK `iphonesimulator`. +# 2 - Missing target. + +BEGIN { + status = 0; +} + +{ + print; +} + +/Testing with the '(.+)' SDK is not yet supported/ { + status = 1; +} + +/does not contain a target named/ { + status = 2; +} + +END { + exit status; +} From c2d2583f146053d812da0e3fb6d14f63598c8509 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Nov 2015 16:27:03 -0500 Subject: [PATCH 210/460] Fix 32-bit overflow in randomgen --- SwiftCheck/Random.swift | 2 +- SwiftCheckTests/TestSpec.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index faeb566..caac0ab 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -282,7 +282,7 @@ private func mkStdRNG(o : Int) -> StdGen { clock_gettime(0, &tt) let (sec, psec) = (tt.tv_sec, tt.tv_nsec) let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) - return mkStdGen32(ll + psec + ct + o) + return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index d8a3c4e..e65810a 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -12,7 +12,7 @@ extension Dictionary { init(_ pairs : S) { self.init() var g = pairs.generate() - while let (k, v): (Key, Value) = g.next() { + while let (k, v) : (Key, Value) = g.next() { self[k] = v } } From baf809a74223e8527c8a01da3c39326af46a5306 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 8 Dec 2015 18:05:45 -0500 Subject: [PATCH 211/460] Bump Podspec Version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 743440e..25ba66f 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.4.0" + s.version = "0.4.1" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 3e4d3274d903c76dba95c4cdcfbe1b8317beb214 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 9 Dec 2015 17:50:48 -0500 Subject: [PATCH 212/460] Add effects annotations _everywhere_ --- SwiftCheck/Arbitrary.swift | 55 ++++++++++++++++++++++++++++++++++ SwiftCheck/Check.swift | 2 ++ SwiftCheck/Equatable.swift | 9 ++++++ SwiftCheck/Gen.swift | 35 ++++++++++++++++++++++ SwiftCheck/Property.swift | 33 ++++++++++++++++++++ SwiftCheck/Random.swift | 21 ++++++++++++- SwiftCheck/Rose.swift | 13 ++++++++ SwiftCheck/Test.swift | 54 +++++++++++++++++---------------- SwiftCheck/TestOperators.swift | 6 ++++ SwiftCheck/Witness.swift | 8 +++++ 10 files changed, 210 insertions(+), 26 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index e7eb5bc..21dce90 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -74,6 +74,7 @@ extension Bool : Arbitrary { return Gen.choose((false, true)) } + @effects(readnone) public static func shrink(x : Bool) -> [Bool] { if x { return [false] @@ -89,6 +90,7 @@ extension Int : Arbitrary { } } + @effects(readnone) public static func shrink(x : Int) -> [Int] { return x.shrinkIntegral } @@ -101,6 +103,7 @@ extension Int8 : Arbitrary { } } + @effects(readnone) public static func shrink(x : Int8) -> [Int8] { return x.shrinkIntegral } @@ -113,6 +116,7 @@ extension Int16 : Arbitrary { } } + @effects(readnone) public static func shrink(x : Int16) -> [Int16] { return x.shrinkIntegral } @@ -125,6 +129,7 @@ extension Int32 : Arbitrary { } } + @effects(readnone) public static func shrink(x : Int32) -> [Int32] { return x.shrinkIntegral } @@ -137,6 +142,7 @@ extension Int64 : Arbitrary { } } + @effects(readnone) public static func shrink(x : Int64) -> [Int64] { return x.shrinkIntegral } @@ -147,6 +153,7 @@ extension UInt : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt(n))) } } + @effects(readnone) public static func shrink(x : UInt) -> [UInt] { return x.shrinkIntegral } @@ -159,6 +166,7 @@ extension UInt8 : Arbitrary { } } + @effects(readnone) public static func shrink(x : UInt8) -> [UInt8] { return x.shrinkIntegral } @@ -169,6 +177,7 @@ extension UInt16 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } } + @effects(readnone) public static func shrink(x : UInt16) -> [UInt16] { return x.shrinkIntegral } @@ -179,6 +188,7 @@ extension UInt32 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } } + @effects(readnone) public static func shrink(x : UInt32) -> [UInt32] { return x.shrinkIntegral } @@ -189,6 +199,7 @@ extension UInt64 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt64(n))) } } + @effects(readnone) public static func shrink(x : UInt64) -> [UInt64] { return x.shrinkIntegral } @@ -209,6 +220,7 @@ extension Float : Arbitrary { } } + @effects(readnone) public static func shrink(x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { @@ -235,6 +247,7 @@ extension Double : Arbitrary { } } + @effects(readnone) public static func shrink(x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { @@ -251,6 +264,7 @@ extension UnicodeScalar : Arbitrary { return UInt32.arbitrary.bind(Gen.pure • UnicodeScalar.init) } + @effects(readnone) public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) return nub([ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ]).filter { $0 < x } @@ -263,6 +277,7 @@ extension String : Arbitrary { return chars >>- (Gen.pure • String.init) } + @effects(readnone) public static func shrink(s : String) -> [String] { return [Character].shrink([Character](s.characters)).map(String.init) } @@ -273,6 +288,7 @@ extension Character : Arbitrary { return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) } + @effects(readnone) public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) @@ -292,6 +308,7 @@ extension Array where Element : Arbitrary { } } + @effects(readnone) public static func shrink(bl : Array) -> [[Element]] { return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) } @@ -312,6 +329,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { return AnyBidirectionalCollection.init <^> [Element].arbitrary } + @effects(readnone) public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } @@ -344,6 +362,7 @@ extension AnySequence where Element : Arbitrary { return AnySequence.init <^> [Element].arbitrary } + @effects(readnone) public static func shrink(bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } @@ -364,6 +383,7 @@ extension ArraySlice where Element : Arbitrary { return ArraySlice.init <^> [Element].arbitrary } + @effects(readnone) public static func shrink(bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } @@ -404,6 +424,7 @@ extension Optional where Wrapped : Arbitrary { ]) } + @effects(readnone) public static func shrink(bl : Optional) -> [Optional] { if let x = bl { return [.None] + Wrapped.shrink(x).map(Optional.Some) @@ -427,6 +448,7 @@ extension ContiguousArray where Element : Arbitrary { return ContiguousArray.init <^> [Element].arbitrary } + @effects(readnone) public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } @@ -452,6 +474,7 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } + @effects(readnone) public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } @@ -482,6 +505,7 @@ extension HalfOpenInterval where Bound : protocol { } } + @effects(readnone) public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } @@ -492,6 +516,7 @@ extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary } + @effects(readnone) public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) } @@ -528,6 +553,7 @@ extension Range where Element : protocol) -> [Range] { return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) } @@ -542,6 +568,7 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element + @effects(readnone) public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) @@ -563,6 +590,7 @@ extension Set where Element : protocol { } } + @effects(readnone) public static func shrink(s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } @@ -600,6 +628,7 @@ public func coarbitraryPrintable(x : A) -> Gen -> Gen { } extension Bool : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Bool) -> Gen -> Gen { return { g in if x { @@ -611,12 +640,14 @@ extension Bool : CoArbitrary { } extension UnicodeScalar : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { return UInt32.coarbitrary(x.value) } } extension Character : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Character) -> (Gen -> Gen) { let ss = String(x).unicodeScalars return UnicodeScalar.coarbitrary(ss[ss.startIndex]) @@ -624,6 +655,7 @@ extension Character : CoArbitrary { } extension String : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : String) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -633,60 +665,70 @@ extension String : CoArbitrary { } extension Int : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Int) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Int8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Int16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Int32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Int64) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UInt) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UInt8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UInt16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UInt32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : UInt64) -> Gen -> Gen { return x.coarbitraryIntegral() } @@ -694,18 +736,21 @@ extension UInt64 : CoArbitrary { // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Float) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Double) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Array : CoArbitrary { + @effects(readnone) public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { if a.isEmpty { return { $0.variant(0) } @@ -715,6 +760,7 @@ extension Array : CoArbitrary { } extension Dictionary : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Dictionary) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -724,6 +770,7 @@ extension Dictionary : CoArbitrary { } extension Optional : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Optional) -> (Gen -> Gen) { if let _ = x { return { $0.variant(0) } @@ -733,6 +780,7 @@ extension Optional : CoArbitrary { } extension Set : CoArbitrary { + @effects(readnone) public static func coarbitrary(x : Set) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -743,6 +791,7 @@ extension Set : CoArbitrary { /// MARK: - Implementation Details +@effects(readnone) private func bits(n : N) -> Int { if n / 2 == 0 { return 0 @@ -750,10 +799,12 @@ private func bits(n : N) -> Int { return 1 + bits(n / 2) } +@effects(readnone) private func nub(xs : [A]) -> [A] { return [A](Set(xs)) } +@effects(readnone) private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { var acc = [A]() var ini = initial @@ -764,6 +815,7 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { return acc } +@effects(readnone) private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { let xs1 = take(k, xs: xs) let xs2 = drop(k, xs: xs) @@ -777,16 +829,19 @@ private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { } } +@effects(readnone) private func take(num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[0..(num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[n..(xs : [A]) -> [[A]] { if xs.isEmpty { return [] diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index b05b451..377e83d 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -31,6 +31,7 @@ /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. +@effects(readnone) public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -51,6 +52,7 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest assert. The /// property will still generate console output during testing. +@effects(readnone) public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } diff --git a/SwiftCheck/Equatable.swift b/SwiftCheck/Equatable.swift index 9a95678..7f9badf 100644 --- a/SwiftCheck/Equatable.swift +++ b/SwiftCheck/Equatable.swift @@ -6,38 +6,47 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +@effects(readnone) public func == >(lhs : Blind, rhs : Blind) -> Bool { return lhs.getBlind == rhs.getBlind } +@effects(readnone) public func == >(lhs : Static, rhs : Static) -> Bool { return lhs.getStatic == rhs.getStatic } +@effects(readnone) public func == >(lhs : ArrayOf, rhs : ArrayOf) -> Bool { return lhs.getArray == rhs.getArray } +@effects(readnone) public func == , V : protocol>(lhs : DictionaryOf, rhs : DictionaryOf) -> Bool { return lhs.getDictionary == rhs.getDictionary } +@effects(readnone) public func == >(lhs : OptionalOf, rhs : OptionalOf) -> Bool { return lhs.getOptional == rhs.getOptional } +@effects(readnone) public func == >(lhs : SetOf, rhs : SetOf) -> Bool { return lhs.getSet == rhs.getSet } +@effects(readnone) public func == >(lhs : Positive, rhs : Positive) -> Bool { return lhs.getPositive == rhs.getPositive } +@effects(readnone) public func == >(lhs : NonZero, rhs : NonZero) -> Bool { return lhs.getNonZero == rhs.getNonZero } +@effects(readnone) public func == >(lhs : NonNegative, rhs : NonNegative) -> Bool { return lhs.getNonNegative == rhs.getNonNegative } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index a9131a0..901b19b 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -33,6 +33,7 @@ public struct Gen { /// only that value. /// /// The input collection is required to be non-empty. + @effects(readnone) public static func fromElementsOf>(xs : S) -> Gen { return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).fmap { i in return xs[i] @@ -43,6 +44,7 @@ public struct Gen { /// that value. /// /// The input interval is required to be non-empty. + @effects(readnone) public static func fromElementsIn(xs : S) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") @@ -54,6 +56,7 @@ public struct Gen { /// parameter. /// /// The input array is required to be non-empty. + @effects(readnone) public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") @@ -64,6 +67,7 @@ public struct Gen { } /// Constructs a Generator that produces permutations of a given array. + @effects(readnone) public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { if xs.isEmpty { return Gen<[S]>.pure([]) @@ -75,6 +79,7 @@ public struct Gen { } /// Constructs a generator that depends on a size parameter. + @effects(readnone) public static func sized(f : Int -> Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -89,6 +94,7 @@ public struct Gen { /// `A`. For example: /// /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + @effects(readnone) public static func choose(rng : (A, A)) -> Gen { return Gen(unGen: { s in return { (_) in @@ -103,6 +109,7 @@ public struct Gen { /// /// If control over the distribution of generators is needed, see `Gen.frequency` or /// `Gen.weighted`. + @effects(readnone) public static func oneOf, S.Index : protocol>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") @@ -116,6 +123,7 @@ public struct Gen { /// /// Only use this function when you need to assign uneven "weights" to each generator. If all /// generators need to have an equal chance of being selected, use `Gen.oneOf`. + @effects(readnone) public static func frequency)>(xs : S) -> Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") @@ -132,11 +140,13 @@ public struct Gen { /// and `Gen.fromElementsIn` but for any type rather than only Generators. It can help in cases /// where your `Gen.from*` call contains only `Gen.pure` calls by allowing you to remove every /// `.pure` in favor of a direct list of values. + @effects(readnone) public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } /// Zips together 2 generators of type `A` and `B` into a generator of pairs `(A, B)`. + @effects(readnone) public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return gen1.bind { l in return gen2.bind { r in @@ -150,6 +160,7 @@ public struct Gen { extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. + @effects(readnone) public func variant(seed : S) -> Gen { return Gen(unGen: { r in return { n in @@ -159,6 +170,7 @@ extension Gen { } /// Modifies a Generator to always use a given size. + @effects(readnone) public func resize(n : Int) -> Gen { return Gen(unGen: { r in return { (_) in @@ -173,6 +185,7 @@ extension Gen { /// Because the Generator will spin until it reaches a non-failing case, executing a condition /// that fails more often than it succeeds may result in a space leak. At that point, it is /// better to use `suchThatOptional` or `.invert` the test case. + @effects(readnone) public func suchThat(p : A -> Bool) -> Gen { return self.suchThatOptional(p).bind { mx in switch mx { @@ -189,6 +202,7 @@ extension Gen { /// Modifies a Generator such that it attempts to generate values that satisfy a predicate. All /// attempts are encoded in the form of an `Optional` where values satisfying the predicate are /// wrapped in `.Some` and failing values are `.None`. + @effects(readnone) public func suchThatOptional(p : A -> Bool) -> Gen> { return Gen>.sized { n in return attemptBoundedTry(self, k: 0, n: max(n, 1), p: p) @@ -197,6 +211,7 @@ extension Gen { /// Modifies a Generator such that it produces arrays with a length determined by the receiver's /// size parameter. + @effects(readnone) public func proliferate() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((0, n)) >>- self.proliferateSized @@ -205,6 +220,7 @@ extension Gen { /// Modifies a Generator such that it produces non-empty arrays with a length determined by the /// receiver's size parameter. + @effects(readnone) public func proliferateNonEmpty() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))) >>- self.proliferateSized @@ -212,6 +228,7 @@ extension Gen { } /// Modifies a Generator such that it only produces arrays of a given length. + @effects(readnone) public func proliferateSized(k : Int) -> Gen<[A]> { return sequence(Array>(count: k, repeatedValue: self)) } @@ -223,6 +240,7 @@ extension Gen /*: Functor*/ { typealias B = Swift.Any /// Returns a new generator that applies a given function to any outputs the receiver creates. + @effects(readnone) public func fmap(f : (A -> B)) -> Gen { return f <^> self } @@ -235,6 +253,7 @@ extension Gen /*: Functor*/ { /// example, you might have a Generator of `Character` values that you then `.proliferate()` into an /// `Array` of `Character`s. You can then use `fmap` to convert that generator of `Array`s to a /// generator of `String`s. +@effects(readnone) public func <^> (f : A -> B, g : Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -247,6 +266,7 @@ extension Gen /*: Applicative*/ { typealias FAB = Gen B> /// Lifts a value into a generator that will only generate that value. + @effects(readnone) public static func pure(a : A) -> Gen { return Gen(unGen: { (_) in return { (_) in @@ -257,6 +277,7 @@ extension Gen /*: Applicative*/ { /// Given a generator of functions, applies any generated function to any outputs the receiver /// creates. + @effects(readnone) public func ap(fn : Gen B>) -> Gen { return fn <*> self } @@ -275,6 +296,7 @@ extension Gen /*: Applicative*/ { /// the zipped function to the zipped value. /// /// Promotes function application to a Generator of functions applied to a Generator of values. +@effects(readnone) public func <*> (fn : Gen B>, g : Gen) -> Gen { return fn >>- { x1 in return g >>- { x2 in @@ -290,6 +312,7 @@ extension Gen /*: Monad*/ { /// `bind` allows for the creation of Generators that depend on other generators. One might, /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. + @effects(readnone) public func bind(fn : A -> Gen) -> Gen { return self >>- fn } @@ -301,6 +324,7 @@ extension Gen /*: Monad*/ { /// `bind` allows for the creation of Generators that depend on other generators. One might, /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. +@effects(readnone) public func >>- (m : Gen, fn : A -> Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -317,6 +341,7 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// The array that is created is guaranteed to use each of the given Generators in the order they /// were given to the function exactly once. Thus all arrays generated are of the same rank as the /// array that was given. +@effects(readnone) public func sequence(ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in return x.bind { x1 in @@ -328,6 +353,7 @@ public func sequence(ms : [Gen]) -> Gen<[A]> { } /// Flattens a generator of generators by one level. +@effects(readnone) public func join(rs : Gen>) -> Gen { return rs.bind { x in return x @@ -335,6 +361,7 @@ public func join(rs : Gen>) -> Gen { } /// Lifts a function from some A to some R to a function from generators of A to generators of R. +@effects(readnone) public func liftM(f : A -> R)(m1 : Gen) -> Gen { return m1.bind{ x1 in return Gen.pure(f(x1)) @@ -342,6 +369,7 @@ public func liftM(f : A -> R)(m1 : Gen) -> Gen { } /// Promotes a rose of generators to a generator of rose values. +@effects(readnone) public func promote(x : Rose>) -> Gen> { return delay().bind { (let eval : Gen -> A) in return Gen>.pure(liftM(eval)(m1: x)) @@ -349,12 +377,14 @@ public func promote(x : Rose>) -> Gen> { } /// Promotes a function returning generators to a generator of functions. +@effects(readnone) public func promote(m : A -> Gen) -> Gen B> { return delay().bind { (let eval : Gen -> B) in return Gen B>.pure({ x in eval(m(x)) }) } } +@effects(readnone) internal func delay() -> Gen -> A> { return Gen(unGen: { r in return { n in @@ -369,12 +399,14 @@ internal func delay() -> Gen -> A> { import func Darwin.log +@effects(readnone) private func vary(k : S)(r : StdGen) -> StdGen { let s = r.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2)(r: r) } +@effects(readnone) private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) -> Gen> { if n == 0 { return Gen.pure(.None) @@ -387,11 +419,13 @@ private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) - } } +@effects(readnone) private func size(k : S)(m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } +@effects(readnone) private func selectOne(xs : [A]) -> [(A, [A])] { if xs.isEmpty { return [] @@ -401,6 +435,7 @@ private func selectOne(xs : [A]) -> [(A, [A])] { return [(y, ys)] + selectOne(ys).map({ t in (t.0, [y] + t.1) }) } +@effects(readnone) private func pick(n : Int)(lst : [(Int, Gen)]) -> Gen { let (k, x) = lst[0] let tl = Array<(Int, Gen)>(lst[1.. Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.fmap { $0.unProp } @@ -31,6 +32,7 @@ public func conjoin(ps : Testable...) -> Property { /// distribution map of the success rate of each sub-property. /// /// When disjoining properties all calls to `expectFailure` will fail. +@effects(readnone) public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.fmap { $0.unProp } @@ -45,6 +47,7 @@ public func disjoin(ps : Testable...) -> Property { /// The resulting property makes 100 random choices to test any of the given properties. Thus, /// running multiple test cases will result in distinct arbitrary sequences of each property being /// tested. +@effects(readnone) public func conjamb(ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) @@ -52,11 +55,13 @@ public func conjamb(ps : () -> Testable...) -> Property { extension Testable { /// Applies a function that modifies the property generator's inner `Prop`. + @effects(readnone) public func mapProp(f : Prop -> Prop) -> Property { return Property(f <^> self.property.unProperty) } /// Applies a function that modifies the property generator's size. + @effects(readnone) public func mapSize(f : Int -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) @@ -64,6 +69,7 @@ extension Testable { } /// Applies a function that modifies the result of a test case. + @effects(readnone) public func mapTotalResult(f : TestResult -> TestResult) -> Property { return self.mapRoseResult { rs in return protectResults(f <^> rs) @@ -71,6 +77,7 @@ extension Testable { } /// Applies a function that modifies the result of a test case. + @effects(readnone) public func mapResult(f : TestResult -> TestResult) -> Property { return self.mapRoseResult { rs in return f <^> rs @@ -78,6 +85,7 @@ extension Testable { } /// Applies a function that modifies the underlying Rose Tree that a test case has generated. + @effects(readnone) public func mapRoseResult(f : Rose -> Rose) -> Property { return self.mapProp { t in return Prop(unProp: f(t.unProp)) @@ -128,6 +136,7 @@ extension Testable { } /// Attaches a callback to a test case. + @effects(readnone) public func withCallback(cb : Callback) -> Property { return self.mapResult { (res) in return TestResult(ok: res.ok @@ -143,6 +152,7 @@ extension Testable { } /// Adds the given string to the counterexamples of a failing property. + @effects(readnone) public func counterexample(s : String) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample) { _ in return print(s) @@ -150,6 +160,7 @@ extension Testable { } /// Executes an action after the last failure of the property. + @effects(readnone) public func whenFail(m : () -> ()) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { _ in return m() @@ -160,6 +171,7 @@ extension Testable { /// /// Because the action is executed after every failing test it can be used to track the list of /// failures generated by the shrinking mechanism. + @effects(readnone) public func whenEachFail(m : () -> ()) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in if res.ok == .Some(false) { @@ -236,16 +248,19 @@ extension Testable { /// test cases need to be distinct from one another. In addition to shrunken test cases, upon /// failure SwiftCheck will print a distribution map for the property that shows a percentage /// success rate for the property. + @effects(readnone) public func label(s : String) -> Property { return self.classify(true)(s: s) } /// Labels a property with a printable value. + @effects(readnone) public func collect(x : A) -> Property { return self.label(String(x)) } /// Conditionally labels a property with a value. + @effects(readnone) public func classify(b : Bool)(s : String) -> Property { return self.cover(b)(n: 0)(s: s) } @@ -253,6 +268,7 @@ extension Testable { /// Checks that at least the given proportion of successful test cases belong to the given class. /// /// Discarded tests (i.e. ones with a false precondition) do not affect coverage. + @effects(readnone) public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { return self.mapResult { res in @@ -275,6 +291,7 @@ extension Testable { /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is only necessary /// when you must override the default behavior. +@effects(readnone) public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { rs in return Prop(unProp: joinRose(rs.fmap { x in @@ -382,6 +399,7 @@ public struct TestResult { /// Lifts a `Bool`ean value to a TestResult by mapping true to `TestResult.suceeded` and false /// to `TestResult.failed`. + @effects(readnone) public static func liftBool(b : Bool) -> TestResult { if b { return TestResult.succeeded @@ -392,16 +410,19 @@ public struct TestResult { /// MARK: - Implementation Details +@effects(readnone) private func exception(msg : String) -> ErrorType -> TestResult { return { e in TestResult.failed(String(e)) } } +@effects(readnone) private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) } +@effects(readnone) private func result(ok : Bool?, reason : String = "") -> TestResult { return TestResult( ok: ok , expect: true @@ -415,6 +436,7 @@ private func result(ok : Bool?, reason : String = "") -> TestResult { ) } +@effects(readnone) private func protectResults(rs : Rose) -> Rose { return onRose({ x in return { rs in @@ -425,10 +447,12 @@ private func protectResults(rs : Rose) -> Rose { })(rs: rs) } +@effects(readnone) internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { return { protect(Rose.pure • exception("Exception"))(x: f) } } +@effects(readnone) internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { do { return try x() @@ -437,18 +461,22 @@ internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { } } +@effects(readnone) private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"))(x: r) } } +@effects(readnone) internal func id(x : A) -> A { return x } +@effects(readnone) internal func • (f : B -> C, g : A -> B) -> A -> C { return { f(g($0)) } } +@effects(readnone) internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : Dictionary) -> Dictionary { let oldV = m[k] if let existV = oldV { @@ -459,6 +487,7 @@ internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : return m } +@effects(readnone) internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l l.forEach { (k, v) in @@ -470,6 +499,7 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, return map } +@effects(readnone) private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in return TestResult(ok: res.ok @@ -484,6 +514,7 @@ private func addCallbacks(result : TestResult) -> TestResult -> TestResult { } } +@effects(readnone) private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in return TestResult(ok: res.ok @@ -498,6 +529,7 @@ private func addLabels(result : TestResult) -> TestResult -> TestResult { } } +@effects(readnone) private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) @@ -539,6 +571,7 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose fatalError("Non-exhaustive if-else statement reached") } +@effects(readnone) private func disj(p : Rose, q : Rose) -> Rose { func sep(l : String, r : String) -> String { if l.isEmpty { diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index caac0ab..752b6d2 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -85,6 +85,7 @@ public struct StdGen : RandomGeneneratorType, CustomStringConvertible { private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. +@effects(readwrite) public func newStdGen() -> StdGen { let (left, right) = theStdGen.split theStdGen = left @@ -102,6 +103,7 @@ public func randomBound, G : RandomGenener } extension Bool : RandomType { + @effects(readnone) public static func randomInRange(range: (Bool, Bool), gen: G) -> (Bool, G) { let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) return (x == 1, gg) @@ -109,6 +111,7 @@ extension Bool : RandomType { } extension Character : RandomType { + @effects(readnone) public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! @@ -120,6 +123,7 @@ extension Character : RandomType { } extension UnicodeScalar : RandomType { + @effects(readnone) public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) return (UnicodeScalar(val), gg) @@ -127,6 +131,7 @@ extension UnicodeScalar : RandomType { } extension Int : RandomType { + @effects(readnone) public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -135,6 +140,7 @@ extension Int : RandomType { } extension Int8 : RandomType { + @effects(readnone) public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -143,6 +149,7 @@ extension Int8 : RandomType { } extension Int16 : RandomType { + @effects(readnone) public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -151,6 +158,7 @@ extension Int16 : RandomType { } extension Int32 : RandomType { + @effects(readnone) public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -159,6 +167,7 @@ extension Int32 : RandomType { } extension Int64 : RandomType { + @effects(readnone) public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { let (l, h) = range if l > h { @@ -188,6 +197,7 @@ extension Int64 : RandomType { } extension UInt : RandomType { + @effects(readnone) public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -196,6 +206,7 @@ extension UInt : RandomType { } extension UInt8 : RandomType { + @effects(readnone) public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -204,6 +215,7 @@ extension UInt8 : RandomType { } extension UInt16 : RandomType { + @effects(readnone) public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -212,6 +224,7 @@ extension UInt16 : RandomType { } extension UInt32 : RandomType { + @effects(readnone) public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -228,6 +241,7 @@ extension UInt64 : RandomType { } extension Float : RandomType { + @effects(readnone) public static func random(rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) let twoto24 = Int32(2) ^ Int32(24) @@ -236,6 +250,7 @@ extension Float : RandomType { return (Float(mask24 & (x)) / Float(twoto24), rng_) } + @effects(readnone) public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { let (l, h) = range if l > h { @@ -248,6 +263,7 @@ extension Float : RandomType { } extension Double : RandomType { + @effects(readnone) public static func random(rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) let twoto53 = Int64(2) ^ Int64(53) @@ -256,6 +272,7 @@ extension Double : RandomType { return (Double(mask53 & (x)) / Double(twoto53), rng_) } + @effects(readnone) public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { let (l, h) = range if l > h { @@ -269,12 +286,13 @@ extension Double : RandomType { /// Implementation Details Follow +@effects(readnone) private func mkStdRNG(o : Int) -> StdGen { func mkStdGen32(sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 - return StdGen(s1+1, s2+1) + return StdGen(s1 + 1, s2 + 1) } let ct = Int(clock()) @@ -285,6 +303,7 @@ private func mkStdRNG(o : Int) -> StdGen { return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } +@effects(readwrite) private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { var now : timeval = timeval() let rv = gettimeofday(&now, nil) diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index ceb47d8..4929420 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -26,11 +26,13 @@ extension Rose /*: Functor*/ { /// /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` branches the map is suspended. + @effects(readnone) public func fmap(f : (A -> B)) -> Rose { return f <^> self } } +@effects(readnone) public func <^> (f : A -> B, g : Rose) -> Rose { switch g { case .MkRose(let root, let children): @@ -44,6 +46,7 @@ extension Rose /*: Applicative*/ { typealias FAB = Rose B> /// Lifts a value into a Rose Tree. + @effects(readnone) public static func pure(a : A) -> Rose { return .MkRose({ a }, { [] }) } @@ -53,11 +56,13 @@ extension Rose /*: Applicative*/ { /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and /// applied, executing all side-effects along the way. + @effects(readnone) public func ap(fn : Rose B>) -> Rose { return fn <*> self } } +@effects(readnone) public func <*> (fn : Rose B>, g : Rose) -> Rose { switch fn { case .MkRose(let f, _): @@ -69,16 +74,19 @@ public func <*> (fn : Rose B>, g : Rose) -> Rose { extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all together. + @effects(readnone) public func bind(fn : A -> Rose) -> Rose { return self >>- fn } } +@effects(readnone) public func >>- (m : Rose, fn : A -> Rose) -> Rose { return joinRose(m.fmap(fn)) } /// Lifts functions to functions over Rose Trees. +@effects(readnone) public func liftM(f : A -> R)(m1 : Rose) -> Rose { return m1.bind { x1 in return Rose.pure(f(x1)) @@ -91,6 +99,7 @@ public func liftM(f : A -> R)(m1 : Rose) -> Rose { /// the node dictates the behavior of the join. For `.IORose` sub-trees The join is suspended. For /// `.MkRose` the result is the value at the sub-tree node and a recursive call to join the branch's /// tree to its sub-trees. +@effects(readnone) public func joinRose(rs : Rose>) -> Rose { switch rs { case .IORose(let rs): @@ -107,6 +116,7 @@ public func joinRose(rs : Rose>) -> Rose { /// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is /// encountered. That branch is then returned. +@effects(readnone) public func reduce(rs : Rose) -> Rose { switch rs { case .MkRose(_, _): @@ -117,6 +127,7 @@ public func reduce(rs : Rose) -> Rose { } /// Case analysis for a Rose Tree. +@effects(readnone) public func onRose(f : (A -> [Rose] -> Rose))(rs : Rose) -> Rose { switch rs { case .MkRose(let x, let rs): @@ -127,6 +138,7 @@ public func onRose(f : (A -> [Rose] -> Rose))(rs : Rose) -> Rose } /// Sequences an array of Rose Trees into a Rose Tree of an array. +@effects(readnone) public func sequence(ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in return m.bind { x in @@ -139,6 +151,7 @@ public func sequence(ms : [Rose]) -> Rose<[A]> { /// Sequences the result of mapping values to Rose trees into a single rose tree of an array of /// values. +@effects(readnone) public func mapM(f : A -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 35b3cfd..766fb67 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -85,112 +85,112 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B) throws -> Testable) -> Property { return forAll({ t in forAll({ b in try pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c in try pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in try pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified property using the /// default shrinker for that type. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 2 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 3 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 4 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 5 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 6 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 7 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 8 types. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -200,7 +200,7 @@ public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -210,7 +210,7 @@ public func forAllNoShrink(gen : Gen, pf : (A throws -> Testable)) -> Prop /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } @@ -220,7 +220,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) thr /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -230,7 +230,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -240,7 +240,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -250,7 +250,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -260,7 +260,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ g /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -270,14 +270,14 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. -@warn_unused_result +@warn_unused_result @effects(readnone) public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in @@ -306,12 +306,14 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T /// [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). `SNF` involves turning /// every `exists` into a function returning the existential value, taking any other parameters /// being quantified over as needed. +@effects(readnone) public func exists(pf : A throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially quantified property using /// the default shrinker for that type. +@effects(readnone) public func exists(gen : Gen, pf : A throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok @@ -815,6 +817,7 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { return rhs } +@effects(readnone) private func pluralize(s : String, i : Int) -> String { if i == 1 { return s @@ -823,6 +826,7 @@ private func pluralize(s : String, i : Int) -> String { } extension Array { + @effects(readnone) internal func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { if list.isEmpty { diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index c00b721..2e9b5ec 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -49,6 +49,7 @@ infix operator ==> { /// Models implication for properties. That is, the property holds if the first argument is false /// (in which case the test case is discarded), or if the given property holds. +@effects(readnone) public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { if b { return p().property @@ -58,6 +59,7 @@ public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { /// Models implication for properties. That is, the property holds if the first argument is false /// (in which case the test case is discarded), or if the given property holds. +@effects(readnone) public func ==>(b : Bool, p : () -> Testable) -> Property { if b { return p().property @@ -70,6 +72,7 @@ infix operator ==== { } /// Like equality but prints a verbose description when it fails. +@effects(readnone) public func ====(x : A, y : A) -> Property { return (x == y).counterexample(String(x) + "/=" + String(y)) } @@ -86,6 +89,7 @@ infix operator { /// test cases need to be distinct from one another. In addition to shrunken test cases, upon /// failure SwiftCheck will print a distribution map for the property that shows a percentage /// success rate for the property. +@effects(readnone) public func (p : Testable, s : String) -> Property { return p.label(s) } @@ -99,6 +103,7 @@ infix operator ^&&^ { /// /// Conjoined properties succeed only when both sub-properties succeed and fail when one or more /// sub-properties fail. +@effects(readnone) public func ^&&^(p1 : Testable, p2 : Testable) -> Property { return conjoin(p1.property, p2.property) } @@ -113,6 +118,7 @@ infix operator ^||^ { /// /// Disjoined properties succeed only when one or more sub-properties succeed and fail when both /// sub-properties fail. +@effects(readnone) public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index eaa5fdc..20a5298 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -14,48 +14,56 @@ public protocol WitnessedArbitrary { /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. +@effects(readnone) public func forAll(pf : (A -> Testable)) -> Property { return A.forAllWitnessed(id)(pf: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. +@effects(readnone) public func forAll(pf : (A, B) -> Testable) -> Property { return forAll({ t in forAll({ b in pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. +@effects(readnone) public func forAll(pf : (A, B, C) -> Testable) -> Property { return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. +@effects(readnone) public func forAll(pf : (A, B, C, D) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. +@effects(readnone) public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. +@effects(readnone) public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. +@effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. +@effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } From 1ad9c3be338a9e05aedd4b79841d6c8f0df7d032 Mon Sep 17 00:00:00 2001 From: Alexander Altman Date: Fri, 11 Dec 2015 19:51:14 -0800 Subject: [PATCH 213/460] Add Gitter integration for Travis --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3f0f109..7e2f20a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,10 @@ install: true script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/1d781e1bcbabade5de35 + on_success: always + on_failure: always + on_start: always From 1af12a02fad336556103fd78663527a7ca69ba90 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 14:59:17 -0500 Subject: [PATCH 214/460] Generate Mirrors --- SwiftCheck/Arbitrary.swift | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 21dce90..8516857 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -544,6 +544,39 @@ extension LazySequence where Base : protocol { } } +extension Mirror : Arbitrary { + public static var arbitrary : Gen { + let genAny : Gen = Gen.oneOf([ + Bool.arbitrary.fmap(asAny), + Int.arbitrary.fmap(asAny), + Int8.arbitrary.fmap(asAny), + Int64.arbitrary.fmap(asAny), + UInt.arbitrary.fmap(asAny), + UInt8.arbitrary.fmap(asAny), + UInt64.arbitrary.fmap(asAny), + Float.arbitrary.fmap(asAny), + Double.arbitrary.fmap(asAny), + UnicodeScalar.arbitrary.fmap(asAny), + String.arbitrary.fmap(asAny), + Character.arbitrary.fmap(asAny), + ]) + + let genAnyWitnessed : Gen = Gen.oneOf([ + Optional.arbitrary.fmap(asAny), + ImplicitlyUnwrappedOptional.arbitrary.fmap(asAny), + Range.arbitrary.fmap(asAny), + Repeat.arbitrary.fmap(asAny), + Array.arbitrary.fmap(asAny), + Set.arbitrary.fmap(asAny), + ]) + + return Gen.oneOf([ + genAny, + genAnyWitnessed, + ]).fmap(Mirror.init) + } +} + extension Range where Element : protocol { public static var arbitrary : Gen> { return Element.arbitrary.bind { l in @@ -791,6 +824,11 @@ extension Set : CoArbitrary { /// MARK: - Implementation Details +@effects(readnone) +private func asAny(x : T) -> Any { + return x +} + @effects(readnone) private func bits(n : N) -> Int { if n / 2 == 0 { From 9a68589e68937c86f8d554a7374812c31c705a64 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 22:17:52 -0500 Subject: [PATCH 215/460] Split files --- SwiftCheck.xcodeproj/project.pbxproj | 12 + SwiftCheck/Arbitrary.swift | 569 +-------------------------- SwiftCheck/CoArbitrary.swift | 190 +++++++++ SwiftCheck/WitnessedArbitrary.swift | 393 ++++++++++++++++++ 4 files changed, 596 insertions(+), 568 deletions(-) create mode 100644 SwiftCheck/CoArbitrary.swift create mode 100644 SwiftCheck/WitnessedArbitrary.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 716ca7b..b8f2b87 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; + 82ED49DF1C210D85008E9595 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; + 82ED49E01C210D85008E9595 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; + 82ED49E21C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; + 82ED49E31C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; @@ -102,6 +106,8 @@ 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; + 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoArbitrary.swift; sourceTree = ""; }; + 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WitnessedArbitrary.swift; sourceTree = ""; }; 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; usesTabs = 1; }; @@ -191,6 +197,7 @@ isa = PBXGroup; children = ( 844FCCA9198B323800EB242A /* Arbitrary.swift */, + 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */, 84572C241A6DBAA800241F68 /* Check.swift */, 844FCCAB198B32DC00EB242A /* Gen.swift */, 842015101AF5C91C00F1F3CD /* Lattice.swift */, @@ -204,6 +211,7 @@ 84572C2A1A6DBABA00241F68 /* Testable.swift */, 8450D2491AF8003700095EF6 /* TestOperators.swift */, 827749F71B65ABCC00A7965F /* Witness.swift */, + 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */, D46395B51B1A94D200AA1B65 /* Equatable.swift */, 844FCC90198B320500EB242A /* Supporting Files */, ); @@ -435,6 +443,8 @@ 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */, 844FCCB4198B39F300EB242A /* State.swift in Sources */, 827749F81B65ABCC00A7965F /* Witness.swift in Sources */, + 82ED49DF1C210D85008E9595 /* CoArbitrary.swift in Sources */, + 82ED49E21C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */, 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -475,6 +485,8 @@ 84DF761B1B0BD58100C912B0 /* State.swift in Sources */, 84DF761C1B0BD58100C912B0 /* Test.swift in Sources */, 827749F91B65ABCC00A7965F /* Witness.swift in Sources */, + 82ED49E01C210D85008E9595 /* CoArbitrary.swift in Sources */, + 82ED49E31C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */, 84DF761D1B0BD58100C912B0 /* Testable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 8516857..40f3210 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -295,56 +295,6 @@ extension Character : Arbitrary { } } -extension Array where Element : Arbitrary { - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).bind { k in - if k == 0 { - return Gen.pure([]) - } - - return sequence((0...k).map { _ in Element.arbitrary }) - } - } - } - - @effects(readnone) - public static func shrink(bl : Array) -> [[Element]] { - return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) - } -} - -extension Array : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : ([Element] -> Testable)) -> Property { - return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - -extension AnyBidirectionalCollection where Element : Arbitrary { - public static var arbitrary : Gen> { - return AnyBidirectionalCollection.init <^> [Element].arbitrary - } - - @effects(readnone) - public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { - return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) - } -} - -extension AnyBidirectionalCollection : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (AnyBidirectionalCollection -> Testable)) -> Property { - return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in - return pf(AnyBidirectionalCollection(bl.map(wit))) - }) - } -} - extension AnyForwardIndex : Arbitrary { public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) @@ -357,485 +307,7 @@ extension AnyRandomAccessIndex : Arbitrary { } } -extension AnySequence where Element : Arbitrary { - public static var arbitrary : Gen> { - return AnySequence.init <^> [Element].arbitrary - } - - @effects(readnone) - public static func shrink(bl : AnySequence) -> [AnySequence] { - return [Element].shrink([Element](bl)).map(AnySequence.init) - } -} - -extension AnySequence : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (AnySequence -> Testable)) -> Property { - return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in - return pf(AnySequence(bl.map(wit))) - }) - } -} - -extension ArraySlice where Element : Arbitrary { - public static var arbitrary : Gen> { - return ArraySlice.init <^> [Element].arbitrary - } - - @effects(readnone) - public static func shrink(bl : ArraySlice) -> [ArraySlice] { - return [Element].shrink([Element](bl)).map(ArraySlice.init) - } -} - -extension ArraySlice : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (ArraySlice -> Testable)) -> Property { - return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in - return pf(ArraySlice(bl.map(wit))) - }) - } -} - -extension CollectionOfOne where Element : Arbitrary { - public static var arbitrary : Gen> { - return CollectionOfOne.init <^> Element.arbitrary - } -} - -extension CollectionOfOne : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (CollectionOfOne -> Testable)) -> Property { - return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in - return pf(CollectionOfOne(wit(bl[.Zero]))) - }) - } -} - -/// Generates an Optional of arbitrary values of type A. -extension Optional where Wrapped : Arbitrary { - public static var arbitrary : Gen> { - return Gen>.frequency([ - (1, Gen>.pure(.None)), - (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), - ]) - } - - @effects(readnone) - public static func shrink(bl : Optional) -> [Optional] { - if let x = bl { - return [.None] + Wrapped.shrink(x).map(Optional.Some) - } - return [] - } -} - -extension Optional : WitnessedArbitrary { - public typealias Param = Wrapped - - public static func forAllWitnessed(wit : A -> Wrapped)(pf : (Optional -> Testable)) -> Property { - return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - -extension ContiguousArray where Element : Arbitrary { - public static var arbitrary : Gen> { - return ContiguousArray.init <^> [Element].arbitrary - } - - @effects(readnone) - public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { - return [Element].shrink([Element](bl)).map(ContiguousArray.init) - } -} - -extension ContiguousArray : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (ContiguousArray -> Testable)) -> Property { - return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in - return pf(ContiguousArray(bl.map(wit))) - }) - } -} - -/// Generates an dictionary of arbitrary keys and values. -extension Dictionary where Key : Arbitrary, Value : Arbitrary { - public static var arbitrary : Gen> { - return [Key].arbitrary.bind { k in - return [Value].arbitrary.bind { v in - return Gen.pure(Dictionary(Zip2Sequence(k, v))) - } - } - } - - @effects(readnone) - public static func shrink(d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } - } -} - -extension Dictionary { - init(_ pairs : S) { - self.init() - var g = pairs.generate() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } -} - -extension EmptyCollection : Arbitrary { - public static var arbitrary : Gen> { - return Gen.pure(EmptyCollection()) - } -} - -extension HalfOpenInterval where Bound : protocol { - public static var arbitrary : Gen> { - return Bound.arbitrary.bind { l in - return Bound.arbitrary.bind { r in - return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) - } - } - } - - @effects(readnone) - public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { - return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) - } -} - -extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { - public static var arbitrary : Gen> { - return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary - } - - @effects(readnone) - public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { - return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) - } -} - -extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { - public typealias Param = Wrapped - - public static func forAllWitnessed(wit : A -> Wrapped)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { - return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - -extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { - public static var arbitrary : Gen> { - return LazyCollection.arbitrary - } -} - -extension LazySequence where Base : protocol { - public static var arbitrary : Gen> { - return LazySequence.arbitrary - } -} - -extension Mirror : Arbitrary { - public static var arbitrary : Gen { - let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.fmap(asAny), - Int.arbitrary.fmap(asAny), - Int8.arbitrary.fmap(asAny), - Int64.arbitrary.fmap(asAny), - UInt.arbitrary.fmap(asAny), - UInt8.arbitrary.fmap(asAny), - UInt64.arbitrary.fmap(asAny), - Float.arbitrary.fmap(asAny), - Double.arbitrary.fmap(asAny), - UnicodeScalar.arbitrary.fmap(asAny), - String.arbitrary.fmap(asAny), - Character.arbitrary.fmap(asAny), - ]) - - let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.fmap(asAny), - ImplicitlyUnwrappedOptional.arbitrary.fmap(asAny), - Range.arbitrary.fmap(asAny), - Repeat.arbitrary.fmap(asAny), - Array.arbitrary.fmap(asAny), - Set.arbitrary.fmap(asAny), - ]) - - return Gen.oneOf([ - genAny, - genAnyWitnessed, - ]).fmap(Mirror.init) - } -} - -extension Range where Element : protocol { - public static var arbitrary : Gen> { - return Element.arbitrary.bind { l in - return Element.arbitrary.bind { r in - return Gen.pure(Range(start: min(l, r), end: max(l, r))) - } - } - } - - @effects(readnone) - public static func shrink(bl : Range) -> [Range] { - return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) - } -} - -extension Repeat where Element : Arbitrary { - public static var arbitrary : Gen> { - return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) - } -} - -extension Repeat : WitnessedArbitrary { - public typealias Param = Element - - @effects(readnone) - public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { - return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in - let xs = bl.map(wit) - return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) - }) - } -} - -extension Set where Element : protocol { - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).bind { k in - if k == 0 { - return Gen.pure(Set([])) - } - - return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) - } - } - } - - @effects(readnone) - public static func shrink(s : Set) -> [Set] { - return [Element].shrink([Element](s)).map(Set.init) - } -} - -extension Set : WitnessedArbitrary { - public typealias Param = Element - - public static func forAllWitnessed(wit : A -> Element)(pf : (Set -> Testable)) -> Property { - return forAll { (xs : [A]) in - return pf(Set(xs.map(wit))) - } - } -} - -/// Coarbitrary types must take an arbitrary value of their type and yield a function that -/// transforms a given generator by returning a new generator that depends on the input value. Put -/// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. -public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a generator. - static func coarbitrary(x : Self) -> (Gen -> Gen) -} - -extension IntegerType { - /// A coarbitrary implementation for any IntegerType - public func coarbitraryIntegral() -> Gen -> Gen { - return { $0.variant(self) } - } -} - -/// A coarbitrary implementation for any Printable type. Avoid using this function if you can, it -/// can be quite an expensive operation given a detailed enough description. -public func coarbitraryPrintable(x : A) -> Gen -> Gen { - return String.coarbitrary(String(x)) -} - -extension Bool : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Bool) -> Gen -> Gen { - return { g in - if x { - return g.variant(1) - } - return g.variant(0) - } - } -} - -extension UnicodeScalar : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { - return UInt32.coarbitrary(x.value) - } -} - -extension Character : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Character) -> (Gen -> Gen) { - let ss = String(x).unicodeScalars - return UnicodeScalar.coarbitrary(ss[ss.startIndex]) - } -} - -extension String : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : String) -> (Gen -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.startIndex.successor()..(x : Int) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension Int8 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Int8) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension Int16 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Int16) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension Int32 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Int32) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension Int64 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Int64) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension UInt : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UInt) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension UInt8 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UInt8) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension UInt16 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UInt16) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension UInt32 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UInt32) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -extension UInt64 : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : UInt64) -> Gen -> Gen { - return x.coarbitraryIntegral() - } -} - -// In future, implement these with Ratios like QuickCheck. -extension Float : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Float) -> (Gen -> Gen) { - return Int64(x).coarbitraryIntegral() - } -} - -extension Double : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Double) -> (Gen -> Gen) { - return Int64(x).coarbitraryIntegral() - } -} - -extension Array : CoArbitrary { - @effects(readnone) - public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { - if a.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(x : Dictionary) -> (Gen -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - -extension Optional : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Optional) -> (Gen -> Gen) { - if let _ = x { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - -extension Set : CoArbitrary { - @effects(readnone) - public static func coarbitrary(x : Set) -> (Gen -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - -/// MARK: - Implementation Details - -@effects(readnone) -private func asAny(x : T) -> Any { - return x -} - -@effects(readnone) -private func bits(n : N) -> Int { - if n / 2 == 0 { - return 0 - } - return 1 + bits(n / 2) -} +// MARK: - Implementation Details Follow @effects(readnone) private func nub(xs : [A]) -> [A] { @@ -852,42 +324,3 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { } return acc } - -@effects(readnone) -private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 = take(k, xs: xs) - let xs2 = drop(k, xs: xs) - - if k > n { - return [] - } else if xs2.isEmpty { - return [[]] - } else { - return [xs2] + removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) - } -} - -@effects(readnone) -private func take(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n..(xs : [A]) -> [[A]] { - if xs.isEmpty { - return [] - } else if let x = xs.first { - let xss = [A](xs[1..(x : Self) -> (Gen -> Gen) +} + +extension IntegerType { + /// A coarbitrary implementation for any IntegerType + public func coarbitraryIntegral() -> Gen -> Gen { + return { $0.variant(self) } + } +} + +/// A coarbitrary implementation for any Printable type. Avoid using this function if you can, it +/// can be quite an expensive operation given a detailed enough description. +public func coarbitraryPrintable(x : A) -> Gen -> Gen { + return String.coarbitrary(String(x)) +} + +extension Bool : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Bool) -> Gen -> Gen { + return { g in + if x { + return g.variant(1) + } + return g.variant(0) + } + } +} + +extension UnicodeScalar : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { + return UInt32.coarbitrary(x.value) + } +} + +extension Character : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Character) -> (Gen -> Gen) { + let ss = String(x).unicodeScalars + return UnicodeScalar.coarbitrary(ss[ss.startIndex]) + } +} + +extension String : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : String) -> (Gen -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.startIndex.successor()..(x : Int) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension Int8 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Int8) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension Int16 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Int16) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension Int32 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Int32) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension Int64 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Int64) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension UInt : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UInt) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension UInt8 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UInt8) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension UInt16 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UInt16) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension UInt32 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UInt32) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +extension UInt64 : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : UInt64) -> Gen -> Gen { + return x.coarbitraryIntegral() + } +} + +// In future, implement these with Ratios like QuickCheck. +extension Float : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Float) -> (Gen -> Gen) { + return Int64(x).coarbitraryIntegral() + } +} + +extension Double : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Double) -> (Gen -> Gen) { + return Int64(x).coarbitraryIntegral() + } +} + +extension Array : CoArbitrary { + @effects(readnone) + public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(x : Dictionary) -> (Gen -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} + +extension Optional : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Optional) -> (Gen -> Gen) { + if let _ = x { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} + +extension Set : CoArbitrary { + @effects(readnone) + public static func coarbitrary(x : Set) -> (Gen -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } +} diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift new file mode 100644 index 0000000..e562c99 --- /dev/null +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -0,0 +1,393 @@ +// +// WitnessedArbitrary.swift +// SwiftCheck +// +// Created by Robert Widmann on 12/15/15. +// Copyright © 2015 Robert Widmann. All rights reserved. +// + +extension Array where Element : Arbitrary { + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).bind { k in + if k == 0 { + return Gen.pure([]) + } + + return sequence((0...k).map { _ in Element.arbitrary }) + } + } + } + + @effects(readnone) + public static func shrink(bl : Array) -> [[Element]] { + return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) + } +} + +extension Array : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : ([Element] -> Testable)) -> Property { + return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + +extension AnyBidirectionalCollection where Element : Arbitrary { + public static var arbitrary : Gen> { + return AnyBidirectionalCollection.init <^> [Element].arbitrary + } + + @effects(readnone) + public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) + } +} + +extension AnyBidirectionalCollection : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (AnyBidirectionalCollection -> Testable)) -> Property { + return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in + return pf(AnyBidirectionalCollection(bl.map(wit))) + }) + } +} + +extension AnySequence where Element : Arbitrary { + public static var arbitrary : Gen> { + return AnySequence.init <^> [Element].arbitrary + } + + @effects(readnone) + public static func shrink(bl : AnySequence) -> [AnySequence] { + return [Element].shrink([Element](bl)).map(AnySequence.init) + } +} + +extension AnySequence : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (AnySequence -> Testable)) -> Property { + return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in + return pf(AnySequence(bl.map(wit))) + }) + } +} + +extension ArraySlice where Element : Arbitrary { + public static var arbitrary : Gen> { + return ArraySlice.init <^> [Element].arbitrary + } + + @effects(readnone) + public static func shrink(bl : ArraySlice) -> [ArraySlice] { + return [Element].shrink([Element](bl)).map(ArraySlice.init) + } +} + +extension ArraySlice : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (ArraySlice -> Testable)) -> Property { + return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in + return pf(ArraySlice(bl.map(wit))) + }) + } +} + +extension CollectionOfOne where Element : Arbitrary { + public static var arbitrary : Gen> { + return CollectionOfOne.init <^> Element.arbitrary + } +} + +extension CollectionOfOne : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (CollectionOfOne -> Testable)) -> Property { + return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in + return pf(CollectionOfOne(wit(bl[.Zero]))) + }) + } +} + +/// Generates an Optional of arbitrary values of type A. +extension Optional where Wrapped : Arbitrary { + public static var arbitrary : Gen> { + return Gen>.frequency([ + (1, Gen>.pure(.None)), + (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), + ]) + } + + @effects(readnone) + public static func shrink(bl : Optional) -> [Optional] { + if let x = bl { + return [.None] + Wrapped.shrink(x).map(Optional.Some) + } + return [] + } +} + +extension Optional : WitnessedArbitrary { + public typealias Param = Wrapped + + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (Optional -> Testable)) -> Property { + return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + +extension ContiguousArray where Element : Arbitrary { + public static var arbitrary : Gen> { + return ContiguousArray.init <^> [Element].arbitrary + } + + @effects(readnone) + public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { + return [Element].shrink([Element](bl)).map(ContiguousArray.init) + } +} + +extension ContiguousArray : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (ContiguousArray -> Testable)) -> Property { + return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in + return pf(ContiguousArray(bl.map(wit))) + }) + } +} + +/// Generates an dictionary of arbitrary keys and values. +extension Dictionary where Key : Arbitrary, Value : Arbitrary { + public static var arbitrary : Gen> { + return [Key].arbitrary.bind { k in + return [Value].arbitrary.bind { v in + return Gen.pure(Dictionary(Zip2Sequence(k, v))) + } + } + } + + @effects(readnone) + public static func shrink(d : Dictionary) -> [Dictionary] { + return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } + } +} + +extension Dictionary { + init(_ pairs : S) { + self.init() + var g = pairs.generate() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } +} + +extension EmptyCollection : Arbitrary { + public static var arbitrary : Gen> { + return Gen.pure(EmptyCollection()) + } +} + +extension HalfOpenInterval where Bound : protocol { + public static var arbitrary : Gen> { + return Bound.arbitrary.bind { l in + return Bound.arbitrary.bind { r in + return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) + } + } + } + + @effects(readnone) + public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { + return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) + } +} + +extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { + public static var arbitrary : Gen> { + return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary + } + + @effects(readnone) + public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { + return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) + } +} + +extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { + public typealias Param = Wrapped + + public static func forAllWitnessed(wit : A -> Wrapped)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { + return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } +} + +extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { + public static var arbitrary : Gen> { + return LazyCollection.arbitrary + } +} + +extension LazySequence where Base : protocol { + public static var arbitrary : Gen> { + return LazySequence.arbitrary + } +} + +extension Mirror : Arbitrary { + public static var arbitrary : Gen { + let genAny : Gen = Gen.oneOf([ + Bool.arbitrary.fmap(asAny), + Int.arbitrary.fmap(asAny), + Int8.arbitrary.fmap(asAny), + Int64.arbitrary.fmap(asAny), + UInt.arbitrary.fmap(asAny), + UInt8.arbitrary.fmap(asAny), + UInt64.arbitrary.fmap(asAny), + Float.arbitrary.fmap(asAny), + Double.arbitrary.fmap(asAny), + UnicodeScalar.arbitrary.fmap(asAny), + String.arbitrary.fmap(asAny), + Character.arbitrary.fmap(asAny), + ]) + + let genAnyWitnessed : Gen = Gen.oneOf([ + Optional.arbitrary.fmap(asAny), + ImplicitlyUnwrappedOptional.arbitrary.fmap(asAny), + Range.arbitrary.fmap(asAny), + Repeat.arbitrary.fmap(asAny), + Array.arbitrary.fmap(asAny), + Set.arbitrary.fmap(asAny), + ]) + + return Gen.oneOf([ + genAny, + genAnyWitnessed, + ]).fmap(Mirror.init) + } +} + +extension Range where Element : protocol { + public static var arbitrary : Gen> { + return Element.arbitrary.bind { l in + return Element.arbitrary.bind { r in + return Gen.pure(Range(start: min(l, r), end: max(l, r))) + } + } + } + + @effects(readnone) + public static func shrink(bl : Range) -> [Range] { + return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) + } +} + +extension Repeat where Element : Arbitrary { + public static var arbitrary : Gen> { + return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) + } +} + +extension Repeat : WitnessedArbitrary { + public typealias Param = Element + + @effects(readnone) + public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { + return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in + let xs = bl.map(wit) + return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) + }) + } +} + +extension Set where Element : protocol { + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).bind { k in + if k == 0 { + return Gen.pure(Set([])) + } + + return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) + } + } + } + + @effects(readnone) + public static func shrink(s : Set) -> [Set] { + return [Element].shrink([Element](s)).map(Set.init) + } +} + +extension Set : WitnessedArbitrary { + public typealias Param = Element + + public static func forAllWitnessed(wit : A -> Element)(pf : (Set -> Testable)) -> Property { + return forAll { (xs : [A]) in + return pf(Set(xs.map(wit))) + } + } +} + +// MARK: - Implementation Details Follow + +@effects(readnone) +private func asAny(x : T) -> Any { + return x +} + +@effects(readnone) +private func bits(n : N) -> Int { + if n / 2 == 0 { + return 0 + } + return 1 + bits(n / 2) +} + +@effects(readnone) +private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { + let xs1 = take(k, xs: xs) + let xs2 = drop(k, xs: xs) + + if k > n { + return [] + } else if xs2.isEmpty { + return [[]] + } else { + return [xs2] + removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + } +} + +@effects(readnone) +private func take(num : Int, xs : [T]) -> [T] { + let n = (num < xs.count) ? num : xs.count + return [T](xs[0..(num : Int, xs : [T]) -> [T] { + let n = (num < xs.count) ? num : xs.count + return [T](xs[n..(xs : [A]) -> [[A]] { + if xs.isEmpty { + return [] + } else if let x = xs.first { + let xss = [A](xs[1.. Date: Tue, 15 Dec 2015 22:35:23 -0500 Subject: [PATCH 216/460] Rejigger the docs --- SwiftCheck/Arbitrary.swift | 24 ++++++++++++------------ SwiftCheck/CoArbitrary.swift | 10 ++++++++-- SwiftCheck/Lattice.swift | 2 +- SwiftCheck/Test.swift | 7 ++++--- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 40f3210..d7e2ad8 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -8,29 +8,29 @@ /// A type that implements random generation and shrinking of values. /// -/// While testing, SwiftCheck will invoke `arbitrary()` a given amount of times (usually 100 if the +/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times (usually 100 if the /// default settings are used). During that time, the receiver has an opportunity to call through /// to any data or sources of randomness it needs to return what it deems an "Arbitrary" value. /// /// Shrinking is reduction in the complexity of a tested value to remove noise and present a minimal -/// counterexample when a property fails. While it may seem counterintuitive, a shrink necessitates -/// returning a list of all possible "smaller" values for SwiftCheck to run through. As long as -/// each individual value in the returned list is less than or equal to the size of the input value, -/// and is not a duplicate of the input value, a minimal case should be reached fairly efficiently. -/// Shrinking is an optional extension of normal testing. If no implementation of `shrink` is -/// provided, SwiftCheck will default to an empty one. +/// counterexample when a property fails. A shrink necessitates returning a list of all possible +/// "smaller" values for SwiftCheck to run through. As long as each individual value in the +/// returned list is less than or equal to the size of the input value, and is not a duplicate of +/// the input value, a minimal case should be reached fairly efficiently. Shrinking is an optional +/// extension of normal testing. If no implementation of `shrink` is provided, SwiftCheck will +/// default to an empty one - that is, no shrinking will occur. /// /// As an example, take the `ArrayOf` implementation of shrink: /// /// Arbitrary.shrink(ArrayOf([1, 2, 3])) /// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// -/// SwiftCheck will search each case one-by-one and continue shrinking until it has reached a case -/// it deems minimal enough to present. +/// SwiftCheck will search each case forward, one-by-one, and continue shrinking until it has +/// reached a case it deems minimal enough to present. /// -/// SwiftCheck implements a number of generators for common STL types for convenience. If more fine- -/// grained testing is required see `Modifiers.swift` for an example of how to define a "Modifier" -/// type to implement it. +/// SwiftCheck implements a number of generators for common Swift Standard Library types for +/// convenience. If more fine-grained testing is required see `Modifiers.swift` for an example of +/// how to define a "Modifier" type to implement it. public protocol Arbitrary { /// The generator for this particular type. /// diff --git a/SwiftCheck/CoArbitrary.swift b/SwiftCheck/CoArbitrary.swift index 3572063..9d90762 100644 --- a/SwiftCheck/CoArbitrary.swift +++ b/SwiftCheck/CoArbitrary.swift @@ -6,9 +6,15 @@ // Copyright © 2015 Robert Widmann. All rights reserved. // -/// Coarbitrary types must take an arbitrary value of their type and yield a function that +/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` allows generating +/// random values, `CoArbitrary` allows observance of random values passing through as input to +/// random functions. A `CoArbitrary` type is thus able to influence the flow of values in the +/// function. +/// +/// `CoArbitrary` types must take an arbitrary value of their type and yield a function that /// transforms a given generator by returning a new generator that depends on the input value. Put -/// simply, the function should perturb the given generator (more than likely using `Gen.variant()`. +/// simply, the function should perturb the given generator (more than likely using `Gen.variant()`) +/// based on the value it observes. public protocol CoArbitrary { /// Uses an instance of the receiver to return a function that perturbs a generator. static func coarbitrary(x : Self) -> (Gen -> Gen) diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index 048fb95..d9a962e 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -90,7 +90,7 @@ extension AnyRandomAccessIndex : LatticeType { } -/// float.h does not export Float80's limits, nor does the Swift STL. +/// float.h does not export Float80's limits, nor does the Swift Standard Library. // rdar://18404510 //extension Swift.Float80 : LatticeType { // public static var min : Swift.Float80 { diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 766fb67..9fd2baa 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -633,9 +633,10 @@ internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { // This ridiculously stateful looping nonsense is due to limitations of the Swift unroller and, more // importantly, ARC. This has been written with recursion in the past, and it was fabulous and // beautiful, but it generated useless objects that ARC couldn't release on the order of Gigabytes -// for complex shrinks (much like `split` in the Swift STL), and was slow as hell. This way we stay -// in one stack frame no matter what and give ARC a chance to cleanup after us. Plus we get to -// stay within a reasonable ~50-100 megabytes for truly horrendous tests that used to eat 8 gigs. +// for complex shrinks (much like `split` in the Swift Standard Library), and was slow as hell. +// This way we stay in one stack frame no matter what and give ARC a chance to cleanup after us. +// Plus we get to stay within a reasonable ~50-100 megabytes for truly horrendous tests that used to +/// eat 8 gigs. internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") From 8d76b2aa6fca63e03dddc3f765f21c5ce09a4a89 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 22:39:04 -0500 Subject: [PATCH 217/460] Whitespace --- SwiftCheck/WitnessedArbitrary.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index e562c99..63a8dd7 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -120,7 +120,7 @@ extension Optional where Wrapped : Arbitrary { return Gen>.frequency([ (1, Gen>.pure(.None)), (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), - ]) + ]) } @effects(readnone) @@ -258,7 +258,7 @@ extension Mirror : Arbitrary { UnicodeScalar.arbitrary.fmap(asAny), String.arbitrary.fmap(asAny), Character.arbitrary.fmap(asAny), - ]) + ]) let genAnyWitnessed : Gen = Gen.oneOf([ Optional.arbitrary.fmap(asAny), @@ -272,7 +272,7 @@ extension Mirror : Arbitrary { return Gen.oneOf([ genAny, genAnyWitnessed, - ]).fmap(Mirror.init) + ]).fmap(Mirror.init) } } From e814359a7a3e566dcf0673604c26471a19e1fa8d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 22:43:09 -0500 Subject: [PATCH 218/460] Reduce the number of cases in Mirror gen --- SwiftCheck/Arbitrary.swift | 25 ++++++++++++++++++++++ SwiftCheck/WitnessedArbitrary.swift | 33 ----------------------------- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index d7e2ad8..17e1a3b 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -307,6 +307,31 @@ extension AnyRandomAccessIndex : Arbitrary { } } +extension Mirror : Arbitrary { + public static var arbitrary : Gen { + let genAny : Gen = Gen.oneOf([ + Bool.arbitrary.fmap(asAny), + Int.arbitrary.fmap(asAny), + UInt.arbitrary.fmap(asAny), + Float.arbitrary.fmap(asAny), + Double.arbitrary.fmap(asAny), + Character.arbitrary.fmap(asAny), + ]) + + let genAnyWitnessed : Gen = Gen.oneOf([ + Optional.arbitrary.fmap(asAny), + Array.arbitrary.fmap(asAny), + Set.arbitrary.fmap(asAny), + ]) + + return Gen.oneOf([ + genAny, + genAnyWitnessed, + ]).fmap(Mirror.init) + } +} + + // MARK: - Implementation Details Follow @effects(readnone) diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index 63a8dd7..afc9f89 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -243,39 +243,6 @@ extension LazySequence where Base : protocol { } } -extension Mirror : Arbitrary { - public static var arbitrary : Gen { - let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.fmap(asAny), - Int.arbitrary.fmap(asAny), - Int8.arbitrary.fmap(asAny), - Int64.arbitrary.fmap(asAny), - UInt.arbitrary.fmap(asAny), - UInt8.arbitrary.fmap(asAny), - UInt64.arbitrary.fmap(asAny), - Float.arbitrary.fmap(asAny), - Double.arbitrary.fmap(asAny), - UnicodeScalar.arbitrary.fmap(asAny), - String.arbitrary.fmap(asAny), - Character.arbitrary.fmap(asAny), - ]) - - let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.fmap(asAny), - ImplicitlyUnwrappedOptional.arbitrary.fmap(asAny), - Range.arbitrary.fmap(asAny), - Repeat.arbitrary.fmap(asAny), - Array.arbitrary.fmap(asAny), - Set.arbitrary.fmap(asAny), - ]) - - return Gen.oneOf([ - genAny, - genAnyWitnessed, - ]).fmap(Mirror.init) - } -} - extension Range where Element : protocol { public static var arbitrary : Gen> { return Element.arbitrary.bind { l in From 89af65dd840d152935267b21e6406c48824d8a76 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 22:44:01 -0500 Subject: [PATCH 219/460] Errr... --- SwiftCheck/Arbitrary.swift | 5 +++++ SwiftCheck/WitnessedArbitrary.swift | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 17e1a3b..8c20118 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -334,6 +334,11 @@ extension Mirror : Arbitrary { // MARK: - Implementation Details Follow +@effects(readnone) +private func asAny(x : T) -> Any { + return x +} + @effects(readnone) private func nub(xs : [A]) -> [A] { return [A](Set(xs)) diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index afc9f89..ccd0441 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -307,11 +307,6 @@ extension Set : WitnessedArbitrary { // MARK: - Implementation Details Follow -@effects(readnone) -private func asAny(x : T) -> Any { - return x -} - @effects(readnone) private func bits(n : N) -> Int { if n / 2 == 0 { From 4f0be7be8c263cb9ed181d916d8cb1961d1f4bc2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 15 Dec 2015 23:00:28 -0500 Subject: [PATCH 220/460] Upgrade CI instance --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e2f20a..3484b40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.1 +osx_image: xcode7.2 env: - TEST_CONFIG="RELEASE" - TEST_CONFIG="PODS" From 2c1e8aec5402e386f893b887cb68ee975d212404 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 16 Dec 2015 00:32:06 -0500 Subject: [PATCH 221/460] Improve compile times @robrix --- SwiftCheck/Arbitrary.swift | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 8c20118..d84f4fe 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -209,13 +209,16 @@ extension Float : Arbitrary { public static var arbitrary : Gen { let precision : Int64 = 9999999999999 - return Gen.sized { n in + return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - >>- { a in Gen.choose((1, precision)) + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator >>- { b in Gen.pure(Float(a) / Float(b)) } } } } @@ -236,13 +239,16 @@ extension Double : Arbitrary { public static var arbitrary : Gen { let precision : Int64 = 9999999999999 - return Gen.sized { n in + return Gen.sized { n in if n == 0 { return Gen.pure(0.0) } - return Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - >>- { a in Gen.choose((1, precision)) + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator >>- { b in Gen.pure(Double(a) / Double(b)) } } } } @@ -267,7 +273,7 @@ extension UnicodeScalar : Arbitrary { @effects(readnone) public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) - return nub([ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ]).filter { $0 < x } + return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } } } @@ -339,9 +345,10 @@ private func asAny(x : T) -> Any { return x } -@effects(readnone) -private func nub(xs : [A]) -> [A] { - return [A](Set(xs)) +extension Array where Element : Hashable { + private var nub : [Element] { + return [Element](Set(self)) + } } @effects(readnone) From ebe3a59bdd47667a869b9ee69a98a61c7d5b89d9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 17:47:19 -0500 Subject: [PATCH 222/460] Temporarily check function body times --- SwiftCheck.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index b8f2b87..7869681 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -630,7 +630,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = ""; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -663,7 +663,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = ""; + OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; From d540bdfc9e9c04f4a7c3f89963c7d6c1d728da60 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 17:47:36 -0500 Subject: [PATCH 223/460] Optimize Gen for typechecker --- SwiftCheck/Gen.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 901b19b..15a664a 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -432,7 +432,8 @@ private func selectOne(xs : [A]) -> [(A, [A])] { } let y = xs.first! let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) + return [(y, ys)] + rec } @effects(readnone) From cc891c9e9edbcf4218937654c94a51d5e6244354 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 17:47:50 -0500 Subject: [PATCH 224/460] Split out private functions from disj --- SwiftCheck/Property.swift | 70 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 6157dc7..a927736 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -499,6 +499,31 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, return map } +@effects(readnone) +private func sep(l : String, r : String) -> String { + if l.isEmpty { + return r + } + + if r.isEmpty { + return l + } + return l + ", " + r +} + +@effects(readnone) +private func mplus(l : Optional, r : Optional) -> Optional { + if let ls = l, rs = r { + return .Some(ls + rs) + } + + if l == nil { + return r + } + + return l +} + @effects(readnone) private func addCallbacks(result : TestResult) -> TestResult -> TestResult { return { res in @@ -573,46 +598,23 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose @effects(readnone) private func disj(p : Rose, q : Rose) -> Rose { - func sep(l : String, r : String) -> String { - if l.isEmpty { - return r - } - - if r.isEmpty { - return l - } - return l + ", " + r - } - - func mplus(l : Optional, r : Optional) -> Optional { - if let ls = l, rs = r { - return .Some(ls + rs) - } - - if l == nil { - return r - } - - return l - } - return p.bind { result1 in if !result1.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result1.ok { case .Some(true): - return Rose.pure(result1) + return Rose.pure(result1) case .Some(false): - return q.bind { result2 in + return q.bind { (result2 : TestResult) in if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { case .Some(true): - return Rose.pure(result2) + return Rose.pure(result2) case .Some(false): - return Rose.pure(TestResult(ok: .Some(false), + return Rose.pure(TestResult(ok: .Some(false), expect: true, reason: sep(result1.reason, r: result2.reason), theException: mplus(result1.theException, r: result2.theException), @@ -625,19 +627,19 @@ private func disj(p : Rose, q : Rose) -> Rose.pure(result2) } } case .None: - return q.bind { result2 in + return q.bind { (result2 : TestResult) in if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { case .Some(true): - return Rose.pure(result2) + return Rose.pure(result2) default: - return Rose.pure(result1) + return Rose.pure(result1) } } } From b7075697206d5f4454ddff2bfc0164f409eb9a56 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 17:48:00 -0500 Subject: [PATCH 225/460] Split up summary --- SwiftCheck/Test.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 9fd2baa..165369a 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -755,10 +755,8 @@ internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestRe } internal func summary(s : CheckerState) -> [(String, Int)] { - let l = s.collected - .flatMap({ l in l.map({ "," + $0 }).filter({ !$0.isEmpty }) }) - .sort() - .groupBy(==) + let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) + let l : [[String]] = lff.sort().groupBy(==) return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } From 835528b982a1a5571b6c269195528ed2f17c4247 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 17:48:05 -0500 Subject: [PATCH 226/460] Annotate removes --- SwiftCheck/WitnessedArbitrary.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index ccd0441..74673e1 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -317,8 +317,8 @@ private func bits(n : N) -> Int { @effects(readnone) private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 = take(k, xs: xs) - let xs2 = drop(k, xs: xs) + let xs1 : [A] = take(k, xs: xs) + let xs2 : [A] = drop(k, xs: xs) if k > n { return [] From 15e8e7314ffe88d159d90e9253f1dbe837fac1d6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 18 Dec 2015 18:10:31 -0500 Subject: [PATCH 227/460] Type recursive calls --- SwiftCheck/Property.swift | 9 +++++---- SwiftCheck/Test.swift | 20 ++++++++++---------- SwiftCheck/WitnessedArbitrary.swift | 17 ++++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index a927736..9861d08 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -614,16 +614,17 @@ private func disj(p : Rose, q : Rose) -> Rose.pure(result2) case .Some(false): + let callbacks : [Callback] = [.AfterFinalFailure(kind: .Counterexample, + f: { _ in + return print("") + })] return Rose.pure(TestResult(ok: .Some(false), expect: true, reason: sep(result1.reason, r: result2.reason), theException: mplus(result1.theException, r: result2.theException), labels: [:], stamp: Set(), - callbacks: result1.callbacks + [.AfterFinalFailure(kind: .Counterexample, - f: { _ in - return print("") - })] + result2.callbacks, + callbacks: result1.callbacks + callbacks + result2.callbacks, abort: false, quantifier: .Universal)) case .None: diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 165369a..b69ece0 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -754,13 +754,13 @@ internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestRe } } -internal func summary(s : CheckerState) -> [(String, Int)] { +private func summary(s : CheckerState) -> [(String, Int)] { let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) let l : [[String]] = lff.sort().groupBy(==) return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } -internal func labelPercentage(l : String, st : CheckerState) -> Int { +private func labelPercentage(l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap(Array.init).filter { $0 == l } return (100 * occur.count) / st.maxAllowableSuccessfulTests } @@ -778,17 +778,17 @@ internal func printLabels(st : TestResult) { } } -internal func printDistributionGraph(st : CheckerState) { - func showP(n : Int) -> String { - return (n < 10 ? " " : "") + "\(n)" + "%" - } +private func showP(n : Int) -> String { + return (n < 10 ? " " : "") + "\(n)" + "%" +} - let gAllLabels = st.collected.map({ (s : Set) in +private func printDistributionGraph(st : CheckerState) { + let gAllLabels : [String] = st.collected.map({ (s : Set) in return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) }) - let gAll = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) - let gPrint = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) - let allLabels = Array(gPrint.sort().reverse()) + let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) + let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) + let allLabels : [String] = Array(gPrint.sort().reverse()) var covers = [String]() st.labels.forEach { (l, reqP) in diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index 74673e1..d89b25c 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -21,7 +21,8 @@ extension Array where Element : Arbitrary { @effects(readnone) public static func shrink(bl : Array) -> [[Element]] { - return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + shrinkOne(bl) + let rec : [[Element]] = shrinkOne(bl) + return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec } } @@ -126,7 +127,8 @@ extension Optional where Wrapped : Arbitrary { @effects(readnone) public static func shrink(bl : Optional) -> [Optional] { if let x = bl { - return [.None] + Wrapped.shrink(x).map(Optional.Some) + let rec : [Optional] = Wrapped.shrink(x).map(Optional.Some) + return [.None] + rec } return [] } @@ -325,7 +327,8 @@ private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { } else if xs2.isEmpty { return [[]] } else { - return [xs2] + removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + return [xs2] + rec } } @@ -344,11 +347,11 @@ private func drop(num : Int, xs : [T]) -> [T] { @effects(readnone) private func shrinkOne(xs : [A]) -> [[A]] { if xs.isEmpty { - return [] - } else if let x = xs.first { + return [[A]]() + } else if let x : A = xs.first { let xss = [A](xs[1.. Date: Mon, 28 Dec 2015 17:09:56 -0500 Subject: [PATCH 228/460] Remove effects annotations --- SwiftCheck/Arbitrary.swift | 18 ---------- SwiftCheck/Check.swift | 2 -- SwiftCheck/CoArbitrary.swift | 20 ----------- SwiftCheck/Equatable.swift | 9 ----- SwiftCheck/Gen.swift | 35 ------------------- SwiftCheck/Property.swift | 35 ------------------- SwiftCheck/Random.swift | 19 ---------- SwiftCheck/Rose.swift | 13 ------- SwiftCheck/Test.swift | 54 +++++++++++++---------------- SwiftCheck/TestOperators.swift | 6 ---- SwiftCheck/Witness.swift | 8 ----- SwiftCheck/WitnessedArbitrary.swift | 17 --------- 12 files changed, 25 insertions(+), 211 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index d84f4fe..b52547c 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -74,7 +74,6 @@ extension Bool : Arbitrary { return Gen.choose((false, true)) } - @effects(readnone) public static func shrink(x : Bool) -> [Bool] { if x { return [false] @@ -90,7 +89,6 @@ extension Int : Arbitrary { } } - @effects(readnone) public static func shrink(x : Int) -> [Int] { return x.shrinkIntegral } @@ -103,7 +101,6 @@ extension Int8 : Arbitrary { } } - @effects(readnone) public static func shrink(x : Int8) -> [Int8] { return x.shrinkIntegral } @@ -116,7 +113,6 @@ extension Int16 : Arbitrary { } } - @effects(readnone) public static func shrink(x : Int16) -> [Int16] { return x.shrinkIntegral } @@ -129,7 +125,6 @@ extension Int32 : Arbitrary { } } - @effects(readnone) public static func shrink(x : Int32) -> [Int32] { return x.shrinkIntegral } @@ -142,7 +137,6 @@ extension Int64 : Arbitrary { } } - @effects(readnone) public static func shrink(x : Int64) -> [Int64] { return x.shrinkIntegral } @@ -153,7 +147,6 @@ extension UInt : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt(n))) } } - @effects(readnone) public static func shrink(x : UInt) -> [UInt] { return x.shrinkIntegral } @@ -166,7 +159,6 @@ extension UInt8 : Arbitrary { } } - @effects(readnone) public static func shrink(x : UInt8) -> [UInt8] { return x.shrinkIntegral } @@ -177,7 +169,6 @@ extension UInt16 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } } - @effects(readnone) public static func shrink(x : UInt16) -> [UInt16] { return x.shrinkIntegral } @@ -188,7 +179,6 @@ extension UInt32 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } } - @effects(readnone) public static func shrink(x : UInt32) -> [UInt32] { return x.shrinkIntegral } @@ -199,7 +189,6 @@ extension UInt64 : Arbitrary { return Gen.sized { n in Gen.choose((0, UInt64(n))) } } - @effects(readnone) public static func shrink(x : UInt64) -> [UInt64] { return x.shrinkIntegral } @@ -223,7 +212,6 @@ extension Float : Arbitrary { } } - @effects(readnone) public static func shrink(x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { @@ -253,7 +241,6 @@ extension Double : Arbitrary { } } - @effects(readnone) public static func shrink(x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { @@ -270,7 +257,6 @@ extension UnicodeScalar : Arbitrary { return UInt32.arbitrary.bind(Gen.pure • UnicodeScalar.init) } - @effects(readnone) public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } @@ -283,7 +269,6 @@ extension String : Arbitrary { return chars >>- (Gen.pure • String.init) } - @effects(readnone) public static func shrink(s : String) -> [String] { return [Character].shrink([Character](s.characters)).map(String.init) } @@ -294,7 +279,6 @@ extension Character : Arbitrary { return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) } - @effects(readnone) public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) @@ -340,7 +324,6 @@ extension Mirror : Arbitrary { // MARK: - Implementation Details Follow -@effects(readnone) private func asAny(x : T) -> Any { return x } @@ -351,7 +334,6 @@ extension Array where Element : Hashable { } } -@effects(readnone) private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { var acc = [A]() var ini = initial diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 377e83d..b05b451 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -31,7 +31,6 @@ /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -@effects(readnone) public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -52,7 +51,6 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest assert. The /// property will still generate console output during testing. -@effects(readnone) public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } diff --git a/SwiftCheck/CoArbitrary.swift b/SwiftCheck/CoArbitrary.swift index 9d90762..245defa 100644 --- a/SwiftCheck/CoArbitrary.swift +++ b/SwiftCheck/CoArbitrary.swift @@ -34,7 +34,6 @@ public func coarbitraryPrintable(x : A) -> Gen -> Gen { } extension Bool : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Bool) -> Gen -> Gen { return { g in if x { @@ -46,14 +45,12 @@ extension Bool : CoArbitrary { } extension UnicodeScalar : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { return UInt32.coarbitrary(x.value) } } extension Character : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Character) -> (Gen -> Gen) { let ss = String(x).unicodeScalars return UnicodeScalar.coarbitrary(ss[ss.startIndex]) @@ -61,7 +58,6 @@ extension Character : CoArbitrary { } extension String : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : String) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -71,70 +67,60 @@ extension String : CoArbitrary { } extension Int : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Int) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Int8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Int16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Int32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Int64) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UInt) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UInt8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UInt16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UInt32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : UInt64) -> Gen -> Gen { return x.coarbitraryIntegral() } @@ -142,21 +128,18 @@ extension UInt64 : CoArbitrary { // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Float) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Double) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Array : CoArbitrary { - @effects(readnone) public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { if a.isEmpty { return { $0.variant(0) } @@ -166,7 +149,6 @@ extension Array : CoArbitrary { } extension Dictionary : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Dictionary) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -176,7 +158,6 @@ extension Dictionary : CoArbitrary { } extension Optional : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Optional) -> (Gen -> Gen) { if let _ = x { return { $0.variant(0) } @@ -186,7 +167,6 @@ extension Optional : CoArbitrary { } extension Set : CoArbitrary { - @effects(readnone) public static func coarbitrary(x : Set) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } diff --git a/SwiftCheck/Equatable.swift b/SwiftCheck/Equatable.swift index 7f9badf..9a95678 100644 --- a/SwiftCheck/Equatable.swift +++ b/SwiftCheck/Equatable.swift @@ -6,47 +6,38 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -@effects(readnone) public func == >(lhs : Blind, rhs : Blind) -> Bool { return lhs.getBlind == rhs.getBlind } -@effects(readnone) public func == >(lhs : Static, rhs : Static) -> Bool { return lhs.getStatic == rhs.getStatic } -@effects(readnone) public func == >(lhs : ArrayOf, rhs : ArrayOf) -> Bool { return lhs.getArray == rhs.getArray } -@effects(readnone) public func == , V : protocol>(lhs : DictionaryOf, rhs : DictionaryOf) -> Bool { return lhs.getDictionary == rhs.getDictionary } -@effects(readnone) public func == >(lhs : OptionalOf, rhs : OptionalOf) -> Bool { return lhs.getOptional == rhs.getOptional } -@effects(readnone) public func == >(lhs : SetOf, rhs : SetOf) -> Bool { return lhs.getSet == rhs.getSet } -@effects(readnone) public func == >(lhs : Positive, rhs : Positive) -> Bool { return lhs.getPositive == rhs.getPositive } -@effects(readnone) public func == >(lhs : NonZero, rhs : NonZero) -> Bool { return lhs.getNonZero == rhs.getNonZero } -@effects(readnone) public func == >(lhs : NonNegative, rhs : NonNegative) -> Bool { return lhs.getNonNegative == rhs.getNonNegative } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 15a664a..e59fb9e 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -33,7 +33,6 @@ public struct Gen { /// only that value. /// /// The input collection is required to be non-empty. - @effects(readnone) public static func fromElementsOf>(xs : S) -> Gen { return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).fmap { i in return xs[i] @@ -44,7 +43,6 @@ public struct Gen { /// that value. /// /// The input interval is required to be non-empty. - @effects(readnone) public static func fromElementsIn(xs : S) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") @@ -56,7 +54,6 @@ public struct Gen { /// parameter. /// /// The input array is required to be non-empty. - @effects(readnone) public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") @@ -67,7 +64,6 @@ public struct Gen { } /// Constructs a Generator that produces permutations of a given array. - @effects(readnone) public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { if xs.isEmpty { return Gen<[S]>.pure([]) @@ -79,7 +75,6 @@ public struct Gen { } /// Constructs a generator that depends on a size parameter. - @effects(readnone) public static func sized(f : Int -> Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -94,7 +89,6 @@ public struct Gen { /// `A`. For example: /// /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - @effects(readnone) public static func choose(rng : (A, A)) -> Gen { return Gen(unGen: { s in return { (_) in @@ -109,7 +103,6 @@ public struct Gen { /// /// If control over the distribution of generators is needed, see `Gen.frequency` or /// `Gen.weighted`. - @effects(readnone) public static func oneOf, S.Index : protocol>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") @@ -123,7 +116,6 @@ public struct Gen { /// /// Only use this function when you need to assign uneven "weights" to each generator. If all /// generators need to have an equal chance of being selected, use `Gen.oneOf`. - @effects(readnone) public static func frequency)>(xs : S) -> Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") @@ -140,13 +132,11 @@ public struct Gen { /// and `Gen.fromElementsIn` but for any type rather than only Generators. It can help in cases /// where your `Gen.from*` call contains only `Gen.pure` calls by allowing you to remove every /// `.pure` in favor of a direct list of values. - @effects(readnone) public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } /// Zips together 2 generators of type `A` and `B` into a generator of pairs `(A, B)`. - @effects(readnone) public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return gen1.bind { l in return gen2.bind { r in @@ -160,7 +150,6 @@ public struct Gen { extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. - @effects(readnone) public func variant(seed : S) -> Gen { return Gen(unGen: { r in return { n in @@ -170,7 +159,6 @@ extension Gen { } /// Modifies a Generator to always use a given size. - @effects(readnone) public func resize(n : Int) -> Gen { return Gen(unGen: { r in return { (_) in @@ -185,7 +173,6 @@ extension Gen { /// Because the Generator will spin until it reaches a non-failing case, executing a condition /// that fails more often than it succeeds may result in a space leak. At that point, it is /// better to use `suchThatOptional` or `.invert` the test case. - @effects(readnone) public func suchThat(p : A -> Bool) -> Gen { return self.suchThatOptional(p).bind { mx in switch mx { @@ -202,7 +189,6 @@ extension Gen { /// Modifies a Generator such that it attempts to generate values that satisfy a predicate. All /// attempts are encoded in the form of an `Optional` where values satisfying the predicate are /// wrapped in `.Some` and failing values are `.None`. - @effects(readnone) public func suchThatOptional(p : A -> Bool) -> Gen> { return Gen>.sized { n in return attemptBoundedTry(self, k: 0, n: max(n, 1), p: p) @@ -211,7 +197,6 @@ extension Gen { /// Modifies a Generator such that it produces arrays with a length determined by the receiver's /// size parameter. - @effects(readnone) public func proliferate() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((0, n)) >>- self.proliferateSized @@ -220,7 +205,6 @@ extension Gen { /// Modifies a Generator such that it produces non-empty arrays with a length determined by the /// receiver's size parameter. - @effects(readnone) public func proliferateNonEmpty() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))) >>- self.proliferateSized @@ -228,7 +212,6 @@ extension Gen { } /// Modifies a Generator such that it only produces arrays of a given length. - @effects(readnone) public func proliferateSized(k : Int) -> Gen<[A]> { return sequence(Array>(count: k, repeatedValue: self)) } @@ -240,7 +223,6 @@ extension Gen /*: Functor*/ { typealias B = Swift.Any /// Returns a new generator that applies a given function to any outputs the receiver creates. - @effects(readnone) public func fmap(f : (A -> B)) -> Gen { return f <^> self } @@ -253,7 +235,6 @@ extension Gen /*: Functor*/ { /// example, you might have a Generator of `Character` values that you then `.proliferate()` into an /// `Array` of `Character`s. You can then use `fmap` to convert that generator of `Array`s to a /// generator of `String`s. -@effects(readnone) public func <^> (f : A -> B, g : Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -266,7 +247,6 @@ extension Gen /*: Applicative*/ { typealias FAB = Gen B> /// Lifts a value into a generator that will only generate that value. - @effects(readnone) public static func pure(a : A) -> Gen { return Gen(unGen: { (_) in return { (_) in @@ -277,7 +257,6 @@ extension Gen /*: Applicative*/ { /// Given a generator of functions, applies any generated function to any outputs the receiver /// creates. - @effects(readnone) public func ap(fn : Gen B>) -> Gen { return fn <*> self } @@ -296,7 +275,6 @@ extension Gen /*: Applicative*/ { /// the zipped function to the zipped value. /// /// Promotes function application to a Generator of functions applied to a Generator of values. -@effects(readnone) public func <*> (fn : Gen B>, g : Gen) -> Gen { return fn >>- { x1 in return g >>- { x2 in @@ -312,7 +290,6 @@ extension Gen /*: Monad*/ { /// `bind` allows for the creation of Generators that depend on other generators. One might, /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. - @effects(readnone) public func bind(fn : A -> Gen) -> Gen { return self >>- fn } @@ -324,7 +301,6 @@ extension Gen /*: Monad*/ { /// `bind` allows for the creation of Generators that depend on other generators. One might, /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. -@effects(readnone) public func >>- (m : Gen, fn : A -> Gen) -> Gen { return Gen(unGen: { r in return { n in @@ -341,7 +317,6 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// The array that is created is guaranteed to use each of the given Generators in the order they /// were given to the function exactly once. Thus all arrays generated are of the same rank as the /// array that was given. -@effects(readnone) public func sequence(ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in return x.bind { x1 in @@ -353,7 +328,6 @@ public func sequence(ms : [Gen]) -> Gen<[A]> { } /// Flattens a generator of generators by one level. -@effects(readnone) public func join(rs : Gen>) -> Gen { return rs.bind { x in return x @@ -361,7 +335,6 @@ public func join(rs : Gen>) -> Gen { } /// Lifts a function from some A to some R to a function from generators of A to generators of R. -@effects(readnone) public func liftM(f : A -> R)(m1 : Gen) -> Gen { return m1.bind{ x1 in return Gen.pure(f(x1)) @@ -369,7 +342,6 @@ public func liftM(f : A -> R)(m1 : Gen) -> Gen { } /// Promotes a rose of generators to a generator of rose values. -@effects(readnone) public func promote(x : Rose>) -> Gen> { return delay().bind { (let eval : Gen -> A) in return Gen>.pure(liftM(eval)(m1: x)) @@ -377,14 +349,12 @@ public func promote(x : Rose>) -> Gen> { } /// Promotes a function returning generators to a generator of functions. -@effects(readnone) public func promote(m : A -> Gen) -> Gen B> { return delay().bind { (let eval : Gen -> B) in return Gen B>.pure({ x in eval(m(x)) }) } } -@effects(readnone) internal func delay() -> Gen -> A> { return Gen(unGen: { r in return { n in @@ -399,14 +369,12 @@ internal func delay() -> Gen -> A> { import func Darwin.log -@effects(readnone) private func vary(k : S)(r : StdGen) -> StdGen { let s = r.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2)(r: r) } -@effects(readnone) private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) -> Gen> { if n == 0 { return Gen.pure(.None) @@ -419,13 +387,11 @@ private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) - } } -@effects(readnone) private func size(k : S)(m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } -@effects(readnone) private func selectOne(xs : [A]) -> [(A, [A])] { if xs.isEmpty { return [] @@ -436,7 +402,6 @@ private func selectOne(xs : [A]) -> [(A, [A])] { return [(y, ys)] + rec } -@effects(readnone) private func pick(n : Int)(lst : [(Int, Gen)]) -> Gen { let (k, x) = lst[0] let tl = Array<(Int, Gen)>(lst[1.. Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.fmap { $0.unProp } @@ -32,7 +31,6 @@ public func conjoin(ps : Testable...) -> Property { /// distribution map of the success rate of each sub-property. /// /// When disjoining properties all calls to `expectFailure` will fail. -@effects(readnone) public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.fmap { $0.unProp } @@ -47,7 +45,6 @@ public func disjoin(ps : Testable...) -> Property { /// The resulting property makes 100 random choices to test any of the given properties. Thus, /// running multiple test cases will result in distinct arbitrary sequences of each property being /// tested. -@effects(readnone) public func conjamb(ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) @@ -55,13 +52,11 @@ public func conjamb(ps : () -> Testable...) -> Property { extension Testable { /// Applies a function that modifies the property generator's inner `Prop`. - @effects(readnone) public func mapProp(f : Prop -> Prop) -> Property { return Property(f <^> self.property.unProperty) } /// Applies a function that modifies the property generator's size. - @effects(readnone) public func mapSize(f : Int -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) @@ -69,7 +64,6 @@ extension Testable { } /// Applies a function that modifies the result of a test case. - @effects(readnone) public func mapTotalResult(f : TestResult -> TestResult) -> Property { return self.mapRoseResult { rs in return protectResults(f <^> rs) @@ -77,7 +71,6 @@ extension Testable { } /// Applies a function that modifies the result of a test case. - @effects(readnone) public func mapResult(f : TestResult -> TestResult) -> Property { return self.mapRoseResult { rs in return f <^> rs @@ -85,7 +78,6 @@ extension Testable { } /// Applies a function that modifies the underlying Rose Tree that a test case has generated. - @effects(readnone) public func mapRoseResult(f : Rose -> Rose) -> Property { return self.mapProp { t in return Prop(unProp: f(t.unProp)) @@ -136,7 +128,6 @@ extension Testable { } /// Attaches a callback to a test case. - @effects(readnone) public func withCallback(cb : Callback) -> Property { return self.mapResult { (res) in return TestResult(ok: res.ok @@ -152,7 +143,6 @@ extension Testable { } /// Adds the given string to the counterexamples of a failing property. - @effects(readnone) public func counterexample(s : String) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample) { _ in return print(s) @@ -160,7 +150,6 @@ extension Testable { } /// Executes an action after the last failure of the property. - @effects(readnone) public func whenFail(m : () -> ()) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { _ in return m() @@ -171,7 +160,6 @@ extension Testable { /// /// Because the action is executed after every failing test it can be used to track the list of /// failures generated by the shrinking mechanism. - @effects(readnone) public func whenEachFail(m : () -> ()) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in if res.ok == .Some(false) { @@ -248,19 +236,16 @@ extension Testable { /// test cases need to be distinct from one another. In addition to shrunken test cases, upon /// failure SwiftCheck will print a distribution map for the property that shows a percentage /// success rate for the property. - @effects(readnone) public func label(s : String) -> Property { return self.classify(true)(s: s) } /// Labels a property with a printable value. - @effects(readnone) public func collect(x : A) -> Property { return self.label(String(x)) } /// Conditionally labels a property with a value. - @effects(readnone) public func classify(b : Bool)(s : String) -> Property { return self.cover(b)(n: 0)(s: s) } @@ -268,7 +253,6 @@ extension Testable { /// Checks that at least the given proportion of successful test cases belong to the given class. /// /// Discarded tests (i.e. ones with a false precondition) do not affect coverage. - @effects(readnone) public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { return self.mapResult { res in @@ -291,7 +275,6 @@ extension Testable { /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is only necessary /// when you must override the default behavior. -@effects(readnone) public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { rs in return Prop(unProp: joinRose(rs.fmap { x in @@ -399,7 +382,6 @@ public struct TestResult { /// Lifts a `Bool`ean value to a TestResult by mapping true to `TestResult.suceeded` and false /// to `TestResult.failed`. - @effects(readnone) public static func liftBool(b : Bool) -> TestResult { if b { return TestResult.succeeded @@ -410,19 +392,16 @@ public struct TestResult { /// MARK: - Implementation Details -@effects(readnone) private func exception(msg : String) -> ErrorType -> TestResult { return { e in TestResult.failed(String(e)) } } -@effects(readnone) private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) } -@effects(readnone) private func result(ok : Bool?, reason : String = "") -> TestResult { return TestResult( ok: ok , expect: true @@ -436,7 +415,6 @@ private func result(ok : Bool?, reason : String = "") -> TestResult { ) } -@effects(readnone) private func protectResults(rs : Rose) -> Rose { return onRose({ x in return { rs in @@ -447,12 +425,10 @@ private func protectResults(rs : Rose) -> Rose { })(rs: rs) } -@effects(readnone) internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { return { protect(Rose.pure • exception("Exception"))(x: f) } } -@effects(readnone) internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { do { return try x() @@ -461,22 +437,18 @@ internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { } } -@effects(readnone) private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"))(x: r) } } -@effects(readnone) internal func id(x : A) -> A { return x } -@effects(readnone) internal func • (f : B -> C, g : A -> B) -> A -> C { return { f(g($0)) } } -@effects(readnone) internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : Dictionary) -> Dictionary { let oldV = m[k] if let existV = oldV { @@ -487,7 +459,6 @@ internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : return m } -@effects(readnone) internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l l.forEach { (k, v) in @@ -499,7 +470,6 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, return map } -@effects(readnone) private func sep(l : String, r : String) -> String { if l.isEmpty { return r @@ -511,7 +481,6 @@ private func sep(l : String, r : String) -> String { return l + ", " + r } -@effects(readnone) private func mplus(l : Optional, r : Optional) -> Optional { if let ls = l, rs = r { return .Some(ls + rs) @@ -524,7 +493,6 @@ private func mplus(l : Optional, r : Optional) -> Optional TestResult -> TestResult { return { res in return TestResult(ok: res.ok @@ -539,7 +507,6 @@ private func addCallbacks(result : TestResult) -> TestResult -> TestResult { } } -@effects(readnone) private func addLabels(result : TestResult) -> TestResult -> TestResult { return { res in return TestResult(ok: res.ok @@ -554,7 +521,6 @@ private func addLabels(result : TestResult) -> TestResult -> TestResult { } } -@effects(readnone) private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) @@ -596,7 +562,6 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose fatalError("Non-exhaustive if-else statement reached") } -@effects(readnone) private func disj(p : Rose, q : Rose) -> Rose { return p.bind { result1 in if !result1.expect { diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 752b6d2..f3bbf9c 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -85,7 +85,6 @@ public struct StdGen : RandomGeneneratorType, CustomStringConvertible { private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. -@effects(readwrite) public func newStdGen() -> StdGen { let (left, right) = theStdGen.split theStdGen = left @@ -103,7 +102,6 @@ public func randomBound, G : RandomGenener } extension Bool : RandomType { - @effects(readnone) public static func randomInRange(range: (Bool, Bool), gen: G) -> (Bool, G) { let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) return (x == 1, gg) @@ -111,7 +109,6 @@ extension Bool : RandomType { } extension Character : RandomType { - @effects(readnone) public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! @@ -123,7 +120,6 @@ extension Character : RandomType { } extension UnicodeScalar : RandomType { - @effects(readnone) public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) return (UnicodeScalar(val), gg) @@ -131,7 +127,6 @@ extension UnicodeScalar : RandomType { } extension Int : RandomType { - @effects(readnone) public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -140,7 +135,6 @@ extension Int : RandomType { } extension Int8 : RandomType { - @effects(readnone) public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -149,7 +143,6 @@ extension Int8 : RandomType { } extension Int16 : RandomType { - @effects(readnone) public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -158,7 +151,6 @@ extension Int16 : RandomType { } extension Int32 : RandomType { - @effects(readnone) public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -167,7 +159,6 @@ extension Int32 : RandomType { } extension Int64 : RandomType { - @effects(readnone) public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { let (l, h) = range if l > h { @@ -197,7 +188,6 @@ extension Int64 : RandomType { } extension UInt : RandomType { - @effects(readnone) public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -206,7 +196,6 @@ extension UInt : RandomType { } extension UInt8 : RandomType { - @effects(readnone) public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -215,7 +204,6 @@ extension UInt8 : RandomType { } extension UInt16 : RandomType { - @effects(readnone) public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -224,7 +212,6 @@ extension UInt16 : RandomType { } extension UInt32 : RandomType { - @effects(readnone) public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -241,7 +228,6 @@ extension UInt64 : RandomType { } extension Float : RandomType { - @effects(readnone) public static func random(rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) let twoto24 = Int32(2) ^ Int32(24) @@ -250,7 +236,6 @@ extension Float : RandomType { return (Float(mask24 & (x)) / Float(twoto24), rng_) } - @effects(readnone) public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { let (l, h) = range if l > h { @@ -263,7 +248,6 @@ extension Float : RandomType { } extension Double : RandomType { - @effects(readnone) public static func random(rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) let twoto53 = Int64(2) ^ Int64(53) @@ -272,7 +256,6 @@ extension Double : RandomType { return (Double(mask53 & (x)) / Double(twoto53), rng_) } - @effects(readnone) public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { let (l, h) = range if l > h { @@ -286,7 +269,6 @@ extension Double : RandomType { /// Implementation Details Follow -@effects(readnone) private func mkStdRNG(o : Int) -> StdGen { func mkStdGen32(sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max @@ -303,7 +285,6 @@ private func mkStdRNG(o : Int) -> StdGen { return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } -@effects(readwrite) private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { var now : timeval = timeval() let rv = gettimeofday(&now, nil) diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 4929420..ceb47d8 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -26,13 +26,11 @@ extension Rose /*: Functor*/ { /// /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` branches the map is suspended. - @effects(readnone) public func fmap(f : (A -> B)) -> Rose { return f <^> self } } -@effects(readnone) public func <^> (f : A -> B, g : Rose) -> Rose { switch g { case .MkRose(let root, let children): @@ -46,7 +44,6 @@ extension Rose /*: Applicative*/ { typealias FAB = Rose B> /// Lifts a value into a Rose Tree. - @effects(readnone) public static func pure(a : A) -> Rose { return .MkRose({ a }, { [] }) } @@ -56,13 +53,11 @@ extension Rose /*: Applicative*/ { /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and /// applied, executing all side-effects along the way. - @effects(readnone) public func ap(fn : Rose B>) -> Rose { return fn <*> self } } -@effects(readnone) public func <*> (fn : Rose B>, g : Rose) -> Rose { switch fn { case .MkRose(let f, _): @@ -74,19 +69,16 @@ public func <*> (fn : Rose B>, g : Rose) -> Rose { extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all together. - @effects(readnone) public func bind(fn : A -> Rose) -> Rose { return self >>- fn } } -@effects(readnone) public func >>- (m : Rose, fn : A -> Rose) -> Rose { return joinRose(m.fmap(fn)) } /// Lifts functions to functions over Rose Trees. -@effects(readnone) public func liftM(f : A -> R)(m1 : Rose) -> Rose { return m1.bind { x1 in return Rose.pure(f(x1)) @@ -99,7 +91,6 @@ public func liftM(f : A -> R)(m1 : Rose) -> Rose { /// the node dictates the behavior of the join. For `.IORose` sub-trees The join is suspended. For /// `.MkRose` the result is the value at the sub-tree node and a recursive call to join the branch's /// tree to its sub-trees. -@effects(readnone) public func joinRose(rs : Rose>) -> Rose { switch rs { case .IORose(let rs): @@ -116,7 +107,6 @@ public func joinRose(rs : Rose>) -> Rose { /// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is /// encountered. That branch is then returned. -@effects(readnone) public func reduce(rs : Rose) -> Rose { switch rs { case .MkRose(_, _): @@ -127,7 +117,6 @@ public func reduce(rs : Rose) -> Rose { } /// Case analysis for a Rose Tree. -@effects(readnone) public func onRose(f : (A -> [Rose] -> Rose))(rs : Rose) -> Rose { switch rs { case .MkRose(let x, let rs): @@ -138,7 +127,6 @@ public func onRose(f : (A -> [Rose] -> Rose))(rs : Rose) -> Rose } /// Sequences an array of Rose Trees into a Rose Tree of an array. -@effects(readnone) public func sequence(ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in return m.bind { x in @@ -151,7 +139,6 @@ public func sequence(ms : [Rose]) -> Rose<[A]> { /// Sequences the result of mapping values to Rose trees into a single rose tree of an array of /// values. -@effects(readnone) public func mapM(f : A -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index b69ece0..135891e 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -85,112 +85,112 @@ /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B) throws -> Testable) -> Property { return forAll({ t in forAll({ b in try pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c in try pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in try pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified property using the /// default shrinker for that type. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 2 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 3 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 4 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 5 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 6 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 7 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified property using the /// default shrinkers for those 8 types. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -200,7 +200,7 @@ public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -210,7 +210,7 @@ public func forAllNoShrink(gen : Gen, pf : (A throws -> Testable)) -> Prop /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } @@ -220,7 +220,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) thr /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -230,7 +230,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -240,7 +240,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -250,7 +250,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -260,7 +260,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ g /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -270,14 +270,14 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, /// /// This variant of `forAll` does not shrink its argument but allows generators of any type, not /// just those that conform to `Arbitrary`. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a universally quantified /// property. -@warn_unused_result @effects(readnone) +@warn_unused_result public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { return Property(gen.bind { x in return shrinking(shrinker, initial: x, prop: { xs in @@ -306,14 +306,12 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T /// [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). `SNF` involves turning /// every `exists` into a function returning the existential value, taking any other parameters /// being quantified over as needed. -@effects(readnone) public func exists(pf : A throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially quantified property using /// the default shrinker for that type. -@effects(readnone) public func exists(gen : Gen, pf : A throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok @@ -816,7 +814,6 @@ internal func cons(lhs : T, var _ rhs : [T]) -> [T] { return rhs } -@effects(readnone) private func pluralize(s : String, i : Int) -> String { if i == 1 { return s @@ -825,7 +822,6 @@ private func pluralize(s : String, i : Int) -> String { } extension Array { - @effects(readnone) internal func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { if list.isEmpty { diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 2e9b5ec..c00b721 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -49,7 +49,6 @@ infix operator ==> { /// Models implication for properties. That is, the property holds if the first argument is false /// (in which case the test case is discarded), or if the given property holds. -@effects(readnone) public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { if b { return p().property @@ -59,7 +58,6 @@ public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { /// Models implication for properties. That is, the property holds if the first argument is false /// (in which case the test case is discarded), or if the given property holds. -@effects(readnone) public func ==>(b : Bool, p : () -> Testable) -> Property { if b { return p().property @@ -72,7 +70,6 @@ infix operator ==== { } /// Like equality but prints a verbose description when it fails. -@effects(readnone) public func ====(x : A, y : A) -> Property { return (x == y).counterexample(String(x) + "/=" + String(y)) } @@ -89,7 +86,6 @@ infix operator { /// test cases need to be distinct from one another. In addition to shrunken test cases, upon /// failure SwiftCheck will print a distribution map for the property that shows a percentage /// success rate for the property. -@effects(readnone) public func (p : Testable, s : String) -> Property { return p.label(s) } @@ -103,7 +99,6 @@ infix operator ^&&^ { /// /// Conjoined properties succeed only when both sub-properties succeed and fail when one or more /// sub-properties fail. -@effects(readnone) public func ^&&^(p1 : Testable, p2 : Testable) -> Property { return conjoin(p1.property, p2.property) } @@ -118,7 +113,6 @@ infix operator ^||^ { /// /// Disjoined properties succeed only when one or more sub-properties succeed and fail when both /// sub-properties fail. -@effects(readnone) public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index 20a5298..eaa5fdc 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -14,56 +14,48 @@ public protocol WitnessedArbitrary { /// Converts a function into a universally quantified property using the default shrinker and /// generator for that type. -@effects(readnone) public func forAll(pf : (A -> Testable)) -> Property { return A.forAllWitnessed(id)(pf: pf) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 2 types. -@effects(readnone) public func forAll(pf : (A, B) -> Testable) -> Property { return forAll({ t in forAll({ b in pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 3 types. -@effects(readnone) public func forAll(pf : (A, B, C) -> Testable) -> Property { return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 4 types. -@effects(readnone) public func forAll(pf : (A, B, C, D) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 5 types. -@effects(readnone) public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 6 types. -@effects(readnone) public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 7 types. -@effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default shrinker and /// generator for 8 types. -@effects(readnone) public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index d89b25c..140af15 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -19,7 +19,6 @@ extension Array where Element : Arbitrary { } } - @effects(readnone) public static func shrink(bl : Array) -> [[Element]] { let rec : [[Element]] = shrinkOne(bl) return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec @@ -41,7 +40,6 @@ extension AnyBidirectionalCollection where Element : Arbitrary { return AnyBidirectionalCollection.init <^> [Element].arbitrary } - @effects(readnone) public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } @@ -62,7 +60,6 @@ extension AnySequence where Element : Arbitrary { return AnySequence.init <^> [Element].arbitrary } - @effects(readnone) public static func shrink(bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } @@ -83,7 +80,6 @@ extension ArraySlice where Element : Arbitrary { return ArraySlice.init <^> [Element].arbitrary } - @effects(readnone) public static func shrink(bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } @@ -124,7 +120,6 @@ extension Optional where Wrapped : Arbitrary { ]) } - @effects(readnone) public static func shrink(bl : Optional) -> [Optional] { if let x = bl { let rec : [Optional] = Wrapped.shrink(x).map(Optional.Some) @@ -149,7 +144,6 @@ extension ContiguousArray where Element : Arbitrary { return ContiguousArray.init <^> [Element].arbitrary } - @effects(readnone) public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } @@ -175,7 +169,6 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } - @effects(readnone) public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } @@ -206,7 +199,6 @@ extension HalfOpenInterval where Bound : protocol { } } - @effects(readnone) public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } @@ -217,7 +209,6 @@ extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary } - @effects(readnone) public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) } @@ -254,7 +245,6 @@ extension Range where Element : protocol) -> [Range] { return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) } @@ -269,7 +259,6 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element - @effects(readnone) public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) @@ -291,7 +280,6 @@ extension Set where Element : protocol { } } - @effects(readnone) public static func shrink(s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } @@ -309,7 +297,6 @@ extension Set : WitnessedArbitrary { // MARK: - Implementation Details Follow -@effects(readnone) private func bits(n : N) -> Int { if n / 2 == 0 { return 0 @@ -317,7 +304,6 @@ private func bits(n : N) -> Int { return 1 + bits(n / 2) } -@effects(readnone) private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { let xs1 : [A] = take(k, xs: xs) let xs2 : [A] = drop(k, xs: xs) @@ -332,19 +318,16 @@ private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { } } -@effects(readnone) private func take(num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[0..(num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[n..(xs : [A]) -> [[A]] { if xs.isEmpty { return [[A]]() From 0442c2a38444b23a9a839de5cd88b244908d4181 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 28 Dec 2015 17:14:06 -0500 Subject: [PATCH 229/460] Remove flags; prepare for merge --- SwiftCheck.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 7869681..b8f2b87 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -630,7 +630,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -663,7 +663,7 @@ "-framework", XCTest, ); - OTHER_SWIFT_FLAGS = "-Xfrontend -debug-time-function-bodies"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; From d5b6c7c7420ebecf27519d69ad3f040c7f8123ed Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 31 Dec 2015 19:49:32 -0700 Subject: [PATCH 230/460] Add a section on replaying --- Tutorial.playground/Contents.swift | 54 +++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index f78a473..3881a24 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -514,10 +514,15 @@ struct ArbitraryEmail : Arbitrary { // Here we use `emailGen` to generate our cases out of convenience, but there are much // more efficient ways we could have done this. See `Modifiers.swift` for examples. static func shrink(tt : ArbitraryEmail) -> [ArbitraryEmail] { - return emailGen.suchThat({ $0.unicodeScalars.count <= (tt.getEmail.unicodeScalars.count / 2) }) // Halve the size of the input address for efficient shrinking. - .proliferateNonEmpty() // Proliferate an array - .generate // Generate - .map(ArbitraryEmail.init) // Then wrap in our Modifier Type + // If we're down to 1 character addresses, we probably should stop shrinking. + if (tt.getEmail.unicodeScalars.indexOf("\u{0040}") == tt.getEmail.unicodeScalars.startIndex.successor()) { + return [] + } + print(tt.getEmail) + return emailGen.resize(tt.getEmail.unicodeScalars.count / 2) // Halve the size of the previous addresses + .proliferateSized(2) // Proliferate a small array of alternatives + .generate // Generate + .map(ArbitraryEmail.init) // Then wrap in our Modifier Type } } @@ -626,7 +631,7 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: //: *** Failed! Proposition: All Prime //: Falsifiable (after 11 tests and 2 shrinks): -//: Positive( 4 ) // or Positive( 10 ) +//: Positive( 4 ) // or Positive( 9 ) //: 0 //: //: What's wrong here? @@ -693,6 +698,45 @@ property("All Prime") <- forAll { (n : Positive) in return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } +//; # One More Thing + +//: When working with failing tests, it's often tough to be able to replicate the exact conditions +//: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework +//: comes with a replay mechanism that allows the arguments that lead to a failing test to be generated +//: in exactly the same order, with exactly the same values, as they did the first time. When a test +//: fails, SwiftCheck will present a helpful message that looks something like this in Xcode: + +//: > failed - Falsifiable; Replay with 123456789 123456789 + +//: Or this message in your log: + +//: > Pass the seed values 123456789 123456789 to replay the test. + +//: These are called *seeds*, and they can be fed back into the property that generated them to +//: activate the replay feature. For example, here's an annoying test to debug because it only fails +//: every so often on one particular value: + +reportProperty("Screw this value in particular") <- forAll { (n : UInt) in + if (n == 42) { + return false + } + + return true +} + +//: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because +//: 42 will always be generated as the first value. We've turned on verbose mode to demonstrate this. + +/// By passing this argument to the test, SwiftCheck will automatically use the given seed values and +/// size to completely replicate a particular set of values that caused the first test to fail. +let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) +reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in + if (n == 42) { + return false + } + return true +}.verbose + //: # Conclusion //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators From c08eee11122abd1fea9e316e0411582f674c2720 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 3 Jan 2016 19:17:39 -0700 Subject: [PATCH 231/460] Rewrite glue. --- Tutorial.playground/Contents.swift | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 3881a24..29126f7 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -270,19 +270,12 @@ let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap //: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how //: about some glue? -// Concatenates 5 strings together in order. -func glue5(l : String)(m : String)(m2 : String)(m3 : String)(r : String) -> String { - return l + m + m2 + m3 + r +// Concatenates an array of `String` `Gen`erators together in order. +func glue(parts : [Gen]) -> Gen { + return sequence(parts).fmap { ps in ps.reduce("", combine: +) } } -//: This big thing looks a bit complicated, let's go through it part by part: - -//: +--- Here's our glue function. -//: | +--- This says we're "lifting" and mapping that function over all these pieces. -//: | | +--- Here's our "platforms" from before. -//: | | | -//: v v v -let emailGen = glue5 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld +let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) //: And we're done! @@ -510,20 +503,6 @@ struct ArbitraryEmail : Arbitrary { init(email : String) { self.getEmail = email } static var arbitrary : Gen { return emailGen.fmap(ArbitraryEmail.init) } - - // Here we use `emailGen` to generate our cases out of convenience, but there are much - // more efficient ways we could have done this. See `Modifiers.swift` for examples. - static func shrink(tt : ArbitraryEmail) -> [ArbitraryEmail] { - // If we're down to 1 character addresses, we probably should stop shrinking. - if (tt.getEmail.unicodeScalars.indexOf("\u{0040}") == tt.getEmail.unicodeScalars.startIndex.successor()) { - return [] - } - print(tt.getEmail) - return emailGen.resize(tt.getEmail.unicodeScalars.count / 2) // Halve the size of the previous addresses - .proliferateSized(2) // Proliferate a small array of alternatives - .generate // Generate - .map(ArbitraryEmail.init) // Then wrap in our Modifier Type - } } // Let's be wrong for the sake of example From b92e04b6306eefe604471bbcf52d475aac2530ba Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 3 Jan 2016 19:21:03 -0700 Subject: [PATCH 232/460] Remove crappy explanation of ap --- Tutorial.playground/Contents.swift | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 29126f7..4e92839 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -203,7 +203,6 @@ generatorBoundedSizeArrays.generate //: * `<*>` is an alias for `ap` //: * `>>-` is an alias for `bind` -// <^> is backwards for aesthetic and historical purposes. Its true use will be revealled soon. let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive fromTwoToSix_.generate @@ -218,16 +217,6 @@ generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate -//: Now that you've seen what generators can do, we'll use all we've learned to create a generator -//: that produces email addresses. To do this, we'll need one more operator/method notated `<*>` or -//: `ap`. `ap` comes from -//: [Applicative Functors](http://staff.city.ac.uk/~ross/papers/Applicative.html) and is used to -//: "zip together" `Gen`erators of functions with `Gen`erators of of values. Unlike `zip`, when -//: a function gets paired with a value the latter is applied to the former to produce a new -//: value. For our purposes, we don't even need that definition. We can think of `ap` like -//: a platform that a lifted value can ride atop as a function is carried through. You'll -//: see what this means in detail shortly. -//: //: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. //: @@ -272,7 +261,7 @@ let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap // Concatenates an array of `String` `Gen`erators together in order. func glue(parts : [Gen]) -> Gen { - return sequence(parts).fmap { ps in ps.reduce("", combine: +) } + return sequence(parts).fmap { $0.reduce("", combine: +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) From b6f45037b74768da679e801e4351fedc12a2313b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 3 Jan 2016 19:23:38 -0700 Subject: [PATCH 233/460] Add carthage and gitter badges to README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fac48f..beaf9a8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/typelift/SwiftCheck.svg?branch=master)](https://travis-ci.org/typelift/SwiftCheck) - +[![Gitter chat](https://badges.gitter.im/DPVN/chat.png)](https://gitter.im/typelift/general?utm_source=share-link&utm_medium=link&utm_campaign=share-link) + + SwiftCheck ========== From c5a684e8d7ac4652606d0e6ce39f7e202210c38a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 3 Jan 2016 22:00:04 -0700 Subject: [PATCH 234/460] Add tvOS target --- .travis.yml | 3 +- SwiftCheck.podspec | 1 + SwiftCheck.xcodeproj/project.pbxproj | 297 +++++++++++++++++- .../xcschemes/SwiftCheck-tvOS.xcscheme | 99 ++++++ 4 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-tvOS.xcscheme diff --git a/.travis.yml b/.travis.yml index 3484b40..57f75f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,9 @@ env: before_install: true install: true -script: +script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' ; fi - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi notifications: webhooks: diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 25ba66f..a53f640 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -33,6 +33,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.osx.deployment_target = "10.9" s.ios.deployment_target = "8.0" + s.tvos.deployment_target = "9.0" s.framework = "XCTest" s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } s.source_files = "SwiftCheck/*.swift", "**/Operadics/*.swift" diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index b8f2b87..976a3cd 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -11,6 +11,37 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; + 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; + 8240CCC81C3A124B00EF4D29 /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCA9198B323800EB242A /* Arbitrary.swift */; }; + 8240CCC91C3A124B00EF4D29 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; + 8240CCCA1C3A124B00EF4D29 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; + 8240CCCB1C3A124B00EF4D29 /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAB198B32DC00EB242A /* Gen.swift */; }; + 8240CCCC1C3A124B00EF4D29 /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; + 8240CCCD1C3A124B00EF4D29 /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; + 8240CCCE1C3A124B00EF4D29 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; + 8240CCCF1C3A124B00EF4D29 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAD198B367000EB242A /* Property.swift */; }; + 8240CCD01C3A124B00EF4D29 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; + 8240CCD11C3A124B00EF4D29 /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; + 8240CCD21C3A124B00EF4D29 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCB3198B39F300EB242A /* State.swift */; }; + 8240CCD31C3A124B00EF4D29 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAF198B36BE00EB242A /* Test.swift */; }; + 8240CCD41C3A124B00EF4D29 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; + 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; + 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; + 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; + 8240CCD81C3A124B00EF4D29 /* Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46395B51B1A94D200AA1B65 /* Equatable.swift */; }; + 8240CCD91C3A125800EF4D29 /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 844FCC92198B320500EB242A /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 8240CCDC1C3A12AB00EF4D29 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */; }; + 8240CCDD1C3A12AB00EF4D29 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; + 8240CCDE1C3A12AB00EF4D29 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; + 8240CCDF1C3A12AB00EF4D29 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; + 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4A91B16D37800280089 /* GenSpec.swift */; }; + 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; + 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */; }; + 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; + 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */; }; + 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; + 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; @@ -71,6 +102,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 8240CCBC1C3A123700EF4D29 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 844FCC84198B320500EB242A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8240CCB01C3A123600EF4D29; + remoteInfo = "SwiftCheck-tvOS"; + }; 844FCC9A198B320500EB242A /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 844FCC84198B320500EB242A /* Project object */; @@ -88,6 +126,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 8240CCDA1C3A126100EF4D29 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 841408BA1B1A859B00BA2B6C /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -103,6 +151,8 @@ /* Begin PBXFileReference section */ 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; + 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; @@ -139,6 +189,21 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 8240CCAD1C3A123600EF4D29 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8240CCB71C3A123700EF4D29 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844FCC89198B320500EB242A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -189,6 +254,8 @@ 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */, 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */, 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */, + 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */, + 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */, ); name = Products; sourceTree = ""; @@ -256,6 +323,14 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 8240CCAE1C3A123600EF4D29 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8240CCD91C3A125800EF4D29 /* SwiftCheck.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844FCC8A198B320500EB242A /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -275,6 +350,43 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8240CCC61C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOS" */; + buildPhases = ( + 8240CCAC1C3A123600EF4D29 /* Sources */, + 8240CCAD1C3A123600EF4D29 /* Frameworks */, + 8240CCAE1C3A123600EF4D29 /* Headers */, + 8240CCAF1C3A123600EF4D29 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SwiftCheck-tvOS"; + productName = "SwiftCheck-tvOS"; + productReference = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; + productType = "com.apple.product-type.framework"; + }; + 8240CCB91C3A123700EF4D29 /* SwiftCheck-tvOSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8240CCC71C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOSTests" */; + buildPhases = ( + 8240CCB61C3A123700EF4D29 /* Sources */, + 8240CCB71C3A123700EF4D29 /* Frameworks */, + 8240CCB81C3A123700EF4D29 /* Resources */, + 8240CCDA1C3A126100EF4D29 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 8240CCBD1C3A123700EF4D29 /* PBXTargetDependency */, + ); + name = "SwiftCheck-tvOSTests"; + productName = "SwiftCheck-tvOSTests"; + productReference = 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 844FCC8C198B320500EB242A /* SwiftCheck */ = { isa = PBXNativeTarget; buildConfigurationList = 844FCCA3198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheck" */; @@ -354,10 +466,16 @@ 844FCC84198B320500EB242A /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0710; + LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Robert Widmann"; TargetAttributes = { + 8240CCB01C3A123600EF4D29 = { + CreatedOnToolsVersion = 7.2; + }; + 8240CCB91C3A123700EF4D29 = { + CreatedOnToolsVersion = 7.2; + }; 844FCC8C198B320500EB242A = { CreatedOnToolsVersion = 6.0; }; @@ -389,11 +507,27 @@ 844FCC97198B320500EB242A /* SwiftCheckTests */, 84DF75F71B0BD54600C912B0 /* SwiftCheck-iOS */, 84DF76011B0BD54600C912B0 /* SwiftCheck-iOSTests */, + 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */, + 8240CCB91C3A123700EF4D29 /* SwiftCheck-tvOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 8240CCAF1C3A123600EF4D29 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8240CCB81C3A123700EF4D29 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844FCC8B198B320500EB242A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -425,6 +559,48 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 8240CCAC1C3A123600EF4D29 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8240CCC81C3A124B00EF4D29 /* Arbitrary.swift in Sources */, + 8240CCC91C3A124B00EF4D29 /* CoArbitrary.swift in Sources */, + 8240CCCA1C3A124B00EF4D29 /* Check.swift in Sources */, + 8240CCCB1C3A124B00EF4D29 /* Gen.swift in Sources */, + 8240CCCC1C3A124B00EF4D29 /* Lattice.swift in Sources */, + 8240CCCD1C3A124B00EF4D29 /* Modifiers.swift in Sources */, + 8240CCCE1C3A124B00EF4D29 /* Operators.swift in Sources */, + 8240CCCF1C3A124B00EF4D29 /* Property.swift in Sources */, + 8240CCD01C3A124B00EF4D29 /* Random.swift in Sources */, + 8240CCD11C3A124B00EF4D29 /* Rose.swift in Sources */, + 8240CCD21C3A124B00EF4D29 /* State.swift in Sources */, + 8240CCD31C3A124B00EF4D29 /* Test.swift in Sources */, + 8240CCD41C3A124B00EF4D29 /* Testable.swift in Sources */, + 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */, + 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */, + 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */, + 8240CCD81C3A124B00EF4D29 /* Equatable.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8240CCB61C3A123700EF4D29 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8240CCDC1C3A12AB00EF4D29 /* BooleanIdentitySpec.swift in Sources */, + 8240CCDD1C3A12AB00EF4D29 /* ComplexSpec.swift in Sources */, + 8240CCDE1C3A12AB00EF4D29 /* DiscardSpec.swift in Sources */, + 8240CCDF1C3A12AB00EF4D29 /* FailureSpec.swift in Sources */, + 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */, + 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */, + 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */, + 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */, + 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */, + 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */, + 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844FCC88198B320500EB242A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -512,6 +688,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 8240CCBD1C3A123700EF4D29 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */; + targetProxy = 8240CCBC1C3A123700EF4D29 /* PBXContainerItemProxy */; + }; 844FCC9B198B320500EB242A /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 844FCC8C198B320500EB242A /* SwiftCheck */; @@ -525,6 +706,98 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 8240CCC21C3A123700EF4D29 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftCheck/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; + PRODUCT_NAME = SwiftCheck; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 8240CCC31C3A123700EF4D29 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; + COPY_PHASE_STRIP = NO; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftCheck/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; + PRODUCT_NAME = SwiftCheck; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 8240CCC41C3A123700EF4D29 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftCheckTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TVOS_DEPLOYMENT_TARGET = 9.0; + }; + name = Debug; + }; + 8240CCC51C3A123700EF4D29 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = SwiftCheckTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + TVOS_DEPLOYMENT_TARGET = 9.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; 844FCCA1198B320500EB242A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -739,6 +1012,8 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; TARGETED_DEVICE_FAMILY = "1,2,3"; + TVOS_DEPLOYMENT_TARGET = 9.0; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; @@ -769,7 +1044,9 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; TARGETED_DEVICE_FAMILY = "1,2,3"; + TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; @@ -815,6 +1092,24 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 8240CCC61C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8240CCC21C3A123700EF4D29 /* Debug */, + 8240CCC31C3A123700EF4D29 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8240CCC71C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOSTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8240CCC41C3A123700EF4D29 /* Debug */, + 8240CCC51C3A123700EF4D29 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 844FCC87198B320500EB242A /* Build configuration list for PBXProject "SwiftCheck" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-tvOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-tvOS.xcscheme new file mode 100644 index 0000000..e6d1e1b --- /dev/null +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-tvOS.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 914bf01bd4c88338bf8c60614dc3ccd3f22aaefe Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 3 Jan 2016 22:08:43 -0700 Subject: [PATCH 235/460] bump podspec --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index a53f640..45b5bd3 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.4.1" + s.version = "0.4.4" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From d153912418e12b690e8bee0880847bb087a813e6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:24:39 -0700 Subject: [PATCH 236/460] Add sample and scale --- SwiftCheck/Gen.swift | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index e59fb9e..665e992 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -22,13 +22,23 @@ public struct Gen { /// Generates a value. /// - /// This method exists as a convenience mostly to test generators. It will always generate with - /// size 30. + /// This property exists as a convenience mostly to test generators. In practice, you should + /// never use this property because it hinders the replay functionality and the robustness of + /// tests in general. public var generate : A { let r = newStdGen() return unGen(r)(30) } + /// Generates some example values. + /// + /// This property exists as a convenience mostly to test generators. In practice, you should + /// never use this property because it hinders the replay functionality and the robustness of + /// tests in general. + public var sample : [A] { + return sequence((2...20).map { self.resize($0) }).generate + } + /// Constructs a Generator that selects a random value from the given collection and produces /// only that value. /// @@ -167,6 +177,13 @@ extension Gen { }) } + /// Modifiers a Generator's size parameter by transforming it with the given function. + public func scale(f : Int -> Int) -> Gen { + return Gen.sized { n in + return self.resize(f(n)) + } + } + /// Modifies a Generator such that it only returns values that satisfy a predicate. When the /// predicate fails the test case is treated as though it never occured. /// From 72e8bff4dfda7c934077b1152213c553d94a2e75 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:30:02 -0700 Subject: [PATCH 237/460] Uncurry Gen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I made the decision to uncurry Gen’erators because, unlike Haskell, the Swift compiler keeps all levels of lambdas nested inside of each other. This way, we remove a level of abstraction and thus, a function call to one of the hot paths in this framework. --- SwiftCheck/Gen.swift | 67 ++++++++++++++++--------------------------- SwiftCheck/Test.swift | 22 +++++++------- 2 files changed, 36 insertions(+), 53 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 665e992..abf09a6 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -14,11 +14,11 @@ public struct Gen { /// The function underlying the receiver. /// - /// +--- An RNG - /// | +--- The size of generated values. - /// | | - /// v v - let unGen : StdGen -> Int -> A + /// +--- An RNG + /// | +--- The size of generated values. + /// | | + /// v v + let unGen : (StdGen, Int) -> A /// Generates a value. /// @@ -27,7 +27,7 @@ public struct Gen { /// tests in general. public var generate : A { let r = newStdGen() - return unGen(r)(30) + return unGen(r, 30) } /// Generates some example values. @@ -86,10 +86,8 @@ public struct Gen { /// Constructs a generator that depends on a size parameter. public static func sized(f : Int -> Gen) -> Gen { - return Gen(unGen: { r in - return { n in - return f(n).unGen(r)(n) - } + return Gen(unGen: { r, n in + return f(n).unGen(r, n) }) } @@ -100,11 +98,8 @@ public struct Gen { /// /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) public static func choose(rng : (A, A)) -> Gen { - return Gen(unGen: { s in - return { (_) in - let (x, _) = A.randomInRange(rng, gen: s) - return x - } + return Gen(unGen: { s, _ in + return A.randomInRange(rng, gen: s).0 }) } @@ -161,19 +156,15 @@ public struct Gen { extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. public func variant(seed : S) -> Gen { - return Gen(unGen: { r in - return { n in - return self.unGen(vary(seed)(r: r))(n) - } + return Gen(unGen: { r, n in + return self.unGen(vary(seed)(r: r), n) }) } /// Modifies a Generator to always use a given size. public func resize(n : Int) -> Gen { - return Gen(unGen: { r in - return { (_) in - return self.unGen(r)(n) - } + return Gen(unGen: { r, _ in + return self.unGen(r, n) }) } @@ -253,10 +244,8 @@ extension Gen /*: Functor*/ { /// `Array` of `Character`s. You can then use `fmap` to convert that generator of `Array`s to a /// generator of `String`s. public func <^> (f : A -> B, g : Gen) -> Gen { - return Gen(unGen: { r in - return { n in - return f(g.unGen(r)(n)) - } + return Gen(unGen: { r, n in + return f(g.unGen(r, n)) }) } @@ -265,10 +254,8 @@ extension Gen /*: Applicative*/ { /// Lifts a value into a generator that will only generate that value. public static func pure(a : A) -> Gen { - return Gen(unGen: { (_) in - return { (_) in - return a - } + return Gen(unGen: { _ in + return a }) } @@ -319,12 +306,10 @@ extension Gen /*: Monad*/ { /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. public func >>- (m : Gen, fn : A -> Gen) -> Gen { - return Gen(unGen: { r in - return { n in - let (r1, r2) = r.split - let m2 = fn(m.unGen(r1)(n)) - return m2.unGen(r2)(n) - } + return Gen(unGen: { r, n in + let (r1, r2) = r.split + let m2 = fn(m.unGen(r1, n)) + return m2.unGen(r2, n) }) } @@ -373,11 +358,9 @@ public func promote(m : A -> Gen) -> Gen B> { } internal func delay() -> Gen -> A> { - return Gen(unGen: { r in - return { n in - return { g in - return g.unGen(r)(n) - } + return Gen(unGen: { r, n in + return { g in + return g.unGen(r, n) } }) } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 135891e..1f13443 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -328,7 +328,7 @@ public func exists(gen : Gen, pf : A throws -> Testable) -> Pr /// Tests a property and prints the results to stdout. public func quickCheck(prop : Testable, name : String = "") { - quickCheckWithResult(CheckerArguments(name: name), p: prop) + quickCheckWithResult(CheckerArguments(name: name), prop) } /// MARK: - Implementation Details @@ -369,7 +369,7 @@ internal indirect enum Either { case Right(R) } -internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Result { +internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> Result { func roundTo(n : Int)(m : Int) -> Int { return (n / m) * m } @@ -441,12 +441,12 @@ internal func quickCheckWithResult(args : CheckerArguments, p : Testable) -> Res // - doneTesting: Invoked when testing the property fails or succeeds once and for all. // - giveUp: When the number of discarded tests exceeds the number given in the arguments we just // give up turning the run loop to prevent excessive generation. -internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { +internal func test(st : CheckerState, f : (StdGen, Int) -> Prop) -> Result { var state = st while true { switch runATest(state)(f: f) { case let .Left(fail): - switch (fail.0, doneTesting(fail.1)(f: f)) { + switch (fail.0, doneTesting(fail.1)) { case (.Success(_, _, _), _): return fail.0 case let (_, .NoExpectedFailure(numTests, labels, output)): @@ -467,10 +467,10 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { } case let .Right(lsta): if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { - return doneTesting(lsta)(f: f) + return doneTesting(lsta) } if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { - return giveUp(lsta)(f: f) + return giveUp(lsta) } state = lsta } @@ -480,12 +480,12 @@ internal func test(st : CheckerState, f : (StdGen -> Int -> Prop)) -> Result { // Executes a single test of the property given an initial state and the generator function. // // On success the next state is returned. On failure the final result and state are returned. -internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either<(Result, CheckerState), CheckerState> { +internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount)(st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split // Execute the Rose Tree for the test and reduce to .MkRose. - switch reduce(f(rnd1)(size).unProp) { + switch f(rnd1, size).unProp.reduce { case .MkRose(let resC, let ts): let res = resC() // Force the result only once. dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks @@ -609,7 +609,7 @@ internal func runATest(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Either } } -internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { +internal func doneTesting(st : CheckerState) -> Result { if st.hasFulfilledExpectedFailure { print("*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) @@ -620,7 +620,7 @@ internal func doneTesting(st : CheckerState)(f : (StdGen -> Int -> Prop)) -> Res } } -internal func giveUp(st: CheckerState)(f : (StdGen -> Int -> Prop)) -> Result { +internal func giveUp(st: CheckerState) -> Result { printDistributionGraph(st) return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -662,7 +662,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts // Try all possible courses of action in this Rose Tree branches.forEach { r in - switch reduce(r) { + switch r.reduce { case .MkRose(let resC, let ts1): let res1 = resC() dispatchAfterTestCallbacks(st, res: res1) From 3cb1c7775d64c33e507722405a944437701f801a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:30:11 -0700 Subject: [PATCH 238/460] Add OrderedArrayOf --- SwiftCheck/Modifiers.swift | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 7633ebd..d864c5a 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -131,6 +131,31 @@ extension ArrayOf : CoArbitrary { } } +/// Generates a sorted array of arbitrary values of type A. +public struct OrderedArrayOf> : Arbitrary, CustomStringConvertible { + public let getOrderedArray : [A] + public var getContiguousArray : ContiguousArray { + return ContiguousArray(self.getOrderedArray) + } + + public init(_ array : [A]) { + self.getOrderedArray = array.sort() + } + + public var description : String { + return "\(self.getOrderedArray)" + } + + public static var arbitrary : Gen> { + return OrderedArrayOf.init <^> Array.arbitrary + } + + public static func shrink(bl : OrderedArrayOf) -> [OrderedArrayOf] { + return Array.shrink(bl.getOrderedArray).filter({ $0.sort() == $0 }).map(OrderedArrayOf.init) + } +} + + /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { public let getDictionary : Dictionary From af9b8995e089e1f6511b835d2a84b96cca44fef6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:31:06 -0700 Subject: [PATCH 239/460] Make more things stored properties and member functions --- SwiftCheck/Property.swift | 32 ++++++++++++-------------- SwiftCheck/Rose.swift | 42 +++++++++++++++++----------------- SwiftCheck/TestOperators.swift | 8 +++---- 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index bd7e328..1fb6d42 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -86,13 +86,11 @@ extension Testable { /// Modifies a property so it will not shrink when it fails. public var noShrinking : Property { - return self.mapRoseResult({ rs in - return onRose({ res in - return { (_) in - return .MkRose({ res }, { [] }) - } - })(rs: rs) - }) + return self.mapRoseResult { rs in + return rs.onRose { res, _ in + return .MkRose({ res }, { [] }) + } + } } /// Inverts the result of a test. That is, test cases that would pass now fail and vice versa. @@ -217,7 +215,7 @@ extension Testable { /// /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { - return self.mapTotalResult({ res in + return self.mapTotalResult { res in return TestResult(ok: res.ok , expect: false , reason: res.reason @@ -227,7 +225,7 @@ extension Testable { , callbacks: res.callbacks , abort: res.abort , quantifier: res.quantifier) - }) + } } /// Attaches a label to a property. @@ -416,13 +414,11 @@ private func result(ok : Bool?, reason : String = "") -> TestResult { } private func protectResults(rs : Rose) -> Rose { - return onRose({ x in - return { rs in - return .IORose({ - return .MkRose(protectResult({ x }), { rs.map(protectResults) }) - }) - } - })(rs: rs) + return rs.onRose { x, rs in + return .IORose({ + return .MkRose(protectResult({ x }), { rs.map(protectResults) }) + }) + } } internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { @@ -526,7 +522,7 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) } else if let p = xs.first { return .IORose(/*protectRose*/({ - let rose = reduce(p) + let rose = p.reduce switch rose { case .MkRose(let result, _): if !result().expect { @@ -539,7 +535,7 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose case .Some(false): return rose case .None: - let rose2 = reduce(conj(addCallbacks(result()) • k, xs: [Rose](xs[1..](xs[1.. { case MkRose(() -> A, () -> [Rose]) case IORose(() -> Rose) + + /// Case analysis for a Rose Tree. + public func onRose(f : (A, [Rose]) -> Rose) -> Rose { + switch self { + case .MkRose(let x, let rs): + return f(x(), rs()) + case .IORose(let m): + return .IORose({ m().onRose(f) }) + } + } + + /// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is + /// encountered. That branch is then returned. + public var reduce : Rose { + switch self { + case .MkRose(_, _): + return self + case .IORose(let m): + return m().reduce + } + } } extension Rose /*: Functor*/ { @@ -105,27 +126,6 @@ public func joinRose(rs : Rose>) -> Rose { } } -/// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is -/// encountered. That branch is then returned. -public func reduce(rs : Rose) -> Rose { - switch rs { - case .MkRose(_, _): - return rs - case .IORose(let m): - return reduce(m()) - } -} - -/// Case analysis for a Rose Tree. -public func onRose(f : (A -> [Rose] -> Rose))(rs : Rose) -> Rose { - switch rs { - case .MkRose(let x, let rs): - return f(x())(rs()) - case .IORose(let m): - return .IORose({ onRose(f)(rs: m()) }) - } -} - /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index c00b721..10106c0 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -10,7 +10,7 @@ infix operator <- {} /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - switch quickCheckWithResult(checker.args, p: test()) { + switch quickCheckWithResult(checker.args, test()) { case let .Failure(_, sz, seed, _, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): @@ -22,7 +22,7 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - /// Binds a Testable value to a property. public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { - switch quickCheckWithResult(checker.args, p: test()) { + switch quickCheckWithResult(checker.args, test()) { case let .Failure(_, sz, seed, _, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): @@ -34,12 +34,12 @@ public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { /// Binds a Testable value to a property. public func <-(checker : ReportiveQuickCheck, test : () -> Testable) { - quickCheckWithResult(checker.args, p: test()) + quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. public func <-(checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - quickCheckWithResult(checker.args, p: test()) + quickCheckWithResult(checker.args, test()) } infix operator ==> { From 2bc077627bef0c207676eb15150b63c338724ffb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:31:25 -0700 Subject: [PATCH 240/460] Make StdGens Equatable Thanks to the deterministic RNG, StdGen now has an identity. --- SwiftCheck/Random.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index f3bbf9c..42fbcd8 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -28,7 +28,7 @@ public protocol RandomGeneneratorType { /// repeatable results, by starting with a specified initial random number generator, or to get /// different results on each run by using the system-initialised generator or by supplying a seed /// from some other source. -public struct StdGen : RandomGeneneratorType, CustomStringConvertible { +public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible { let seed1 : Int let seed2 : Int @@ -82,6 +82,10 @@ public struct StdGen : RandomGeneneratorType, CustomStringConvertible { } } +public func ==(l : StdGen, r : StdGen) -> Bool { + return l.seed1 == r.seed1 && l.seed2 == r.seed2 +} + private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. From 8c8f17082d6a433f77946293fc03c38b61c5678d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 6 Jan 2016 22:31:45 -0700 Subject: [PATCH 241/460] Add real Prop tests --- SwiftCheckTests/PropertySpec.swift | 102 ++++++++++++++++++++++++++++- Tutorial.playground/Contents.swift | 4 +- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index f67da76..d4b8760 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -6,10 +6,40 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import SwiftCheck +@testable import SwiftCheck + +func ==(l : Property, r : Property) -> Bool { + let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) + let res2 = quickCheckWithResult(CheckerArguments(name: ""), r) + + switch (res1, res2) { + case (.Success(_, _, _), .Success(_, _, _)): + return true + case (.GaveUp(_, _, _), .GaveUp(_, _, _)): + return true + case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): + return true + case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): + return true + case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): + return true + default: + return false + } +} + +func ==(l : Property, r : Bool) -> Bool { + let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) + switch res1 { + case .Success(_, _, _): + return r == true + default: + return r == false + } +} class PropertySpec : XCTestCase { - func testAll() { + func testProperties() { property("Once really only tests a property once") <- forAll { (n : Int) in var bomb : Optional = .Some(n) return forAll { (_ : Int) in @@ -48,5 +78,73 @@ class PropertySpec : XCTestCase { property("Existential Quantification works") <- exists { (x : Int) in return true } + + property("Prop ==> true") <- forAll(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in + let p = p2 ==> p1 + if case .Success(_, _, _) = quickCheckWithResult(CheckerArguments(name: ""), p) { + return (p1 ==== true) ^||^ (p ^&&^ p1 ^&&^ p2) + } else { + return (p1 ==== false) ^||^ (p ^&&^ p1 ^&&^ p2) + } + } + + property("==> Short Circuits") <- forAll { (n : Int) in + func isPositive(n : Int) -> Bool { + if n > 0 { + return true + } else if (n & 1) == 0 { + fatalError("Should never get here") + } else { + return isPositive(n) // or here + } + } + return (n > 0) ==> isPositive(n) + } + + property("Prop Law of complements") <- forAll { (x : Bool) in + return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) + } + + property("Prop Law of double negation") <- forAll { (x : Bool) in + return x.invert.invert == x + } + + property("Prop Law of idempotency") <- forAll { (x : Bool) in + return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) + } + + property("Prop Law of dominance") <- forAll { (x : Bool) in + return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) + } + + property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) + } + + property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) + } + + property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) + let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) + return l ^&&^ r + } + + property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x ^||^ y)) == x + let r = (x ^||^ (x ^&&^ y)) == x + return l ^&&^ r + } + + property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) + let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) + return l ^&&^ r + } + + property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) + } } } diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 4e92839..0327f8b 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -520,7 +520,7 @@ func sieve(n : Int) -> [Int] { return [] } - var marked : [Bool] = (0...n).map({ _ in false }) + var marked : [Bool] = (0...n).map { _ in false } marked[0] = true marked[1] = true @@ -623,7 +623,7 @@ func sieveProperly(n : Int) -> [Int] { return [] } - var marked : [Bool] = (0...n).map({ _ in false }) + var marked : [Bool] = (0...n).map { _ in false } marked[0] = true marked[1] = true From 5b4373d24a87ba9b1f313670a62c3c0ea55bb3dd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 00:33:42 -0700 Subject: [PATCH 242/460] Uncurry liftM --- SwiftCheck/Gen.swift | 4 ++-- SwiftCheck/Rose.swift | 2 +- SwiftCheck/WitnessedArbitrary.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index abf09a6..8befc46 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -337,7 +337,7 @@ public func join(rs : Gen>) -> Gen { } /// Lifts a function from some A to some R to a function from generators of A to generators of R. -public func liftM(f : A -> R)(m1 : Gen) -> Gen { +public func liftM(f : A -> R, _ m1 : Gen) -> Gen { return m1.bind{ x1 in return Gen.pure(f(x1)) } @@ -346,7 +346,7 @@ public func liftM(f : A -> R)(m1 : Gen) -> Gen { /// Promotes a rose of generators to a generator of rose values. public func promote(x : Rose>) -> Gen> { return delay().bind { (let eval : Gen -> A) in - return Gen>.pure(liftM(eval)(m1: x)) + return Gen>.pure(liftM(eval, x)) } } diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 9fcd77c..0c2a3b9 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -100,7 +100,7 @@ public func >>- (m : Rose, fn : A -> Rose) -> Rose { } /// Lifts functions to functions over Rose Trees. -public func liftM(f : A -> R)(m1 : Rose) -> Rose { +public func liftM(f : A -> R, _ m1 : Rose) -> Rose { return m1.bind { x1 in return Rose.pure(f(x1)) } diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index 140af15..3e7a7ea 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -116,7 +116,7 @@ extension Optional where Wrapped : Arbitrary { public static var arbitrary : Gen> { return Gen>.frequency([ (1, Gen>.pure(.None)), - (3, liftM(Optional.Some)(m1: Wrapped.arbitrary)), + (3, liftM(Optional.Some, Wrapped.arbitrary)), ]) } From 9c6d83e5f77acb5d7b74f144595635e35869a21d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 00:33:58 -0700 Subject: [PATCH 243/460] Add lambda calculus spec from QuickCheck --- SwiftCheck.xcodeproj/project.pbxproj | 8 ++ SwiftCheckTests/LambdaSpec.swift | 191 +++++++++++++++++++++++++++ SwiftCheckTests/PropertySpec.swift | 24 ++-- 3 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 SwiftCheckTests/LambdaSpec.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 976a3cd..70aeb48 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -42,6 +42,9 @@ 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */; }; 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; + 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; + 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; + 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; @@ -153,6 +156,7 @@ 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; @@ -301,6 +305,7 @@ 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */, 8445C4A91B16D37800280089 /* GenSpec.swift */, + 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */, 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, @@ -594,6 +599,7 @@ 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */, 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */, 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */, + 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */, 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */, 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */, @@ -636,6 +642,7 @@ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, + 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */, @@ -678,6 +685,7 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, + 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */, diff --git a/SwiftCheckTests/LambdaSpec.swift b/SwiftCheckTests/LambdaSpec.swift new file mode 100644 index 0000000..86583ee --- /dev/null +++ b/SwiftCheckTests/LambdaSpec.swift @@ -0,0 +1,191 @@ +// +// LambdaSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 1/6/16. +// Copyright © 2016 Robert Widmann. All rights reserved. +// + +import SwiftCheck + +struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { + let unName : String + + static var arbitrary : Gen { + let gc : Gen = Gen.fromElementsIn("a"..."z") + return gc.fmap { Name(unName: String($0)) } + } + + var description : String { + return self.unName + } + + var hashValue : Int { + return self.unName.hashValue + } +} + +func == (l : Name, r : Name) -> Bool { + return l.unName == r.unName +} + +private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { + return m1.bind { x1 in + return m2.bind { x2 in + return Gen.pure(f(x1, x2)) + } + } +} + +indirect enum Exp : Equatable { + case Lam(Name, Exp) + case App(Exp, Exp) + case Var(Name) +} + +func == (l : Exp, r : Exp) -> Bool { + switch (l, r) { + case let (.Lam(ln, le), .Lam(rn, re)): + return ln == rn && le == re + case let (.App(ln, le), .App(rn, re)): + return ln == rn && le == re + case let (.Var(n1), .Var(n2)): + return n1 == n2 + default: + return false + } +} + +extension Exp : Arbitrary { + private static func arbExpr(n : Int) -> Gen { + return Gen.frequency([ + (2, liftM(Exp.Var, Name.arbitrary)), + ] + ((n <= 0) ? [] : [ + (5, liftM2(Exp.Lam, Name.arbitrary, arbExpr(n.predecessor()))), + (5, liftM2(Exp.App, arbExpr(n/2), arbExpr(n/2))), + ])) + } + + static var arbitrary : Gen { + return Gen.sized(self.arbExpr) + } + + static func shrink(e : Exp) -> [Exp] { + switch e { + case .Var(_): + return [] + case let .Lam(x, a): + return [a] + Exp.shrink(a).map { .Lam(x, $0) } + case let .App(a, b): + let part1 : [Exp] = [a, b] + + [a].flatMap({ (expr : Exp) -> Exp? in + if case let .Lam(x, a) = expr { + return a.subst(x, b) + } + return nil + }) + + let part2 : [Exp] = Exp.shrink(a).map { App($0, b) } + + Exp.shrink(b).map { App(a, $0) } + return part1 + part2 + } + } + + var free : Set { + switch self { + case let .Var(x): + return Set([x]) + case let .Lam(x, a): + return a.free.subtract([x]) + case let .App(a, b): + return a.free.union(b.free) + } + } + + func rename(x : Name, _ y : Name) -> Exp { + if x == y { + return self + } + return self.subst(x, .Var(y)) + } + + func subst(x : Name, _ c : Exp) -> Exp { + switch self { + case let .Var(y) where x == y : + return c + case let .Lam(y, a) where x != y: + return .Lam(y, a.subst(x, c)) + case let .App(a, b): + return .App(a.subst(x, c), b.subst(x, c)) + default: + return self + } + } + + var eval : Exp { + switch self { + case .Var(_): + fatalError("Cannot evaluate free variable!") + case let .App(a, b): + switch a.eval { + case let .Lam(x, aPrime): + return aPrime.subst(x, b) + default: + return .App(a.eval, b.eval) + } + default: + return self + } + } +} + +extension Exp : CustomStringConvertible { + var description : String { + switch self { + case let .Var(x): + return "$" + x.description + case let .Lam(x, t): + return "(λ $\(x.description).\(t.description))" + case let .App(a, b): + return "(\(a.description) \(b.description))" + } + } +} + +extension Name { + func fresh(ys : Set) -> Name { + let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } + return Set(zz).subtract(ys).first ?? self + } +} + +private func showResult(x : A, f : A -> Testable) -> Property { + return f(x).whenFail { + print("Result: \(x)") + } +} + +class LambdaSpec : XCTestCase { + func testAll() { + let tiny = CheckerArguments(maxTestCaseSize: 10) + + property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return a.free.contains(x) + ==> subst_x_b_a.free == a.free.subtract([x]).union(b.free) + } + }.expectFailure + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a == a + } + } + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a.free == a.free + } + } + } +} diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index d4b8760..93c95ee 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -79,7 +79,7 @@ class PropertySpec : XCTestCase { return true } - property("Prop ==> true") <- forAll(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in + property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in let p = p2 ==> p1 if case .Success(_, _, _) = quickCheckWithResult(CheckerArguments(name: ""), p) { return (p1 ==== true) ^||^ (p ^&&^ p1 ^&&^ p2) @@ -99,52 +99,52 @@ class PropertySpec : XCTestCase { } } return (n > 0) ==> isPositive(n) - } + }.noShrinking property("Prop Law of complements") <- forAll { (x : Bool) in return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) - } + }.noShrinking property("Prop Law of double negation") <- forAll { (x : Bool) in return x.invert.invert == x - } + }.noShrinking property("Prop Law of idempotency") <- forAll { (x : Bool) in return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) - } + }.noShrinking property("Prop Law of dominance") <- forAll { (x : Bool) in return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) - } + }.noShrinking property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) - } + }.noShrinking property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) - } + }.noShrinking property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) return l ^&&^ r - } + }.noShrinking property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ (x ^||^ y)) == x let r = (x ^||^ (x ^&&^ y)) == x return l ^&&^ r - } + }.noShrinking property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) return l ^&&^ r - } + }.noShrinking property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) - } + }.noShrinking } } From 50a5f0cf12b41d1e983432887e682d44e12170c7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 00:41:42 -0700 Subject: [PATCH 244/460] Make things look like Swift --- SwiftCheck/Arbitrary.swift | 26 ++-- SwiftCheck/Gen.swift | 36 +++-- SwiftCheck/Modifiers.swift | 16 +-- SwiftCheck/Property.swift | 18 +-- SwiftCheck/Rose.swift | 23 ++-- SwiftCheck/Test.swift | 2 +- SwiftCheck/WitnessedArbitrary.swift | 16 +-- SwiftCheckTests/ComplexSpec.swift | 14 +- SwiftCheckTests/GenSpec.swift | 12 +- SwiftCheckTests/LambdaSpec.swift | 6 +- SwiftCheckTests/TestSpec.swift | 2 +- Tutorial.playground/Contents.swift | 206 ++++++++++++++-------------- 12 files changed, 184 insertions(+), 193 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index b52547c..5748b12 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -254,7 +254,7 @@ extension Double : Arbitrary { extension UnicodeScalar : Arbitrary { public static var arbitrary : Gen { - return UInt32.arbitrary.bind(Gen.pure • UnicodeScalar.init) + return UInt32.arbitrary.flatMap(Gen.pure • UnicodeScalar.init) } public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { @@ -287,37 +287,37 @@ extension Character : Arbitrary { extension AnyForwardIndex : Arbitrary { public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyForwardIndex.init) + return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyForwardIndex.init) } } extension AnyRandomAccessIndex : Arbitrary { public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).bind(Gen.pure • AnyRandomAccessIndex.init) + return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyRandomAccessIndex.init) } } extension Mirror : Arbitrary { public static var arbitrary : Gen { let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.fmap(asAny), - Int.arbitrary.fmap(asAny), - UInt.arbitrary.fmap(asAny), - Float.arbitrary.fmap(asAny), - Double.arbitrary.fmap(asAny), - Character.arbitrary.fmap(asAny), + Bool.arbitrary.map(asAny), + Int.arbitrary.map(asAny), + UInt.arbitrary.map(asAny), + Float.arbitrary.map(asAny), + Double.arbitrary.map(asAny), + Character.arbitrary.map(asAny), ]) let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.fmap(asAny), - Array.arbitrary.fmap(asAny), - Set.arbitrary.fmap(asAny), + Optional.arbitrary.map(asAny), + Array.arbitrary.map(asAny), + Set.arbitrary.map(asAny), ]) return Gen.oneOf([ genAny, genAnyWitnessed, - ]).fmap(Mirror.init) + ]).map(Mirror.init) } } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 8befc46..2949de2 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -44,7 +44,7 @@ public struct Gen { /// /// The input collection is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { - return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).fmap { i in + return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).map { i in return xs[i] } } @@ -79,8 +79,8 @@ public struct Gen { return Gen<[S]>.pure([]) } - return Gen<(S, [S])>.fromElementsOf(selectOne(xs)).bind { (y, ys) in - return Gen.fromShufflingElementsOf(ys).fmap { [y] + $0 } + return Gen<(S, [S])>.fromElementsOf(selectOne(xs)).flatMap { (y, ys) in + return Gen.fromShufflingElementsOf(ys).map { [y] + $0 } } } @@ -125,7 +125,7 @@ public struct Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") - return choose((1, xs.map({ $0.0 }).reduce(0, combine: +))).bind { l in + return choose((1, xs.map({ $0.0 }).reduce(0, combine: +))).flatMap { l in return pick(l)(lst: xs) } } @@ -143,8 +143,8 @@ public struct Gen { /// Zips together 2 generators of type `A` and `B` into a generator of pairs `(A, B)`. public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return gen1.bind { l in - return gen2.bind { r in + return gen1.flatMap { l in + return gen2.flatMap { r in return Gen<(A, B)>.pure((l, r)) } } @@ -182,7 +182,7 @@ extension Gen { /// that fails more often than it succeeds may result in a space leak. At that point, it is /// better to use `suchThatOptional` or `.invert` the test case. public func suchThat(p : A -> Bool) -> Gen { - return self.suchThatOptional(p).bind { mx in + return self.suchThatOptional(p).flatMap { mx in switch mx { case .Some(let x): return Gen.pure(x) @@ -228,10 +228,8 @@ extension Gen { /// MARK: Instances extension Gen /*: Functor*/ { - typealias B = Swift.Any - /// Returns a new generator that applies a given function to any outputs the receiver creates. - public func fmap(f : (A -> B)) -> Gen { + public func map(f : (A -> B)) -> Gen { return f <^> self } } @@ -250,8 +248,6 @@ public func <^> (f : A -> B, g : Gen) -> Gen { } extension Gen /*: Applicative*/ { - typealias FAB = Gen B> - /// Lifts a value into a generator that will only generate that value. public static func pure(a : A) -> Gen { return Gen(unGen: { _ in @@ -294,7 +290,7 @@ extension Gen /*: Monad*/ { /// `bind` allows for the creation of Generators that depend on other generators. One might, /// for example, use a Generator of integers to control the length of a Generator of strings, or /// use it to choose a random index into a Generator of arrays. - public func bind(fn : A -> Gen) -> Gen { + public func flatMap(fn : A -> Gen) -> Gen { return self >>- fn } } @@ -321,8 +317,8 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// array that was given. public func sequence(ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in - return x.bind { x1 in - return y.bind { xs in + return x.flatMap { x1 in + return y.flatMap { xs in return Gen<[A]>.pure([x1] + xs) } } @@ -331,28 +327,28 @@ public func sequence(ms : [Gen]) -> Gen<[A]> { /// Flattens a generator of generators by one level. public func join(rs : Gen>) -> Gen { - return rs.bind { x in + return rs.flatMap { x in return x } } /// Lifts a function from some A to some R to a function from generators of A to generators of R. public func liftM(f : A -> R, _ m1 : Gen) -> Gen { - return m1.bind{ x1 in + return m1.flatMap{ x1 in return Gen.pure(f(x1)) } } /// Promotes a rose of generators to a generator of rose values. public func promote(x : Rose>) -> Gen> { - return delay().bind { (let eval : Gen -> A) in + return delay().flatMap { (let eval : Gen -> A) in return Gen>.pure(liftM(eval, x)) } } /// Promotes a function returning generators to a generator of functions. public func promote(m : A -> Gen) -> Gen B> { - return delay().bind { (let eval : Gen -> B) in + return delay().flatMap { (let eval : Gen -> B) in return Gen B>.pure({ x in eval(m(x)) }) } } @@ -379,7 +375,7 @@ private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) - if n == 0 { return Gen.pure(.None) } - return gen.resize(2 * k + n).bind { (let x : A) -> Gen> in + return gen.resize(2 * k + n).flatMap { (let x : A) -> Gen> in if p(x) { return Gen.pure(.Some(x)) } diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index d864c5a..5ea463e 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -227,7 +227,7 @@ public struct SetOf> : Arbitrary, CustomString public static var arbitrary : Gen> { return Gen.sized { n in - return Gen.choose((0, n)).bind { k in + return Gen.choose((0, n)).flatMap { k in if k == 0 { return Gen.pure(SetOf(Set([]))) } @@ -268,7 +268,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { } public static var arbitrary : Gen> { - return PointerOfImpl.arbitrary.fmap(PointerOf.init) + return PointerOfImpl.arbitrary.map(PointerOf.init) } } @@ -285,7 +285,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi } public static var arbitrary : Gen> { - return ArrowOfImpl.arbitrary.fmap(ArrowOf.init) + return ArrowOfImpl.arbitrary.map(ArrowOf.init) } } @@ -315,7 +315,7 @@ public struct IsoOf, U : protocol } public static var arbitrary : Gen> { - return IsoOfImpl.arbitrary.fmap(IsoOf.init) + return IsoOfImpl.arbitrary.map(IsoOf.init) } } @@ -341,7 +341,7 @@ public struct Large> : Arbitr } public static var arbitrary : Gen> { - return Gen.choose((A.min, A.max)).fmap(Large.init) + return Gen.choose((A.min, A.max)).map(Large.init) } public static func shrink(bl : Large) -> [Large] { @@ -362,7 +362,7 @@ public struct Positive> : Arbitrary, C } public static var arbitrary : Gen> { - return A.arbitrary.fmap(Positive.init • abs).suchThat { $0.getPositive > 0 } + return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } } public static func shrink(bl : Positive) -> [Positive] { @@ -526,7 +526,7 @@ private final class IsoOfImpl, U return T.coarbitrary(a)(U.arbitrary) }), promote({ a in return U.coarbitrary(a)(T.arbitrary) - })).fmap { IsoOfImpl($0, $1) } + })).map { IsoOfImpl($0, $1) } } static func shrink(f : IsoOfImpl) -> [IsoOfImpl] { @@ -575,7 +575,7 @@ private final class PointerOfImpl : Arbitrary { } let pt = UnsafeMutablePointer.alloc(n) let gt = pt.initializeFrom <^> sequence(Array((0.. Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.fmap { $0.unProp } - })).bind({ roses in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in return Gen.pure(Prop(unProp: conj(id, xs: roses))) })) } @@ -33,8 +33,8 @@ public func conjoin(ps : Testable...) -> Property { /// When disjoining properties all calls to `expectFailure` will fail. public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.fmap { $0.unProp } - })).bind({ roses in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in return Gen.pure(Prop(unProp: roses.reduce(.MkRose({ TestResult.failed() }, { [] }), combine: disj))) })) } @@ -274,8 +274,8 @@ extension Testable { /// Shrinking is handled automatically by SwiftCheck. Invoking this function is only necessary /// when you must override the default behavior. public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { - return Property(promote(props(shrinker, original: initial, pf: prop)).fmap { rs in - return Prop(unProp: joinRose(rs.fmap { x in + return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in + return Prop(unProp: joinRose(rs.map { x in return x.unProp })) }) @@ -559,7 +559,7 @@ private func conj(k : TestResult -> TestResult, xs : [Rose]) -> Rose } private func disj(p : Rose, q : Rose) -> Rose { - return p.bind { result1 in + return p.flatMap { result1 in if !result1.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } @@ -567,7 +567,7 @@ private func disj(p : Rose, q : Rose) -> Rose.pure(result1) case .Some(false): - return q.bind { (result2 : TestResult) in + return q.flatMap { (result2 : TestResult) in if !result2.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } @@ -593,7 +593,7 @@ private func disj(p : Rose, q : Rose) -> Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 0c2a3b9..fd1be69 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -40,14 +40,11 @@ public enum Rose { } extension Rose /*: Functor*/ { - typealias B = Swift.Any - typealias FB = Rose - /// Maps a function over all the nodes of a Rose Tree. /// /// For `.MkRose` branches the computation is applied to the node's value then application /// recurses into the sub-trees. For `.IORose` branches the map is suspended. - public func fmap(f : (A -> B)) -> Rose { + public func map(f : (A -> B)) -> Rose { return f <^> self } } @@ -55,15 +52,13 @@ extension Rose /*: Functor*/ { public func <^> (f : A -> B, g : Rose) -> Rose { switch g { case .MkRose(let root, let children): - return .MkRose({ f(root()) }, { children().map() { $0.fmap(f) } }) + return .MkRose({ f(root()) }, { children().map() { $0.map(f) } }) case .IORose(let rs): - return .IORose({ rs().fmap(f) }) + return .IORose({ rs().map(f) }) } } extension Rose /*: Applicative*/ { - typealias FAB = Rose B> - /// Lifts a value into a Rose Tree. public static func pure(a : A) -> Rose { return .MkRose({ a }, { [] }) @@ -82,7 +77,7 @@ extension Rose /*: Applicative*/ { public func <*> (fn : Rose B>, g : Rose) -> Rose { switch fn { case .MkRose(let f, _): - return g.fmap(f()) + return g.map(f()) case .IORose(let rs): return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW } @@ -90,18 +85,18 @@ public func <*> (fn : Rose B>, g : Rose) -> Rose { extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all together. - public func bind(fn : A -> Rose) -> Rose { + public func flatMap(fn : A -> Rose) -> Rose { return self >>- fn } } public func >>- (m : Rose, fn : A -> Rose) -> Rose { - return joinRose(m.fmap(fn)) + return joinRose(m.map(fn)) } /// Lifts functions to functions over Rose Trees. public func liftM(f : A -> R, _ m1 : Rose) -> Rose { - return m1.bind { x1 in + return m1.flatMap { x1 in return Rose.pure(f(x1)) } } @@ -129,8 +124,8 @@ public func joinRose(rs : Rose>) -> Rose { /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in - return m.bind { x in - return n.bind { xs in + return m.flatMap { x in + return n.flatMap { xs in return Rose<[A]>.pure([x] + xs) } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 1f13443..b478f47 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -279,7 +279,7 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { - return Property(gen.bind { x in + return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in do { return (try f(xs)).counterexample(String(xs)) diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index 3e7a7ea..f0ae108 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -9,7 +9,7 @@ extension Array where Element : Arbitrary { public static var arbitrary : Gen> { return Gen.sized { n in - return Gen.choose((0, n)).bind { k in + return Gen.choose((0, n)).flatMap { k in if k == 0 { return Gen.pure([]) } @@ -162,8 +162,8 @@ extension ContiguousArray : WitnessedArbitrary { /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { public static var arbitrary : Gen> { - return [Key].arbitrary.bind { k in - return [Value].arbitrary.bind { v in + return [Key].arbitrary.flatMap { k in + return [Value].arbitrary.flatMap { v in return Gen.pure(Dictionary(Zip2Sequence(k, v))) } } @@ -192,8 +192,8 @@ extension EmptyCollection : Arbitrary { extension HalfOpenInterval where Bound : protocol { public static var arbitrary : Gen> { - return Bound.arbitrary.bind { l in - return Bound.arbitrary.bind { r in + return Bound.arbitrary.flatMap { l in + return Bound.arbitrary.flatMap { r in return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) } } @@ -238,8 +238,8 @@ extension LazySequence where Base : protocol { extension Range where Element : protocol { public static var arbitrary : Gen> { - return Element.arbitrary.bind { l in - return Element.arbitrary.bind { r in + return Element.arbitrary.flatMap { l in + return Element.arbitrary.flatMap { r in return Gen.pure(Range(start: min(l, r), end: max(l, r))) } } @@ -270,7 +270,7 @@ extension Repeat : WitnessedArbitrary { extension Set where Element : protocol { public static var arbitrary : Gen> { return Gen.sized { n in - return Gen.choose((0, n)).bind { k in + return Gen.choose((0, n)).flatMap { k in if k == 0 { return Gen.pure(Set([])) } diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 7ed026c..d291afc 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -24,15 +24,15 @@ class ComplexSpec : XCTestCase { lower, numeric, special, - ]).proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).fmap(String.init) + ]).proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).map(String.init) let hostname = Gen.oneOf([ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty().fmap(String.init) + ]).proliferateNonEmpty().map(String.init) - let tld = lower.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) + let tld = lower.proliferateNonEmpty().suchThat({ $0.count > 1 }).map(String.init) let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld @@ -43,10 +43,10 @@ class ComplexSpec : XCTestCase { func testIPv6Properties() { let ipHexDigits = Gen.oneOf([ - hexDigits.proliferateSized(1).fmap{ String.init($0) + ":" }, - hexDigits.proliferateSized(2).fmap{ String.init($0) + ":" }, - hexDigits.proliferateSized(3).fmap{ String.init($0) + ":" }, - hexDigits.proliferateSized(4).fmap{ String.init($0) + ":" }, + hexDigits.proliferateSized(1).map{ String.init($0) + ":" }, + hexDigits.proliferateSized(2).map{ String.init($0) + ":" }, + hexDigits.proliferateSized(3).map{ String.init($0) + ":" }, + hexDigits.proliferateSized(4).map{ String.init($0) + ":" }, ]) let ipGen = { $0.initial() } <^> (wrap2 <^> ipHexDigits <*> ipHexDigits <*> ipHexDigits <*> ipHexDigits) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 0d06fe4..729fc0f 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -149,12 +149,12 @@ class GenSpec : XCTestCase { let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.fmap(id)) == id(x) + return (x.map(id)) == id(x) } property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in return forAllNoShrink(lawfulGen) { (x : Gen) in - return ((f.getArrow • g.getArrow) <^> x) == (x.fmap(g.getArrow).fmap(f.getArrow)) + return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) } } @@ -163,14 +163,14 @@ class GenSpec : XCTestCase { } property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.fmap({ $0.getArrow }) - let g = gl.fmap({ $0.getArrow }) + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) } property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.fmap({ $0.getArrow }) - let g = gl.fmap({ $0.getArrow }) + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) } diff --git a/SwiftCheckTests/LambdaSpec.swift b/SwiftCheckTests/LambdaSpec.swift index 86583ee..cdcd886 100644 --- a/SwiftCheckTests/LambdaSpec.swift +++ b/SwiftCheckTests/LambdaSpec.swift @@ -13,7 +13,7 @@ struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { static var arbitrary : Gen { let gc : Gen = Gen.fromElementsIn("a"..."z") - return gc.fmap { Name(unName: String($0)) } + return gc.map { Name(unName: String($0)) } } var description : String { @@ -30,8 +30,8 @@ func == (l : Name, r : Name) -> Bool { } private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { - return m1.bind { x1 in - return m2.bind { x2 in + return m1.flatMap { x1 in + return m2.flatMap { x2 in return Gen.pure(f(x1, x2)) } } diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index e65810a..8a783d9 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -21,7 +21,7 @@ extension Dictionary { class TestSpec : XCTestCase { func testAll() { - let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate().fmap(Dictionary.init) + let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate().map(Dictionary.init) property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in return true diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 0327f8b..d198f95 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -169,9 +169,9 @@ oddLengthArrays.generate.count //: Generators also admit functional methods like `map` and `flatMap`, but with different names than //: you might be used to. -// `fmap` (function map) works exactly like Array's `map` method; it applies the function to any +// `map` works exactly like Array's `map` method; it applies the function to any // values it generates. -let fromTwoToSix = fromOnetoFive.fmap { $0 + 1 } +let fromTwoToSix = fromOnetoFive.map { $0 + 1 } fromTwoToSix.generate fromTwoToSix.generate @@ -179,14 +179,14 @@ fromTwoToSix.generate fromTwoToSix.generate fromTwoToSix.generate -// `bind` works exactly like Array's `flatMap`, but instead of concatenating the generated arrays it -// produces a new generator that picks values from among the newly created generators produced by -// the function. +// `Gen.flatMap` works exactly like `Array`'s `flatMap`, but instead of concatenating the generated +// arrays it produces a new generator that picks values from among the newly created generators +// produced by the function. // -// While that definition may *technically* be what occurs, it is better to think of `bind` as a way -// of making a generator depend on another. For example, you can use a generator of sizes to limit -// the length of generators of arrays: -let generatorBoundedSizeArrays = fromOnetoFive.bind { len in +// While that definition may *technically* be what occurs, it is better to think of `flatMap` as a +// way of making a generator depend on another. For example, you can use a generator of sizes to +// limit the length of generators of arrays: +let generatorBoundedSizeArrays = fromOnetoFive.flatMap { len in return characterArray.suchThat { xs in xs.count <= len } } @@ -194,15 +194,15 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate -generatorBoundedSizeArrays.generate - -//: Because SwiftCheck is based on the functional concepts in our other library +generatorBoundedSizeArrays.generate//: Because SwiftCheck is based on the functional concepts in our other library //: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: //: //: * `<^>` is an alias for `fmap` //: * `<*>` is an alias for `ap` //: * `>>-` is an alias for `bind` + + let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive fromTwoToSix_.generate @@ -215,64 +215,66 @@ let generatorBoundedSizeArrays_ = fromOnetoFive >>- { len in generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate - -//: For our purposes, we will say that an email address consists of 3 parts: A local part, a +generatorBoundedSizeArrays_.generate//: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. //: //: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, //: numbers, and certain kinds of special characters. We already have generators for upper and //: lower cased letters, so all we need are special characters and a more complete number generator: + + let numeric : Gen = Gen.fromElementsIn("0"..."9") -let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."])//: Now for the actual generator + -//: Now for the actual generator let allowedLocalCharacters : Gen = Gen.oneOf([ upperCaseLetters, lowerCaseLetters, numeric, special, -]) - -//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` +])//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` //: to get a `String` back. + + let localEmail = allowedLocalCharacters .proliferateNonEmpty() // Make a non-empty array of characters .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. - .fmap(String.init) // Then make a string. -//: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some + .map(String.init) // Then make a string.//: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine both steps into one big generator. + let hostname = Gen.oneOf([ lowerCaseLetters, numeric, Gen.pure("-"), -]).proliferateNonEmpty().fmap(String.init) +]).proliferateNonEmpty().map(String.init) //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. -let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).fmap(String.init) +let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).map(String.init) + //: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how //: about some glue? - // Concatenates an array of `String` `Gen`erators together in order. func glue(parts : [Gen]) -> Gen { - return sequence(parts).fmap { $0.reduce("", combine: +) } + return sequence(parts).map { $0.reduce("", combine: +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) -//: And we're done! -// Yes, these are in fact, all valid email addresses. +///: And we're done! +/ Yes, these are in fact, all valid email addresses. emailGen.generate emailGen.generate emailGen.generate + + //: By now you may be asking "why do we need all of this in the first place? Can't we just apply //: the parts to the function to get back a result?" Well, we do it because we aren't working with //: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply @@ -282,17 +284,15 @@ emailGen.generate //: //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: - -//: # Arbitrary - -//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were +///: # Arbitrary +///: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were //: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on //: values that would ask them to generate a "next" value. But that would have been incredibly //: boring! Instead, we wrote a protocol called `Arbitrary` and let Types, not values, do all the //: work. //: //: The `Arbitrary` protocol looks like this: -// + // public protocol Arbitrary { // /// The generator for this particular type. // /// @@ -302,18 +302,18 @@ emailGen.generate // static var arbitrary : Gen { get } // } // -//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator + +i//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator //: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of //: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance //: for `Int` calls `arc4random_uniform`. //: //: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen //: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. +mport class Foundation.NSDate -import class Foundation.NSDate +////: Here's the obvious way to do it -//: Here's the obvious way to do it -// // extension NSDate : Arbitrary { // public static var arbitrary : Gen { // return Gen.oneOf([ @@ -325,12 +325,12 @@ import class Foundation.NSDate // } // } // -//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` + +s//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` //: in the wrong position. What to do? //: //: Let's write a wrapper! - -struct ArbitraryDate : Arbitrary { +truct ArbitraryDate : Arbitrary { let getDate : NSDate init(date : NSDate) { self.getDate = date } @@ -341,27 +341,27 @@ struct ArbitraryDate : Arbitrary { Gen.pure(NSDate.distantFuture()), Gen.pure(NSDate.distantPast()), NSDate.init <^> NSTimeInterval.arbitrary, - ]).fmap(ArbitraryDate.init) + ]).map(ArbitraryDate.init) } } ArbitraryDate.arbitrary.generate.getDate ArbitraryDate.arbitrary.generate.getDate -//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't + +pu//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't //: generate with another that we can. //: //: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: - -public struct ArbitraryPositive> : Arbitrary { +blic struct ArbitraryPositive> : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } public static var arbitrary : Gen> { - return A.arbitrary.fmap { ArbitraryPositive.init(abs($0)) } + return A.arbitrary.map { ArbitraryPositive.init(abs($0)) } } } @@ -369,9 +369,10 @@ ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive -//: # Quantifiers -//: What we've seen so far are the building blocks we need to introduce the final part of the +// +//: # Quantifiers +///: What we've seen so far are the building blocks we need to introduce the final part of the //: library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. //: //: A Quantifier is a contract that serves as a guarantee that a property holds when the given @@ -380,14 +381,13 @@ ArbitraryPositive.arbitrary.generate.getPositive //: requires type annotations for all value positions being requested. There is only one quantifier //: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec //: must pass "for all" of the values. Here's what it looks like: +/ func forAll(_ : (A... -> Bool)) -> Property // -// func forAll(_ : (A... -> Bool)) -> Property -// -//: The actual type of `forAll` is much more general and expressive than this, but for now this will do. + +// //: The actual type of `forAll` is much more general and expressive than this, but for now this will do. //: //: Here is an example of a simple property - -// + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. + + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. // | + This backwards arrow binds a property name and a property to each other. // | | // v v @@ -397,9 +397,9 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // From now on, all of our examples will take the form above. -//: Because `forAll` is variadic it works for a large number and variety of types too: -// +--- This Modifier Type produces Arrays of Integers. +// //: Because `forAll` is variadic it works for a large number and variety of types too: + +--- This Modifier Type produces Arrays of Integers. // | +--- This Modifier Type generates functions. That's right, SwiftCheck // | | can generate *functions*!! // v v @@ -417,7 +417,8 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in return l && r } -//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not + +// //: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not //: once did we have to invoke `.generate` or have to construct a generator. We simply told the //: `forAll` block how many variables we wanted and of what type and SwiftCheck automagically went //: out and was able to produce random values. @@ -426,8 +427,7 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in //: to construct default generators for each type and a testing mechanism that invokes the testing //: block for the proper number of tests. For some real magic, let's see what happens when we fail //: a test: - -// `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, +`reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. reportProperty("Obviously wrong") <- forAll({ (x : Int) in @@ -436,7 +436,8 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in print("Oh noes!") } -//: If you open the console for the playground, you'll see output very similar to the following: +// +///: If you open the console for the playground, you'll see output very similar to the following: //: //: *** Failed! Proposition: Obviously wrong //: Falsifiable (after 1 test): @@ -449,8 +450,7 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in //: the integer supposedly being random. What's going on here? //: //: To find out, let's see the full definition of the `Arbitrary` protocol: -// -// public protocol Arbitrary { +/ public protocol Arbitrary { // /// The generator for this particular type. // /// // /// This function should call out to any sources of randomness or state necessary to generate @@ -468,22 +468,22 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in // static func shrink(_ : Self) -> [Self] // } // -//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is + +Arr//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is //: a strategy for reducing randomly generated values. To shrink a value, all you need to do is //: return an array of "smaller values", whether in magnitude or value. For example, the shrinker //: for `Array` returns Arrays that have a size less than or equal to that of the input array. +ay.shrink([1, 2, 3]) -Array.shrink([1, 2, 3]) -//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes + +////: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes //: the shrinker, tries the property again on the values of the array until it finds another failing //: case, then repeats the process until it runs out of cases to try. In other words, it *shrinks* //: the value down to the least possible size then reports that to you as the failing test case //: rather than the randomly generated value which could be unnecessarily large or complex. - -//: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: - -// SwiftCheck defines default shrinkers for most of the types it gives Arbitrary instances. There + //: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: +SwiftCheck defines default shrinkers for most of the types it gives Arbitrary instances. There // will often be times when those default shrinkers don't cut it, or you need more control over // what happens when you generate or shrink values. Modifier Types to the rescue! struct ArbitraryEmail : Arbitrary { @@ -491,7 +491,7 @@ struct ArbitraryEmail : Arbitrary { init(email : String) { self.getEmail = email } - static var arbitrary : Gen { return emailGen.fmap(ArbitraryEmail.init) } + static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } } // Let's be wrong for the sake of example @@ -501,12 +501,12 @@ property("email addresses don't come with a TLD") <- forAll { (email : Arbitrary // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail // and live up to your expectations, SwiftCheck treats that as a failure of the test case. -//: # All Together Now! -//: Let's put all of our newfound understanding of this framework to use by writing a property that -//: tests an implementation of the Sieve of Eratosthenes: -// The Sieve of Eratosthenes: +// //: # All Together Now! +T//: Let's put all of our newfound understanding of this framework to use by writing a property that +//: tests an implementation of the Sieve of Eratosthenes: +he Sieve of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -559,10 +559,10 @@ func isPrime(n : Int) -> Bool { return true } -//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the -//: following property: -reportProperty("All Prime") <- forAll { (n : Positive) in +repo//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the +//: following property: +rtProperty("All Prime") <- forAll { (n : Positive) in let primes = sieve(n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) @@ -572,6 +572,9 @@ reportProperty("All Prime") <- forAll { (n : Positive) in } } + + +// //: This test introduces several new concepts that we'll go through 1-by-1: //: //: * `Positive`: This is a Modifier Type defined by SwiftCheck that only produces @@ -594,8 +597,7 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: `forAll` that takes a user-supplied generator. For those times when you want //: absolute control over generated values, like we do here, use that particular //: series of overloads. - -//: If you check the console, you'll notice that this property doesn't hold! +///: If you check the console, you'll notice that this property doesn't hold! //: //: *** Failed! Proposition: All Prime //: Falsifiable (after 11 tests and 2 shrinks): @@ -603,10 +605,8 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: 0 //: //: What's wrong here? - -//: Let's go back to the spec we had for the sieve: -// -// The Sieve of Eratosthenes: +///: Let's go back to the spec we had for the sieve: + The Sieve of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -616,9 +616,9 @@ reportProperty("All Prime") <- forAll { (n : Positive) in // } // - Remaining indices of unmarked numbers are primes // -//: Looks like we used `to:` when we meant `through:`. Let's try again: -func sieveProperly(n : Int) -> [Int] { +func//: Looks like we used `to:` when we meant `through:`. Let's try again: + sieveProperly(n : Int) -> [Int] { if n <= 1 { return [] } @@ -653,38 +653,38 @@ property("All Prime") <- forAll { (n : Positive) in } } -//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm + + +pro//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm //: isn't handling the case presented. So you search through some specification to find the mistake in //: logic and try again. Along the way, SwiftCheck will do its best help you by presenting minimal //: cases at the least, and, with more advanced uses of the framework, the names of specific sub-parts of //: cases and even percentages of failing vs. passing tests. - -//: Just for fun, let's try a simpler property that checks the same outcome: - -property("All Prime") <- forAll { (n : Positive) in +p//: Just for fun, let's try a simpler property that checks the same outcome: +erty("All Prime") <- forAll { (n : Positive) in // Sieving Properly then filtering for primes is the same as just Sieving, right? return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } //; # One More Thing + + + + + //: When working with failing tests, it's often tough to be able to replicate the exact conditions //: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework //: comes with a replay mechanism that allows the arguments that lead to a failing test to be generated //: in exactly the same order, with exactly the same values, as they did the first time. When a test //: fails, SwiftCheck will present a helpful message that looks something like this in Xcode: - -//: > failed - Falsifiable; Replay with 123456789 123456789 - -//: Or this message in your log: - -//: > Pass the seed values 123456789 123456789 to replay the test. - -//: These are called *seeds*, and they can be fed back into the property that generated them to +r//: > failed - Falsifiable; Replay with 123456789 123456789 +e//: Or this message in your log: +p//: > Pass the seed values 123456789 123456789 to replay the test. +o//: These are called *seeds*, and they can be fed back into the property that generated them to //: activate the replay feature. For example, here's an annoying test to debug because it only fails //: every so often on one particular value: - -reportProperty("Screw this value in particular") <- forAll { (n : UInt) in +rtProperty("Screw this value in particular") <- forAll { (n : UInt) in if (n == 42) { return false } @@ -692,10 +692,10 @@ reportProperty("Screw this value in particular") <- forAll { (n : UInt) in return true } -//: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because -//: 42 will always be generated as the first value. We've turned on verbose mode to demonstrate this. -/// By passing this argument to the test, SwiftCheck will automatically use the given seed values and +/// //: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because +//: 42 will always be generated as the first value. We've turned on verbose mode to demonstrate this. +By passing this argument to the test, SwiftCheck will automatically use the given seed values and /// size to completely replicate a particular set of values that caused the first test to fail. let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in @@ -705,8 +705,9 @@ reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in return true }.verbose -//: # Conclusion + +//: # Conclusion //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators //: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, //: but they are all variations on the themes present in ths tutorial. With the power of SwiftCheck @@ -723,4 +724,3 @@ reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in //: * [The Original (slightly outdated) QuickCheck Tutorial](http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html) //: //: Go forth and test. - From 7eb2e40394dea86e55fa381f8c9aed95ddd3de86 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 14:08:21 -0700 Subject: [PATCH 245/460] Move map* --- SwiftCheck/Property.swift | 66 +++++++++++++++++++-------------------- SwiftCheck/Random.swift | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 3a0fe71..58d5e67 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -51,39 +51,6 @@ public func conjamb(ps : () -> Testable...) -> Property { } extension Testable { - /// Applies a function that modifies the property generator's inner `Prop`. - public func mapProp(f : Prop -> Prop) -> Property { - return Property(f <^> self.property.unProperty) - } - - /// Applies a function that modifies the property generator's size. - public func mapSize(f : Int -> Int) -> Property { - return Property(Gen.sized { n in - return self.property.unProperty.resize(f(n)) - }) - } - - /// Applies a function that modifies the result of a test case. - public func mapTotalResult(f : TestResult -> TestResult) -> Property { - return self.mapRoseResult { rs in - return protectResults(f <^> rs) - } - } - - /// Applies a function that modifies the result of a test case. - public func mapResult(f : TestResult -> TestResult) -> Property { - return self.mapRoseResult { rs in - return f <^> rs - } - } - - /// Applies a function that modifies the underlying Rose Tree that a test case has generated. - public func mapRoseResult(f : Rose -> Rose) -> Property { - return self.mapProp { t in - return Prop(unProp: f(t.unProp)) - } - } - /// Modifies a property so it will not shrink when it fails. public var noShrinking : Property { return self.mapRoseResult { rs in @@ -267,6 +234,39 @@ extension Testable { } return self.property } + + /// Applies a function that modifies the property generator's inner `Prop`. + public func mapProp(f : Prop -> Prop) -> Property { + return Property(f <^> self.property.unProperty) + } + + /// Applies a function that modifies the property generator's size. + public func mapSize(f : Int -> Int) -> Property { + return Property(Gen.sized { n in + return self.property.unProperty.resize(f(n)) + }) + } + + /// Applies a function that modifies the result of a test case. + public func mapTotalResult(f : TestResult -> TestResult) -> Property { + return self.mapRoseResult { rs in + return protectResults(f <^> rs) + } + } + + /// Applies a function that modifies the result of a test case. + public func mapResult(f : TestResult -> TestResult) -> Property { + return self.mapRoseResult { rs in + return f <^> rs + } + } + + /// Applies a function that modifies the underlying Rose Tree that a test case has generated. + public func mapRoseResult(f : Rose -> Rose) -> Property { + return self.mapProp { t in + return Prop(unProp: f(t.unProp)) + } + } } /// Using a shrinking function, shrinks a given argument to a property if it fails. diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 42fbcd8..3019190 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -82,7 +82,7 @@ public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible } } -public func ==(l : StdGen, r : StdGen) -> Bool { +public func == (l : StdGen, r : StdGen) -> Bool { return l.seed1 == r.seed1 && l.seed2 == r.seed2 } From 364b5cdf1d455057bcf65145ffd60e6486b1cf11 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 22:30:47 -0700 Subject: [PATCH 246/460] Reflow docs to 80 characters --- SwiftCheck/Arbitrary.swift | 53 +++-- SwiftCheck/Check.swift | 37 ++-- SwiftCheck/CoArbitrary.swift | 22 +- SwiftCheck/Gen.swift | 208 +++++++++--------- SwiftCheck/Lattice.swift | 9 +- SwiftCheck/Modifiers.swift | 45 ++-- SwiftCheck/Property.swift | 98 +++++---- SwiftCheck/Random.swift | 26 ++- SwiftCheck/Rose.swift | 48 ++-- SwiftCheck/State.swift | 26 ++- SwiftCheck/Test.swift | 350 ++++++++++++++++-------------- SwiftCheck/TestOperators.swift | 33 +-- SwiftCheck/Testable.swift | 29 ++- SwiftCheck/Witness.swift | 32 +-- SwiftCheckTests/ComplexSpec.swift | 2 +- 15 files changed, 556 insertions(+), 462 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 5748b12..bc1368a 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -8,44 +8,49 @@ /// A type that implements random generation and shrinking of values. /// -/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times (usually 100 if the -/// default settings are used). During that time, the receiver has an opportunity to call through -/// to any data or sources of randomness it needs to return what it deems an "Arbitrary" value. +/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times +/// (usually 100 if the default settings are used). During that time, the +/// receiver has an opportunity to call through to any data or sources of +/// randomness it needs to return what it deems an "Arbitrary" value. /// -/// Shrinking is reduction in the complexity of a tested value to remove noise and present a minimal -/// counterexample when a property fails. A shrink necessitates returning a list of all possible -/// "smaller" values for SwiftCheck to run through. As long as each individual value in the -/// returned list is less than or equal to the size of the input value, and is not a duplicate of -/// the input value, a minimal case should be reached fairly efficiently. Shrinking is an optional -/// extension of normal testing. If no implementation of `shrink` is provided, SwiftCheck will -/// default to an empty one - that is, no shrinking will occur. +/// Shrinking is reduction in the complexity of a tested value to remove noise +/// and present a minimal counterexample when a property fails. A shrink +/// necessitates returning a list of all possible "smaller" values for +/// SwiftCheck to run through. As long as each individual value in the returned +/// list is less than or equal to the size of the input value, and is not a +/// duplicate of the input value, a minimal case should be reached fairly +/// efficiently. Shrinking is an optional extension of normal testing. If no +/// implementation of `shrink` is provided, SwiftCheck will default to an empty +/// one - that is, no shrinking will occur. /// /// As an example, take the `ArrayOf` implementation of shrink: /// /// Arbitrary.shrink(ArrayOf([1, 2, 3])) /// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// -/// SwiftCheck will search each case forward, one-by-one, and continue shrinking until it has -/// reached a case it deems minimal enough to present. +/// SwiftCheck will search each case forward, one-by-one, and continue shrinking +/// until it has reached a case it deems minimal enough to present. /// -/// SwiftCheck implements a number of generators for common Swift Standard Library types for -/// convenience. If more fine-grained testing is required see `Modifiers.swift` for an example of -/// how to define a "Modifier" type to implement it. +/// SwiftCheck implements a number of generators for common Swift Standard +/// Library types for convenience. If more fine-grained testing is required see +/// `Modifiers.swift` for an example of how to define a "Modifier" type to +/// implement it. public protocol Arbitrary { /// The generator for this particular type. /// - /// This function should call out to any sources of randomness or state necessary to generate - /// values. It should not, however, be written as a deterministic function. If such a - /// generator is needed, combinators are provided in `Gen.swift`. + /// This function should call out to any sources of randomness or state + /// necessary to generate values. It should not, however, be written as a + /// deterministic function. If such a generator is needed, combinators are + /// provided in `Gen.swift`. static var arbitrary : Gen { get } - /// An optional shrinking function. If this function goes unimplemented, it is the same as - /// returning the empty list. + /// An optional shrinking function. If this function goes unimplemented, it + /// is the same as returning the empty list. /// - /// Shrunken values must be less than or equal to the "size" of the original type but never the - /// same as the value provided to this function (or a loop will form in the shrinker). It is - /// recommended that they be presented smallest to largest to speed up the overall shrinking - /// process. + /// Shrunken values must be less than or equal to the "size" of the original + /// type but never the same as the value provided to this function (or a loop + /// will form in the shrinker). It is recommended that they be presented + /// smallest to largest to speed up the overall shrinking process. static func shrink(_ : Self) -> [Self] } diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index b05b451..7ea1699 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -6,25 +6,27 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// The main interface for the SwiftCheck testing mechanism. `property` notation is used to define -/// a property that SwiftCheck can generate test cases for and a human-readable label for debugging -/// output. A simple property test might look like the following: +/// The main interface for the SwiftCheck testing mechanism. `property` +/// notation is used to define a property that SwiftCheck can generate test +/// cases for and a human-readable label for debugging output. A simple +/// property test might look like the following: /// /// property("reflexitivity") <- forAll { (i : Int8) in /// return i == i /// } /// -/// SwiftCheck will report all failures through the XCTest mechanism like a normal testing assert, -/// but with the minimal failing case reported as well. +/// SwiftCheck will report all failures through the XCTest mechanism like a +/// normal testing assert, but with the minimal failing case reported as well. /// -/// If necessary, arguments can be provided to this function to change the behavior of the testing -/// mechanism: +/// If necessary, arguments can be provided to this function to change the +/// behavior of the testing mechanism: /// -/// let args = CheckerArguments( replay: Optional.Some((newStdGen(), 10)) // Replays all tests with a new generator of size 10 -/// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. -/// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. -/// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. -/// ) +/// let args = CheckerArguments +/// ( replay: Optional.Some((newStdGen(), 10)) // Replays all tests with a new generator of size 10 +/// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. +/// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. +/// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. +/// ) /// /// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in /// return i == i @@ -49,8 +51,8 @@ public struct AssertiveQuickCheck { } } -/// The interface for properties to be run through SwiftCheck without an XCTest assert. The -/// property will still generate console output during testing. +/// The interface for properties to be run through SwiftCheck without an XCTest +/// assert. The property will still generate console output during testing. public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -69,12 +71,13 @@ public struct ReportiveQuickCheck { } } -/// Represents the arguments the test driver will use while performing testing, shrinking, and -/// printing results. +/// Represents the arguments the test driver will use while performing testing, +/// shrinking, and printing results. public struct CheckerArguments { /// Provides a way of re-doing a test at the given size with a new generator. let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself passes. + /// The maximum number of test cases that must pass before the property itself + /// passes. /// /// The default value of this property is 100. In general, some tests may require more than /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` diff --git a/SwiftCheck/CoArbitrary.swift b/SwiftCheck/CoArbitrary.swift index 245defa..61db239 100644 --- a/SwiftCheck/CoArbitrary.swift +++ b/SwiftCheck/CoArbitrary.swift @@ -6,15 +6,16 @@ // Copyright © 2015 Robert Widmann. All rights reserved. // -/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` allows generating -/// random values, `CoArbitrary` allows observance of random values passing through as input to -/// random functions. A `CoArbitrary` type is thus able to influence the flow of values in the -/// function. +/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` +/// allows generating random values, `CoArbitrary` allows observance of random +/// values passing through as input to random functions. A `CoArbitrary` type +/// is thus able to influence the flow of values in the function. /// -/// `CoArbitrary` types must take an arbitrary value of their type and yield a function that -/// transforms a given generator by returning a new generator that depends on the input value. Put -/// simply, the function should perturb the given generator (more than likely using `Gen.variant()`) -/// based on the value it observes. +/// `CoArbitrary` types must take an arbitrary value of their type and yield a +/// function that transforms a given generator by returning a new generator that +/// depends on the input value. Put simply, the function should perturb the +/// given generator (more than likely using `Gen.variant()`) based on the value +/// it observes. public protocol CoArbitrary { /// Uses an instance of the receiver to return a function that perturbs a generator. static func coarbitrary(x : Self) -> (Gen -> Gen) @@ -27,8 +28,9 @@ extension IntegerType { } } -/// A coarbitrary implementation for any Printable type. Avoid using this function if you can, it -/// can be quite an expensive operation given a detailed enough description. +/// A coarbitrary implementation for any Printable type. Avoid using this +/// function if you can, it can be quite an expensive operation given a detailed +/// enough description. public func coarbitraryPrintable(x : A) -> Gen -> Gen { return String.coarbitrary(String(x)) } diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 2949de2..3e94f53 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -8,9 +8,10 @@ /// `Gen` represents a generator for random arbitrary values of type `A`. /// -/// `Gen` wraps a function that, when given a random number generator and a size, can be used to -/// control the distribution of resultant values. A generator relies on its size to help control -/// aspects like the length of generated arrays and the magnitude of integral values. +/// `Gen` wraps a function that, when given a random number generator and a +/// size, can be used to control the distribution of resultant values. A +/// generator relies on its size to help control aspects like the length of +/// generated arrays and the magnitude of integral values. public struct Gen { /// The function underlying the receiver. /// @@ -22,9 +23,9 @@ public struct Gen { /// Generates a value. /// - /// This property exists as a convenience mostly to test generators. In practice, you should - /// never use this property because it hinders the replay functionality and the robustness of - /// tests in general. + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. public var generate : A { let r = newStdGen() return unGen(r, 30) @@ -32,15 +33,15 @@ public struct Gen { /// Generates some example values. /// - /// This property exists as a convenience mostly to test generators. In practice, you should - /// never use this property because it hinders the replay functionality and the robustness of - /// tests in general. + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. public var sample : [A] { return sequence((2...20).map { self.resize($0) }).generate } - /// Constructs a Generator that selects a random value from the given collection and produces - /// only that value. + /// Constructs a Generator that selects a random value from the given + /// collection and produces only that value. /// /// The input collection is required to be non-empty. public static func fromElementsOf>(xs : S) -> Gen { @@ -49,8 +50,8 @@ public struct Gen { } } - /// Constructs a Generator that selects a random value from the given interval and produces only - /// that value. + /// Constructs a Generator that selects a random value from the given + /// interval and produces only that value. /// /// The input interval is required to be non-empty. public static func fromElementsIn(xs : S) -> Gen { @@ -59,16 +60,16 @@ public struct Gen { return choose((xs.start, xs.end)) } - /// Constructs a Generator that uses a given array to produce smaller arrays composed of its - /// initial segments. The size of each initial segment increases with the receiver's size - /// parameter. + /// Constructs a Generator that uses a given array to produce smaller arrays + /// composed of its initial segments. The size of each initial segment + /// increases with the receiver's size parameter. /// /// The input array is required to be non-empty. public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") return Gen<[S]>.sized { n in - let ss = xs[xs.startIndex...pure([S](ss)) } } @@ -93,8 +94,8 @@ public struct Gen { /// Constructs a random element in the range of two `RandomType`s. /// - /// When using this function, it is necessary to explicitly specialize the generic parameter - /// `A`. For example: + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: /// /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) public static func choose(rng : (A, A)) -> Gen { @@ -103,11 +104,11 @@ public struct Gen { }) } - /// Constructs a Generator that randomly selects and uses a particular generator from the given - /// sequence of Generators. + /// Constructs a Generator that randomly selects and uses a particular + /// generator from the given sequence of Generators. /// - /// If control over the distribution of generators is needed, see `Gen.frequency` or - /// `Gen.weighted`. + /// If control over the distribution of generators is needed, see + /// `Gen.frequency` or `Gen.weighted`. public static func oneOf, S.Index : protocol>(gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") @@ -116,32 +117,34 @@ public struct Gen { } } - /// Given a sequence of Generators and weights associated with them, this function randomly - /// selects and uses a Generator. + /// Given a sequence of Generators and weights associated with them, this + /// function randomly selects and uses a Generator. /// - /// Only use this function when you need to assign uneven "weights" to each generator. If all - /// generators need to have an equal chance of being selected, use `Gen.oneOf`. + /// Only use this function when you need to assign uneven "weights" to each + /// generator. If all generators need to have an equal chance of being + /// selected, use `Gen.oneOf`. public static func frequency)>(xs : S) -> Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") return choose((1, xs.map({ $0.0 }).reduce(0, combine: +))).flatMap { l in - return pick(l)(lst: xs) + return pick(l, xs) } } - /// Given a list of values and weights associated with them, this function randomly selects and - /// uses a Generator wrapping one of the values. + /// Given a list of values and weights associated with them, this function + /// randomly selects and uses a Generator wrapping one of the values. /// - /// This function operates in exactly the same manner as `Gen.frequency`, `Gen.fromElementsOf`, - /// and `Gen.fromElementsIn` but for any type rather than only Generators. It can help in cases - /// where your `Gen.from*` call contains only `Gen.pure` calls by allowing you to remove every - /// `.pure` in favor of a direct list of values. + /// This function operates in exactly the same manner as `Gen.frequency`, + /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather + /// than only Generators. It can help in cases where your `Gen.from*` call + /// contains only `Gen.pure` calls by allowing you to remove every + /// `Gen.pure` in favor of a direct list of values. public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } - /// Zips together 2 generators of type `A` and `B` into a generator of pairs `(A, B)`. + /// Zips together 2 generators of type `A` and `B` into a generator of pairs. public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return gen1.flatMap { l in return gen2.flatMap { r in @@ -151,13 +154,13 @@ public struct Gen { } } -/// MARK: Generator Modifiers +// MARK: Generator Modifiers extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. public func variant(seed : S) -> Gen { - return Gen(unGen: { r, n in - return self.unGen(vary(seed)(r: r), n) + return Gen(unGen: { rng, n in + return self.unGen(vary(seed, rng), n) }) } @@ -168,19 +171,22 @@ extension Gen { }) } - /// Modifiers a Generator's size parameter by transforming it with the given function. + /// Modifiers a Generator's size parameter by transforming it with the given + /// function. public func scale(f : Int -> Int) -> Gen { return Gen.sized { n in return self.resize(f(n)) } } - /// Modifies a Generator such that it only returns values that satisfy a predicate. When the - /// predicate fails the test case is treated as though it never occured. + /// Modifies a Generator such that it only returns values that satisfy a + /// predicate. When the predicate fails the test case is treated as though + /// it never occured. /// - /// Because the Generator will spin until it reaches a non-failing case, executing a condition - /// that fails more often than it succeeds may result in a space leak. At that point, it is - /// better to use `suchThatOptional` or `.invert` the test case. + /// Because the Generator will spin until it reaches a non-failing case, + /// executing a condition that fails more often than it succeeds may result + /// in a space leak. At that point, it is better to use `suchThatOptional` + /// or `.invert` the test case. public func suchThat(p : A -> Bool) -> Gen { return self.suchThatOptional(p).flatMap { mx in switch mx { @@ -194,25 +200,26 @@ extension Gen { } } - /// Modifies a Generator such that it attempts to generate values that satisfy a predicate. All - /// attempts are encoded in the form of an `Optional` where values satisfying the predicate are - /// wrapped in `.Some` and failing values are `.None`. + /// Modifies a Generator such that it attempts to generate values that + /// satisfy a predicate. All attempts are encoded in the form of an + /// `Optional` where values satisfying the predicate are wrapped in `.Some` + /// and failing values are `.None`. public func suchThatOptional(p : A -> Bool) -> Gen> { return Gen>.sized { n in - return attemptBoundedTry(self, k: 0, n: max(n, 1), p: p) + return attemptBoundedTry(self, 0, max(n, 1), p) } } - /// Modifies a Generator such that it produces arrays with a length determined by the receiver's - /// size parameter. + /// Modifies a Generator such that it produces arrays with a length + /// determined by the receiver's size parameter. public func proliferate() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((0, n)) >>- self.proliferateSized } } - /// Modifies a Generator such that it produces non-empty arrays with a length determined by the - /// receiver's size parameter. + /// Modifies a Generator such that it produces non-empty arrays with a + /// length determined by the receiver's size parameter. public func proliferateNonEmpty() -> Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))) >>- self.proliferateSized @@ -225,22 +232,24 @@ extension Gen { } } -/// MARK: Instances +// MARK: Instances extension Gen /*: Functor*/ { - /// Returns a new generator that applies a given function to any outputs the receiver creates. + /// Returns a new generator that applies a given function to any outputs the + /// receiver creates. public func map(f : (A -> B)) -> Gen { return f <^> self } } -/// Fmap | Returns a new generator that applies a given function to any outputs the given generator -/// creates. +/// Fmap | Returns a new generator that applies a given function to any outputs +/// the given generator creates. /// -/// This function is most useful for converting between generators of inter-related types. For -/// example, you might have a Generator of `Character` values that you then `.proliferate()` into an -/// `Array` of `Character`s. You can then use `fmap` to convert that generator of `Array`s to a -/// generator of `String`s. +/// This function is most useful for converting between generators of inter- +/// related types. For example, you might have a Generator of `Character` +/// values that you then `.proliferate()` into an `Array` of `Character`s. You +/// can then use `fmap` to convert that generator of `Array`s to a generator of +/// `String`s. public func <^> (f : A -> B, g : Gen) -> Gen { return Gen(unGen: { r, n in return f(g.unGen(r, n)) @@ -255,26 +264,28 @@ extension Gen /*: Applicative*/ { }) } - /// Given a generator of functions, applies any generated function to any outputs the receiver - /// creates. + /// Given a generator of functions, applies any generated function to any + /// outputs the receiver creates. public func ap(fn : Gen B>) -> Gen { return fn <*> self } } -/// Ap | Returns a Generator that uses the first given Generator to produce functions and the second -/// given Generator to produce values that it applies to those functions. It can be used in -/// conjunction with <^> to simplify the application of "combining" functions to a large amount of -/// sub-generators. For example: +/// Ap | Returns a Generator that uses the first given Generator to produce +/// functions and the second given Generator to produce values that it applies +/// to those functions. It can be used in conjunction with <^> to simplify the +/// application of "combining" functions to a large amount of sub-generators. +/// For example: /// /// struct Foo { let b : Int; let c : Int; let d : Int } /// /// let genFoo = curry(Foo.init) <^> Int.arbitrary <*> Int.arbitrary <*> Int.arbitrary /// -/// This combinator acts like `zip`, but instead of creating pairs it creates values after applying -/// the zipped function to the zipped value. +/// This combinator acts like `zip`, but instead of creating pairs it creates +/// values after applying the zipped function to the zipped value. /// -/// Promotes function application to a Generator of functions applied to a Generator of values. +/// Promotes function application to a Generator of functions applied to a +/// Generator of values. public func <*> (fn : Gen B>, g : Gen) -> Gen { return fn >>- { x1 in return g >>- { x2 in @@ -284,23 +295,25 @@ public func <*> (fn : Gen B>, g : Gen) -> Gen { } extension Gen /*: Monad*/ { - /// Applies the function to any generated values to yield a new generator. This generator is - /// then given a new random seed and returned. + /// Applies the function to any generated values to yield a new generator. + /// This generator is then given a new random seed and returned. /// - /// `bind` allows for the creation of Generators that depend on other generators. One might, - /// for example, use a Generator of integers to control the length of a Generator of strings, or - /// use it to choose a random index into a Generator of arrays. + /// `bind` allows for the creation of Generators that depend on other + /// generators. One might, for example, use a Generator of integers to + /// control the length of a Generator of strings, or use it to choose a + /// random index into a Generator of arrays. public func flatMap(fn : A -> Gen) -> Gen { return self >>- fn } } -/// Applies the function to any generated values to yield a new generator. This generator is -/// then given a new random seed and returned. +/// Applies the function to any generated values to yield a new generator. This +/// generator is then given a new random seed and returned. /// -/// `bind` allows for the creation of Generators that depend on other generators. One might, -/// for example, use a Generator of integers to control the length of a Generator of strings, or -/// use it to choose a random index into a Generator of arrays. +/// `bind` allows for the creation of Generators that depend on other +/// generators. One might, for example, use a Generator of integers to control +/// the length of a Generator of strings, or use it to choose a random index +/// into a Generator of arrays. public func >>- (m : Gen, fn : A -> Gen) -> Gen { return Gen(unGen: { r, n in let (r1, r2) = r.split @@ -309,12 +322,12 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { }) } -/// Creates and returns a Generator of arrays of values drawn from each generator in the given -/// array. +/// Creates and returns a Generator of arrays of values drawn from each +/// generator in the given array. /// -/// The array that is created is guaranteed to use each of the given Generators in the order they -/// were given to the function exactly once. Thus all arrays generated are of the same rank as the -/// array that was given. +/// The array that is created is guaranteed to use each of the given Generators +/// in the order they were given to the function exactly once. Thus all arrays +/// generated are of the same rank as the array that was given. public func sequence(ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in return x.flatMap { x1 in @@ -332,7 +345,8 @@ public func join(rs : Gen>) -> Gen { } } -/// Lifts a function from some A to some R to a function from generators of A to generators of R. +/// Lifts a function from some A to some R to a function from generators of A to +/// generators of R. public func liftM(f : A -> R, _ m1 : Gen) -> Gen { return m1.flatMap{ x1 in return Gen.pure(f(x1)) @@ -361,29 +375,29 @@ internal func delay() -> Gen -> A> { }) } -/// MARK: - Implementation Details +// MARK: - Implementation Details import func Darwin.log -private func vary(k : S)(r : StdGen) -> StdGen { - let s = r.split +private func vary(k : S, _ rng : StdGen) -> StdGen { + let s = rng.split let gen = ((k % 2) == 0) ? s.0 : s.1 - return (k == (k / 2)) ? gen : vary(k / 2)(r: r) + return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(gen: Gen, k : Int, n : Int, p: A -> Bool) -> Gen> { - if n == 0 { +private func attemptBoundedTry(gen: Gen, _ k : Int, _ bound : Int, _ pred : A -> Bool) -> Gen> { + if bound == 0 { return Gen.pure(.None) } - return gen.resize(2 * k + n).flatMap { (let x : A) -> Gen> in - if p(x) { + return gen.resize(2 * k + bound).flatMap { (let x : A) -> Gen> in + if pred(x) { return Gen.pure(.Some(x)) } - return attemptBoundedTry(gen, k: k.successor(), n: n - 1, p: p) + return attemptBoundedTry(gen, k.successor(), bound - 1, pred) } } -private func size(k : S)(m : Int) -> Int { +private func size(k : S, _ m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } @@ -398,11 +412,11 @@ private func selectOne(xs : [A]) -> [(A, [A])] { return [(y, ys)] + rec } -private func pick(n : Int)(lst : [(Int, Gen)]) -> Gen { +private func pick(n : Int, _ lst : [(Int, Gen)]) -> Gen { let (k, x) = lst[0] let tl = Array<(Int, Gen)>(lst[1..) in /// return x.description == "(*)" /// } /// -/// For an example of the latter see the `ArrowOf` modifier. Because Swift's type system treats -/// arrows (`->`) as an opaque entity that you can't interact with or extend, SwiftCheck provides -/// `ArrowOf` to enable the generation of functions between 2 types. That's right, we can generate -/// arbitrary functions! +/// For an example of the latter see the `ArrowOf` modifier. Because Swift's +/// type system treats arrows (`->`) as an opaque entity that you can't interact +/// with or extend, SwiftCheck provides `ArrowOf` to enable the generation of +/// functions between 2 types. That's right, we can generate arbitrary +/// functions! /// /// property("map accepts SwiftCheck arrows") <- forAll { (xs : [Int]) in /// return forAll { (f : ArrowOf) in -/// /// Just to prove it really is a function (that is, every input always maps to the -/// /// same output), and not just a trick, we map twice and should get equal arrays. +/// /// Just to prove it really is a function (that is, every input +/// /// always maps to the same output), and not just a trick, we +/// /// map twice and should get equal arrays. /// return xs.map(f.getArrow) == xs.map(f.getArrow) /// } /// } /// -/// Finally, modifiers nest to allow the generation of intricate structures that would not otherwise -/// be possible due to the limitations above. For example, to generate an Array of Arrays of -/// Dictionaries of Integers and Strings (a type that normally looks like -/// `Array>>`), would look like this: +/// Finally, modifiers nest to allow the generation of intricate structures that +/// would not otherwise be possible due to the limitations above. For example, +/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a +/// type that normally looks like `Array>>`), +/// would look like this: /// /// property("Generating monstrous data types is possible") <- forAll { (xs : ArrayOf>>) in /// /// We're gonna need a bigger boat. /// } -/// For types that either do not have a `CustomStringConvertible` instance or that wish to have no -/// description to print, Blind will create a default description for them. +/// For types that either do not have a `CustomStringConvertible` instance or +/// that wish to have no description to print, Blind will create a default +/// description for them. public struct Blind : Arbitrary, CustomStringConvertible { public let getBlind : A diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 58d5e67..a165297 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -6,13 +6,14 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// Takes the conjunction of multiple properties and reports all successes and failures as one -/// combined property. That is, this property holds when all sub-properties hold and fails when one -/// or more sub-properties fail. +/// Takes the conjunction of multiple properties and reports all successes and +/// failures as one combined property. That is, this property holds when all +/// sub-properties hold and fails when one or more sub-properties fail. /// -/// Conjoined properties are each tested normally but are collected and labelled together. This can -/// mean multiple failures in distinct sub-properties are masked. If fine-grained error reporting -/// is needed, use a combination of `disjoin(_:)` and `verbose(_:)`. +/// Conjoined properties are each tested normally but are collected and labelled +/// together. This can mean multiple failures in distinct sub-properties are +/// masked. If fine-grained error reporting is needed, use a combination of +/// `disjoin(_:)` and `verbose(_:)`. /// /// When conjoining properties all calls to `expectFailure` will fail. public func conjoin(ps : Testable...) -> Property { @@ -23,14 +24,17 @@ public func conjoin(ps : Testable...) -> Property { })) } -/// Takes the disjunction of multiple properties and reports all successes and failures of each -/// sub-property distinctly. That is, this property holds when any one of its sub-properties holds -/// and fails when all of its sub-properties fail simultaneously. +/// Takes the disjunction of multiple properties and reports all successes and +/// failures of each sub-property distinctly. That is, this property holds when +/// any one of its sub-properties holds and fails when all of its sub-properties +/// fail simultaneously. /// -/// Disjoined properties, when used in conjunction with labelling, cause SwiftCheck to print a -/// distribution map of the success rate of each sub-property. +/// Disjoined properties, when used in conjunction with labelling, cause +/// SwiftCheck to print a distribution map of the success rate of each sub- +/// property. /// -/// When disjoining properties all calls to `expectFailure` will fail. +/// When disjoining properties all calls to `expectFailure` will fail. You can, +/// however, `invert` the property. public func disjoin(ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } @@ -39,12 +43,12 @@ public func disjoin(ps : Testable...) -> Property { })) } -/// Takes the nondeterministic conjunction of multiple properties and treats them as a single large -/// property. +/// Takes the nondeterministic conjunction of multiple properties and treats +/// them as a single large property. /// -/// The resulting property makes 100 random choices to test any of the given properties. Thus, -/// running multiple test cases will result in distinct arbitrary sequences of each property being -/// tested. +/// The resulting property makes 100 random choices to test any of the given +/// properties. Thus, running multiple test cases will result in distinct +/// arbitrary sequences of each property being tested. public func conjamb(ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) @@ -60,7 +64,8 @@ extension Testable { } } - /// Inverts the result of a test. That is, test cases that would pass now fail and vice versa. + /// Inverts the result of a test. That is, test cases that would pass now + /// fail and vice versa. /// /// Discarded tests remain discarded under inversion. public var invert : Property { @@ -123,8 +128,8 @@ extension Testable { /// Executes an action after the every failure of the property. /// - /// Because the action is executed after every failing test it can be used to track the list of - /// failures generated by the shrinking mechanism. + /// Because the action is executed after every failing test it can be used + /// to track the list of failures generated by the shrinking mechanism. public func whenEachFail(m : () -> ()) -> Property { return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in if res.ok == .Some(false) { @@ -133,11 +138,11 @@ extension Testable { }) } - /// Modifies a property so it prints out every generated test case and the result of the property - /// every time it is tested. + /// Modifies a property so it prints out every generated test case and the + /// result of the property every time it is tested. /// - /// This function maps AfterFinalFailure callbacks that have the .Counterexample kind to AfterTest - /// callbacks. + /// This function maps AfterFinalFailure callbacks that have the + /// `.Counterexample` kind to `.AfterTest` callbacks. public var verbose : Property { func chattyCallbacks(cbs : [Callback]) -> [Callback] { let c = Callback.AfterTest(kind: .Counterexample) { (st, res) in @@ -197,10 +202,11 @@ extension Testable { /// Attaches a label to a property. /// - /// Labelled properties aid in testing conjunctions and disjunctions, or any other cases where - /// test cases need to be distinct from one another. In addition to shrunken test cases, upon - /// failure SwiftCheck will print a distribution map for the property that shows a percentage - /// success rate for the property. + /// Labelled properties aid in testing conjunctions and disjunctions, or any + /// other cases where test cases need to be distinct from one another. In + /// addition to shrunken test cases, upon failure SwiftCheck will print a + /// distribution map for the property that shows a percentage success rate + /// for the property. public func label(s : String) -> Property { return self.classify(true)(s: s) } @@ -215,9 +221,11 @@ extension Testable { return self.cover(b)(n: 0)(s: s) } - /// Checks that at least the given proportion of successful test cases belong to the given class. + /// Checks that at least the given proportion of successful test cases + /// belong to the given class. /// - /// Discarded tests (i.e. ones with a false precondition) do not affect coverage. + /// Discarded tests (i.e. ones with a false precondition) do not affect + /// coverage. public func cover(b : Bool)(n : Int)(s : String) -> Property { if b { return self.mapResult { res in @@ -261,7 +269,8 @@ extension Testable { } } - /// Applies a function that modifies the underlying Rose Tree that a test case has generated. + /// Applies a function that modifies the underlying Rose Tree that a test + /// case has generated. public func mapRoseResult(f : Rose -> Rose) -> Property { return self.mapProp { t in return Prop(unProp: f(t.unProp)) @@ -269,10 +278,11 @@ extension Testable { } } -/// Using a shrinking function, shrinks a given argument to a property if it fails. +/// Using a shrinking function, shrinks a given argument to a property if it +/// fails. /// -/// Shrinking is handled automatically by SwiftCheck. Invoking this function is only necessary -/// when you must override the default behavior. +/// Shrinking is handled automatically by SwiftCheck. Invoking this function is +/// only necessary when you must override the default behavior. public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in return Prop(unProp: joinRose(rs.map { x in @@ -281,9 +291,10 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) }) } -/// A `Callback` is a block of code that can be run after a test case has finished. They consist -/// of a kind and the callback block itself, which is given the state SwiftCheck ran the test case -/// with and the result of the test to do with as it sees fit. +/// A `Callback` is a block of code that can be run after a test case has +/// finished. They consist of a kind and the callback block itself, which is +/// given the state SwiftCheck ran the test case with and the result of the test +/// to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. case AfterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) @@ -326,8 +337,8 @@ public enum Quantification { /// A `TestResult` represents the result of performing a single test. public struct TestResult { - /// The result of executing the test case. For Discarded test cases the value of this property - /// is .None. + /// The result of executing the test case. For Discarded test cases the + /// value of this property is `.None`. let ok : Optional /// Indicates what the expected result of the property is. let expect : Bool @@ -346,7 +357,8 @@ public struct TestResult { let quantifier : Quantification - /// Destructures a test case into a matcher that can be used in switch statement. + /// Destructures a test case into a matcher that can be used in switch + /// statement. public func match() -> TestResultMatcher { return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } @@ -378,8 +390,8 @@ public struct TestResult { return result(Optional.None) } - /// Lifts a `Bool`ean value to a TestResult by mapping true to `TestResult.suceeded` and false - /// to `TestResult.failed`. + /// Lifts a `Bool`ean value to a TestResult by mapping true to + /// `TestResult.suceeded` and false to `TestResult.failed`. public static func liftBool(b : Bool) -> TestResult { if b { return TestResult.succeeded @@ -388,7 +400,7 @@ public struct TestResult { } } -/// MARK: - Implementation Details +// MARK: - Implementation Details private func exception(msg : String) -> ErrorType -> TestResult { return { e in TestResult.failed(String(e)) } diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 3019190..6551846 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -9,14 +9,16 @@ import func Darwin.time import func Darwin.clock -/// Provides a standard interface to an underlying Random Value Generator of any type. It is -/// analogous to `GeneratorType`, but rather than consume a sequence it uses sources of randomness -/// to generate values indefinitely. +/// Provides a standard interface to an underlying Random Value Generator of any +/// type. It is analogous to `GeneratorType`, but rather than consume a +/// sequence it uses sources of randomness to generate values indefinitely. public protocol RandomGeneneratorType { - /// The next operation returns an Int that is uniformly distributed in the range returned by - /// `genRange` (including both end points), and a new generator. + /// The next operation returns an Int that is uniformly distributed in the + /// range returned by `genRange` (including both end points), and a new + /// generator. var next : (Int, Self) { get } - /// The genRange operation yields the range of values returned by the generator. + /// The genRange operation yields the range of values returned by the + /// generator. /// /// This property must return integers in ascending order. var genRange : (Int, Int) { get } @@ -24,15 +26,17 @@ public protocol RandomGeneneratorType { var split : (Self, Self) { get } } -/// `StdGen` represents a pseudo-random number generator. The library makes it possible to generate -/// repeatable results, by starting with a specified initial random number generator, or to get -/// different results on each run by using the system-initialised generator or by supplying a seed -/// from some other source. +/// `StdGen` represents a pseudo-random number generator. The library makes it +/// possible to generate repeatable results, by starting with a specified +/// initial random number generator, or to get different results on each run by +/// using the system-initialised generator or by supplying a seed from some +/// other source. public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible { let seed1 : Int let seed2 : Int - /// Creates a `StdGen` initialized at the given seeds that is suitable for replaying of tests. + /// Creates a `StdGen` initialized at the given seeds that is suitable for + /// replaying of tests. public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { self.seed1 = replaySeed1 self.seed2 = replaySeed2 diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index fd1be69..c70a4fb 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -6,13 +6,14 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the steps necessary for -/// testing a property. The first case, .MkRose, consists of a value and a list of trees. The -/// second, case, .IORose, is a suspended IO action SwiftCheck must execute in order to produce -/// another Rose tree. All values in a `Rose` are lazy. +/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the +/// steps necessary for testing a property. The first case, .MkRose, consists +/// of a value and a list of trees. The second, case, .IORose, is a suspended +/// IO action SwiftCheck must execute in order to produce another Rose tree. +/// All values in a `Rose` are lazy. /// -/// In practice SwiftCheck will minimize the side-effects performed in a given `IORose` to printing -/// values to the console and executing callbacks. +/// In practice SwiftCheck will minimize the side-effects performed in a given +/// `IORose` to printing values to the console and executing callbacks. public enum Rose { case MkRose(() -> A, () -> [Rose]) case IORose(() -> Rose) @@ -27,8 +28,8 @@ public enum Rose { } } - /// Reduces a rose tree by evaluating all `.IORose` branches until the first `.MkRose` branch is - /// encountered. That branch is then returned. + /// Reduces a rose tree by evaluating all `.IORose` branches until the first + /// `.MkRose` branch is encountered. That branch is then returned. public var reduce : Rose { switch self { case .MkRose(_, _): @@ -42,8 +43,9 @@ public enum Rose { extension Rose /*: Functor*/ { /// Maps a function over all the nodes of a Rose Tree. /// - /// For `.MkRose` branches the computation is applied to the node's value then application - /// recurses into the sub-trees. For `.IORose` branches the map is suspended. + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` branches + /// the map is suspended. public func map(f : (A -> B)) -> Rose { return f <^> self } @@ -64,11 +66,13 @@ extension Rose /*: Applicative*/ { return .MkRose({ a }, { [] }) } - /// Applies a Rose Tree of functions to the receiver to yield a new Rose Tree of values. + /// Applies a Rose Tree of functions to the receiver to yield a new Rose + /// Tree of values. /// - /// For `.MkRose` branches the computation is applied to the node's value then application - /// recurses into the sub-trees. For `.IORose` the branch is reduced to a `.MkRose` and - /// applied, executing all side-effects along the way. + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` the branch + /// is reduced to a `.MkRose` and applied, executing all side-effects along + /// the way. public func ap(fn : Rose B>) -> Rose { return fn <*> self } @@ -84,7 +88,8 @@ public func <*> (fn : Rose B>, g : Rose) -> Rose { } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all together. + /// Maps the values in the receiver to Rose Trees and joins them all + /// together. public func flatMap(fn : A -> Rose) -> Rose { return self >>- fn } @@ -103,10 +108,11 @@ public func liftM(f : A -> R, _ m1 : Rose) -> Rose { /// Flattens a Rose Tree of Rose Trees by a single level. /// -/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the kind of subtree at -/// the node dictates the behavior of the join. For `.IORose` sub-trees The join is suspended. For -/// `.MkRose` the result is the value at the sub-tree node and a recursive call to join the branch's -/// tree to its sub-trees. +/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the +/// kind of subtree at the node dictates the behavior of the join. For +/// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the +/// value at the sub-tree node and a recursive call to join the branch's tree to +/// its sub-trees. public func joinRose(rs : Rose>) -> Rose { switch rs { case .IORose(let rs): @@ -132,8 +138,8 @@ public func sequence(ms : [Rose]) -> Rose<[A]> { }) } -/// Sequences the result of mapping values to Rose trees into a single rose tree of an array of -/// values. +/// Sequences the result of mapping values to Rose trees into a single rose tree +/// of an array of values. public func mapM(f : A -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) } diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index 7cf9e76..59c768f 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -10,32 +10,38 @@ public struct CheckerState { /// The name bound to the current property (not labels). let name : String - /// The maximum number of successful tests before SwiftCheck gives up. Defaults to 100. + /// The maximum number of successful tests before SwiftCheck gives up. + /// Defaults to 100. let maxAllowableSuccessfulTests : Int /// The maximum number of discarded tests before SwiftCheck gives up. let maxAllowableDiscardedTests : Int - /// The function that generates the sizes fed to the generators for each test case. + /// The function that generates the sizes fed to the generators for each + /// test case. let computeSize : Int -> Int -> Int /// The count of the number of successful test cases seen so far. let successfulTestCount : Int /// The count of the number of discarded test cases seen so far. let discardedTestCount : Int - /// A dictionary of labels collected inside the test case. Each maps to an integer describing - /// the number of passed tests. It is used in conjunction with the number of successful tests - /// to print a coverage percentage. + /// A dictionary of labels collected inside the test case. Each maps to an + /// integer describing the number of passed tests. It is used in + /// conjunction with the number of successful tests to print a coverage + /// percentage. let labels : Dictionary /// A uniqued collection of all the labels collected during the test case. let collected : [Set] - /// Returns whether the test case has fulfilled its expected failure outcome. If the test case - /// fails and it was expected this property returns true. If the test case doesn't fail and it - /// was not expected to fail this property returns true. Only when the test case's outcome - /// and its failure fulfillment expectation do not match does this property return false. + /// Returns whether the test case has fulfilled its expected failure + /// outcome. If the test case fails and it was expected this property + /// returns true. If the test case doesn't fail and it was not expected to + /// fail this property returns true. Only when the test case's outcome and + /// its failure fulfillment expectation do not match does this property + /// return false. let hasFulfilledExpectedFailure : Bool /// The Random Number Generator backing the testing session. let randomSeedGenerator : StdGen /// Returns the number of successful shrinking steps performed so far. let successfulShrinkCount : Int - /// Returns the number of failed shrinking steps since the last successful shrink. + /// Returns the number of failed shrinking steps since the last successful + /// shrink. let failedShrinkStepDistance : Int /// Returns the number of failed shrink steps. let failedShrinkStepCount : Int diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index b478f47..71b07ce 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -8,32 +8,41 @@ // MARK: - Property Testing with SwiftCheck -/// Property Testing is a more static and expressive form of Test-Driven Development that emphasizes -/// the testability of program properties - A statement or invariant that can be proven to hold when -/// fed any number of arguments of a particular kind. It is akin to Fuzz Testing but is made +/// Property Testing is a more static and expressive form of Test-Driven +/// Development that emphasizes the testability of program properties - A +/// statement or invariant that can be proven to hold when fed any number of +/// arguments of a particular kind. It is akin to Fuzz Testing but is made /// significantly more powerful by the primitives in this framework. /// -/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a value that is capable -/// of producing a framework type called `Prop`, which models individual test cases that themselves -/// are capable of passing or failing "in the small" with a `TestResult`. For those familiar with -/// Protocol-Oriented Programming, lying at the heart of all of these types is a protocol called -/// `Testable` that provides any type a means of converting itself to a `Property`. SwiftCheck -/// uses `Testable` early and often in functions and operators to enable a high level of nesting -/// of framework primitives and an even higher level of genericity in the interface. By default -/// SwiftCheck provides `Testable` instances for `Bool`, `Property`, `Prop`, and several other -/// internal framework types. Practically, this means any assertions you could make in `XCTest` -/// will work immediately with the framework. +/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a +/// value that is capable of producing a framework type called `Prop`, which +/// models individual test cases that themselves are capable of passing or +/// failing "in the small" with a `TestResult`. For those familiar with +/// Protocol-Oriented Programming, lying at the heart of all of these types is a +/// protocol called `Testable` that provides any type a means of converting +/// itself to a `Property`. SwiftCheck uses `Testable` early and often in +/// functions and operators to enable a high level of nesting of framework +/// primitives and an even higher level of genericity in the interface. By +/// default SwiftCheck provides `Testable` instances for `Bool`, `Property`, +/// `Prop`, and several other internal framework types. Practically, this means +/// any assertions you could make in `XCTest` will work immediately with the +/// framework. // MARK: - Quantifiers -/// Below is the method all SwiftCheck properties are based on, `forAll`. `forAll` acts as a -/// "Quantifier", i.e. a contract that serves as a guarantee that a property holds when the given -/// testing block returns `true` or truthy values, and fails when the testing block returns `false` -/// or falsy values. The testing block is usually used with Swift's abbreviated block syntax and -/// requires type annotations for all value positions being requested. For example, +/// Below is the method all SwiftCheck properties are based on, `forAll`. It +/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a +/// property holds when the given testing block returns `true` or truthy values, +/// and fails when the testing block returns `false` or falsy values. The +/// testing block is usually used with Swift's abbreviated block syntax and +/// requires type annotations for all value positions being requested. For +/// example: /// -/// + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. -/// | + This backwards arrow binds a property name and a property to each other. +/// + This is "Property Notation". It allows you to give your properties a +/// | name and instructs SwiftCheck to test it. +/// | +/// | This backwards arrow binds a property name and a property + +/// | to each other. | /// | | /// v v /// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in @@ -43,11 +52,12 @@ /// (xs == xs.reverse().reverse()) "Reverse on the right" /// } /// -/// Why require types? For one, Swift cannot infer the types of local variables because SwiftCheck -/// uses highly polymorphic testing primitives. But, more importantly, types are required because -/// SwiftCheck uses them to select the appropriate `Gen`erators and shrinkers for each data type -/// automagically by default. Those `Gen`erators and shrinkers are then used to create 100 random -/// test cases that are evaluated lazily to produce a final result. +/// Why require types? For one, Swift cannot infer the types of local variables +/// because SwiftCheck uses highly polymorphic testing primitives. But, more +/// importantly, types are required because SwiftCheck uses them to select the +/// appropriate `Gen`erators and shrinkers for each data type automagically by +/// default. Those `Gen`erators and shrinkers are then used to create 100 +/// random test cases that are evaluated lazily to produce a final result. // MARK: - Going Further @@ -62,9 +72,10 @@ /// v /// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in /// -/// /// This part of the property uses `==>`, or the "implication" combinator. Implication -/// /// only executes the following block if the preceding expression returns true. It can -/// /// be used to discard test cases that contain data you don't want to test with. +/// /// This part of the property uses `==>`, or the "implication" +/// /// combinator. Implication only executes the following block if +/// /// the preceding expression returns true. It can be used to +/// /// discard test cases that contain data you don't want to test with. /// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { /// /// /// N.B. `shrinkArbitrary` is a internal method call that invokes the shrinker. @@ -79,205 +90,206 @@ /// | +--- The property will print EVERY generated test case to the console. /// + --- We expect this property not to hold. /// -/// Testing is not limited to just these listed functions. New users should check out our test -/// suite and the files `Gen.swift`, `Property.swift`, `Modifiers.swift`, and the top half of this -/// very file to learn more about the various parts of the SwiftCheck testing mechanism. - -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for that type. -@warn_unused_result +/// Testing is not limited to just these listed functions. New users should +/// check out our test suite and the files `Gen.swift`, `Property.swift`, +/// `Modifiers.swift`, and the top half of this very file to learn more about +/// the various parts of the SwiftCheck testing mechanism. + +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for that type. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 2 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 2 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B) throws -> Testable) -> Property { return forAll({ t in forAll({ b in try pf(t, b) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 3 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 3 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c in try pf(t, b, c) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 4 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 4 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in try pf(t, b, c, d) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 5 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 5 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in try pf(t, b, c, d, e) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 6 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 6 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 7 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 7 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 8 types. -@warn_unused_result +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 8 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } -/// Given an explicit generator, converts a function to a universally quantified property using the -/// default shrinker for that type. -@warn_unused_result +/// Given an explicit generator, converts a function to a universally quantified +/// property using the default shrinker for that type. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } -/// Given 2 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 2 types. -@warn_unused_result +/// Given 2 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 2 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } -/// Given 3 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 3 types. -@warn_unused_result +/// Given 3 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 3 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } -/// Given 4 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 4 types. -@warn_unused_result +/// Given 4 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 4 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } -/// Given 5 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 5 types. -@warn_unused_result +/// Given 5 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 5 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } -/// Given 6 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 6 types. -@warn_unused_result +/// Given 6 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 6 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } -/// Given 7 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 7 types. -@warn_unused_result +/// Given 7 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 7 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } -/// Given 8 explicit generators, converts a function to a universally quantified property using the -/// default shrinkers for those 8 types. -@warn_unused_result +/// Given 8 explicit generators, converts a function to a universally quantified +/// property using the default shrinkers for those 8 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } -/// Given an explicit generator, converts a function to a universally quantified property for that -/// type. +/// Given an explicit generator, converts a function to a universally quantified +/// property for that type. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(gen : Gen, pf : (A throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } -/// Given 2 explicit generators, converts a function to a universally quantified property for those -/// 2 types. +/// Given 2 explicit generators, converts a function to a universally quantified +/// property for those 2 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } -/// Given 3 explicit generators, converts a function to a universally quantified property for those -/// 3 types. +/// Given 3 explicit generators, converts a function to a universally quantified +/// property for those 3 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } -/// Given 4 explicit generators, converts a function to a universally quantified property -/// for those 4 types. +/// Given 4 explicit generators, converts a function to a universally quantified +/// property for those 4 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } -/// Given 5 explicit generators, converts a function to a universally quantified property for those -/// 5 types. +/// Given 5 explicit generators, converts a function to a universally quantified +/// property for those 5 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } -/// Given 6 explicit generators, converts a function to a universally quantified property for those -/// 6 types. +/// Given 6 explicit generators, converts a function to a universally quantified +/// property for those 6 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } -/// Given 7 explicit generators, converts a function to a universally quantified property for those -/// 7 types. +/// Given 7 explicit generators, converts a function to a universally quantified +/// property for those 7 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } -/// Given 8 explicit generators, converts a function to a universally quantified property for those -/// 8 types. +/// Given 8 explicit generators, converts a function to a universally quantified +/// property for those 8 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators of any type, not -/// just those that conform to `Arbitrary`. -@warn_unused_result +/// This variant of `forAll` does not shrink its argument but allows generators +/// of any type, not just those that conform to `Arbitrary`. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } -/// Given an explicit generator and shrinker, converts a function to a universally quantified -/// property. -@warn_unused_result +/// Given an explicit generator and shrinker, converts a function to a +/// universally quantified property. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in @@ -290,28 +302,30 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T }) } -/// Converts a function into an existentially quantified property using the default shrinker and -/// generator for that type to search for a passing case. SwiftCheck only runs a limited number of -/// trials before giving up and failing. +/// Converts a function into an existentially quantified property using the +/// default shrinker and generator for that type to search for a passing case. +/// SwiftCheck only runs a limited number of trials before giving up and failing. /// -/// The nature of Existential Quantification means SwiftCheck would have to enumerate over the -/// entire domain of the type `A` in order to return a proper value. Because such a traversal is -/// both impractical and leads to computationally questionable behavior (infinite loops and the -/// like), SwiftCheck instead interprets `exists` as a finite search over arbitrarily many values -/// (around 500). No shrinking is performed during the search. +/// The nature of Existential Quantification means SwiftCheck would have to +/// enumerate over the entire domain of the type `A` in order to return a proper +/// value. Because such a traversal is both impractical and leads to +/// computationally questionable behavior (infinite loops and the like), +/// SwiftCheck instead interprets `exists` as a finite search over arbitrarily +/// many values (around 500). No shrinking is performed during the search. /// -/// Existential Quantification should rarely be used, and in practice is usually used for *negative* -/// statements "there does not exist `foo` such that `bar`". It is recommended that you avoid -/// `exists` and instead reduce your property to -/// [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). `SNF` involves turning -/// every `exists` into a function returning the existential value, taking any other parameters -/// being quantified over as needed. +/// Existential Quantification should rarely be used, and in practice is usually +/// used for *negative* statements "there does not exist `foo` such that `bar`". +/// It is recommended that you avoid `exists` and instead reduce your property +/// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). +/// `SNF` involves turning every `exists` into a function returning the +/// existential value, taking any other parameters being quantified over as +/// needed. public func exists(pf : A throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } -/// Given an explicit generator, converts a function to an existentially quantified property using -/// the default shrinker for that type. +/// Given an explicit generator, converts a function to an existentially +/// quantified property using the default shrinker for that type. public func exists(gen : Gen, pf : A throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok @@ -331,7 +345,7 @@ public func quickCheck(prop : Testable, name : String = "") { quickCheckWithResult(CheckerArguments(name: name), prop) } -/// MARK: - Implementation Details +// MARK: - Implementation Details internal enum Result { case Success(numTests : Int @@ -434,13 +448,17 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R // Main Testing Loop: // -// Given an initial state and the inner function that runs the property begins turning a runloop -// that starts firing off individual test cases. Only 3 functions get dispatched from this loop: +// Given an initial state and the inner function that runs the property begins +// turning a runloop that starts firing off individual test cases. Only 3 +// functions get dispatched from this loop: // -// - runATest: Does what it says; .Left indicates failure, .Right indicates continuation. -// - doneTesting: Invoked when testing the property fails or succeeds once and for all. -// - giveUp: When the number of discarded tests exceeds the number given in the arguments we just -// give up turning the run loop to prevent excessive generation. +// - runATest: Does what it says; .Left indicates failure, .Right indicates +// continuation. +// - doneTesting: Invoked when testing the property fails or succeeds once and +// for all. +// - giveUp: When the number of discarded tests exceeds the number given in the +// arguments we just give up turning the run loop to prevent excessive +// generation. internal func test(st : CheckerState, f : (StdGen, Int) -> Prop) -> Result { var state = st while true { @@ -477,9 +495,11 @@ internal func test(st : CheckerState, f : (StdGen, Int) -> Prop) -> Result { } } -// Executes a single test of the property given an initial state and the generator function. +// Executes a single test of the property given an initial state and the +// generator function. // -// On success the next state is returned. On failure the final result and state are returned. +// On success the next state is returned. On failure the final result and state +// are returned. internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount)(st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split @@ -537,8 +557,8 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( print("*** Failed! ", terminator: "") } - // Failure of an existential is not necessarily failure of the whole test case, - // so treat this like a discard. + // Failure of an existential is not necessarily failure of the whole + // test case, so treat this like a discard. if quantifier == .Existential { let nstate = CheckerState(name: st.name , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests @@ -625,16 +645,17 @@ internal func giveUp(st: CheckerState) -> Result { return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } -// Interface to shrinking loop. Returns (number of shrinks performed, number of failed shrinks, -// total number of shrinks performed). +// Interface to shrinking loop. Returns (number of shrinks performed, number of +// failed shrinks, total number of shrinks performed). // -// This ridiculously stateful looping nonsense is due to limitations of the Swift unroller and, more -// importantly, ARC. This has been written with recursion in the past, and it was fabulous and -// beautiful, but it generated useless objects that ARC couldn't release on the order of Gigabytes -// for complex shrinks (much like `split` in the Swift Standard Library), and was slow as hell. -// This way we stay in one stack frame no matter what and give ARC a chance to cleanup after us. -// Plus we get to stay within a reasonable ~50-100 megabytes for truly horrendous tests that used to -/// eat 8 gigs. +// This ridiculously stateful looping nonsense is due to limitations of the +// Swift unroller and, more importantly, ARC. This has been written with +// recursion in the past, and it was fabulous and beautiful, but it generated +// useless objects that ARC couldn't release on the order of Gigabytes for +// complex shrinks (much like `split` in the Swift Standard Library), and was +// slow as hell. This way we stay in one stack frame no matter what and give ARC +// a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 +// megabytes for truly horrendous tests that used to eat 8 gigs. internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") @@ -646,10 +667,10 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts var failedShrinkStepDistance = st.failedShrinkStepDistance.successor() var failedShrinkStepCount = st.failedShrinkStepCount - // cont is a sanity check so we don't fall into an infinite loop. It is set to false at each - // new iteration and true when we select a new set of branches to test. If the branch - // selection doesn't change then we have exhausted our possibilities and so must have reached a - // minimal case. + // cont is a sanity check so we don't fall into an infinite loop. It is set + // to false at each new iteration and true when we select a new set of + // branches to test. If the branch selection doesn't change then we have + // exhausted our possibilities and so must have reached a minimal case. var cont = true while cont { /// If we're out of branches we're out of options. @@ -676,7 +697,8 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts break } - // Otherwise increment the tried shrink counter and the failed shrink counter. + // Otherwise increment the tried shrink counter and the failed + // shrink counter. failedShrinkStepDistance++ failedShrinkStepCount++ default: diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 10106c0..2b8f8c9 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -47,8 +47,9 @@ infix operator ==> { precedence 100 } -/// Models implication for properties. That is, the property holds if the first argument is false -/// (in which case the test case is discarded), or if the given property holds. +/// Models implication for properties. That is, the property holds if the first +/// argument is false (in which case the test case is discarded), or if the +/// given property holds. public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { if b { return p().property @@ -56,8 +57,9 @@ public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { return Discard().property } -/// Models implication for properties. That is, the property holds if the first argument is false -/// (in which case the test case is discarded), or if the given property holds. +/// Models implication for properties. That is, the property holds if the first +/// argument is false (in which case the test case is discarded), or if the +/// given property holds. public func ==>(b : Bool, p : () -> Testable) -> Property { if b { return p().property @@ -82,10 +84,11 @@ infix operator { /// Attaches a label to a property. /// -/// Labelled properties aid in testing conjunctions and disjunctions, or any other cases where -/// test cases need to be distinct from one another. In addition to shrunken test cases, upon -/// failure SwiftCheck will print a distribution map for the property that shows a percentage -/// success rate for the property. +/// Labelled properties aid in testing conjunctions and disjunctions, or any +/// other cases where test cases need to be distinct from one another. In +/// addition to shrunken test cases, upon failure SwiftCheck will print a +/// distribution map for the property that shows a percentage success rate for +/// the property. public func (p : Testable, s : String) -> Property { return p.label(s) } @@ -95,10 +98,11 @@ infix operator ^&&^ { precedence 110 } -/// Takes the conjunction of two properties and treats them as a single large property. +/// Takes the conjunction of two properties and treats them as a single large +/// property. /// -/// Conjoined properties succeed only when both sub-properties succeed and fail when one or more -/// sub-properties fail. +/// Conjoined properties succeed only when both sub-properties succeed and fail +/// when one or more sub-properties fail. public func ^&&^(p1 : Testable, p2 : Testable) -> Property { return conjoin(p1.property, p2.property) } @@ -109,10 +113,11 @@ infix operator ^||^ { precedence 110 } -/// Takes the disjunction of two properties and treats them as a single large property. +/// Takes the disjunction of two properties and treats them as a single large +/// property. /// -/// Disjoined properties succeed only when one or more sub-properties succeed and fail when both -/// sub-properties fail. +/// Disjoined properties succeed only when one or more sub-properties succeed +/// and fail when both sub-properties fail. public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } diff --git a/SwiftCheck/Testable.swift b/SwiftCheck/Testable.swift index e36d0f7..4fa3a9b 100644 --- a/SwiftCheck/Testable.swift +++ b/SwiftCheck/Testable.swift @@ -7,20 +7,23 @@ // -/// The type of things that can be tested. Consequently, the type of things that can be returned -/// from a `forAll` block. +/// The type of things that can be tested. Consequently, the type of things +/// that can be returned from a `forAll` block. /// -/// `Testable` values must be able to produce a `Rose`, that is a rose tree of test -/// cases that terminates in a passing or failing `TestResult`. SwiftCheck provides instances for -/// `Bool`, `Discard`, `Prop`, and `Property`. The last of these enables `forAll`s to return -/// further `forAll`s that can depend on previously generated values. +/// `Testable` values must be able to produce a `Rose`, that is a +/// rose tree of test cases that terminates in a passing or failing +/// `TestResult`. SwiftCheck provides instances for `Bool`, `Discard`, `Prop`, +/// and `Property`. The last of these enables `forAll`s to return further +/// `forAll`s that can depend on previously generated values. public protocol Testable { - /// Returns true iff a single test case is exhaustive i.e. adequately covers the search space. + /// Returns true iff a single test case is exhaustive i.e. adequately covers + /// the search space. /// /// If true, the property will only be tested once. Defaults to false. var exhaustive : Bool { get } - /// Returns a `Property`, which SwiftCheck uses to perform test case generation. + /// Returns a `Property`, which SwiftCheck uses to perform test case + /// generation. var property : Property { get } } @@ -30,7 +33,7 @@ extension Testable { } } -/// A property is anything that generates propositions. +/// A property is anything that generates `Prop`s. public struct Property : Testable { let unProperty : Gen @@ -43,7 +46,13 @@ public struct Property : Testable { } } -/// A proposition. +/// A `Prop` describes a strategy for evaluating a test case to a final +/// `TestResult`. It holds a Rose Tree of branches that evaluate the test and +/// any modifiers and mappings that may have been applied to a particular +/// testing tree. +/// +/// As a testable value, it creates a Property that generates only its testing +/// tree. public struct Prop : Testable { var unProp : Rose diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index eaa5fdc..c66535f 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -12,50 +12,50 @@ public protocol WitnessedArbitrary { static func forAllWitnessed(wit : A -> Param)(pf : (Self -> Testable)) -> Property } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for that type. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for that type. public func forAll(pf : (A -> Testable)) -> Property { return A.forAllWitnessed(id)(pf: pf) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 2 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 2 types. public func forAll(pf : (A, B) -> Testable) -> Property { return forAll({ t in forAll({ b in pf(t, b) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 3 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 3 types. public func forAll(pf : (A, B, C) -> Testable) -> Property { return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 4 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 4 types. public func forAll(pf : (A, B, C, D) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 5 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 5 types. public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 6 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 6 types. public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 7 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 7 types. public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } -/// Converts a function into a universally quantified property using the default shrinker and -/// generator for 8 types. +/// Converts a function into a universally quantified property using the default +/// shrinker and generator for 8 types. public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index d291afc..4bbe169 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -57,7 +57,7 @@ class ComplexSpec : XCTestCase { } } -/// MARK: String Conveniences +// MARK: String Conveniences private func wrap(l : String) -> String -> String -> String { return { m in { r in l + m + r } } From 500ca335ce4a210e9650cebe91f0dba678ac489c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 22:36:32 -0700 Subject: [PATCH 247/460] Add better warn_unused_result warnings to things --- SwiftCheck/Check.swift | 2 ++ SwiftCheck/Test.swift | 2 ++ SwiftCheck/Witness.swift | 8 ++++++++ SwiftCheckTests/PropertySpec.swift | 22 +++++++++++----------- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 7ea1699..da77883 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -33,6 +33,7 @@ /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. +@warn_unused_result(message="Did you forget to bind this property to a quantifier?") public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -53,6 +54,7 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. +@warn_unused_result(message="Did you forget to bind this property to a quantifier?") public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 71b07ce..8972043 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -320,12 +320,14 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T /// `SNF` involves turning every `exists` into a function returning the /// existential value, taking any other parameters being quantified over as /// needed. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func exists(pf : A throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func exists(gen : Gen, pf : A throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index c66535f..035c53f 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -14,48 +14,56 @@ public protocol WitnessedArbitrary { /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A -> Testable)) -> Property { return A.forAllWitnessed(id)(pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B) -> Testable) -> Property { return forAll({ t in forAll({ b in pf(t, b) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C) -> Testable) -> Property { return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. +@warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) } diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 93c95ee..9d65714 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -99,52 +99,52 @@ class PropertySpec : XCTestCase { } } return (n > 0) ==> isPositive(n) - }.noShrinking + } property("Prop Law of complements") <- forAll { (x : Bool) in return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) - }.noShrinking + } property("Prop Law of double negation") <- forAll { (x : Bool) in return x.invert.invert == x - }.noShrinking + } property("Prop Law of idempotency") <- forAll { (x : Bool) in return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) - }.noShrinking + } property("Prop Law of dominance") <- forAll { (x : Bool) in return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) - }.noShrinking + } property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) - }.noShrinking + } property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) - }.noShrinking + } property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) return l ^&&^ r - }.noShrinking + } property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ (x ^||^ y)) == x let r = (x ^||^ (x ^&&^ y)) == x return l ^&&^ r - }.noShrinking + } property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) return l ^&&^ r - }.noShrinking + } property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) - }.noShrinking + } } } From 3243ad5bb1160027532e6e4cdd5d9e47cca2228f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 22:45:14 -0700 Subject: [PATCH 248/460] Remove Equatable kit --- SwiftCheck.xcodeproj/project.pbxproj | 8 ------ SwiftCheck/CoArbitrary.swift | 3 +- SwiftCheck/Equatable.swift | 43 ---------------------------- 3 files changed, 2 insertions(+), 52 deletions(-) delete mode 100644 SwiftCheck/Equatable.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 70aeb48..7c31ab0 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -28,7 +28,6 @@ 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; - 8240CCD81C3A124B00EF4D29 /* Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46395B51B1A94D200AA1B65 /* Equatable.swift */; }; 8240CCD91C3A125800EF4D29 /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 844FCC92198B320500EB242A /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8240CCDC1C3A12AB00EF4D29 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */; }; @@ -100,8 +99,6 @@ 84EA2C391B2287200001FB3F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; 84EA2C3A1B2287200001FB3F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; 84F2C4F71A7AD43F00316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; - D46395B61B1A94D200AA1B65 /* Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46395B51B1A94D200AA1B65 /* Equatable.swift */; }; - D46395B71B1A94D200AA1B65 /* Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D46395B51B1A94D200AA1B65 /* Equatable.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -189,7 +186,6 @@ 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 84EA2C381B2287200001FB3F /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; usesTabs = 1; }; 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; usesTabs = 1; }; - D46395B51B1A94D200AA1B65 /* Equatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Equatable.swift; sourceTree = ""; usesTabs = 1; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -283,7 +279,6 @@ 8450D2491AF8003700095EF6 /* TestOperators.swift */, 827749F71B65ABCC00A7965F /* Witness.swift */, 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */, - D46395B51B1A94D200AA1B65 /* Equatable.swift */, 844FCC90198B320500EB242A /* Supporting Files */, ); path = SwiftCheck; @@ -584,7 +579,6 @@ 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */, 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */, 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */, - 8240CCD81C3A124B00EF4D29 /* Equatable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -617,7 +611,6 @@ 84572C251A6DBAA800241F68 /* Check.swift in Sources */, 844FCCC3198EC4F000EB242A /* Random.swift in Sources */, 844FCCAC198B32DC00EB242A /* Gen.swift in Sources */, - D46395B61B1A94D200AA1B65 /* Equatable.swift in Sources */, 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */, 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */, 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */, @@ -659,7 +652,6 @@ 84DF76141B0BD58100C912B0 /* Gen.swift in Sources */, 84DF76151B0BD58100C912B0 /* Lattice.swift in Sources */, 84DF76161B0BD58100C912B0 /* Modifiers.swift in Sources */, - D46395B71B1A94D200AA1B65 /* Equatable.swift in Sources */, 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */, 84DF76181B0BD58100C912B0 /* Property.swift in Sources */, 84DF76191B0BD58100C912B0 /* Random.swift in Sources */, diff --git a/SwiftCheck/CoArbitrary.swift b/SwiftCheck/CoArbitrary.swift index 61db239..32e9453 100644 --- a/SwiftCheck/CoArbitrary.swift +++ b/SwiftCheck/CoArbitrary.swift @@ -17,7 +17,8 @@ /// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a generator. + /// Uses an instance of the receiver to return a function that perturbs a + /// generator. static func coarbitrary(x : Self) -> (Gen -> Gen) } diff --git a/SwiftCheck/Equatable.swift b/SwiftCheck/Equatable.swift deleted file mode 100644 index 9a95678..0000000 --- a/SwiftCheck/Equatable.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Equatable.swift -// SwiftCheck -// -// Created by Robert Widmann on 1/29/15. -// Copyright (c) 2015 TypeLift. All rights reserved. -// - -public func == >(lhs : Blind, rhs : Blind) -> Bool { - return lhs.getBlind == rhs.getBlind -} - -public func == >(lhs : Static, rhs : Static) -> Bool { - return lhs.getStatic == rhs.getStatic -} - -public func == >(lhs : ArrayOf, rhs : ArrayOf) -> Bool { - return lhs.getArray == rhs.getArray -} - -public func == , V : protocol>(lhs : DictionaryOf, rhs : DictionaryOf) -> Bool { - return lhs.getDictionary == rhs.getDictionary -} - -public func == >(lhs : OptionalOf, rhs : OptionalOf) -> Bool { - return lhs.getOptional == rhs.getOptional -} - -public func == >(lhs : SetOf, rhs : SetOf) -> Bool { - return lhs.getSet == rhs.getSet -} - -public func == >(lhs : Positive, rhs : Positive) -> Bool { - return lhs.getPositive == rhs.getPositive -} - -public func == >(lhs : NonZero, rhs : NonZero) -> Bool { - return lhs.getNonZero == rhs.getNonZero -} - -public func == >(lhs : NonNegative, rhs : NonNegative) -> Bool { - return lhs.getNonNegative == rhs.getNonNegative -} From c53d53b12d7980fcfc872ad6c079b3e5d872b3d9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 23:05:30 -0700 Subject: [PATCH 249/460] Little style tweaks --- SwiftCheck/Gen.swift | 2 +- SwiftCheck/Property.swift | 8 ++++++-- SwiftCheck/Random.swift | 15 ++++++++++----- SwiftCheck/Rose.swift | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 3e94f53..4296e3c 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -237,7 +237,7 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the /// receiver creates. - public func map(f : (A -> B)) -> Gen { + public func map(f : A -> B) -> Gen { return f <^> self } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index a165297..aed67e7 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -244,15 +244,19 @@ extension Testable { } /// Applies a function that modifies the property generator's inner `Prop`. + /// + /// This function can be used to completely change the evaluation schema of + /// generated test cases by replacing the test's rose tree with a custom + /// one. public func mapProp(f : Prop -> Prop) -> Property { return Property(f <^> self.property.unProperty) } - /// Applies a function that modifies the property generator's size. + /// Applies a function that modifies the test case generator's size. public func mapSize(f : Int -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) - }) + }) } /// Applies a function that modifies the result of a test case. diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 6551846..3e48862 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -31,7 +31,7 @@ public protocol RandomGeneneratorType { /// initial random number generator, or to get different results on each run by /// using the system-initialised generator or by supplying a seed from some /// other source. -public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible { +public struct StdGen : RandomGeneneratorType { let seed1 : Int let seed2 : Int @@ -53,10 +53,8 @@ public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible self = mkStdGen32(o) } - public var description : String { - return "\(self.seed1) \(self.seed2)" - } - + /// Returns an `Int` generated uniformly within the bounds of the generator + /// and a new distinct random number generator. public var next : (Int, StdGen) { let s1 = self.seed1 let s2 = self.seed2 @@ -74,6 +72,7 @@ public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible return (z_, StdGen(s1__, s2__)) } + /// Splits the receiver and returns two distinct random number generators. public var split : (StdGen, StdGen) { let s1 = self.seed1 let s2 = self.seed2 @@ -86,6 +85,12 @@ public struct StdGen : Equatable, RandomGeneneratorType, CustomStringConvertible } } +extension StdGen : Equatable, CustomStringConvertible { + public var description : String { + return "\(self.seed1) \(self.seed2)" + } +} + public func == (l : StdGen, r : StdGen) -> Bool { return l.seed1 == r.seed1 && l.seed2 == r.seed2 } diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index c70a4fb..542ec66 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -46,7 +46,7 @@ extension Rose /*: Functor*/ { /// For `.MkRose` branches the computation is applied to the node's value /// then application recurses into the sub-trees. For `.IORose` branches /// the map is suspended. - public func map(f : (A -> B)) -> Rose { + public func map(f : A -> B) -> Rose { return f <^> self } } From cf13111066621f2fcda6c8d925e95ebb03e3a291 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 23:44:54 -0700 Subject: [PATCH 250/460] Tease apart curried functions --- SwiftCheck/Gen.swift | 6 +- SwiftCheck/Property.swift | 16 +-- SwiftCheck/State.swift | 11 +- SwiftCheck/Test.swift | 133 +++++++++++---------- SwiftCheck/Witness.swift | 4 +- SwiftCheck/WitnessedArbitrary.swift | 20 ++-- SwiftCheckTests/ComplexSpec.swift | 10 +- SwiftCheckTests/TestSpec.swift | 2 +- Tutorial.playground/Contents.swift | 172 ++++++++++++++-------------- 9 files changed, 192 insertions(+), 182 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 4296e3c..86bb04a 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -212,7 +212,7 @@ extension Gen { /// Modifies a Generator such that it produces arrays with a length /// determined by the receiver's size parameter. - public func proliferate() -> Gen<[A]> { + public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((0, n)) >>- self.proliferateSized } @@ -220,7 +220,7 @@ extension Gen { /// Modifies a Generator such that it produces non-empty arrays with a /// length determined by the receiver's size parameter. - public func proliferateNonEmpty() -> Gen<[A]> { + public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))) >>- self.proliferateSized } @@ -247,7 +247,7 @@ extension Gen /*: Functor*/ { /// /// This function is most useful for converting between generators of inter- /// related types. For example, you might have a Generator of `Character` -/// values that you then `.proliferate()` into an `Array` of `Character`s. You +/// values that you then `.proliferate` into an `Array` of `Character`s. You /// can then use `fmap` to convert that generator of `Array`s to a generator of /// `String`s. public func <^> (f : A -> B, g : Gen) -> Gen { diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index aed67e7..5ac9111 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -208,7 +208,7 @@ extension Testable { /// distribution map for the property that shows a percentage success rate /// for the property. public func label(s : String) -> Property { - return self.classify(true)(s: s) + return self.classify(true, s: s) } /// Labels a property with a printable value. @@ -217,8 +217,8 @@ extension Testable { } /// Conditionally labels a property with a value. - public func classify(b : Bool)(s : String) -> Property { - return self.cover(b)(n: 0)(s: s) + public func classify(b : Bool, s : String) -> Property { + return self.cover(b, n: 0, s: s) } /// Checks that at least the given proportion of successful test cases @@ -226,7 +226,7 @@ extension Testable { /// /// Discarded tests (i.e. ones with a false precondition) do not affect /// coverage. - public func cover(b : Bool)(n : Int)(s : String) -> Property { + public func cover(b : Bool, n : Int, s : String) -> Property { if b { return self.mapResult { res in return TestResult(ok: res.ok @@ -363,7 +363,7 @@ public struct TestResult { /// Destructures a test case into a matcher that can be used in switch /// statement. - public func match() -> TestResultMatcher { + public var match : TestResultMatcher { return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } @@ -438,10 +438,10 @@ private func protectResults(rs : Rose) -> Rose { } internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { - return { protect(Rose.pure • exception("Exception"))(x: f) } + return { protect(Rose.pure • exception("Exception"), x: f) } } -internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { +internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { do { return try x() } catch let e { @@ -450,7 +450,7 @@ internal func protect(f : ErrorType -> A)(x : () throws -> A) -> A { } private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { - return { protect(exception("Exception"))(x: r) } + return { protect(exception("Exception"), x: r) } } internal func id(x : A) -> A { diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index 59c768f..b45ec13 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -17,7 +17,7 @@ public struct CheckerState { let maxAllowableDiscardedTests : Int /// The function that generates the sizes fed to the generators for each /// test case. - let computeSize : Int -> Int -> Int + let computeSize : (Int, Int) -> Int /// The count of the number of successful test cases seen so far. let successfulTestCount : Int /// The count of the number of discarded test cases seen so far. @@ -42,7 +42,7 @@ public struct CheckerState { let successfulShrinkCount : Int /// Returns the number of failed shrinking steps since the last successful /// shrink. - let failedShrinkStepDistance : Int + let failedShrinkStepDistance : Int /// Returns the number of failed shrink steps. let failedShrinkStepCount : Int /// Returns whether the testing system should cease testing altogether. @@ -50,10 +50,11 @@ public struct CheckerState { let quantifier : Quantification + let arguments : CheckerArguments public init( name : String , maxAllowableSuccessfulTests : Int , maxAllowableDiscardedTests : Int - , computeSize : Int -> Int -> Int + , computeSize : (Int, Int) -> Int , successfulTestCount : Int , discardedTestCount : Int , labels : Dictionary @@ -64,7 +65,8 @@ public struct CheckerState { , failedShrinkStepDistance : Int , failedShrinkStepCount : Int , shouldAbort : Bool - , quantifier : Quantification) + , quantifier : Quantification + , arguments : CheckerArguments) { self.name = name self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests @@ -81,5 +83,6 @@ public struct CheckerState { self.failedShrinkStepCount = failedShrinkStepCount self.shouldAbort = shouldAbort self.quantifier = quantifier + self.arguments = arguments } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 8972043..3f18afd 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -386,66 +386,24 @@ internal indirect enum Either { } internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> Result { - func roundTo(n : Int)(m : Int) -> Int { - return (n / m) * m - } - - func rnd() -> StdGen { - switch args.replay { - case Optional.None: - return newStdGen() - case Optional.Some(let (rnd, _)): - return rnd - } - } - - func at0(f : Int -> Int -> Int)(s : Int)(n : Int)(d : Int) -> Int { - if n == 0 && d == 0 { - return s - } else { - return f(n)(d) - } - } - - let computeSize : Int -> Int -> Int = { x in - let computeSize_ : Int -> Int -> Int = { x in - return { y in - if roundTo(x)(m: args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests || - x >= args.maxAllowableSuccessfulTests || - args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { - return min(x % args.maxTestCaseSize + (y / 10), args.maxTestCaseSize) - } else { - return min((x % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + y / 10, args.maxTestCaseSize) - } - } - } - - return { y in - if let (_, sz) = args.replay { - return at0(computeSize_)(s: sz)(n: x)(d: y) - } - return computeSize_(x)(y) - } - } - - - let istate = CheckerState(name: args.name + let istate = CheckerState(name: args.name , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: computeSize + , computeSize: { computeSize(args, vals: $0) } , successfulTestCount: 0 , discardedTestCount: 0 , labels: [:] , collected: [] , hasFulfilledExpectedFailure: false - , randomSeedGenerator: rnd() + , randomSeedGenerator: chooseReplayRNG(args) , successfulShrinkCount: 0 , failedShrinkStepDistance: 0 , failedShrinkStepCount: 0 , shouldAbort: false - , quantifier: .Universal) + , quantifier: .Universal + , arguments: args) let modP : Property = (p.exhaustive ? p.property.once : p.property) - return test(istate, f: modP.unProperty.unGen) + return test(istate, caseGen: modP.unProperty.unGen) } // Main Testing Loop: @@ -461,10 +419,10 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R // - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. -internal func test(st : CheckerState, f : (StdGen, Int) -> Prop) -> Result { +internal func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { var state = st while true { - switch runATest(state)(f: f) { + switch runATest(state, caseGen: caseGen) { case let .Left(fail): switch (fail.0, doneTesting(fail.1)) { case (.Success(_, _, _), _): @@ -502,17 +460,17 @@ internal func test(st : CheckerState, f : (StdGen, Int) -> Prop) -> Result { // // On success the next state is returned. On failure the final result and state // are returned. -internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { - let size = st.computeSize(st.successfulTestCount)(st.discardedTestCount) +internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { + let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split // Execute the Rose Tree for the test and reduce to .MkRose. - switch f(rnd1, size).unProp.reduce { + switch caseGen(rnd1, size).unProp.reduce { case .MkRose(let resC, let ts): let res = resC() // Force the result only once. dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks - switch res.match() { + switch res.match { // Success case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): let nstate = CheckerState(name: st.name @@ -529,7 +487,8 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( , failedShrinkStepDistance: st.failedShrinkStepDistance , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort - , quantifier: quantifier) + , quantifier: quantifier + , arguments: st.arguments) return .Right(nstate) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort, let quantifier): @@ -547,7 +506,8 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( , failedShrinkStepDistance: st.failedShrinkStepDistance , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort - , quantifier: quantifier) + , quantifier: quantifier + , arguments: st.arguments) return .Right(nstate) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): @@ -576,13 +536,14 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( , failedShrinkStepDistance: st.failedShrinkStepDistance , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort - , quantifier: quantifier) + , quantifier: quantifier + , arguments: st.arguments) /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { let resul = Result.ExistentialFailure(numTests: st.successfulTestCount.successor() , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount)(st.discardedTestCount) + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) , reason: "Could not satisfy existential" , labels: summary(st) , output: "*** Failed! " @@ -603,7 +564,7 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( let stat = Result.Failure(numTests: st.successfulTestCount.successor() , numShrinks: numShrinks , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount)(st.discardedTestCount) + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) , reason: res.reason , labels: summary(st) , output: "*** Failed! ") @@ -622,7 +583,8 @@ internal func runATest(st : CheckerState)(f : (StdGen, Int) -> Prop) -> Either<( , failedShrinkStepDistance: st.failedShrinkStepDistance , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort - , quantifier: quantifier) + , quantifier: quantifier + , arguments: st.arguments) return .Left((stat, nstate)) } default: @@ -711,7 +673,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts successfulShrinkCount++ } - let state = CheckerState(name: st.name + let state = CheckerState( name: st.name , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests , computeSize: st.computeSize @@ -725,7 +687,8 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts , failedShrinkStepDistance: failedShrinkStepDistance , failedShrinkStepCount: failedShrinkStepCount , shouldAbort: st.shouldAbort - , quantifier: st.quantifier) + , quantifier: st.quantifier + , arguments: st.arguments) return reportMinimumCaseFound(state, res: lastResult) } @@ -846,7 +809,7 @@ private func pluralize(s : String, i : Int) -> String { } extension Array { - internal func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { + private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { if list.isEmpty { return ([], []) @@ -870,3 +833,47 @@ extension Array { fatalError("groupBy reached a non-empty list that could not produce a first element") } } + +/// Testing loop stuff + +private func computeSize(args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { + func computeSize_(successes : Int, _ discards : Int) -> Int { + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if successes >= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else { + return min((successes % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + discards / 10, args.maxTestCaseSize) + } + } + + if let (_, argSize) = args.replay { + return initialSizeForTest( argSize + , successes: vals.successes + , discards: vals.discards + , computeSize: computeSize_ + ) + } + return computeSize_(vals.successes, vals.discards) +} + +private func roundTo(n : Int, _ m : Int) -> Int { + return (n / m) * m +} + +private func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + if successes == 0 && discards == 0 { + return defaultSize + } else { + return computeSize(successes, discards) + } +} + +private func chooseReplayRNG(args : CheckerArguments) -> StdGen { + if let (rng, _) = args.replay { + return rng + } + return newStdGen() +} diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index 035c53f..cd350b5 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -9,14 +9,14 @@ public protocol WitnessedArbitrary { typealias Param - static func forAllWitnessed(wit : A -> Param)(pf : (Self -> Testable)) -> Property + static func forAllWitnessed(wit : A -> Param, pf : (Self -> Testable)) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A -> Testable)) -> Property { - return A.forAllWitnessed(id)(pf: pf) + return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index f0ae108..636496b 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -28,7 +28,7 @@ extension Array where Element : Arbitrary { extension Array : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : ([Element] -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) }) @@ -48,7 +48,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (AnyBidirectionalCollection -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (AnyBidirectionalCollection -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) }) @@ -68,7 +68,7 @@ extension AnySequence where Element : Arbitrary { extension AnySequence : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (AnySequence -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (AnySequence -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) }) @@ -88,7 +88,7 @@ extension ArraySlice where Element : Arbitrary { extension ArraySlice : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (ArraySlice -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (ArraySlice -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) }) @@ -104,7 +104,7 @@ extension CollectionOfOne where Element : Arbitrary { extension CollectionOfOne : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (CollectionOfOne -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (CollectionOfOne -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[.Zero]))) }) @@ -132,7 +132,7 @@ extension Optional where Wrapped : Arbitrary { extension Optional : WitnessedArbitrary { public typealias Param = Wrapped - public static func forAllWitnessed(wit : A -> Wrapped)(pf : (Optional -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Wrapped, pf : (Optional -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -152,7 +152,7 @@ extension ContiguousArray where Element : Arbitrary { extension ContiguousArray : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (ContiguousArray -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (ContiguousArray -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) }) @@ -217,7 +217,7 @@ extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { public typealias Param = Wrapped - public static func forAllWitnessed(wit : A -> Wrapped)(pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Wrapped, pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -259,7 +259,7 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (Repeat -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) @@ -288,7 +288,7 @@ extension Set where Element : protocol { extension Set : WitnessedArbitrary { public typealias Param = Element - public static func forAllWitnessed(wit : A -> Element)(pf : (Set -> Testable)) -> Property { + public static func forAllWitnessed(wit : A -> Element, pf : (Set -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) } diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 4bbe169..5bb4284 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -24,15 +24,15 @@ class ComplexSpec : XCTestCase { lower, numeric, special, - ]).proliferateNonEmpty().suchThat({ $0[$0.endIndex.predecessor()] != "." }).map(String.init) + ]).proliferateNonEmpty.suchThat({ $0[$0.endIndex.predecessor()] != "." }).map(String.init) let hostname = Gen.oneOf([ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty().map(String.init) + ]).proliferateNonEmpty.map(String.init) - let tld = lower.proliferateNonEmpty().suchThat({ $0.count > 1 }).map(String.init) + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld @@ -49,7 +49,7 @@ class ComplexSpec : XCTestCase { hexDigits.proliferateSized(4).map{ String.init($0) + ":" }, ]) - let ipGen = { $0.initial() } <^> (wrap2 <^> ipHexDigits <*> ipHexDigits <*> ipHexDigits <*> ipHexDigits) + let ipGen = { $0.initial } <^> (wrap2 <^> ipHexDigits <*> ipHexDigits <*> ipHexDigits <*> ipHexDigits) property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 @@ -72,7 +72,7 @@ private func wrap3(l : String) -> String -> String -> String -> String -> String } extension String { - func initial() -> String { + private var initial : String { return self[self.startIndex...zip(String.arbitrary, Int.arbitrary).proliferate().map(Dictionary.init) + let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map(Dictionary.init) property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in return true diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index d198f95..48f3e8a 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -153,23 +153,23 @@ oneToFiveEven.generate oneToFiveEven.generate // `proliferate` turns a generator of single elements into a generator of arrays of those elements. -let characterArray = uppersAndLowers.proliferate() +let characterArray = uppersAndLowers.proliferate characterArray.generate characterArray.generate characterArray.generate /// `proliferateNonEmpty` works like `proliferate` but guarantees the generated array is never empty. -let oddLengthArrays = fromOnetoFive.proliferateNonEmpty().suchThat { $0.count % 2 == 1 } +let oddLengthArrays = fromOnetoFive.proliferateNonEmpty.suchThat { $0.count % 2 == 1 } oddLengthArrays.generate.count oddLengthArrays.generate.count oddLengthArrays.generate.count -//: Generators also admit functional methods like `map` and `flatMap`, but with different names than -//: you might be used to. -// `map` works exactly like Array's `map` method; it applies the function to any +// //: Generators also admit functional methods like `map` and `flatMap`, but with different names than +//: you might be used to. +`map` works exactly like Array's `map` method; it applies the function to any // values it generates. let fromTwoToSix = fromOnetoFive.map { $0 + 1 } @@ -194,16 +194,16 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate -generatorBoundedSizeArrays.generate//: Because SwiftCheck is based on the functional concepts in our other library +generatorBoundedSizeArrays.generate + + +l//: Because SwiftCheck is based on the functional concepts in our other library //: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: //: //: * `<^>` is an alias for `fmap` //: * `<*>` is an alias for `ap` //: * `>>-` is an alias for `bind` - - - -let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive +et fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive fromTwoToSix_.generate fromTwoToSix_.generate @@ -215,51 +215,51 @@ let generatorBoundedSizeArrays_ = fromOnetoFive >>- { len in generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate//: For our purposes, we will say that an email address consists of 3 parts: A local part, a +generatorBoundedSizeArrays_.generate + + +l//: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. //: //: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, //: numbers, and certain kinds of special characters. We already have generators for upper and //: lower cased letters, so all we need are special characters and a more complete number generator: +et numeric : Gen = Gen.fromElementsIn("0"..."9") +let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) - -let numeric : Gen = Gen.fromElementsIn("0"..."9") -let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."])//: Now for the actual generator - - - -let allowedLocalCharacters : Gen = Gen.oneOf([ +l//: Now for the actual generator +et allowedLocalCharacters : Gen = Gen.oneOf([ upperCaseLetters, lowerCaseLetters, numeric, special, -])//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` -//: to get a `String` back. - +]) -let localEmail = allowedLocalCharacters - .proliferateNonEmpty() // Make a non-empty array of characters +l//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` +//: to get a `String` back. +et localEmail = allowedLocalCharacters + .proliferateNonEmpty // Make a non-empty array of characters .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. - .map(String.init) // Then make a string.//: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some -//: steps here and combine both steps into one big generator. + .map(String.init) // Then make a string. - -let hostname = Gen.oneOf([ +let //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some +//: steps here and combine both steps into one big generator. +hostname = Gen.oneOf([ lowerCaseLetters, numeric, Gen.pure("-"), -]).proliferateNonEmpty().map(String.init) +]).proliferateNonEmpty.map(String.init) -//: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. -let tld = lowerCaseLetters.proliferateNonEmpty().suchThat({ $0.count > 1 }).map(String.init) +let tld//: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. + = lowerCaseLetters.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) -//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how +// Concate//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how //: about some glue? -// Concatenates an array of `String` `Gen`erators together in order. +nates an array of `String` `Gen`erators together in order. func glue(parts : [Gen]) -> Gen { return sequence(parts).map { $0.reduce("", combine: +) } } @@ -267,15 +267,16 @@ func glue(parts : [Gen]) -> Gen { let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) -///: And we're done! -/ Yes, these are in fact, all valid email addresses. +// Yes, the//: And we're done! +se are in fact, all valid email addresses. emailGen.generate emailGen.generate emailGen.generate -//: By now you may be asking "why do we need all of this in the first place? Can't we just apply +// +// //: By now you may be asking "why do we need all of this in the first place? Can't we just apply //: the parts to the function to get back a result?" Well, we do it because we aren't working with //: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply //: `Gen` to a function that expects `String`, that wouldn't make any sense - and it would @@ -284,16 +285,15 @@ emailGen.generate //: //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: -///: # Arbitrary -///: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were +p//: # Arbitrary +u//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were //: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on //: values that would ask them to generate a "next" value. But that would have been incredibly //: boring! Instead, we wrote a protocol called `Arbitrary` and let Types, not values, do all the //: work. //: //: The `Arbitrary` protocol looks like this: - -// public protocol Arbitrary { +blic protocol Arbitrary { // /// The generator for this particular type. // /// // /// This function should call out to any sources of randomness or state necessary to generate @@ -303,18 +303,18 @@ emailGen.generate // } // -i//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator +import clas//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator //: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of //: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance //: for `Int` calls `arc4random_uniform`. //: //: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen //: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. -mport class Foundation.NSDate - -////: Here's the obvious way to do it +s Foundation.NSDate -// extension NSDate : Arbitrary { +// +// extens//: Here's the obvious way to do it +ion NSDate : Arbitrary { // public static var arbitrary : Gen { // return Gen.oneOf([ // Gen.pure(NSDate()), @@ -326,11 +326,11 @@ mport class Foundation.NSDate // } // -s//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` +struct Arbi//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` //: in the wrong position. What to do? //: //: Let's write a wrapper! -truct ArbitraryDate : Arbitrary { +traryDate : Arbitrary { let getDate : NSDate init(date : NSDate) { self.getDate = date } @@ -349,13 +349,13 @@ ArbitraryDate.arbitrary.generate.getDate ArbitraryDate.arbitrary.generate.getDate -pu//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't +public struc//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't //: generate with another that we can. //: //: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: -blic struct ArbitraryPositive> : Arbitrary { +t ArbitraryPositive> : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -371,8 +371,8 @@ ArbitraryPositive.arbitrary.generate.getPositive // -//: # Quantifiers -///: What we've seen so far are the building blocks we need to introduce the final part of the +// fun//: # Quantifiers +c//: What we've seen so far are the building blocks we need to introduce the final part of the //: library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. //: //: A Quantifier is a contract that serves as a guarantee that a property holds when the given @@ -381,13 +381,13 @@ ArbitraryPositive.arbitrary.generate.getPositive //: requires type annotations for all value positions being requested. There is only one quantifier //: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec //: must pass "for all" of the values. Here's what it looks like: -/ func forAll(_ : (A... -> Bool)) -> Property + forAll(_ : (A... -> Bool)) -> Property // -// //: The actual type of `forAll` is much more general and expressive than this, but for now this will do. +// + This//: The actual type of `forAll` is much more general and expressive than this, but for now this will do. //: //: Here is an example of a simple property - + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. + is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. // | + This backwards arrow binds a property name and a property to each other. // | | // v v @@ -398,8 +398,8 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // From now on, all of our examples will take the form above. -// //: Because `forAll` is variadic it works for a large number and variety of types too: - +--- This Modifier Type produces Arrays of Integers. +// //: Because `forAll` is variadic it works for a large number and variety of types too: + +--- This Modifier Type produces Arrays of Integers. // | +--- This Modifier Type generates functions. That's right, SwiftCheck // | | can generate *functions*!! // v v @@ -418,7 +418,7 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in } -// //: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not +// `reportPro//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not //: once did we have to invoke `.generate` or have to construct a generator. We simply told the //: `forAll` block how many variables we wanted and of what type and SwiftCheck automagically went //: out and was able to produce random values. @@ -427,7 +427,7 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in //: to construct default generators for each type and a testing mechanism that invokes the testing //: block for the proper number of tests. For some real magic, let's see what happens when we fail //: a test: -`reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, +perty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. reportProperty("Obviously wrong") <- forAll({ (x : Int) in @@ -437,7 +437,7 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in } // -///: If you open the console for the playground, you'll see output very similar to the following: +// publ//: If you open the console for the playground, you'll see output very similar to the following: //: //: *** Failed! Proposition: Obviously wrong //: Falsifiable (after 1 test): @@ -450,7 +450,7 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in //: the integer supposedly being random. What's going on here? //: //: To find out, let's see the full definition of the `Arbitrary` protocol: -/ public protocol Arbitrary { +ic protocol Arbitrary { // /// The generator for this particular type. // /// // /// This function should call out to any sources of randomness or state necessary to generate @@ -469,21 +469,21 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in // } // -Arr//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is +Array.sh//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is //: a strategy for reducing randomly generated values. To shrink a value, all you need to do is //: return an array of "smaller values", whether in magnitude or value. For example, the shrinker //: for `Array` returns Arrays that have a size less than or equal to that of the input array. -ay.shrink([1, 2, 3]) +rink([1, 2, 3]) -////: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes +// SwiftChec//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes //: the shrinker, tries the property again on the values of the array until it finds another failing //: case, then repeats the process until it runs out of cases to try. In other words, it *shrinks* //: the value down to the least possible size then reports that to you as the failing test case //: rather than the randomly generated value which could be unnecessarily large or complex. - //: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: -SwiftCheck defines default shrinkers for most of the types it gives Arbitrary instances. There +k//: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: + defines default shrinkers for most of the types it gives Arbitrary instances. There // will often be times when those default shrinkers don't cut it, or you need more control over // what happens when you generate or shrink values. Modifier Types to the rescue! struct ArbitraryEmail : Arbitrary { @@ -503,10 +503,10 @@ property("email addresses don't come with a TLD") <- forAll { (email : Arbitrary -// //: # All Together Now! -T//: Let's put all of our newfound understanding of this framework to use by writing a property that +// The Sieve //: # All Together Now! +o//: Let's put all of our newfound understanding of this framework to use by writing a property that //: tests an implementation of the Sieve of Eratosthenes: -he Sieve of Eratosthenes: +f Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -560,9 +560,9 @@ func isPrime(n : Int) -> Bool { } -repo//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the +reportProperty//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the //: following property: -rtProperty("All Prime") <- forAll { (n : Positive) in +("All Prime") <- forAll { (n : Positive) in let primes = sieve(n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) @@ -575,7 +575,7 @@ rtProperty("All Prime") <- forAll { (n : Positive) in // -//: This test introduces several new concepts that we'll go through 1-by-1: +// The Sie//: This test introduces several new concepts that we'll go through 1-by-1: //: //: * `Positive`: This is a Modifier Type defined by SwiftCheck that only produces //: integers larger than zero - positive integers. SwiftCheck also has @@ -597,7 +597,7 @@ rtProperty("All Prime") <- forAll { (n : Positive) in //: `forAll` that takes a user-supplied generator. For those times when you want //: absolute control over generated values, like we do here, use that particular //: series of overloads. -///: If you check the console, you'll notice that this property doesn't hold! +v//: If you check the console, you'll notice that this property doesn't hold! //: //: *** Failed! Proposition: All Prime //: Falsifiable (after 11 tests and 2 shrinks): @@ -605,8 +605,8 @@ rtProperty("All Prime") <- forAll { (n : Positive) in //: 0 //: //: What's wrong here? -///: Let's go back to the spec we had for the sieve: - The Sieve of Eratosthenes: +e//: Let's go back to the spec we had for the sieve: + of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -617,8 +617,8 @@ rtProperty("All Prime") <- forAll { (n : Positive) in // - Remaining indices of unmarked numbers are primes // -func//: Looks like we used `to:` when we meant `through:`. Let's try again: - sieveProperly(n : Int) -> [Int] { +func sieveProp//: Looks like we used `to:` when we meant `through:`. Let's try again: +erly(n : Int) -> [Int] { if n <= 1 { return [] } @@ -655,13 +655,13 @@ property("All Prime") <- forAll { (n : Positive) in -pro//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm +property("All//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm //: isn't handling the case presented. So you search through some specification to find the mistake in //: logic and try again. Along the way, SwiftCheck will do its best help you by presenting minimal //: cases at the least, and, with more advanced uses of the framework, the names of specific sub-parts of //: cases and even percentages of failing vs. passing tests. -p//: Just for fun, let's try a simpler property that checks the same outcome: -erty("All Prime") <- forAll { (n : Positive) in + //: Just for fun, let's try a simpler property that checks the same outcome: +Prime") <- forAll { (n : Positive) in // Sieving Properly then filtering for primes is the same as just Sieving, right? return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } @@ -673,18 +673,18 @@ erty("All Prime") <- forAll { (n : Positive) in -//: When working with failing tests, it's often tough to be able to replicate the exact conditions +reportProp//: When working with failing tests, it's often tough to be able to replicate the exact conditions //: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework //: comes with a replay mechanism that allows the arguments that lead to a failing test to be generated //: in exactly the same order, with exactly the same values, as they did the first time. When a test //: fails, SwiftCheck will present a helpful message that looks something like this in Xcode: -r//: > failed - Falsifiable; Replay with 123456789 123456789 -e//: Or this message in your log: -p//: > Pass the seed values 123456789 123456789 to replay the test. -o//: These are called *seeds*, and they can be fed back into the property that generated them to +e//: > failed - Falsifiable; Replay with 123456789 123456789 +r//: Or this message in your log: +t//: > Pass the seed values 123456789 123456789 to replay the test. +y//: These are called *seeds*, and they can be fed back into the property that generated them to //: activate the replay feature. For example, here's an annoying test to debug because it only fails //: every so often on one particular value: -rtProperty("Screw this value in particular") <- forAll { (n : UInt) in +("Screw this value in particular") <- forAll { (n : UInt) in if (n == 42) { return false } @@ -693,9 +693,9 @@ rtProperty("Screw this value in particular") <- forAll { (n : UInt) in } -/// //: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because +/// By passing//: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because //: 42 will always be generated as the first value. We've turned on verbose mode to demonstrate this. -By passing this argument to the test, SwiftCheck will automatically use the given seed values and + this argument to the test, SwiftCheck will automatically use the given seed values and /// size to completely replicate a particular set of values that caused the first test to fail. let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in From 835c434eedf3368e36aefa8ca96c474d91a284bb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 23:48:02 -0700 Subject: [PATCH 251/460] bind -> flatMap --- SwiftCheck/Gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 86bb04a..54082a9 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -298,7 +298,7 @@ extension Gen /*: Monad*/ { /// Applies the function to any generated values to yield a new generator. /// This generator is then given a new random seed and returned. /// - /// `bind` allows for the creation of Generators that depend on other + /// `flatMap` allows for the creation of Generators that depend on other /// generators. One might, for example, use a Generator of integers to /// control the length of a Generator of strings, or use it to choose a /// random index into a Generator of arrays. @@ -310,7 +310,7 @@ extension Gen /*: Monad*/ { /// Applies the function to any generated values to yield a new generator. This /// generator is then given a new random seed and returned. /// -/// `bind` allows for the creation of Generators that depend on other +/// `flatMap` allows for the creation of Generators that depend on other /// generators. One might, for example, use a Generator of integers to control /// the length of a Generator of strings, or use it to choose a random index /// into a Generator of arrays. From b4eb0ba4878a08ecefe0ef7620482849257a5bfc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 7 Jan 2016 23:56:08 -0700 Subject: [PATCH 252/460] Restore Tutorial --- Tutorial.playground/Contents.swift | 274 +++++++++++++++-------------- 1 file changed, 140 insertions(+), 134 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 48f3e8a..a6da3ee 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -167,9 +167,10 @@ oddLengthArrays.generate.count oddLengthArrays.generate.count -// //: Generators also admit functional methods like `map` and `flatMap`, but with different names than +//: Generators also admit functional methods like `map` and `flatMap`, but with different names than //: you might be used to. -`map` works exactly like Array's `map` method; it applies the function to any + +// `Gen.map` works exactly like Array's `map` method; it applies the function to any // values it generates. let fromTwoToSix = fromOnetoFive.map { $0 + 1 } @@ -197,13 +198,14 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate -l//: Because SwiftCheck is based on the functional concepts in our other library +//: Because SwiftCheck is based on the functional concepts in our other library //: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: //: -//: * `<^>` is an alias for `fmap` +//: * `<^>` is an alias for `map` //: * `<*>` is an alias for `ap` -//: * `>>-` is an alias for `bind` -et fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive +//: * `>>-` is an alias for `flatMap` + +let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive fromTwoToSix_.generate fromTwoToSix_.generate @@ -218,18 +220,19 @@ generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate -l//: For our purposes, we will say that an email address consists of 3 parts: A local part, a +//: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. //: -//: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, -//: numbers, and certain kinds of special characters. We already have generators for upper and +//: According to RFC 2822, the local part can consist of uppercase characters, lowercase letters, +//: numbers, and certain kinds of special characters. We already have generators for upper and //: lower cased letters, so all we need are special characters and a more complete number generator: -et numeric : Gen = Gen.fromElementsIn("0"..."9") + +let numeric : Gen = Gen.fromElementsIn("0"..."9") let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +//: Now for the actual generator -l//: Now for the actual generator -et allowedLocalCharacters : Gen = Gen.oneOf([ +let allowedLocalCharacters : Gen = Gen.oneOf([ upperCaseLetters, lowerCaseLetters, numeric, @@ -237,63 +240,67 @@ et allowedLocalCharacters : Gen = Gen.oneOf([ ]) -l//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` +//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` //: to get a `String` back. -et localEmail = allowedLocalCharacters - .proliferateNonEmpty // Make a non-empty array of characters - .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. - .map(String.init) // Then make a string. -let //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some +let localEmail = allowedLocalCharacters + .proliferateNonEmpty // Make a non-empty array of characters + .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. + .map(String.init) // Then make a string. +//: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine both steps into one big generator. -hostname = Gen.oneOf([ + +let hostname = Gen.oneOf([ lowerCaseLetters, numeric, Gen.pure("-"), ]).proliferateNonEmpty.map(String.init) +//: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. -let tld//: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. - = lowerCaseLetters.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) +let tld = lowerCaseLetters + .proliferateNonEmpty + .suchThat({ $0.count > 1 }) + .map(String.init) - -// Concate//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how +//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how //: about some glue? -nates an array of `String` `Gen`erators together in order. + +// Concatenates an array of `String` `Gen`erators together in order. func glue(parts : [Gen]) -> Gen { return sequence(parts).map { $0.reduce("", combine: +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) +//: And we're done! -// Yes, the//: And we're done! -se are in fact, all valid email addresses. +// Yes, these are in fact, all valid email addresses. emailGen.generate emailGen.generate emailGen.generate - - -// -// //: By now you may be asking "why do we need all of this in the first place? Can't we just apply -//: the parts to the function to get back a result?" Well, we do it because we aren't working with -//: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply -//: `Gen` to a function that expects `String`, that wouldn't make any sense - and it would -//: never compile! Instead we use these operators to "lift" our function over `String`s to +//: By now you may be asking "why do we need all of this in the first place? Can't we just apply +//: the parts to the function to get back a result?" Well, we do it because we aren't working with +//: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply +//: `Gen` to a function that expects `String`, that wouldn't make any sense - and it would +//: never compile! Instead we use these operators to "lift" our function over `String`s to //: functions over `Gen`s. //: //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: -p//: # Arbitrary -u//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were -//: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on -//: values that would ask them to generate a "next" value. But that would have been incredibly -//: boring! Instead, we wrote a protocol called `Arbitrary` and let Types, not values, do all the + +//: # Arbitrary + +//: Here at TypeLift, we believe that Types are the most useful part of a program. So when we were +//: writing SwiftCheck, we thought about just using `Gen` everywhere and making instance methods on +//: values that would ask them to generate a "next" value. But that would have been incredibly +//: boring! Instead, we wrote a protocol called `Arbitrary` and let Types, not values, do all the //: work. //: //: The `Arbitrary` protocol looks like this: -blic protocol Arbitrary { +// +// public protocol Arbitrary { // /// The generator for this particular type. // /// // /// This function should call out to any sources of randomness or state necessary to generate @@ -302,19 +309,19 @@ blic protocol Arbitrary { // static var arbitrary : Gen { get } // } // - -import clas//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator -//: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of -//: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance +//: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator +//: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of +//: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance //: for `Int` calls `arc4random_uniform`. //: //: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen //: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. -s Foundation.NSDate +import class Foundation.NSDate + +//: Here's the obvious way to do it // -// extens//: Here's the obvious way to do it -ion NSDate : Arbitrary { +// extension NSDate : Arbitrary { // public static var arbitrary : Gen { // return Gen.oneOf([ // Gen.pure(NSDate()), @@ -325,12 +332,12 @@ ion NSDate : Arbitrary { // } // } // - -struct Arbi//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` +//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` //: in the wrong position. What to do? //: //: Let's write a wrapper! -traryDate : Arbitrary { + +struct ArbitraryDate : Arbitrary { let getDate : NSDate init(date : NSDate) { self.getDate = date } @@ -348,14 +355,14 @@ traryDate : Arbitrary { ArbitraryDate.arbitrary.generate.getDate ArbitraryDate.arbitrary.generate.getDate - -public struc//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't +//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't //: generate with another that we can. //: //: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but -//: we also use them in more benign ways too. For example, we can write a modifier type that only +//: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: -t ArbitraryPositive> : Arbitrary { + +public struct ArbitraryPositive> : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -369,25 +376,25 @@ ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive ArbitraryPositive.arbitrary.generate.getPositive +//: # Quantifiers -// -// fun//: # Quantifiers -c//: What we've seen so far are the building blocks we need to introduce the final part of the +//: What we've seen so far are the building blocks we need to introduce the final part of the //: library: The actual testing interface. The last concept we'll introduce is *Quantifiers*. //: //: A Quantifier is a contract that serves as a guarantee that a property holds when the given //: testing block returns `true` or truthy values, and fails when the testing block returns `false` //: or falsy values. The testing block is usually used with Swift's abbreviated block syntax and //: requires type annotations for all value positions being requested. There is only one quantifier -//: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec +//: in SwiftCheck, `forAll`. As its name implies, `forAll` will produce random data and your spec //: must pass "for all" of the values. Here's what it looks like: - forAll(_ : (A... -> Bool)) -> Property // - -// + This//: The actual type of `forAll` is much more general and expressive than this, but for now this will do. +// func forAll(_ : (A... -> Bool)) -> Property +// +//: The actual type of `forAll` is much more general and expressive than this, but for now this will do. //: //: Here is an example of a simple property - is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. + +// + This is "Property Notation". It allows you to give your properties a name and instructs SwiftCheck to test it. // | + This backwards arrow binds a property name and a property to each other. // | | // v v @@ -397,16 +404,16 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // From now on, all of our examples will take the form above. +//: Because `forAll` is variadic it works for a large number and variety of types too: -// //: Because `forAll` is variadic it works for a large number and variety of types too: - +--- This Modifier Type produces Arrays of Integers. +// +--- This Modifier Type produces Arrays of Integers. // | +--- This Modifier Type generates functions. That's right, SwiftCheck // | | can generate *functions*!! // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow return xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) - // ^ This property says that if we filter an array then apply the predicate + // ^ This property says that if we filter an array then apply the predicate // to all its elements, then they should all respond with `true`. } @@ -417,17 +424,17 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in return l && r } - -// `reportPro//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not -//: once did we have to invoke `.generate` or have to construct a generator. We simply told the -//: `forAll` block how many variables we wanted and of what type and SwiftCheck automagically went +//: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not +//: once did we have to invoke `.generate` or have to construct a generator. We simply told the +//: `forAll` block how many variables we wanted and of what type and SwiftCheck automagically went //: out and was able to produce random values. //: -//: Our not-so-magic trick is enabled behind the scenes by the judicious combination of `Arbitrary` -//: to construct default generators for each type and a testing mechanism that invokes the testing -//: block for the proper number of tests. For some real magic, let's see what happens when we fail +//: Our not-so-magic trick is enabled behind the scenes by the judicious combination of `Arbitrary` +//: to construct default generators for each type and a testing mechanism that invokes the testing +//: block for the proper number of tests. For some real magic, let's see what happens when we fail //: a test: -perty` is a variation of `property` that doesn't assert on failure. It does, however, + +// `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. reportProperty("Obviously wrong") <- forAll({ (x : Int) in @@ -436,21 +443,21 @@ reportProperty("Obviously wrong") <- forAll({ (x : Int) in print("Oh noes!") } -// -// publ//: If you open the console for the playground, you'll see output very similar to the following: +//: If you open the console for the playground, you'll see output very similar to the following: //: //: *** Failed! Proposition: Obviously wrong //: Falsifiable (after 1 test): //: Oh noes! //: 0 -//: -//: The first line tells you what failed, the next how long it took to fail, the next our message +//: +//: The first line tells you what failed, the next how long it took to fail, the next our message //: from the callback, and the last the value of `x` the property failed with. If you keep running -//: the test over and over again you'll notice that the test keeps failing on the number 0 despite +//: the test over and over again you'll notice that the test keeps failing on the number 0 despite //: the integer supposedly being random. What's going on here? //: //: To find out, let's see the full definition of the `Arbitrary` protocol: -ic protocol Arbitrary { +// +// public protocol Arbitrary { // /// The generator for this particular type. // /// // /// This function should call out to any sources of randomness or state necessary to generate @@ -468,22 +475,22 @@ ic protocol Arbitrary { // static func shrink(_ : Self) -> [Self] // } // - -Array.sh//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is -//: a strategy for reducing randomly generated values. To shrink a value, all you need to do is -//: return an array of "smaller values", whether in magnitude or value. For example, the shrinker +//: Here's where we one-up Fuzz Testing and show the real power of Property Testing. A "shrink" is +//: a strategy for reducing randomly generated values. To shrink a value, all you need to do is +//: return an array of "smaller values", whether in magnitude or value. For example, the shrinker //: for `Array` returns Arrays that have a size less than or equal to that of the input array. -rink([1, 2, 3]) - +Array.shrink([1, 2, 3]) -// SwiftChec//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes +//: So herein lies the genius: Whenever SwiftCheck encounters a failing property, it simply invokes //: the shrinker, tries the property again on the values of the array until it finds another failing //: case, then repeats the process until it runs out of cases to try. In other words, it *shrinks* -//: the value down to the least possible size then reports that to you as the failing test case +//: the value down to the least possible size then reports that to you as the failing test case //: rather than the randomly generated value which could be unnecessarily large or complex. -k//: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: - defines default shrinkers for most of the types it gives Arbitrary instances. There + +//: Before we move on, let's write a Modifier Type with a custom shrinker for the email generator we defined a little while ago: + +// SwiftCheck defines default shrinkers for most of the types it gives Arbitrary instances. There // will often be times when those default shrinkers don't cut it, or you need more control over // what happens when you generate or shrink values. Modifier Types to the rescue! struct ArbitraryEmail : Arbitrary { @@ -498,15 +505,15 @@ struct ArbitraryEmail : Arbitrary { property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in return !email.getEmail.containsString(".") }.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` - // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail - // and live up to your expectations, SwiftCheck treats that as a failure of the test case. - + // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail + // and live up to your expectations, SwiftCheck treats that as a failure of the test case. +//: # All Together Now! -// The Sieve //: # All Together Now! -o//: Let's put all of our newfound understanding of this framework to use by writing a property that +//: Let's put all of our newfound understanding of this framework to use by writing a property that //: tests an implementation of the Sieve of Eratosthenes: -f Eratosthenes: + +// The Sieve of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -559,10 +566,10 @@ func isPrime(n : Int) -> Bool { return true } - -reportProperty//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the +//: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the //: following property: -("All Prime") <- forAll { (n : Positive) in + +reportProperty("All Prime") <- forAll { (n : Positive) in let primes = sieve(n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) @@ -572,14 +579,11 @@ reportProperty//: We would like to test whether our sieve works properly, so we } } - - -// -// The Sie//: This test introduces several new concepts that we'll go through 1-by-1: +//: This test introduces several new concepts that we'll go through 1-by-1: //: //: * `Positive`: This is a Modifier Type defined by SwiftCheck that only produces //: integers larger than zero - positive integers. SwiftCheck also has -//: modifiers for `NonZero` (all integers that aren't 0) and `NonNegative` +//: modifiers for `NonZero` (all integers that aren't 0) and `NonNegative` //: (all positive integers including 0). //: //: * `==>`: This operator is called "Implication". It is used to introduce tests that need to @@ -597,7 +601,8 @@ reportProperty//: We would like to test whether our sieve works properly, so we //: `forAll` that takes a user-supplied generator. For those times when you want //: absolute control over generated values, like we do here, use that particular //: series of overloads. -v//: If you check the console, you'll notice that this property doesn't hold! + +//: If you check the console, you'll notice that this property doesn't hold! //: //: *** Failed! Proposition: All Prime //: Falsifiable (after 11 tests and 2 shrinks): @@ -605,8 +610,10 @@ v//: If you check the console, you'll notice that this property doesn't hold! //: 0 //: //: What's wrong here? -e//: Let's go back to the spec we had for the sieve: - of Eratosthenes: + +//: Let's go back to the spec we had for the sieve: +// +// The Sieve of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: // - let l = [2...n] @@ -616,9 +623,9 @@ e//: Let's go back to the spec we had for the sieve: // } // - Remaining indices of unmarked numbers are primes // +//: Looks like we used `to:` when we meant `through:`. Let's try again: -func sieveProp//: Looks like we used `to:` when we meant `through:`. Let's try again: -erly(n : Int) -> [Int] { +func sieveProperly(n : Int) -> [Int] { if n <= 1 { return [] } @@ -653,38 +660,38 @@ property("All Prime") <- forAll { (n : Positive) in } } - - -property("All//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm +//: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm //: isn't handling the case presented. So you search through some specification to find the mistake in //: logic and try again. Along the way, SwiftCheck will do its best help you by presenting minimal //: cases at the least, and, with more advanced uses of the framework, the names of specific sub-parts of //: cases and even percentages of failing vs. passing tests. - //: Just for fun, let's try a simpler property that checks the same outcome: -Prime") <- forAll { (n : Positive) in + +//: Just for fun, let's try a simpler property that checks the same outcome: + +property("All Prime") <- forAll { (n : Positive) in // Sieving Properly then filtering for primes is the same as just Sieving, right? return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } //; # One More Thing - - - - - -reportProp//: When working with failing tests, it's often tough to be able to replicate the exact conditions +//: When working with failing tests, it's often tough to be able to replicate the exact conditions //: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework //: comes with a replay mechanism that allows the arguments that lead to a failing test to be generated //: in exactly the same order, with exactly the same values, as they did the first time. When a test //: fails, SwiftCheck will present a helpful message that looks something like this in Xcode: -e//: > failed - Falsifiable; Replay with 123456789 123456789 -r//: Or this message in your log: -t//: > Pass the seed values 123456789 123456789 to replay the test. -y//: These are called *seeds*, and they can be fed back into the property that generated them to + +//: > failed - Falsifiable; Replay with 123456789 123456789 + +//: Or this message in your log: + +//: > Pass the seed values 123456789 123456789 to replay the test. + +//: These are called *seeds*, and they can be fed back into the property that generated them to //: activate the replay feature. For example, here's an annoying test to debug because it only fails //: every so often on one particular value: -("Screw this value in particular") <- forAll { (n : UInt) in + +reportProperty("Screw this value in particular") <- forAll { (n : UInt) in if (n == 42) { return false } @@ -692,10 +699,10 @@ y//: These are called *seeds*, and they can be fed back into the property that g return true } - -/// By passing//: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because +//: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because //: 42 will always be generated as the first value. We've turned on verbose mode to demonstrate this. - this argument to the test, SwiftCheck will automatically use the given seed values and + +/// By passing this argument to the test, SwiftCheck will automatically use the given seed values and /// size to completely replicate a particular set of values that caused the first test to fail. let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in @@ -705,16 +712,15 @@ reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in return true }.verbose - - //: # Conclusion + //: If you've made it this far, congratulations! That's it. Naturally, there are other combinators -//: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, +//: and fancy ways of creating `Gen`erators and properties with the primitives in this framework, //: but they are all variations on the themes present in ths tutorial. With the power of SwiftCheck -//: and a sufficiently expressive testing suite, we can begin to check our programs not for -//: individual passing cases in a few scattershot unit tests, but declare and enforce immutable -//: properties that better describe the intent and invariants of our programs. If you would like -//: further reading, see the files `Arbitrary.swift`, `Test.swift`, `Modifiers.swift`, and +//: and a sufficiently expressive testing suite, we can begin to check our programs not for +//: individual passing cases in a few scattershot unit tests, but declare and enforce immutable +//: properties that better describe the intent and invariants of our programs. If you would like +//: further reading, see the files `Arbitrary.swift`, `Test.swift`, `Modifiers.swift`, and //: `Property.swift`. Beyond that, there are a number of resources built for the original framework //: and its other derivatives whose concepts translate directly into SwiftCheck: //: From 063c7c5ae190e2486eca7cded2950dab18300923 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 00:44:39 -0700 Subject: [PATCH 253/460] Use a much faster shuffle --- SwiftCheck/Gen.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 54082a9..254fcc5 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -76,12 +76,8 @@ public struct Gen { /// Constructs a Generator that produces permutations of a given array. public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { - if xs.isEmpty { - return Gen<[S]>.pure([]) - } - - return Gen<(S, [S])>.fromElementsOf(selectOne(xs)).flatMap { (y, ys) in - return Gen.fromShufflingElementsOf(ys).map { [y] + $0 } + return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in + return Gen<[S]>.pure(Swift.zip(ns, xs).sort({ l, r in l.0 < r.0 }).map { $0.1 }) } } From 8ccd49ec74b4173a563b9d233a04f6f03221f29b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 01:03:01 -0700 Subject: [PATCH 254/460] Match QuickCheck's Insufficient Coverage features --- SwiftCheck/Property.swift | 12 ++++++------ SwiftCheck/Random.swift | 2 +- SwiftCheck/Test.swift | 29 +++++++++++++++++++++++++---- SwiftCheck/TestOperators.swift | 4 ++++ SwiftCheckTests/PropertySpec.swift | 6 ++++++ 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 5ac9111..5ead1e9 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -208,7 +208,7 @@ extension Testable { /// distribution map for the property that shows a percentage success rate /// for the property. public func label(s : String) -> Property { - return self.classify(true, s: s) + return self.classify(true, label: s) } /// Labels a property with a printable value. @@ -217,8 +217,8 @@ extension Testable { } /// Conditionally labels a property with a value. - public func classify(b : Bool, s : String) -> Property { - return self.cover(b, n: 0, s: s) + public func classify(b : Bool, label : String) -> Property { + return self.cover(b, percentage: 0, label: label) } /// Checks that at least the given proportion of successful test cases @@ -226,15 +226,15 @@ extension Testable { /// /// Discarded tests (i.e. ones with a false precondition) do not affect /// coverage. - public func cover(b : Bool, n : Int, s : String) -> Property { + public func cover(b : Bool, percentage : Int, label : String) -> Property { if b { return self.mapResult { res in return TestResult(ok: res.ok , expect: res.expect , reason: res.reason , theException: res.theException - , labels: insertWith(max, k: s, v: n, m: res.labels) - , stamp: res.stamp.union([s]) + , labels: insertWith(max, k: label, v: percentage, m: res.labels) + , stamp: res.stamp.union([label]) , callbacks: res.callbacks , abort: res.abort , quantifier: res.quantifier) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 3e48862..efaac3e 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -181,7 +181,7 @@ extension Int64 : RandomType { let b = genhi - genlo + 1 let q : Int64 = 1000 - let k = h - l + 1 + let k = Int64.subtractWithOverflow(h, l).0 + 1 let magtgt = k * q func entropize(mag : Int64, _ v : Int64, _ g : G) -> (Int64, G) { diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 3f18afd..60f6e4d 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -378,6 +378,10 @@ internal enum Result { , labels : [(String,Int)] , output : String ) + case InsufficientCoverage(numTests : Int + , labels : [(String,Int)] + , output : String + ) } internal indirect enum Either { @@ -594,13 +598,24 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei } internal func doneTesting(st : CheckerState) -> Result { - if st.hasFulfilledExpectedFailure { - print("*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + if !st.hasFulfilledExpectedFailure { + if insufficientCoverage(st) { + print("+++ OK, failed as expected. ") + print("*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + } + printDistributionGraph(st) - return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .NoExpectedFailure(numTests: st.successfulTestCount, labels: summary(st), output: "") + } else if insufficientCoverage(st) { + print("*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .InsufficientCoverage(numTests: st.successfulTestCount, labels: summary(st), output: "") } else { + print("*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .NoExpectedFailure(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") } } @@ -808,6 +823,12 @@ private func pluralize(s : String, i : Int) -> String { return s + "s" } +private func insufficientCoverage(st : CheckerState) -> Bool { + return st.labels + .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) + .reduce(false, combine: { $0 || $1 }) +} + extension Array { private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index 2b8f8c9..af9f64f 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -15,6 +15,8 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) + case .InsufficientCoverage(_, _, _): + XCTFail("Property coverage insufficient.") default: return } @@ -27,6 +29,8 @@ public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) + case .InsufficientCoverage(_, _, _): + XCTFail("Property coverage insufficient.") default: return } diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 9d65714..6e63bcd 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -23,6 +23,8 @@ func ==(l : Property, r : Property) -> Bool { return true case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): return true + case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): + return true default: return false } @@ -79,6 +81,10 @@ class PropertySpec : XCTestCase { return true } + property("Cover reports failures properly") <- forAll { (s : Set) in + return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 60, label: "large") + }.expectFailure + property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in let p = p2 ==> p1 if case .Success(_, _, _) = quickCheckWithResult(CheckerArguments(name: ""), p) { From bbba6b8be0134e248aed841e2d30b91ac1d63d59 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 01:52:02 -0700 Subject: [PATCH 255/460] Bump to 0.5.0 --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 45b5bd3..8cdab5b 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.4.4" + s.version = "0.5.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 24caf53158a66a9bd03d1efeb273456f19997553 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 01:52:09 -0700 Subject: [PATCH 256/460] Add missing piece of documentation --- SwiftCheck/Modifiers.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 05de49a..979bbc3 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -334,6 +334,8 @@ extension IsoOf : CustomReflectable { } } +/// By default, SwiftCheck generates values drawn from a small range. `Large` +/// gives you values drawn from the entire range instead. public struct Large> : Arbitrary { public let getLarge : A From c9e3a6bc86d3a4f2ff0e0fe3361822a2043cc977 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 01:52:17 -0700 Subject: [PATCH 257/460] Shut the stupid build log up --- SwiftCheckTests/PropertySpec.swift | 86 +++++++++++++++++++----------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 6e63bcd..e8fb592 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -8,35 +8,65 @@ @testable import SwiftCheck +// From http://stackoverflow.com/a/4832902/945847 +func shutup(f : () -> T) -> T { + var bak : Int32 = 0 + var bake : Int32 = 0 + var new : Int32 = 0 + var newe : Int32 = 0 + fflush(stdout) + fflush(stderr) + bak = dup(1) + bake = dup(2) + new = open("/dev/null", O_WRONLY) + newe = open("/dev/null", O_WRONLY) + dup2(new, 1) + dup2(newe, 2) + close(new) + close(newe) + let res = f() + fflush(stdout) + fflush(stderr) + dup2(bak, 1) + dup2(bake, 2) + close(bak) + close(bake) + return res +} + func ==(l : Property, r : Property) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) - let res2 = quickCheckWithResult(CheckerArguments(name: ""), r) - - switch (res1, res2) { - case (.Success(_, _, _), .Success(_, _, _)): - return true - case (.GaveUp(_, _, _), .GaveUp(_, _, _)): - return true - case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): - return true - case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): - return true - case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): - return true - case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): - return true - default: - return false + return shutup { + let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) + let res2 = quickCheckWithResult(CheckerArguments(name: ""), r) + + switch (res1, res2) { + case (.Success(_, _, _), .Success(_, _, _)): + return true + case (.GaveUp(_, _, _), .GaveUp(_, _, _)): + return true + case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): + return true + case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): + return true + case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): + return true + case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): + return true + default: + return false + } } } func ==(l : Property, r : Bool) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) - switch res1 { - case .Success(_, _, _): - return r == true - default: - return r == false + return shutup { + let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) + switch res1 { + case .Success(_, _, _): + return r == true + default: + return r == false + } } } @@ -82,16 +112,12 @@ class PropertySpec : XCTestCase { } property("Cover reports failures properly") <- forAll { (s : Set) in - return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 60, label: "large") + return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") }.expectFailure property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in let p = p2 ==> p1 - if case .Success(_, _, _) = quickCheckWithResult(CheckerArguments(name: ""), p) { - return (p1 ==== true) ^||^ (p ^&&^ p1 ^&&^ p2) - } else { - return (p1 ==== false) ^||^ (p ^&&^ p1 ^&&^ p2) - } + return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) } property("==> Short Circuits") <- forAll { (n : Int) in From 58433d65d39ff2c64bb6968ed43233d1d25341d0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 02:05:07 -0700 Subject: [PATCH 258/460] whoops --- SwiftCheckTests/PropertySpec.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index e8fb592..760cba8 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -19,10 +19,10 @@ func shutup(f : () -> T) -> T { bak = dup(1) bake = dup(2) new = open("/dev/null", O_WRONLY) - newe = open("/dev/null", O_WRONLY) dup2(new, 1) - dup2(newe, 2) close(new) + newe = open("/dev/null", O_WRONLY) + dup2(newe, 2) close(newe) let res = f() fflush(stdout) From c1b31bfc44e4497d72d2eec38cfee09b0193a5a4 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 02:29:48 -0700 Subject: [PATCH 259/460] Try the nuclear option --- SwiftCheck/Check.swift | 11 ++++- SwiftCheck/Property.swift | 13 +++++ SwiftCheck/State.swift | 7 ++- SwiftCheck/Test.swift | 75 +++++++++++++++------------- SwiftCheckTests/PropertySpec.swift | 78 +++++++++--------------------- 5 files changed, 94 insertions(+), 90 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index da77883..cdbb0ee 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -99,13 +99,20 @@ public struct CheckerArguments { /// it becomes too small the samples present in the test case will lose diversity. let maxTestCaseSize : Int + internal let silence : Bool + public init(replay : Optional<(StdGen, Int)> = nil , maxAllowableSuccessfulTests : Int = 100 , maxAllowableDiscardedTests : Int = 500 , maxTestCaseSize : Int = 100 ) { - self = CheckerArguments(replay: replay, maxAllowableSuccessfulTests: maxAllowableSuccessfulTests, maxAllowableDiscardedTests: maxAllowableDiscardedTests, maxTestCaseSize: maxTestCaseSize, name: "") + self = CheckerArguments( replay: replay + , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: maxAllowableDiscardedTests + , maxTestCaseSize: maxTestCaseSize + , name: "" + ) } internal init(replay : Optional<(StdGen, Int)> = nil @@ -113,6 +120,7 @@ public struct CheckerArguments { , maxAllowableDiscardedTests : Int = 500 , maxTestCaseSize : Int = 100 , name : String + , silence : Bool = false ) { @@ -121,6 +129,7 @@ public struct CheckerArguments { self.maxAllowableDiscardedTests = maxAllowableDiscardedTests self.maxTestCaseSize = maxTestCaseSize self.name = name + self.silence = silence } internal var name : String diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 5ead1e9..1942a78 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -533,6 +533,19 @@ private func addLabels(result : TestResult) -> TestResult -> TestResult { } } +private func printLabels(st : TestResult) { + if st.labels.isEmpty { + print("(.)") + } else if st.labels.count == 1, let pt = st.labels.first { + print("(\(pt.0))") + } else { + let gAllLabels = st.labels.map({ (l, _) in + return l + ", " + }).reduce("", combine: +) + print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index b45ec13..d9d29b1 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -51,6 +51,9 @@ public struct CheckerState { let quantifier : Quantification let arguments : CheckerArguments + + let silence : Bool + public init( name : String , maxAllowableSuccessfulTests : Int , maxAllowableDiscardedTests : Int @@ -66,7 +69,8 @@ public struct CheckerState { , failedShrinkStepCount : Int , shouldAbort : Bool , quantifier : Quantification - , arguments : CheckerArguments) + , arguments : CheckerArguments + , silence : Bool) { self.name = name self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests @@ -84,5 +88,6 @@ public struct CheckerState { self.shouldAbort = shouldAbort self.quantifier = quantifier self.arguments = arguments + self.silence = silence } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 60f6e4d..ee5b4e4 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -405,7 +405,8 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R , failedShrinkStepCount: 0 , shouldAbort: false , quantifier: .Universal - , arguments: args) + , arguments: args + , silence: args.silence) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, caseGen: modP.unProperty.unGen) } @@ -492,7 +493,8 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort , quantifier: quantifier - , arguments: st.arguments) + , arguments: st.arguments + , silence: st.silence) return .Right(nstate) // Discard case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort, let quantifier): @@ -511,16 +513,17 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort , quantifier: quantifier - , arguments: st.arguments) + , arguments: st.arguments + , silence: st.silence) return .Right(nstate) // Fail case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): if quantifier == .Existential { // print("") } else if !expect { - print("+++ OK, failed as expected. ", terminator: "") + printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") } else { - print("*** Failed! ", terminator: "") + printCond(st.silence, "*** Failed! ", terminator: "") } // Failure of an existential is not necessarily failure of the whole @@ -541,7 +544,8 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort , quantifier: quantifier - , arguments: st.arguments) + , arguments: st.arguments + , silence: st.silence) /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { @@ -588,7 +592,8 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei , failedShrinkStepCount: st.failedShrinkStepCount , shouldAbort: abort , quantifier: quantifier - , arguments: st.arguments) + , arguments: st.arguments + , silence: st.silence) return .Left((stat, nstate)) } default: @@ -600,8 +605,8 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei internal func doneTesting(st : CheckerState) -> Result { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { - print("+++ OK, failed as expected. ") - print("*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "+++ OK, failed as expected. ") + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -609,11 +614,11 @@ internal func doneTesting(st : CheckerState) -> Result { printDistributionGraph(st) return .NoExpectedFailure(numTests: st.successfulTestCount, labels: summary(st), output: "") } else if insufficientCoverage(st) { - print("*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) return .InsufficientCoverage(numTests: st.successfulTestCount, labels: summary(st), output: "") } else { - print("*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -703,7 +708,8 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts , failedShrinkStepCount: failedShrinkStepCount , shouldAbort: st.shouldAbort , quantifier: st.quantifier - , arguments: st.arguments) + , arguments: st.arguments + , silence: st.silence) return reportMinimumCaseFound(state, res: lastResult) } @@ -711,8 +717,8 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In let testMsg = " (after \(st.successfulTestCount.successor()) test" let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" - print("Proposition: " + st.name) - print(res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } @@ -722,9 +728,9 @@ internal func reportExistentialFailure(st : CheckerState, res : Result) -> Resul case let .ExistentialFailure(_, _, _, reason, _, _, lastTest): let testMsg = " (after \(st.discardedTestCount) test" - print("*** Failed! ", terminator: "") - print("Proposition: " + st.name) - print(reason + pluralize(testMsg, i: st.discardedTestCount) + "):") + printCond(st.silence, "*** Failed! ", terminator: "") + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") dispatchAfterFinalFailureCallbacks(st, res: lastTest) return res default: @@ -733,6 +739,10 @@ internal func reportExistentialFailure(st : CheckerState, res : Result) -> Resul } internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { + guard !st.silence else { + return + } + res.callbacks.forEach { c in switch c { case let .AfterTest(_, f): @@ -744,6 +754,10 @@ internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { } internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { + guard !st.silence else { + return + } + res.callbacks.forEach { c in switch c { case let .AfterFinalFailure(_, f): @@ -765,19 +779,6 @@ private func labelPercentage(l : String, st : CheckerState) -> Int { return (100 * occur.count) / st.maxAllowableSuccessfulTests } -internal func printLabels(st : TestResult) { - if st.labels.isEmpty { - print("(.)") - } else if st.labels.count == 1, let pt = st.labels.first { - print("(\(pt.0))") - } else { - let gAllLabels = st.labels.map({ (l, _) in - return l + ", " - }).reduce("", combine: +) - print("(" + gAllLabels[gAllLabels.startIndex.. String { return (n < 10 ? " " : "") + "\(n)" + "%" } @@ -800,13 +801,13 @@ private func printDistributionGraph(st : CheckerState) { let all = covers + allLabels if all.isEmpty { - print(".") + printCond(st.silence, ".") } else if all.count == 1, let pt = all.first { - print("(\(pt))") + printCond(st.silence, "(\(pt))") } else { - print(":") + printCond(st.silence, ":") all.forEach { pt in - print(pt) + printCond(st.silence, pt) } } } @@ -829,6 +830,12 @@ private func insufficientCoverage(st : CheckerState) -> Bool { .reduce(false, combine: { $0 || $1 }) } +private func printCond(cond : Bool, _ str : String, terminator : String = "\n") { + if !cond { + print(str, terminator: terminator) + } +} + extension Array { private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index 760cba8..c782c7f 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -8,65 +8,35 @@ @testable import SwiftCheck -// From http://stackoverflow.com/a/4832902/945847 -func shutup(f : () -> T) -> T { - var bak : Int32 = 0 - var bake : Int32 = 0 - var new : Int32 = 0 - var newe : Int32 = 0 - fflush(stdout) - fflush(stderr) - bak = dup(1) - bake = dup(2) - new = open("/dev/null", O_WRONLY) - dup2(new, 1) - close(new) - newe = open("/dev/null", O_WRONLY) - dup2(newe, 2) - close(newe) - let res = f() - fflush(stdout) - fflush(stderr) - dup2(bak, 1) - dup2(bake, 2) - close(bak) - close(bake) - return res -} - func ==(l : Property, r : Property) -> Bool { - return shutup { - let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) - let res2 = quickCheckWithResult(CheckerArguments(name: ""), r) - - switch (res1, res2) { - case (.Success(_, _, _), .Success(_, _, _)): - return true - case (.GaveUp(_, _, _), .GaveUp(_, _, _)): - return true - case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): - return true - case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): - return true - case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): - return true - case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): - return true - default: - return false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) + + switch (res1, res2) { + case (.Success(_, _, _), .Success(_, _, _)): + return true + case (.GaveUp(_, _, _), .GaveUp(_, _, _)): + return true + case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): + return true + case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): + return true + case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): + return true + case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): + return true + default: + return false } } func ==(l : Property, r : Bool) -> Bool { - return shutup { - let res1 = quickCheckWithResult(CheckerArguments(name: ""), l) - switch res1 { - case .Success(_, _, _): - return r == true - default: - return r == false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + switch res1 { + case .Success(_, _, _): + return r == true + default: + return r == false } } From 4e4498994117ee2f2608f95df59b80e9aee8626a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 8 Jan 2016 02:55:54 -0700 Subject: [PATCH 260/460] Make InsufficientCoverage fail on the right line --- SwiftCheck/TestOperators.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index af9f64f..ae7c8a4 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -16,7 +16,7 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) case .InsufficientCoverage(_, _, _): - XCTFail("Property coverage insufficient.") + XCTFail("Property coverage insufficient.", file: checker.file, line: checker.line) default: return } @@ -30,7 +30,7 @@ public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { case .NoExpectedFailure(_, _, _): XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) case .InsufficientCoverage(_, _, _): - XCTFail("Property coverage insufficient.") + XCTFail("Property coverage insufficient.", file: checker.file, line: checker.line) default: return } From d2989fa202aaf49aa3b423a7a9d046ddecc35c63 Mon Sep 17 00:00:00 2001 From: Sam Ritchie Date: Fri, 22 Jan 2016 23:25:06 +0800 Subject: [PATCH 261/460] Don't build tests on Run & Analyze --- .../xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index 689429b..e559f2e 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -22,10 +22,10 @@ + buildForAnalyzing = "NO"> + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -66,11 +66,11 @@ Date: Fri, 22 Jan 2016 16:40:56 -0500 Subject: [PATCH 262/460] Add Carthage config again --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 57f75f4..2704295 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,16 @@ osx_image: xcode7.2 env: - TEST_CONFIG="RELEASE" - TEST_CONFIG="PODS" + - TEST_CONFIG="CARTHAGE" -before_install: true +before_install: +- brew update +- brew install carthage install: true script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' ; fi + - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage build --no-skip-current; fi - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi notifications: webhooks: From ad38a5511c551a2487897c2da59e2bc6c6504dc7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 24 Jan 2016 14:30:48 -0500 Subject: [PATCH 263/460] Add a new test/check style test suite for Rose trees --- SwiftCheck.xcodeproj/project.pbxproj | 8 ++++ SwiftCheckTests/RoseSpec.swift | 62 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 SwiftCheckTests/RoseSpec.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 7c31ab0..692580c 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -44,6 +44,9 @@ 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; + 82575B231C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; + 82575B241C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; + 82575B251C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; @@ -154,6 +157,7 @@ 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; + 82575B221C55524A00F0CD54 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoseSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; @@ -304,6 +308,7 @@ 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, + 82575B221C55524A00F0CD54 /* RoseSpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */, @@ -593,6 +598,7 @@ 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */, 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */, 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */, + 82575B251C55524A00F0CD54 /* RoseSpec.swift in Sources */, 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */, 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */, @@ -635,6 +641,7 @@ 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, + 82575B231C55524A00F0CD54 /* RoseSpec.swift in Sources */, 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, @@ -677,6 +684,7 @@ 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, + 82575B241C55524A00F0CD54 /* RoseSpec.swift in Sources */, 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */, 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, diff --git a/SwiftCheckTests/RoseSpec.swift b/SwiftCheckTests/RoseSpec.swift new file mode 100644 index 0000000..cd2153d --- /dev/null +++ b/SwiftCheckTests/RoseSpec.swift @@ -0,0 +1,62 @@ +// +// RoseSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 1/24/16. +// Copyright © 2016 Robert Widmann. All rights reserved. +// + +import SwiftCheck + +extension Rose { + var root : A { + switch self.reduce { + case let .MkRose(root, _): + return root() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var children : [Rose] { + switch self.reduce { + case let .MkRose(_, children): + return children() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var collapse : Rose { + let children = self.children + + let vs = children.map { $0.collapse } + let cs = children.flatMap({ $0.children }).map { $0.collapse } + + return .MkRose({ self.root }, { vs + cs }) + } +} + +class RoseSpec : XCTestCase { + private static func intRoseTree(v : Int) -> Rose { + return .MkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + } + + private static func depthOneChildren(rose : Rose) -> [A] { + return rose.children.map { $0.root } + } + + private static func depthOneAndTwoChildren(rose : Rose) -> [A] { + let topChildren = rose.children + let vs = topChildren.map { $0.root } + let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) + return vs + cs + } + + func testAll() { + property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in + let tree = RoseSpec.intRoseTree(i) + return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) + } + } +} From 3cab31a00aec2d4be8f6bf80742a67989c63d748 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 24 Jan 2016 14:32:15 -0500 Subject: [PATCH 264/460] Add more examples to simple spec and simplify ComplexSpec --- SwiftCheck/Check.swift | 12 ++++++------ SwiftCheck/TestOperators.swift | 2 +- SwiftCheckTests/ComplexSpec.swift | 16 ++++------------ SwiftCheckTests/SimpleSpec.swift | 19 +++++++++++++++++++ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index cdbb0ee..15bcded 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -34,17 +34,17 @@ /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func property(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { +public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } public struct AssertiveQuickCheck { let msg : String - let file : String + let file : StaticString let line : UInt let args : CheckerArguments - private init(msg : String, file : String, line : UInt, args : CheckerArguments) { + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line @@ -55,17 +55,17 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : String = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { +public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } public struct ReportiveQuickCheck { let msg : String - let file : String + let file : StaticString let line : UInt let args : CheckerArguments - private init(msg : String, file : String, line : UInt, args : CheckerArguments) { + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index ae7c8a4..d93d4b2 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -126,4 +126,4 @@ public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } -@exported import XCTest +@_exported import XCTest diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 5bb4284..36ab706 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -34,7 +34,7 @@ class ComplexSpec : XCTestCase { let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) - let emailGen = wrap3 <^> localEmail <*> Gen.pure("@") <*> hostname <*> Gen.pure(".") <*> tld + let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) property("Generated email addresses contain 1 @") <- forAll(emailGen) { (e : String) in return e.characters.filter({ $0 == "@" }).count == 1 @@ -49,7 +49,7 @@ class ComplexSpec : XCTestCase { hexDigits.proliferateSized(4).map{ String.init($0) + ":" }, ]) - let ipGen = { $0.initial } <^> (wrap2 <^> ipHexDigits <*> ipHexDigits <*> ipHexDigits <*> ipHexDigits) + let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 @@ -59,16 +59,8 @@ class ComplexSpec : XCTestCase { // MARK: String Conveniences -private func wrap(l : String) -> String -> String -> String { - return { m in { r in l + m + r } } -} - -private func wrap2(l : String) -> String -> String -> String -> String { - return { m in { m2 in { r in l + m + m2 + r } } } -} - -private func wrap3(l : String) -> String -> String -> String -> String -> String { - return { m in { m2 in { m3 in { r in l + m + m2 + m3 + r } } } } +func glue(parts : [Gen]) -> Gen { + return sequence(parts).map { $0.reduce("", combine: +) } } extension String { diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index cbae1f7..49e8294 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -52,6 +52,25 @@ class SimpleSpec : XCTestCase { property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in return i.x == i.x && i.y == i.y } + + property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in + return + (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) + || + (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) + } + + let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ + ((>), (<=)), + ((<), (>=)), + ((==), (!=)), + ]) + + property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in + return forAll { (x : UInt8, y : UInt8) in + return op(x, y) ==== !iop(x, y) + } + } } } From 74994c0ff25ff6aa2c1ef23731aeaffad077f0bc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 28 Jan 2016 16:23:15 -0500 Subject: [PATCH 265/460] Prepare for migration to Swift 3 --- .travis.yml | 7 ++--- README.md | 4 +-- SwiftCheck/Arbitrary.swift | 2 ++ SwiftCheck/Gen.swift | 2 +- SwiftCheck/Lattice.swift | 1 - SwiftCheck/Property.swift | 32 +++++++++++------------ SwiftCheck/Random.swift | 7 +++-- SwiftCheck/Test.swift | 27 ++++++++++--------- SwiftCheck/TestOperators.swift | 2 +- SwiftCheck/Witness.swift | 14 +++++----- SwiftCheck/WitnessedArbitrary.swift | 24 ++--------------- SwiftCheckTests/BooleanIdentitySpec.swift | 1 + SwiftCheckTests/ComplexSpec.swift | 7 +++-- SwiftCheckTests/DiscardSpec.swift | 1 + SwiftCheckTests/FailureSpec.swift | 3 ++- SwiftCheckTests/GenSpec.swift | 1 + SwiftCheckTests/LambdaSpec.swift | 1 + SwiftCheckTests/ModifierSpec.swift | 1 + SwiftCheckTests/PropertySpec.swift | 1 + SwiftCheckTests/ReplaySpec.swift | 1 + SwiftCheckTests/RoseSpec.swift | 1 + SwiftCheckTests/ShrinkSpec.swift | 1 + SwiftCheckTests/SimpleSpec.swift | 1 + SwiftCheckTests/TestSpec.swift | 1 + 24 files changed, 68 insertions(+), 75 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2704295..02e1614 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,14 @@ language: objective-c -osx_image: xcode7.2 +osx_image: xcode7.3 env: - TEST_CONFIG="RELEASE" - TEST_CONFIG="PODS" - TEST_CONFIG="CARTHAGE" -before_install: -- brew update -- brew install carthage install: true script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' ; fi + - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -verbose test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' ; fi - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage build --no-skip-current; fi - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi notifications: diff --git a/README.md b/README.md index beaf9a8..dab9062 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ property("Shrunken lists of integers always contain [] or [0]") <- forAll { (l : return (!l.getArray.isEmpty && l.getArray != [0]) ==> { let ls = self.shrinkArbitrary(l).map { $0.getArray } return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) - }() + } } ``` @@ -236,7 +236,7 @@ with custom generators as simple as possible: ```swift let onlyEven = Int.arbitrary.suchThat { $0 % 2 == 0 } -let vowels = Gen.fromElementsOf(["A", "E", "I", "O", "U" ]) +let vowels = Gen.fromElementsOf([ "A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index bc1368a..6d8043c 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -348,3 +348,5 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { } return acc } + +import Darwin diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 254fcc5..7b63108 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -359,7 +359,7 @@ public func promote(x : Rose>) -> Gen> { /// Promotes a function returning generators to a generator of functions. public func promote(m : A -> Gen) -> Gen B> { return delay().flatMap { (let eval : Gen -> B) in - return Gen B>.pure({ x in eval(m(x)) }) + return Gen B>.pure(eval • m) } } diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index de4a9e5..281c872 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -90,7 +90,6 @@ extension AnyRandomAccessIndex : LatticeType { } } - /// float.h does not export Float80's limits, nor does the Swift Standard Library. // rdar://18404510 //extension Swift.Float80 : LatticeType { diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 1942a78..b1a23f9 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -449,10 +449,6 @@ internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { } } -private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { - return { protect(exception("Exception"), x: r) } -} - internal func id(x : A) -> A { return x } @@ -461,27 +457,31 @@ internal func • (f : B -> C, g : A -> B) -> A -> C { return { f(g($0)) } } -internal func insertWith(f : (V, V) -> V, k : K, v : V, var m : Dictionary) -> Dictionary { - let oldV = m[k] - if let existV = oldV { - m[k] = f(existV, v) - } else { - m[k] = v - } - return m +private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { + return { protect(exception("Exception"), x: r) } } internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l - l.forEach { (k, v) in - map.updateValue(v, forKey: k) - } r.forEach { (k, v) in - map.updateValue(v, forKey: k) + if let val = map.updateValue(v, forKey: k) { + map.updateValue(f(val, v), forKey: k) + } } return map } +private func insertWith(f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { + var res = m + let oldV = res[k] + if let existV = oldV { + res[k] = f(existV, v) + } else { + res[k] = v + } + return res +} + private func sep(l : String, r : String) -> String { if l.isEmpty { return r diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index efaac3e..abea254 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -6,8 +6,7 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import func Darwin.time -import func Darwin.clock +import Darwin /// Provides a standard interface to an underlying Random Value Generator of any /// type. It is analogous to `GeneratorType`, but rather than consume a @@ -181,7 +180,7 @@ extension Int64 : RandomType { let b = genhi - genlo + 1 let q : Int64 = 1000 - let k = Int64.subtractWithOverflow(h, l).0 + 1 + let k = Int64.subtractWithOverflow(h, Int64.addWithOverflow(l, 1).0).0 let magtgt = k * q func entropize(mag : Int64, _ v : Int64, _ g : G) -> (Int64, G) { @@ -195,7 +194,7 @@ extension Int64 : RandomType { } let (v, rng_) = entropize(1, 0, gen) - return (l + (v % k), rng_) + return (l + (v % (k == 0 ? Int64.min : k)), rng_) } } } diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index ee5b4e4..459743f 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -106,49 +106,49 @@ public func forAll(pf : (A throws -> Testable)) -> Property { /// shrinker and generator for 2 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B) throws -> Testable) -> Property { - return forAll({ t in forAll({ b in try pf(t, b) }) }) + return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c in try pf(t, b, c) }) }) + return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d in try pf(t, b, c, d) }) }) + return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e in try pf(t, b, c, d, e) }) }) + return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) + return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) + return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) + return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified @@ -683,14 +683,14 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts // Otherwise increment the tried shrink counter and the failed // shrink counter. - failedShrinkStepDistance++ - failedShrinkStepCount++ + failedShrinkStepDistance = failedShrinkStepDistance.successor() + failedShrinkStepCount = failedShrinkStepCount.successor() default: fatalError("Rose should not have reduced to IO") } } - successfulShrinkCount++ + successfulShrinkCount = successfulShrinkCount.successor() } let state = CheckerState( name: st.name @@ -812,9 +812,10 @@ private func printDistributionGraph(st : CheckerState) { } } -internal func cons(lhs : T, var _ rhs : [T]) -> [T] { - rhs.insert(lhs, atIndex: 0) - return rhs +internal func cons(lhs : T, _ rhs : [T]) -> [T] { + var res = rhs + res.insert(lhs, atIndex: 0) + return res } private func pluralize(s : String, i : Int) -> String { diff --git a/SwiftCheck/TestOperators.swift b/SwiftCheck/TestOperators.swift index d93d4b2..3badaa9 100644 --- a/SwiftCheck/TestOperators.swift +++ b/SwiftCheck/TestOperators.swift @@ -126,4 +126,4 @@ public func ^||^(p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } -@_exported import XCTest +import XCTest diff --git a/SwiftCheck/Witness.swift b/SwiftCheck/Witness.swift index cd350b5..a325444 100644 --- a/SwiftCheck/Witness.swift +++ b/SwiftCheck/Witness.swift @@ -23,47 +23,47 @@ public func forAll(pf : (A -> /// shrinker and generator for 2 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B) -> Testable) -> Property { - return forAll({ t in forAll({ b in pf(t, b) }) }) + return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C) -> Testable) -> Property { - return forAll({ t in forAll({ b, c in pf(t, b, c) }) }) + return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d in pf(t, b, c, d) }) }) + return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e in pf(t, b, c, d, e) }) }) + return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f in pf(t, b, c, d, e, f) }) }) + return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g in pf(t, b, c, d, e, f, g) }) }) + return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { - return forAll({ t in forAll({ b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) }) }) + return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/SwiftCheck/WitnessedArbitrary.swift b/SwiftCheck/WitnessedArbitrary.swift index 636496b..33696c7 100644 --- a/SwiftCheck/WitnessedArbitrary.swift +++ b/SwiftCheck/WitnessedArbitrary.swift @@ -204,26 +204,6 @@ extension HalfOpenInterval where Bound : protocol { } } -extension ImplicitlyUnwrappedOptional where Wrapped : Arbitrary { - public static var arbitrary : Gen> { - return ImplicitlyUnwrappedOptional.init <^> Optional.arbitrary - } - - public static func shrink(bl : ImplicitlyUnwrappedOptional) -> [ImplicitlyUnwrappedOptional] { - return Optional.shrink(bl).map(ImplicitlyUnwrappedOptional.init) - } -} - -extension ImplicitlyUnwrappedOptional : WitnessedArbitrary { - public typealias Param = Wrapped - - public static func forAllWitnessed(wit : A -> Wrapped, pf : (ImplicitlyUnwrappedOptional -> Testable)) -> Property { - return forAllShrink(ImplicitlyUnwrappedOptional.arbitrary, shrinker: ImplicitlyUnwrappedOptional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { public static var arbitrary : Gen> { return LazyCollection.arbitrary @@ -240,13 +220,13 @@ extension Range where Element : protocol> { return Element.arbitrary.flatMap { l in return Element.arbitrary.flatMap { r in - return Gen.pure(Range(start: min(l, r), end: max(l, r))) + return Gen.pure(min(l, r)..) -> [Range] { - return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(Range.init) + return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(..<) } } diff --git a/SwiftCheckTests/BooleanIdentitySpec.swift b/SwiftCheckTests/BooleanIdentitySpec.swift index 31d0ef9..d8954b8 100644 --- a/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/SwiftCheckTests/BooleanIdentitySpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class BooleanIdentitySpec : XCTestCase { func testAll() { diff --git a/SwiftCheckTests/ComplexSpec.swift b/SwiftCheckTests/ComplexSpec.swift index 36ab706..604c07f 100644 --- a/SwiftCheckTests/ComplexSpec.swift +++ b/SwiftCheckTests/ComplexSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest let upper : Gen= Gen.fromElementsIn("A"..."Z") let lower : Gen = Gen.fromElementsIn("a"..."z") @@ -36,9 +37,11 @@ class ComplexSpec : XCTestCase { let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) - property("Generated email addresses contain 1 @") <- forAll(emailGen) { (e : String) in + let args = CheckerArguments(maxTestCaseSize: 10) + + property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in return e.characters.filter({ $0 == "@" }).count == 1 - } + }.once } func testIPv6Properties() { diff --git a/SwiftCheckTests/DiscardSpec.swift b/SwiftCheckTests/DiscardSpec.swift index 0c9e6fe..a6ffc26 100644 --- a/SwiftCheckTests/DiscardSpec.swift +++ b/SwiftCheckTests/DiscardSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class DiscardSpec : XCTestCase { func testDiscardFailure() { diff --git a/SwiftCheckTests/FailureSpec.swift b/SwiftCheckTests/FailureSpec.swift index 1736928..63b3e23 100644 --- a/SwiftCheckTests/FailureSpec.swift +++ b/SwiftCheckTests/FailureSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest enum SwiftCheckError : ErrorType { case Bogus @@ -52,7 +53,7 @@ class FailureSpec : XCTestCase { assert(false, "Assertion should never throw.") } else { // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) - failCount++ + failCount = failCount.successor() } } diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index 729fc0f..c9d9cb3 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class GenSpec : XCTestCase { func testAll() { diff --git a/SwiftCheckTests/LambdaSpec.swift b/SwiftCheckTests/LambdaSpec.swift index cdcd886..46f3a92 100644 --- a/SwiftCheckTests/LambdaSpec.swift +++ b/SwiftCheckTests/LambdaSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { let unName : String diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index d564cdb..a01cfd7 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class ModifierSpec : XCTestCase { func testModifiers() { diff --git a/SwiftCheckTests/PropertySpec.swift b/SwiftCheckTests/PropertySpec.swift index c782c7f..f3ab987 100644 --- a/SwiftCheckTests/PropertySpec.swift +++ b/SwiftCheckTests/PropertySpec.swift @@ -7,6 +7,7 @@ // @testable import SwiftCheck +import XCTest func ==(l : Property, r : Property) -> Bool { let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) diff --git a/SwiftCheckTests/ReplaySpec.swift b/SwiftCheckTests/ReplaySpec.swift index a711d61..96dac68 100644 --- a/SwiftCheckTests/ReplaySpec.swift +++ b/SwiftCheckTests/ReplaySpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class ReplaySpec : XCTestCase { func testProperties() { diff --git a/SwiftCheckTests/RoseSpec.swift b/SwiftCheckTests/RoseSpec.swift index cd2153d..987b64c 100644 --- a/SwiftCheckTests/RoseSpec.swift +++ b/SwiftCheckTests/RoseSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest extension Rose { var root : A { diff --git a/SwiftCheckTests/ShrinkSpec.swift b/SwiftCheckTests/ShrinkSpec.swift index eb63207..58e29ba 100644 --- a/SwiftCheckTests/ShrinkSpec.swift +++ b/SwiftCheckTests/ShrinkSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest class ShrinkSpec : XCTestCase { func shrinkArbitrary(x : A) -> [A] { diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index 49e8294..e1a306f 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest public struct ArbitraryFoo { let x : Int diff --git a/SwiftCheckTests/TestSpec.swift b/SwiftCheckTests/TestSpec.swift index f2a30e4..bb9200a 100644 --- a/SwiftCheckTests/TestSpec.swift +++ b/SwiftCheckTests/TestSpec.swift @@ -7,6 +7,7 @@ // import SwiftCheck +import XCTest extension Dictionary { init(_ pairs : S) { From e132c449aa1e120652edb37ee1db60cfbae47769 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 17 Feb 2016 21:05:31 -0500 Subject: [PATCH 266/460] Add github contribution boilerplate --- .github/CONTRIBUTING.md | 25 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE.md | 35 ++++++++++++++++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 24 ++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..e2542ed --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,25 @@ +We love that you're interested in contributing to this project! + +To make the process as painless as possible, we have just a couple of guidelines +that should make life easier for everyone involved. + +## Prefer Pull Requests + +If you know exactly how to implement the feature being suggested or fix the bug +being reported, please open a pull request instead of an issue. Pull requests are easier than +patches or inline code blocks for discussing and merging the changes. + +If you can't make the change yourself, please open an issue after making sure +that one isn't already logged. + +## Contributing Code + +Fork this repository, make it awesomer (preferably in a branch named for the +topic), send a pull request! + +All code contributions should match our the framework's conventions. When in +doubt, you can look around the project for similar code, or just use [GitHub's +coding conventions](https://github.com/github/swift-style-guide). + +Thanks for contributing! :boom::camel: + diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..8250ae0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,35 @@ +Version +======== + +_Share the git commit hash of the version of the framework that you are using. You can find it by running `git rev-parse HEAD` in the framework directory._ + +Environment +=========== + +_What's your environment? Mac OS X, Linux, or something else?_ + +Description +============ + +_In your own words, briefly describe the issue._ + +Steps To Reproduce +=================== + +_List the actions that will reproduce the issue._ + +Expected Result +================ + +_What was the expected result after running the steps above?_ + +Actual Result +============== + +_What was the actual result after running the steps above?_ + +Additional information +====================== + +_Please provide any additional information that helps debugging, e.g. log output, stack traces, error codes, etc._ + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..97bb481 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ +What's in this pull request? +============================ + +_Briefly describe the contents of this pull request. What did you add, remove, +change?_ + +Why merge this pull request? +============================ + +_Give us a short description of why this is important. For example, future +plans, cleanup, motivations for additional features, etc._ + +What's worth discussing about this pull request? +================================================ + +_Is there any part of this pull request that is especially important, +controversial, or that you're unsure of? We can totally help!_ + +What downsides are there to merging this pull request? +====================================================== + +_If you answered the last question in the affirmative, do you wish to discuss +alternative implementations or have any other overarching concerns?_ + From 99d741cbac6c22ab5b2c9b3c8c4da89fb6cb816f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 17 Feb 2016 21:37:26 -0500 Subject: [PATCH 267/460] Work around swiftc --- SwiftCheck.xcodeproj/project.pbxproj | 10 ++- SwiftCheck/Arbitrary.swift | 2 +- SwiftCheck/Property.swift | 6 +- SwiftCheck/Random.swift | 2 +- SwiftCheckTests/PathSpec.swift | 101 +++++++++++++++++++++++++++ 5 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 SwiftCheckTests/PathSpec.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 692580c..77f5f65 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -47,6 +47,9 @@ 82575B231C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; 82575B241C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; 82575B251C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; + 825794A71C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; + 825794A81C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; + 825794A91C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; @@ -158,6 +161,7 @@ 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; 82575B221C55524A00F0CD54 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoseSpec.swift; sourceTree = ""; }; + 825794A61C6BDAD100BA20EA /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PathSpec.swift; sourceTree = ""; }; 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; @@ -305,8 +309,9 @@ 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */, 8445C4A91B16D37800280089 /* GenSpec.swift */, 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */, - 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, + 825794A61C6BDAD100BA20EA /* PathSpec.swift */, + 84EA2C381B2287200001FB3F /* PropertySpec.swift */, 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, 82575B221C55524A00F0CD54 /* RoseSpec.swift */, 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, @@ -604,6 +609,7 @@ 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */, 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */, 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */, + 825794A91C6BDAD100BA20EA /* PathSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -647,6 +653,7 @@ 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, + 825794A71C6BDAD100BA20EA /* PathSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -690,6 +697,7 @@ 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */, 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, + 825794A81C6BDAD100BA20EA /* PathSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 6d8043c..cbc362f 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -70,7 +70,7 @@ extension IntegerType { } let n = i / 2 return .Some((n, n)) - }, initial: self < 0 ? (self * -1) : self) + }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) } } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index b1a23f9..ae265af 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -437,9 +437,9 @@ private func protectResults(rs : Rose) -> Rose { } } -internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { - return { protect(Rose.pure • exception("Exception"), x: f) } -} +//internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { +// return { protect(Rose.pure • exception("Exception"), x: f) } +//} internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { do { diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index abea254..fe72c47 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -202,7 +202,7 @@ extension Int64 : RandomType { extension UInt : RandomType { public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) return (UInt(truncatingBitPattern: bb), gg) } } diff --git a/SwiftCheckTests/PathSpec.swift b/SwiftCheckTests/PathSpec.swift new file mode 100644 index 0000000..bd556af --- /dev/null +++ b/SwiftCheckTests/PathSpec.swift @@ -0,0 +1,101 @@ +// +// PathSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 2/10/16. +// Copyright © 2016 Robert Widmann. All rights reserved. +// + +import SwiftCheck +import XCTest + +struct Path : Arbitrary { + let unPath : [A] + + private static func pathFrom(x : A) -> Gen<[A]> { + return Gen.sized { n in + return Gen<[A]>.oneOf( + [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } + ).map { [x] + $0 } + } + } + + static var arbitrary : Gen> { + return A.arbitrary >>- { x in + return pathFrom(x).map(Path.init) + } + } +} + +func path(p : A -> Bool, _ pth : Path) -> Bool { + return pth.unPath.reduce(true, combine: { $0 && p($1) }) +} + +func somePath(p : A -> Bool, _ pth : Path) -> Property { + return path({ !p($0) }, pth).expectFailure +} + +struct Extremal> : Arbitrary { + let getExtremal : A + + static var arbitrary : Gen> { + return Gen.frequency([ + (1, Gen.pure(A.min)), + (1, Gen.pure(A.max)), + (8, A.arbitrary) + ]).map(Extremal.init) + } + + static func shrink(x : Extremal) -> [Extremal] { + return A.shrink(x.getExtremal).map(Extremal.init) + } +} + +class PathSpec : XCTestCase { + private static func smallProp>(pth : Path) -> Bool { + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, pth) + } + + private static func largeProp>(pth : Path) -> Property { + return somePath({ x in + return (x < -1000000 || x > 1000000) + }, pth) + } + + func testAll() { + property("Int") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > -1000000) + }, x) + } + + property("Int32") <- forAll { (x : Path) in + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, x) + } + + property("UInt") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > 0) + }, x) + } + + property("UInt32") <- forAll { (x : Path) in + return path({ x in + return (x >= 0 || -100 >= 0) && x <= 100 + }, x) + } + + property("Large Int") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + + property("Large UInt") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + } +} + From 6c1360d1be658703adfb5299e99ea002406ded57 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 18 Feb 2016 20:48:39 -0500 Subject: [PATCH 268/460] Finish documenting the modifiers --- SwiftCheck/Arbitrary.swift | 41 +++++++++++++++++-- SwiftCheck/Modifiers.swift | 44 ++++++++++++++++++-- SwiftCheck/Rose.swift | 3 ++ SwiftCheck/Test.swift | 82 +++++++++++++++++++------------------- 4 files changed, 123 insertions(+), 47 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index cbc362f..85b9ec5 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -25,8 +25,8 @@ /// /// As an example, take the `ArrayOf` implementation of shrink: /// -/// Arbitrary.shrink(ArrayOf([1, 2, 3])) -/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] +/// Arbitrary.shrink(ArrayOf([1, 2, 3])) +/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// /// SwiftCheck will search each case forward, one-by-one, and continue shrinking /// until it has reached a case it deems minimal enough to present. @@ -62,7 +62,7 @@ extension Arbitrary { } extension IntegerType { - /// Shrinks any IntegerType. + /// Shrinks any `IntegerType`. public var shrinkIntegral : [Self] { return unfoldr({ i in if i <= 0 { @@ -75,10 +75,12 @@ extension IntegerType { } extension Bool : Arbitrary { + /// Returns a generator of `Bool`ean values. public static var arbitrary : Gen { return Gen.choose((false, true)) } + /// The default shrinking function for `Bool`ean values. public static func shrink(x : Bool) -> [Bool] { if x { return [false] @@ -88,118 +90,139 @@ extension Bool : Arbitrary { } extension Int : Arbitrary { + /// Returns a generator of `Int` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.choose((-n, n)) } } + /// The default shrinking function for `Int` values. public static func shrink(x : Int) -> [Int] { return x.shrinkIntegral } } extension Int8 : Arbitrary { + /// Returns a generator of `Int8` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) } } + /// The default shrinking function for `Int8` values. public static func shrink(x : Int8) -> [Int8] { return x.shrinkIntegral } } extension Int16 : Arbitrary { + /// Returns a generator of `Int16` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) } } + /// The default shrinking function for `Int16` values. public static func shrink(x : Int16) -> [Int16] { return x.shrinkIntegral } } extension Int32 : Arbitrary { + /// Returns a generator of `Int32` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) } } + /// The default shrinking function for `Int32` values. public static func shrink(x : Int32) -> [Int32] { return x.shrinkIntegral } } extension Int64 : Arbitrary { + /// Returns a generator of `Int64` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.choose((Int64(-n), Int64(n))) } } + /// The default shrinking function for `Int64` values. public static func shrink(x : Int64) -> [Int64] { return x.shrinkIntegral } } extension UInt : Arbitrary { + /// Returns a generator of `UInt` values. public static var arbitrary : Gen { return Gen.sized { n in Gen.choose((0, UInt(n))) } } + /// The default shrinking function for `UInt` values. public static func shrink(x : UInt) -> [UInt] { return x.shrinkIntegral } } extension UInt8 : Arbitrary { + /// Returns a generator of `UInt8` values. public static var arbitrary : Gen { return Gen.sized { n in return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } } } + /// The default shrinking function for `UInt8` values. public static func shrink(x : UInt8) -> [UInt8] { return x.shrinkIntegral } } extension UInt16 : Arbitrary { + /// Returns a generator of `UInt16` values. public static var arbitrary : Gen { return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } } + /// The default shrinking function for `UInt16` values. public static func shrink(x : UInt16) -> [UInt16] { return x.shrinkIntegral } } extension UInt32 : Arbitrary { + /// Returns a generator of `UInt32` values. public static var arbitrary : Gen { return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } } + /// The default shrinking function for `UInt32` values. public static func shrink(x : UInt32) -> [UInt32] { return x.shrinkIntegral } } extension UInt64 : Arbitrary { + /// Returns a generator of `UInt64` values. public static var arbitrary : Gen { return Gen.sized { n in Gen.choose((0, UInt64(n))) } } + /// The default shrinking function for `UInt64` values. public static func shrink(x : UInt64) -> [UInt64] { return x.shrinkIntegral } } extension Float : Arbitrary { + /// Returns a generator of `Float` values. public static var arbitrary : Gen { let precision : Int64 = 9999999999999 @@ -217,6 +240,7 @@ extension Float : Arbitrary { } } + /// The default shrinking function for `Float` values. public static func shrink(x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { @@ -229,6 +253,7 @@ extension Float : Arbitrary { } extension Double : Arbitrary { + /// Returns a generator of `Double` values. public static var arbitrary : Gen { let precision : Int64 = 9999999999999 @@ -246,6 +271,7 @@ extension Double : Arbitrary { } } + /// The default shrinking function for `Double` values. public static func shrink(x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { @@ -258,10 +284,12 @@ extension Double : Arbitrary { } extension UnicodeScalar : Arbitrary { + /// Returns a generator of `UnicodeScalar` values. public static var arbitrary : Gen { return UInt32.arbitrary.flatMap(Gen.pure • UnicodeScalar.init) } + /// The default shrinking function for `UnicodeScalar` values. public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } @@ -269,21 +297,25 @@ extension UnicodeScalar : Arbitrary { } extension String : Arbitrary { + /// Returns a generator of `String` values. public static var arbitrary : Gen { let chars = Gen.sized(Character.arbitrary.proliferateSized) return chars >>- (Gen.pure • String.init) } + /// The default shrinking function for `String` values. public static func shrink(s : String) -> [String] { return [Character].shrink([Character](s.characters)).map(String.init) } } extension Character : Arbitrary { + /// Returns a generator of `Character` values. public static var arbitrary : Gen { return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) } + /// The default shrinking function for `Character` values. public static func shrink(x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) @@ -291,18 +323,21 @@ extension Character : Arbitrary { } extension AnyForwardIndex : Arbitrary { + /// Returns a generator of `AnyForwardIndex` values. public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyForwardIndex.init) } } extension AnyRandomAccessIndex : Arbitrary { + /// Returns a generator of `AnyRandomAccessIndex` values. public static var arbitrary : Gen { return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyRandomAccessIndex.init) } } extension Mirror : Arbitrary { + /// Returns a generator of `Mirror` values. public static var arbitrary : Gen { let genAny : Gen = Gen.oneOf([ Bool.arbitrary.map(asAny), diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 979bbc3..7e5d756 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -52,12 +52,16 @@ /// that wish to have no description to print, Blind will create a default /// description for them. public struct Blind : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying value. public let getBlind : A public init(_ blind : A) { self.getBlind = blind } + /// A default short description for the blind value. + /// + /// By default, the value of this property is `(*)`. public var description : String { return "(*)" } @@ -80,12 +84,14 @@ extension Blind : CoArbitrary { /// Guarantees test cases for its underlying type will not be shrunk. public struct Static : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying value. public let getStatic : A public init(_ fixed : A) { self.getStatic = fixed } + /// A textual representation of `self`. public var description : String { return "Static( \(self.getStatic) )" } @@ -104,7 +110,10 @@ extension Static : CoArbitrary { /// Generates an array of arbitrary values of type A. public struct ArrayOf : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying array of values. public let getArray : [A] + + /// Retrieves the underlying array of values as a contiguous array. public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getArray) } @@ -113,6 +122,7 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { self.getArray = array } + /// A textual representation of `self`. public var description : String { return "\(self.getArray)" } @@ -138,7 +148,11 @@ extension ArrayOf : CoArbitrary { /// Generates a sorted array of arbitrary values of type A. public struct OrderedArrayOf> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying sorted array of values. public let getOrderedArray : [A] + + /// Retrieves the underlying sorted array of value values as a contiguous + /// array. public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getOrderedArray) } @@ -147,6 +161,7 @@ public struct OrderedArrayOf> : Arbitrary, C self.getOrderedArray = array.sort() } + /// A textual representation of `self`. public var description : String { return "\(self.getOrderedArray)" } @@ -163,12 +178,14 @@ public struct OrderedArrayOf> : Arbitrary, C /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying dictionary of values. public let getDictionary : Dictionary public init(_ dict : Dictionary) { self.getDictionary = dict } + /// A textual representation of `self`. public var description : String { return "\(self.getDictionary)" } @@ -190,12 +207,14 @@ extension DictionaryOf : CoArbitrary { /// Generates an Optional of arbitrary values of type A. public struct OptionalOf : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying optional value. public let getOptional : A? public init(_ opt : A?) { self.getOptional = opt } + /// A textual representation of `self`. public var description : String { return "\(self.getOptional)" } @@ -220,12 +239,14 @@ extension OptionalOf : CoArbitrary { /// Generates a set of arbitrary values of type A. public struct SetOf> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying set of values. public let getSet : Set public init(_ set : Set) { self.getSet = set } + /// A textual representation of `self`. public var description : String { return "\(self.getSet)" } @@ -260,6 +281,7 @@ extension SetOf : CoArbitrary { public struct PointerOf : Arbitrary, CustomStringConvertible { private let _impl : PointerOfImpl + /// Retrieves the underlying pointer value. public var getPointer : UnsafePointer { return UnsafePointer(self._impl.ptr) } @@ -268,6 +290,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { return self._impl.size } + /// A textual representation of `self`. public var description : String { return self._impl.description } @@ -281,10 +304,12 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { public struct ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { private let _impl : ArrowOfImpl + /// Retrieves the underlying function value, `T -> U`. public var getArrow : T -> U { return self._impl.arr } - + + /// A textual representation of `self`. public var description : String { return self._impl.description } @@ -303,18 +328,21 @@ extension ArrowOf : CustomReflectable { } } -/// Generates two isomorphic Swift function from T to U and back again. +/// Generates two isomorphic Swift functions from `T` to `U` and back again. public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { private let _impl : IsoOfImpl + /// Retrieves the underlying embedding function, `T -> U`. public var getTo : T -> U { return self._impl.embed } + /// Retrieves the underlying projecting function, `U -> T`. public var getFrom : U -> T { return self._impl.project } + /// A textual representation of `self`. public var description : String { return self._impl.description } @@ -337,12 +365,14 @@ extension IsoOf : CustomReflectable { /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. public struct Large> : Arbitrary { + /// Retrieves the underlying large value. public let getLarge : A public init(_ lrg : A) { self.getLarge = lrg } + /// A textual representation of `self`. public var description : String { return "Large( \(self.getLarge) )" } @@ -358,12 +388,14 @@ public struct Large> : Arbitr /// Guarantees that every generated integer is greater than 0. public struct Positive> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying positive value. public let getPositive : A public init(_ pos : A) { self.getPositive = pos } + /// A textual representation of `self`. public var description : String { return "Positive( \(self.getPositive) )" } @@ -386,12 +418,14 @@ extension Positive : CoArbitrary { /// Guarantees that every generated integer is never 0. public struct NonZero> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying non-zero value. public let getNonZero : A public init(_ non : A) { self.getNonZero = non } + /// A textual representation of `self`. public var description : String { return "NonZero( \(self.getNonZero) )" } @@ -413,12 +447,14 @@ extension NonZero : CoArbitrary { /// Guarantees that every generated integer is greater than or equal to 0. public struct NonNegative> : Arbitrary, CustomStringConvertible { + /// Retrieves the underlying non-negative value. public let getNonNegative : A public init(_ non : A) { self.getNonNegative = non } + /// A textual representation of `self`. public var description : String { return "NonNegative( \(self.getNonNegative) )" } @@ -438,7 +474,9 @@ extension NonNegative : CoArbitrary { } } -/// Implementation Details + +// MARK: - Implementation Details Follow + private func undefined() -> A { fatalError("") diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 542ec66..2acdd64 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -15,7 +15,10 @@ /// In practice SwiftCheck will minimize the side-effects performed in a given /// `IORose` to printing values to the console and executing callbacks. public enum Rose { + /// A normal branch in the Rose Tree. case MkRose(() -> A, () -> [Rose]) + /// An IO branch in the Rose Tree. That is, a branch that must execute + /// side effects before revealing further structure. case IORose(() -> Rose) /// Case analysis for a Rose Tree. diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index 459743f..1b7457e 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -28,37 +28,6 @@ /// any assertions you could make in `XCTest` will work immediately with the /// framework. -// MARK: - Quantifiers - -/// Below is the method all SwiftCheck properties are based on, `forAll`. It -/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a -/// property holds when the given testing block returns `true` or truthy values, -/// and fails when the testing block returns `false` or falsy values. The -/// testing block is usually used with Swift's abbreviated block syntax and -/// requires type annotations for all value positions being requested. For -/// example: -/// -/// + This is "Property Notation". It allows you to give your properties a -/// | name and instructs SwiftCheck to test it. -/// | -/// | This backwards arrow binds a property name and a property + -/// | to each other. | -/// | | -/// v v -/// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in -/// return -/// (xs.reverse().reverse() == xs) "Reverse on the left" -/// ^&&^ -/// (xs == xs.reverse().reverse()) "Reverse on the right" -/// } -/// -/// Why require types? For one, Swift cannot infer the types of local variables -/// because SwiftCheck uses highly polymorphic testing primitives. But, more -/// importantly, types are required because SwiftCheck uses them to select the -/// appropriate `Gen`erators and shrinkers for each data type automagically by -/// default. Those `Gen`erators and shrinkers are then used to create 100 -/// random test cases that are evaluated lazily to produce a final result. - // MARK: - Going Further /// As mentioned before, SwiftCheck types do not exist in a bubble. They are highly compositional @@ -95,6 +64,37 @@ /// `Modifiers.swift`, and the top half of this very file to learn more about /// the various parts of the SwiftCheck testing mechanism. +// MARK: - Quantifiers + +/// Below is the method all SwiftCheck properties are based on, `forAll`. It +/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a +/// property holds when the given testing block returns `true` or truthy values, +/// and fails when the testing block returns `false` or falsy values. The +/// testing block is usually used with Swift's abbreviated block syntax and +/// requires type annotations for all value positions being requested. For +/// example: +/// +/// + This is "Property Notation". It allows you to give your properties a +/// | name and instructs SwiftCheck to test it. +/// | +/// | This backwards arrow binds a property name and a property + +/// | to each other. | +/// | | +/// v v +/// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in +/// return +/// (xs.reverse().reverse() == xs) "Reverse on the left" +/// ^&&^ +/// (xs == xs.reverse().reverse()) "Reverse on the right" +/// } +/// +/// Why require types? For one, Swift cannot infer the types of local variables +/// because SwiftCheck uses highly polymorphic testing primitives. But, more +/// importantly, types are required because SwiftCheck uses them to select the +/// appropriate `Gen`erators and shrinkers for each data type automagically by +/// default. Those `Gen`erators and shrinkers are then used to create 100 +/// random test cases that are evaluated lazily to produce a final result. + /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. @warn_unused_result(message="Did you forget to bind this quantifier to a property?") @@ -424,7 +424,7 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R // - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. -internal func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { +private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { var state = st while true { switch runATest(state, caseGen: caseGen) { @@ -465,7 +465,7 @@ internal func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result // // On success the next state is returned. On failure the final result and state // are returned. -internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { +private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split @@ -602,7 +602,7 @@ internal func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Ei } } -internal func doneTesting(st : CheckerState) -> Result { +private func doneTesting(st : CheckerState) -> Result { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { printCond(st.silence, "+++ OK, failed as expected. ") @@ -624,7 +624,7 @@ internal func doneTesting(st : CheckerState) -> Result { } } -internal func giveUp(st: CheckerState) -> Result { +private func giveUp(st: CheckerState) -> Result { printDistributionGraph(st) return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -640,7 +640,7 @@ internal func giveUp(st: CheckerState) -> Result { // slow as hell. This way we stay in one stack frame no matter what and give ARC // a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 // megabytes for truly horrendous tests that used to eat 8 gigs. -internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { +private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") } @@ -713,7 +713,7 @@ internal func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts return reportMinimumCaseFound(state, res: lastResult) } -internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { +private func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { let testMsg = " (after \(st.successfulTestCount.successor()) test" let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" @@ -723,7 +723,7 @@ internal func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (In return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } -internal func reportExistentialFailure(st : CheckerState, res : Result) -> Result { +private func reportExistentialFailure(st : CheckerState, res : Result) -> Result { switch res { case let .ExistentialFailure(_, _, _, reason, _, _, lastTest): let testMsg = " (after \(st.discardedTestCount) test" @@ -738,7 +738,7 @@ internal func reportExistentialFailure(st : CheckerState, res : Result) -> Resul } } -internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { guard !st.silence else { return } @@ -753,7 +753,7 @@ internal func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { } } -internal func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { guard !st.silence else { return } @@ -812,7 +812,7 @@ private func printDistributionGraph(st : CheckerState) { } } -internal func cons(lhs : T, _ rhs : [T]) -> [T] { +private func cons(lhs : T, _ rhs : [T]) -> [T] { var res = rhs res.insert(lhs, atIndex: 0) return res From 3950b48b96996a2725127fbea6e62555a47b6594 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 18 Feb 2016 21:01:49 -0500 Subject: [PATCH 269/460] Document the Random range --- SwiftCheck/Random.swift | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index fe72c47..fcecffd 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -105,6 +105,13 @@ public func newStdGen() -> StdGen { /// Types that can generate random versions of themselves. public protocol RandomType { + /// Takes a range `(lo, hi)` and a random number generator `G`, and returns + /// a random value uniformly distributed in the closed interval `[lo,hi]`, + /// together with a new generator. It is unspecified what happens if lo>hi. + /// + /// For continuous types there is no requirement that the values `lo` and + /// `hi` are ever produced, but they may be, depending on the implementation + /// and the interval. static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) } @@ -114,13 +121,15 @@ public func randomBound, G : RandomGenener } extension Bool : RandomType { - public static func randomInRange(range: (Bool, Bool), gen: G) -> (Bool, G) { + /// Returns a random `Bool`ean value using the given range and generator. + public static func randomInRange(range : (Bool, Bool), gen: G) -> (Bool, G) { let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) return (x == 1, gg) } } extension Character : RandomType { + /// Returns a random `Character` value using the given range and generator. public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! @@ -132,6 +141,7 @@ extension Character : RandomType { } extension UnicodeScalar : RandomType { + /// Returns a random `UnicodeScalar` value using the given range and generator. public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) return (UnicodeScalar(val), gg) @@ -139,6 +149,7 @@ extension UnicodeScalar : RandomType { } extension Int : RandomType { + /// Returns a random `Int` value using the given range and generator. public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -147,6 +158,7 @@ extension Int : RandomType { } extension Int8 : RandomType { + /// Returns a random `Int8` value using the given range and generator. public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -155,6 +167,7 @@ extension Int8 : RandomType { } extension Int16 : RandomType { + /// Returns a random `Int16` value using the given range and generator. public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -163,6 +176,7 @@ extension Int16 : RandomType { } extension Int32 : RandomType { + /// Returns a random `Int32` value using the given range and generator. public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -171,6 +185,7 @@ extension Int32 : RandomType { } extension Int64 : RandomType { + /// Returns a random `Int64` value using the given range and generator. public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { let (l, h) = range if l > h { @@ -200,6 +215,7 @@ extension Int64 : RandomType { } extension UInt : RandomType { + /// Returns a random `UInt` value using the given range and generator. public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) @@ -208,6 +224,7 @@ extension UInt : RandomType { } extension UInt8 : RandomType { + /// Returns a random `UInt8` value using the given range and generator. public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -216,6 +233,7 @@ extension UInt8 : RandomType { } extension UInt16 : RandomType { + /// Returns a random `UInt16` value using the given range and generator. public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -224,6 +242,7 @@ extension UInt16 : RandomType { } extension UInt32 : RandomType { + /// Returns a random `UInt32` value using the given range and generator. public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -232,6 +251,7 @@ extension UInt32 : RandomType { } extension UInt64 : RandomType { + /// Returns a random `UInt64` value using the given range and generator. public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) @@ -240,6 +260,7 @@ extension UInt64 : RandomType { } extension Float : RandomType { + /// Produces a random `Float` value in the range `[Float.min, Float.max]`. public static func random(rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) let twoto24 = Int32(2) ^ Int32(24) @@ -248,6 +269,7 @@ extension Float : RandomType { return (Float(mask24 & (x)) / Float(twoto24), rng_) } + /// Returns a random `Float` value using the given range and generator. public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { let (l, h) = range if l > h { @@ -260,6 +282,7 @@ extension Float : RandomType { } extension Double : RandomType { + /// Produces a random `Float` value in the range `[Double.min, Double.max]`. public static func random(rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) let twoto53 = Int64(2) ^ Int64(53) @@ -268,6 +291,7 @@ extension Double : RandomType { return (Double(mask53 & (x)) / Double(twoto53), rng_) } + /// Returns a random `Double` value using the given range and generator. public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { let (l, h) = range if l > h { From 1d75b9c94ceb798e7ef386b411a6d2c639a8947b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 18 Feb 2016 21:04:14 -0500 Subject: [PATCH 270/460] Sequence the proper direction --- SwiftCheck/Gen.swift | 12 ++++++------ SwiftCheck/Lattice.swift | 2 ++ SwiftCheck/Rose.swift | 2 +- SwiftCheckTests/GenSpec.swift | 6 ++++++ Tutorial.playground/timeline.xctimeline | 6 ------ script/cibuild | 4 ++-- 6 files changed, 17 insertions(+), 15 deletions(-) delete mode 100644 Tutorial.playground/timeline.xctimeline diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 7b63108..1d9cede 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -325,7 +325,7 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), combine: { y, x in + return ms.reverse().reduce(Gen<[A]>.pure([]), combine: { y, x in return x.flatMap { x1 in return y.flatMap { xs in return Gen<[A]>.pure([x1] + xs) @@ -363,7 +363,11 @@ public func promote(m : A -> Gen) -> Gen B> { } } -internal func delay() -> Gen -> A> { +// MARK: - Implementation Details + +import func Darwin.log + +private func delay() -> Gen -> A> { return Gen(unGen: { r, n in return { g in return g.unGen(r, n) @@ -371,10 +375,6 @@ internal func delay() -> Gen -> A> { }) } -// MARK: - Implementation Details - -import func Darwin.log - private func vary(k : S, _ rng : StdGen) -> StdGen { let s = rng.split let gen = ((k % 2) == 0) ? s.0 : s.1 diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index 281c872..33acf42 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -15,7 +15,9 @@ import Darwin /// a "limit" is flexible, generally custom types that wish to conform to /// `LatticeType` must come with some kind of supremum or infimum. public protocol LatticeType { + /// The lower limit of the type. static var min : Self { get } + /// The upper limit of the type. static var max : Self { get } } diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 2acdd64..9712fa8 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -132,7 +132,7 @@ public func joinRose(rs : Rose>) -> Rose { /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(ms : [Rose]) -> Rose<[A]> { - return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in + return ms.reverse().reduce(Rose<[A]>.pure([]), combine: { n, m in return m.flatMap { x in return n.flatMap { xs in return Rose<[A]>.pure([x] + xs) diff --git a/SwiftCheckTests/GenSpec.swift b/SwiftCheckTests/GenSpec.swift index c9d9cb3..5c7becd 100644 --- a/SwiftCheckTests/GenSpec.swift +++ b/SwiftCheckTests/GenSpec.swift @@ -142,6 +142,12 @@ class GenSpec : XCTestCase { return str.rangeOfString(",") == nil } } + + property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in + return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in + return ss == xs + } + } } func testLaws() { diff --git a/Tutorial.playground/timeline.xctimeline b/Tutorial.playground/timeline.xctimeline deleted file mode 100644 index bf468af..0000000 --- a/Tutorial.playground/timeline.xctimeline +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/script/cibuild b/script/cibuild index 33b5129..1698536 100755 --- a/script/cibuild +++ b/script/cibuild @@ -110,10 +110,10 @@ run_xctool () { if [ -n "$XCWORKSPACE" ] then - xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 + xctool -reporter pretty -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 elif [ -n "$XCODEPROJ" ] then - xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 + xctool -reporter pretty -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 else echo "*** No workspace or project file found." exit 1 From 7fd76e23ded137e0020a39a854a704b89b1e766d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 21 Feb 2016 12:21:22 -0500 Subject: [PATCH 271/460] Try a linux build too --- .swift-version | 1 + .travis.yml | 36 +++++++++++++++++++++++++----------- Package.swift | 9 +++++++++ SwiftCheck/Arbitrary.swift | 6 +++++- SwiftCheck/Gen.swift | 8 ++++---- SwiftCheck/Lattice.swift | 8 ++++++-- SwiftCheck/Random.swift | 8 ++++++-- SwiftCheck/Rose.swift | 4 ++-- 8 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 .swift-version create mode 100644 Package.swift diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..3c18da7 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +swift-2.2-SNAPSHOT-2015-12-22-a diff --git a/.travis.yml b/.travis.yml index 02e1614..a5a8c61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,30 @@ -language: objective-c -osx_image: xcode7.3 env: - - TEST_CONFIG="RELEASE" - - TEST_CONFIG="PODS" - - TEST_CONFIG="CARTHAGE" - -install: true + global: + - LC_CTYPE=en_US.UTF-8 +matrix: + include: + - os: osx + language: objective-c + osx_image: xcode7.3 + - os: linux + language: generic + sudo: required + dist: trusty + before_install: + - curl -sL https://gist.github.com/kylef/5c0475ff02b7c7671d2a/raw/621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash + script: + - . ~/.swiftenv/init + - swift build +git: + submodules: false +before_install: + - git submodule update --init --recursive script: - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi - - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then xcodebuild -verbose test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' ; fi - - if [[ "$TEST_CONFIG" == "CARTHAGE" ]]; then carthage build --no-skip-current; fi - - if [[ "$TEST_CONFIG" == "PODS" ]]; then pod lib lint; fi + - pod lib lint + - set -o pipefail + - script/cibuild SwiftCheck SwiftCheck-iOS + - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' + - carthage build --no-skip-current notifications: webhooks: urls: diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..7984dd2 --- /dev/null +++ b/Package.swift @@ -0,0 +1,9 @@ +import PackageDescription + +let package = Package( + name: "SwiftCheck", + dependencies: [ + .Package(url: "https://github.com/typelift/Operadics.git", Version(0, 2, 0)), + ] +) + diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 85b9ec5..0cb6ede 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -384,4 +384,8 @@ private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { return acc } -import Darwin +#if os(Linux) + import Glibc +#else + import Darwin +#endif diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index 1d9cede..e3b323d 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -325,10 +325,10 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(ms : [Gen]) -> Gen<[A]> { - return ms.reverse().reduce(Gen<[A]>.pure([]), combine: { y, x in - return x.flatMap { x1 in - return y.flatMap { xs in - return Gen<[A]>.pure([x1] + xs) + return ms.reduce(Gen<[A]>.pure([]), combine: { n, m in + return m.flatMap { x in + return n.flatMap { xs in + return Gen<[A]>.pure(xs + [x]) } } }) diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index 33acf42..e99150e 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -7,8 +7,6 @@ // Released under the MIT license. // -import Darwin - /// Lattice types are types that have definable upper and lower limits. For /// types like the `Int` and `Float`, their limits are the minimum and maximum /// possible values representable in their bit- width. While the definition of @@ -103,3 +101,9 @@ extension AnyRandomAccessIndex : LatticeType { // return LDBL_MAX // } //} + +#if os(Linux) + import Glibc +#else + import Darwin +#endif diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index fcecffd..12550e8 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -6,8 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -import Darwin - /// Provides a standard interface to an underlying Random Value Generator of any /// type. It is analogous to `GeneratorType`, but rather than consume a /// sequence it uses sources of randomness to generate values indefinitely. @@ -332,3 +330,9 @@ private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int return 0 } + +#if os(Linux) + import Glibc +#else + import Darwin +#endif diff --git a/SwiftCheck/Rose.swift b/SwiftCheck/Rose.swift index 9712fa8..4b73839 100644 --- a/SwiftCheck/Rose.swift +++ b/SwiftCheck/Rose.swift @@ -132,10 +132,10 @@ public func joinRose(rs : Rose>) -> Rose { /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(ms : [Rose]) -> Rose<[A]> { - return ms.reverse().reduce(Rose<[A]>.pure([]), combine: { n, m in + return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in return m.flatMap { x in return n.flatMap { xs in - return Rose<[A]>.pure([x] + xs) + return Rose<[A]>.pure(xs + [x]) } } }) From 710ae6a9668cbafd94c8117a6dc38e4dc9e98466 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 21 Feb 2016 13:23:04 -0500 Subject: [PATCH 272/460] Remove explicit let bindings --- SwiftCheck/Gen.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/SwiftCheck/Gen.swift b/SwiftCheck/Gen.swift index e3b323d..7ee6235 100644 --- a/SwiftCheck/Gen.swift +++ b/SwiftCheck/Gen.swift @@ -351,22 +351,20 @@ public func liftM(f : A -> R, _ m1 : Gen) -> Gen { /// Promotes a rose of generators to a generator of rose values. public func promote(x : Rose>) -> Gen> { - return delay().flatMap { (let eval : Gen -> A) in + return delay().flatMap { eval in return Gen>.pure(liftM(eval, x)) } } /// Promotes a function returning generators to a generator of functions. public func promote(m : A -> Gen) -> Gen B> { - return delay().flatMap { (let eval : Gen -> B) in + return delay().flatMap { eval in return Gen B>.pure(eval • m) } } // MARK: - Implementation Details -import func Darwin.log - private func delay() -> Gen -> A> { return Gen(unGen: { r, n in return { g in @@ -385,7 +383,7 @@ private func attemptBoundedTry(gen: Gen, _ k : Int, _ bound : Int, _ pred if bound == 0 { return Gen.pure(.None) } - return gen.resize(2 * k + bound).flatMap { (let x : A) -> Gen> in + return gen.resize(2 * k + bound).flatMap { x in if pred(x) { return Gen.pure(.Some(x)) } @@ -416,3 +414,10 @@ private func pick(n : Int, _ lst : [(Int, Gen)]) -> Gen { } return pick(n - k, tl) } + +#if os(Linux) + import Glibc +#else + import Darwin +#endif + From cdec5b741b2dad80cf20033884b2e8af630c52dd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 21 Feb 2016 13:29:40 -0500 Subject: [PATCH 273/460] Remove Operadics dependency in package manager --- .travis.yml | 1 + Package.swift | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a5a8c61..5e0f26f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ matrix: sudo: required dist: trusty before_install: + - git submodule update --init --recursive - curl -sL https://gist.github.com/kylef/5c0475ff02b7c7671d2a/raw/621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash script: - . ~/.swiftenv/init diff --git a/Package.swift b/Package.swift index 7984dd2..3cc0951 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,4 @@ import PackageDescription -let package = Package( - name: "SwiftCheck", - dependencies: [ - .Package(url: "https://github.com/typelift/Operadics.git", Version(0, 2, 0)), - ] -) +let package = Package(name: "SwiftCheck") From cad5446212a7256c6814e82ba110b80ca02f5a24 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 21 Feb 2016 13:47:37 -0500 Subject: [PATCH 274/460] Include limits in Linux Build --- SwiftCheck/Lattice.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/SwiftCheck/Lattice.swift b/SwiftCheck/Lattice.swift index e99150e..5ffc7de 100644 --- a/SwiftCheck/Lattice.swift +++ b/SwiftCheck/Lattice.swift @@ -104,6 +104,13 @@ extension AnyRandomAccessIndex : LatticeType { #if os(Linux) import Glibc + + /// Matches http://www.opensource.apple.com/source/gcc/gcc-934.3/float.h + public var FLT_MAX: Float = 3.40282347e+38 + public var FLT_MIN: Float = 1.17549435e-38 + + public var DBL_MAX: Double = 1.7976931348623157e+308 + public var DBL_MIN: Double = 2.2250738585072014e-308 #else import Darwin #endif From 456914a51d0cd93ce9d36014419e0e97294c961c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Feb 2016 12:54:06 -0500 Subject: [PATCH 275/460] Update to 2.2 --- .swift-version | 2 +- .travis.yml | 4 ++-- SwiftCheck.podspec | 2 +- SwiftCheck/Check.swift | 4 ++-- SwiftCheck/Operators.swift | Bin 0 -> 306900 bytes SwiftCheck/Witness.swift | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) create mode 100644 SwiftCheck/Operators.swift diff --git a/.swift-version b/.swift-version index 3c18da7..09d1e5e 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -swift-2.2-SNAPSHOT-2015-12-22-a +swift-2.2-SNAPSHOT-2016-01-11-a diff --git a/.travis.yml b/.travis.yml index 5e0f26f..c45a75e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,9 +23,9 @@ before_install: script: - pod lib lint - set -o pipefail - - script/cibuild SwiftCheck SwiftCheck-iOS - - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' - carthage build --no-skip-current + - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' + - script/cibuild SwiftCheck SwiftCheck-iOS notifications: webhooks: urls: diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 8cdab5b..07f32a8 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -36,5 +36,5 @@ Pod::Spec.new do |s| s.tvos.deployment_target = "9.0" s.framework = "XCTest" s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } - s.source_files = "SwiftCheck/*.swift", "**/Operadics/*.swift" + s.source_files = "SwiftCheck/*.swift" end diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index 15bcded..94b37c9 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -34,7 +34,7 @@ /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = __FILE__, line : UInt = __LINE__) -> AssertiveQuickCheck { +public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -55,7 +55,7 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = __FILE__, line : UInt = __LINE__) -> ReportiveQuickCheck { +public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } diff --git a/SwiftCheck/Operators.swift b/SwiftCheck/Operators.swift new file mode 100644 index 0000000000000000000000000000000000000000..efbd1b751dd9084885dada41c114cb505aa19bd3 GIT binary patch literal 306900 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%0A+$}WOF=31-?^@Df^i>+W^5rPm=JU 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

{kf3sL|RcrwgE`q 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

{kf3sL|RcrwgE`q z7{HahU|oIu*Mo%$L@KoQVE)|cOKyxz!O10&=$qykGC}x$-hkhD(<)?}vxeeJ)>>EcYJN#-tpnGH2B?kyexj zYtpbZ^g4StmQ5JVcT%-dN6P=1ICYhE$PPYZ#P_WEx|#}c0&JX+92XoRQfA@DY^E=4 zg97S0N3f!zc-vGb8VUp}i)nE0VSB=tzk&f9>X=NA;n#u8<)vXj;$Zo1t-=fGb)4py z6_8#ZCSanu7CSR?1g47_z;NQ(H=?O-w;;B0J$h^|eLHqp5rgHem|PP9|BeVo_-rqU z8}-Xo{K4&p&Ux-P3BZv=7+rYC@`Ah;14mlOIN`ibJ8O4TABWQUqFnVpzLv!#9*~JG zjYLBmRTNp-N4ZH4+mr!8DSB@I7q|RILV0MfWx?J3|53(R(m6GFA?iMnmh+4^F`Ce6 z^rIW>PKs-)XzunIWiX8L1n>2qm;Zr&vTEo}Q4Lwz6OnmKQ4?;f`O$ky-S32x_FScZ zG+^Opp13ha3Zw2&%giz*_}g+p+0!V;mycHB?eDpVW(5xhN5=>n#o0_wNY-memu$aY zA5&c|P?^w}kKUT0uLP8)UspwVAidUz}itkC(4a_e~1V&50+K;xWiysx0k2@C*bGSw|QPUkKj{ZG2^nfuF0D2KAq8p7p7F z6@OOnS$|IW=8|!dJ(OwK$ZsQW&%c#A)AhaBoum#w$@U@u z0!NSoDV4#|)A8d|QUKZc7@_ZN24di+HUieLx!Kq;IrwT|E~S3i0wDawE8c?jirFL1 zG|Z!IwgM>{1uWx%xu(N!&+P$WXVpD`#8O#P)VtMHLZ~oew{>U=q6LxofWJ{wvB++j z>9^38l0a>s{6uKez<@ozAPAJFNoZYZ=vMjz1jl|{m|K7bFuBYO(R!X+j%$putGhB@ zA=kd3^_}FbV!8=cte?UAIUA4IqbF4cs#5));cwV^nW-hr1As7D{kdpwh>A((l%;p< z0d>5QuyV~I2R}WpU*a9!XW}q8%t_%^(Dfn#2G)(}mFYIqE zc)CDS31;bQ&D%n>vcL!31NAGh>H?J4Q@8NM)wg^j<{!>Xa5Z(eOP$cdEy@=n9G9wZV_Kubtm^?;GrAKtJ+!Yt6vzmd!bl6N4WB@;Rw zAW8BA2Rl!K2cqs|8d=Bs89>iE`p)=_Bjd_7@r(j(Fb?tMh~nB)gR^4J$0M+jfHHrh zZOz5-aU#lpqCF>%9`KXabAwRnOAMz=!GH8plmrISj zOpFMC3n>OsLG_IH=jrz6Z>Bn#pNEv`0wlo>)QS~J^m+K_Vh?#;>c>J5J@^i^gpO@Q&{DCW_~A%jO3@!|Y1xGC=EoR$dn3(P~a@U9caCiGW(ALT>PPM*AXBKmLrVGa#~^Ix9w{JopQo0AXm6zmF5rbbi*IUA)gc!OhpIx!!ne1@-w z#~pDt0M-)bA^G+u@x|{T(g?|GVsFMa__?7eKkkV42 zd!~MA{#KZ}7ivk{Q^^%g3e=Z9^On+CmW8gaMGP1bxp=9roPNtt3wH))fIgEqAc5@a zoNKXEb*^k+VTEC~WVDRHH=NT?-K1%Mw9JntgxW2WC|Mf+aJ>NziHALrhp8esdOvBY zhWHcFL3GfEs6e7mH}p+QI72o*+B+eSIpgM-+JQ8CA>J~+_S&~ziB~k`GvQc^Q_!rd zvF-ZoJQOj~I%Vs|UKu_I$!OQ~3-yYvbZCA4J?m`VjuV8Rz^ zGHYY#VB}fWfDm=LU41W3MbYJU7+RhPZQ@_7!0!42{A!;8`=EtYMI#k(>ik!ee$~Ej zWA;JkI!2C|2JwT`M1`;$I4+4p!PQJPJ>3b^fgAMA@s7)b6b*Bu6iJfQ4&#z2mUE9e z%8uNX?4wEIQMYvwRB|jc^MnM0ye=MitMZy{Ood8Fw;XC`1B_r3gcPyLw6lhidnvlaa1{*{@mA^%qVB*rk1LI@!Je-Z^Kl-xRhR0mK&)158eAND#6 zQ;S(ae^VwrJSx}vwVb#l=5qGlhuwW1WZg!Il0xI`|9vGSy}ew4t7zB;9|L{{lnExV zypZENS=a@mJ#Y;Ac9w8^uwP#vSzDjP=jRQ$g`X8c4+f?QwP&gCyYuamUi8*-FBF&e z>j~F%I-XB0Ocpom%1n{}=_)=JzMPk-A=9I7{`Fvj!^1zzbKFqNXy{; z0Go3j>x^1iSk>d4b=L81{P=k)GYJ2msBm3%iqwKn3-nerri>-ta7)onr+qUu zVIxw3^VcL8dH_W=Js9D)4zbMeMm*fR;*>47vXuA8nMAHSBB{t}(yfYv$mjkFF&c5+ z7i_RHe(}8)Fw6I6@>vKnZQO4q3uLNbgtBLX@4W>a)`8UN^RoY`PW)>uT`@)TpG+t5 zez<7!YwtNi8JW)_thcfzFkyHsnm_GtVbhq#<#sP>R0}bo;n?IPS`HauLr)UDBYM|v z#m`*1MI#5n8lsxzc{-K}PP=JNUE6OeNc_M*$}3qWAW}m3hrLJZ z{{k&!6)Xb~F&r`bt$*%@6%sqZq}P&7&%3oC2i>)d*@Xo4MBmd0x*^V#_dLbTNLy$On0)|J4Qe4)`b%fgE8p((K&THQ3j#X|wF5k^T4YeK#pHB&DZ+RM?{hLmykoDl!@X zW}fr~hv^)&s4!hHk!AfouYV)w+vj)M#U(Fg_4bVd0~=(`AsBQXrYg4tTmG$h`DGzm z_{g&bYz^S8icc+PEYa7)ZlwmxXuvPaqaT{JEh~$n?)s2ELmCoZLo_~f^b3kQ9F$%1 zUql>_+e`;$K6ulj|l{}H60mqr{VYc5bWztbU7m!XmLaXk#RF{Q|Sd?0M z*y$Oe?#Kfp#ZIsaxA-zSu8VZ;Ok_93Yz?aC>mLZTDOsaw5+4(BZv9s5#y$^P3OsVT zT64*y^&hh4XdHYeKfKa0(MQcMHp0=n&Yxj>ql>JxEtS@i$qdUmdJgqfs4JMh5Y49k zyJkUUO3m_Ns<(YERN@U-%yn~fZ&z%7ztRTT!3ta|$8bq7Z0fHTliSa3z{}{Qt$WQ2 zBQGFTlLYuNSp27g5!)*79&n1~UFVA-_bJn!TvS&7JZ^0?V7EpkG2Yh6$ihEeZ$a}B zx$e-VFR~R`@E}a^ZhbFMKpu=~1)hzZK?rt9yIe@i64X@FgE~NMQFsEC`!N85;Wt$3 zLKwx?BL1p|T$^6%HNcVWb`IX7^@Q-4wxI=8ru~d7cXF}s6~%~rHCTKRHYnpI<+&;O z%D>#_GX1jj^12cjX0p=WJ_V*dx#S{X&fMxXR@LDdz+0M!$A?u<4nL8*C#l<9nJ$p(}5vU5q`;aZf=F9Kc!LB+bn|=xmBcA?8mBU5x;;ND@8xjy_-J01L$&dKk}|GcAym=Mb z0%Kr6HW}nA7~`gJ{-40)(2LoDfQngb%=E>jFs?R5u-mD=$d+PW3*h{Hcw5A5uu|Mq-qIoEIL1->FX-<#_By#J z0`8e1m05AdZ`S(ihN5m=f|7AHwfaL+N0F=&(^r?1*dHyhM>{2>^}bG4j$H>z7-6H* z-hRji!($)VYW+JSkHILHxS`0U-pna0b5W8aoy7y!23#w9n{9-=&H)dc#6S28(3vXj zUAqfHJp|MdzPPpd7?{DlpvGBKLY45U27yWXw}P0rHo&zOv5D5Z@mb0tcePkeNLcA$ zYAcfT%?HKkoS2NzIeL}@yS~y=cd`QYDlf?}odI)xL6Y)P3ao$awL;})650N z$CU;$u8*Z-J?jS0yr4kHI>2;gVn58__dD0q@*3lDA;6PDL+WBqZ>TOfl+jTkgTV^< z`cpMRqm?|_=lP{~P28vFcOqx8moSNG1>ZA)6SDPM9===IpV%VRkX>F@Jhd9-k!M|J z&&VP*;rEh4w*2mmm{X(LoLJQ5@WacqYoVE*Y9i&~g3sW8wqw{y=(o*`-n)^8W^J!C zMSxSg9){98sf~O5AUvpjwUy3EG#*3jK_7EgVl5khM zD{IYBC7?Fr8DdhUpD&%hta}>pSX1IeNd+SUFD^ZszIvavD z883LC{~#VIauDeKnF2Nfk9Ewy^LID3HyvBup|VK?4$p?K*DHuvj{4Avh6&QzBD;zYTbA&7#Eg+aWCL2voSldZPu#Z?$j#kx14A8uvq?yS}A6k^4(wtooQ6=P!EK= zd_}voZ9nS|CR+D#|6z|~_r{mSEQhbwKin&C$NbpgBv)XFYsEK2J;Q z$H}(=YR2%&qsQDj$8pw&WO>p8TS-eLb+ft4M`;Sin{$E0A0&~{LtPlwroA106d=G(97yZ^C0>S@Ex*# z;iBgmh$*_njjcPlY(R;~ONcQc0K5<)-(KWX*?gcp0@zdX zIGW|z-cfyaya$-9? zU$%cl_9TfWB;zxif#TB&=RG!?sp^SyYn^b83@Pc!n&%y_>re`O^4v$pLFw9t6W@@8u zOAI9gGN3C*9DN15(vatmmN5Iom^Xfpj+v5LVazF9W{At{~mWRYHvHcGb3X?he0dsRK6PRi;_eh-#;kEGdMQh%YI5Odoz~kWQotS9 zAWsygrW0c-x7fIy6gXu8aXhqb;ICs(Te{KLeqj@Q7$=}-slm27EF`%ZmdYo9f8pfI zPoj=|IGZR+C)#acF`lxLWGr42<|mLFXTPoHbC+B35g>N{of`*34-MUK&v(d+8gZ+L#hanSWR z&ieU!Hnc7*VZZ&$+LKj2V(v%EfN*aqKxc-){Wc zhKz*!Sj`KTUKoB%UIrYMe%??DgC67`b|^x`71fWlDAWG_J26pvqXbYzyPDexkrEDj zc>ibxmf9mrH?8J`dBX=t@$DDuR;l^O1*@(4w>TMJ2WCN%IAjJrAeSrcl~Zk>hAbAQ zG0$J)wF$vgO41|-O*Fh%VB9jj)KH2fhB5QWO9`cX`IfjnY)+@VCQWdAggBW>1j2yv z@-d%~l@p=wX3R0!Hy-#fyaTv@J=OwUdMG?JIJ01TsW0=2Wb+Y}Jy!3hI*8c8`Fh>v zpn3W@6`H1RN1aWbPcq6X4q9x0Fv)EVl+-~iMSZuGXshGrDDkEG9nnG8(%h6C7BLlU zW%*zJmi8>SDXmV33jp3F?LRcw`(%(kYf2JaS24)MzZTgzpQT5tI$rWIIgAS#$K=PP zA3KTJ6RpPGSOUipTgH0@rHQ(v-T8z*j}@Kan*+MlG9PZBN0^dD{#Vkqh_@C zz2%+Ov=S%ht9AF(zx+*g8dNq{)5mdzxQOJ{)6!v79Ch8juGHmae?pln6~!$iiT5jN z*B1WNzggh&8p4kJ?)8e?x2zy6k8W4+@$hYK@;IU>xh~f9JtY|!$78p_U^I5+g~p%l zCEkTeq#Gcv$lB`u>CsLj=y>tppkN0IiVXRaM#y``hgVQ4%5@;|3i#UK_a5K@KSVXR zcLt|dM`1 zd*t!mxqE007Ei>6%t(Wl zPhVf2qDGIB210O_%RaWzk$s;o;iMjhrN!nB(_CI)WlwnOOCYKRP)hAA0$PQ;)8x-3WILv+`Z4l{l~-e-%Y#lJpAwG zskIrZn3XB34aCuu=xukQII!}f#$kL0>+Q{=0dCwL*SZ8ct&i9BIyDi}ngwb>xMj`m z)LaOMN!x~`iHhjqs@Al^Y3uKBWQ|xoOPXsRK;&ZlOya%eR zTYKgEo{v$45=&AfX*|kCa_7p(4-BCQfcV1_a5!{A`Syemk0iYPb6v@pyD26f_{P7! z>bjXTBu|`Y+n|bBCLAx(wvswYg3%3o=(*GKMi@zdlYLY}S53g0IO_O%kCo1=taor) z>(7(|w*}@~ckK_>f+qU)Kj(eEoS<|3MB%x)hYsje4eYdE=ry@H0kgL0fcRQc4H`?> z-4kke=cD)X>84Q?{6kxTtk0VM40d$#nZ#~{dIo0Nu4lLRoO3nll-)2?+z==J2=Bu0 zjf4w)P`bcseY+dp_h4*tL1rLOtsF19rS-o+p;#5Z8%` zR42MjG|*Vcs#f(>M6}(NcA3)Zo0PEkU7EoA0f~bn2L_$Tg0APbYuDvDCO5(ELu-KK z(k0F;+pIE5L1!^};xIWk*djP*K-X*Ii~=mudD*VBZ7j%oLHgF5^>STx9u$V4$VQd7 zXso_dWe12)JWulqXp@6@YPWVTx21mWg}JPpN7|g%K_@Na?n9Qlb;V;t(dCc4u=yvk7;ZN9`Yz1TR2@WeN1CcidwT7F#1*R zoCvR8B%Pdv$&+sp&)LPOJEGe#AurCNxFrvmFW7af5Z`anePZ@N$TJZy&Ywuy-+E;awYe z%8c!JUizu=wZp^&uA{UOIg%FsMs<6s=`!tl*zppUv~zs9Q&IkaUutNL`dMk;Kc?gd zg2v=ET&Wc{?=brhU_ke~a}DtVKNvmaCZ5XimLD&vHAi>Dl+prU!vz0*?Upg;{Vlh) z-mK>Q82@il-R~GpODB8&E-F@F0}a|T95`DY#JV+qxJbxmSG`ew8GNIP3ktW{X}lJ@ zQkE>HrP5(LOt#A9DhX(cs*+Hfv}phuo@}#ID)+Z`J0|kFaPn;N z)BPp>ulmzn+y=~n8(-x%;TkN=taq74Cfu;M-E+*b?tNP^>HEPW0;@XoP%Myt{yqI&pqdoa zji1;}o$l248GtWk)*q0f#sd|k6}a%lL(fI5eu>w}m#4@bplwdt=U#amomH)^QC%8> z8)g!eRE#rSGd^8fZRr!XJJbe@s!IFz)@C{U1l*=arMbeuR@7+;8g0htgzk~6b3UgGH8r57ADOYhnBsR;*+qiBkdVK8DA))T_* z#}d25+VX|pvaCF_s|eS>|GH=BLo$A~8J8AL>>~g8zj<08T&QOByw~+;k#l*9C&I0# zzx1AFq?Yk%qsv zb7oA_wQ9{Bm~y=N2LsO`@$3CJcJ4n(qM7KoYuk+P({klK#eDoq}W;tn)OVZ?swW!(ikB$H^0)!826*h>uAb5&F@R*S&VwZz`sr zI*L4$6i#E7eYj%=FO8PvL0ZP2%`2B3_V)f=c1W$kA4Gi659qAwj`+xT?Ar+Le(A3zBf0e2H@w4ObhD%ILFb%x=`+S zSH#x&dK@AC@p|=8<+gV@GF4XY$u4OvGX1h|avp_7Mh9Wlzg*+OJLaZxN|CRVzFmHe zbY}9fC`F;#*DR-4gAc(eI6S#I&@rUl)W_2s_u-$s+zkHPtzTgv|JR$@Os*jPAo(G_ zb1B=oKn;1cOr6essRyt#Aubp`;rJpS)02+0q5misBddVbS2A{DJoaf+jFwSt+wDLP zoF9DIk-`R#w@~h2O4o87`rt?=w6(dUmL(#g8v0ZX0O-AvA~*_8dD&W6lcPYR-exqcF8RWh}OXIcB8Aq|Vy#(~0oeYSP06 zgSMj*V(y-VJCiNJ$`~KV^%+x%ZYuwYwnGW%m7CrGe4z$QSg3UKkpoz^Gs%mL=ZoYQ zi|`VAZ$_$gkK%ntJW2^Vs=odRB^y59s0}S0+n+ZlwFs zufkH-74)*zwLr22YlIzd6DX$W$1+>eMR~a2vu+lc{C|7I8Xq0EBLXh4NY=+qa|G+% z6YnpK_tZ<&nj{Dc56n#&N#)B2*ilpSQTnskztg6U4!(xo|L^C_Y|1rmyOAng)_ZfeZ#RDa6ug!xny-NIKkmo%0h`Ko zv42?K*E(?pP`t7eRAZ@u^JSgImRQ<%zJ`zQ#h}HoZRv@6rc=XyjXn0MYe{l8>Gbz4 zkujI_s{RZF&PvUN;qQ>XM!xDO;*33^pq^Ta(-MD1Q_os+SR3RE9jRv08{fIjWUDHz zz|f+%g}yzOJ)c0JNNd@O+zLqC##XVi|8eyDp6fwqT-|hs z9V^}KZ0+dJ-nUm4T>C9}dbqT!$7P@1LGrU==c@~-4@P7X$XDPK zboy15hE6<7-`IK0#8*rcw^^4}dhn<8)JpEn>b52t{JYdirJH|s=5z-0p~kRu?QP&n z*N;M11%y6f8tRk${`t)&>MYX!`d8W26!V^ff}*~2{f37mM@HueD^Ng#cgR=EVr%`} zDGAkA1yyzCgW_<91^%mPlu7|leu^%3>$YM2A|2&cj<_F%30>Fb(Ywu#Esvs5DA2uB%{hED@@i=Qu9Kk z#ATgD)X{a_i0Cq0r>GTZbnc6eIh&>-{&;}nMeiqO7DI6EzakeB%|W@ho$L|hvB)Cz zEqzn#A$Oe?hxC;nWg9bgyB;WqwUJts#I&O)Wv?Z{-%&X+_3KWt>J21&hBveH}>UNJs~$!wfNuI=XZ#It7Dn6{eoG%xeZY%wBkjc z$pOQ)Wiox>hqT141F!3u;2hb~#MvZJ8qu~76j4D653j5qJp$ifXA9~n$XZYiI>#}y zNiw=l49u&`>tpMor|!cEF(o zQ{8&+Voc{#LI(G3tfz4m5sLHyIWZniRQ(ud1k4-+MMj7Qqh zt~0wS*0Ts;S$x1>|8I}p8-&aI-pamb8t^&<$4)@pOiG^9pqhP#o%J*AAgimDB{MPS zSa3C=6B5-kFMhzk&-Fsp{qe=#!zXdSrz=Y_h7r_w@fM%bl)R}QH2i2;dAnA)kiWPc zAa5<*hmiM_$2GMfI52snjj!za1)@UV3!I9Th8!8;zMj7AO*u+6uY@3cM70bij6>7Y zR1JLJNcJWpSfeqLgrfwmTVgXi{I96yDSA1`aul;iZuyuG9M7*dE~4+aB+s{%&U=W6 z?<&9&LOx+UjI67o|H_;emh;tMW|ZX7;3TH2hsHx0MqzKbF}q|{DJ=9X)z1vulBoJ( z-{;8VB%Pk$A&>1v@$i)XP9YZ;;5ALiAGPhV35olpJ}n$jELrsYd9FxL9h!p>LTyHl zxtmJ3eod@LsJ7ciz;jB)Rymub93*?d{O|PCY-lf&RI6dWw*hCIwObF}Tq(t>2IC7o zGevxQ*ZNk`w@Tyn>9e|@ZHnEZ?yxq2zfq?38gl8Wy!dL6z8v*h+r;*Y%nEc|)BfYt zW~FLjPg%l&%_PsNILyCDY)%QDnA<1g`6IhM1^cc}KfN<8nhFpEDJ#$sD|)1UoJ_;m zOcdqBn*-ZHnU298Qy*-YK!Ko;Z>w2$xAGi7$j3ONtDVF6=cd{AS<5c;Q421xSKn1} zQe>x(Izc%8sDarGs{Om_f9c$ga&=vvH~2m4?2)-U--LPc_)~6%%;id) zPpRyl*OW+a>W;lZKsUEJ&S?2x%mWUUXP{4m+1WJ&V*KD>V1Xks$(KnEZNmT&zl)O4)RpzM@A_Sxq0?UdNGFm9_h<*15!-0M)% zd_1o+~3?01~IM+p_ zm?9f?&=+zwnLet;!VWkzIaQ%|`|^UNaFwYQE2Nn;JB<;VCvDd6Xx04JM`Tyt%7lj+qXPjJD%HPsKI+ zJIp4`f+^lFNQo1?nk;OUY-6PzQA`P-C$MI@oH@+MpYvY$doo0A!TYT<7=19>@T}Ee z6r1^ed_IWpaTnJMBhS9J%uC4v)3$SF4>Q)_c3GCnm!)L2hTncSL=!sHjaj-!%TflN zZn1us-+HJss@vwAM?0RpAMvrXXvFwE@A$=kJ9y$rPpR)rQ{oRFW|vBMN{Kbf z!<)faHrp2oV+EzQt-Vxy{f#_RvFoLCY%>5m|z7&t)m zLv{s+W9Wi~2H@wo61LcR-8E2$<-L&2Xue*8k8^h#*HnH|7`O$7&C`5mKKo_%vZN>N z7S<2C#_u4!@^&)gRPfz^b?89@X7wTj8uP_>2pw7XtJ{aaumm41GwF@{(o89{gXn&$ zi7Sqe6EW#A+E zqJ88gd+k#hY(qF_J|Pu5*^%`bowv@Uf6O;WlF`;awH#~5 z&~1Og>;3)_o&NYIdW5MFL*)5GMGX)^hMAp$pV`(O-pIP%SMrk6=(D^chH>{fGBZ2M zEplkmQj(O^|1Q4DS2l>^12)em>Yi!Ae=9asKKIg}yVAmYboSui_S?|hT=v$(F;7+b z4?d-I1_b^-8-q)Ix4qr7Fhl27Ie;R&zGE^n){5sc?u39zr1$z(?HjW^(>~`vdjGz_ zAh&vCWxc*KM&~`wzJV{aGt#9q#avWN+hB{bC)ds;wS0V$9#@^ka>kVV zZf>T!uQ5R>6;JR;WUWy%Dzf2lma)lE;{N_JM?)RtSHlty|LQLY&EJ2H@o*F0z5|;H z{?hi83cHEYbo4TjH?s+bk-MojFEKVD_wqO345Tzk#>7hczn9fr5jub8&znp3A+{@o zi(A12#1W|N+FkC#PhXxhuXz##dtI^b(R7t^)bPOK-PaJWFv5h#k_8|J{Apcc9yW_qh=6}{j>!i3W2ykd2EYbfP%V1E&bK>0Thd_v&b zCU{N{Ucb7SvM4+d>uszF+YCG<6yN>9yz$Gj!xKUWVHC-c4|#sYB8QBYOtO~~YLvd? ze0vo2!|k!wTdTV|?GVr8I0WOYH(AQVx{vZrxypQM-8}9`vWbs3rTZdi8(#7 z+7}=P-W=Z7*%fPvx|gF(J9h`>g8^+l2i|B z`OZ-JZukgp?RDtYr)e8^ppU6%IPTecWScltwx%;LXfo1)E?W_AGr@c?r7@kraS*su zK=}fJ*H@=r4p_l0xuU!yQ>1y^k~ z)Ff3Z58QJmjbj|uKTe&Jd%fg}X_hG-z72cA&@{{MpWXRoyeGv5a{m=q6wb%6FFOOq zbh{1)^|FY0UsL%PJto6nhA#^QJmkosFR5I*WhBFD$mWiontbK{_@!pUC+q5L?Bb}2 z;o=25#4?)`=`B~45yS5AP5c9&LiS+nZC%6xk9}W#Y}^W=H`eIgJ@)4!{WJN#A2(Ff z#v+UON_pPsr8C<8&gayM_xt!m>74B-ZINfE>I0YkEaVjbpqWimGyxtm=1q4L3G6}G zmL`X`QaVY?+C&=#(Jf|7Ts@H+Dh0oFnei7#a5noNBgU38FX2LU)x9wMW0G7yPp?Xo zzYQI^EwYSP!3Z9o+3pL}nU#rY-=Ux~%T{#{U*6~A;Hz`h+JwAmo^=|BnqhtEoPVVO z+90(QuY+1^r#ykbZ9)XE%9Bj$R2T0Mv)$ud>3&4$FyjYTy?$FHg=hQ@eduZu5bM`} zNjnLfnR-a-Fe=6PkL)q0Fv9%)(}v3lr&0Hx+jN6D=ELu_>a}@Z*u0Qi{xu1k7dET> z&Bpn=r$*=Am_z)GQ^P=G&wuGRU*Gg0wz!&oHNHHQN$8eb_9q%(-!>sa`xf8U!4tUC zu~s|5C%({=qx=nyQ{xCb|28-Q8^=(V~0Oo6=e6+j0TkKRW>rO8mnF z=!2wB%oi#ux|Z7UaepVoiXhibzx{t#e45@=b<*oqzpAy)t$rY$)$^oD{ZwgD^;_4e z89_VrThZwg?O6-K0*x7gw?B6#Yxap=oF+Dply4PloH6Ou;MKN22i>+pKnr~k&=k6g z9GW+VLP$FNGnwHC|l<+>`!-|z;sN+DxdAQYc*_cOnO)ukQd@8d$ zQHT}2QzUicxu%CAc(EWL9AVDpLh_VT-BkWK?)rBo2okrF(9&9aLd)IH%e#BLjX-uj z>rvawY`j+}f>Z0YPfzOGl{%@Lr1MVQACkhN$`W-#QcHZrG6Lv{NXQXv%R~@vha}r10d*)4Vp^sVvdSd8sbU zK#!ziW584(xJj+3q(r_-v}4DzTjFP z{)xJl8uMC{Kcn`OFU$H|;X8jd-JgG^Jiq$fAERvXskpC{A959Dyb=y{*U$U>}D21=iZBf2_}tL7ce?N59!u46aylPmr{kyvhhy3d!pI+i4J7}uO? zy42?(YJ%X%j%t_0sTn2(vo8?knR-@15r|BuF0CWz^9Z1l{2!1uc!L^Ap$3L*dQ zae`;{3YwTII=&`B1Eqia+DF^U_k$fru}D9u9PxKIjGS;BC(Tx|ye*&9-`D+mEq_1j zAQ}^6c{Adly@N4Lp@lYL?InvcDt-ZtVefyrS*#ELKx{w|dDrv9U4f)$E00dO4`?p5 zd9LUuq-6cw3fLh$7`?HL;FY*_m_HTY*b>4Do^Pb@{rWZf7LV} z<^E;j)EuF9`uDA8DxqyVso^wRthFb{|NwP#qC@9)@;rE*nF1P3E0Qo zdK^`4kOh}f_kOWC*{g8vKUIQEDhX9J|GlBzuwC8-;W&bnd`_D6U#@n)Bnd?{C9UC~ z>eXD%H@s`hQ+pra)TIk%L{pfqy7qEcB)c)bpU-ga5%4|y0hKlBjjTYIO-uH&F=-Hx zC$`uoz4)zXJZO^?Q+-?s!TJN*_NaHz&Gq9EopeA|$(YdcIyY8^i4|Q~$U7 zNq~pRnjmwW>b@@c;x1{y_rg0h{X7BJllCh8Uw-Jg zZDzyjko!?p)FJZRpwGDp|qz0aTY>HxLWIJ8YL9p#v73 zv6F^R>G)m%kl3!fxAbfMT*cPZdGdzd1-Wzra;U3H*IP59@jvCd=ZpveZvR`qz%?82 zeV(I>HG+ygT%aoA)Xyw*rTm%$#^bZh_TDVTBS%+DSB&U;MdtI_r9$&9jCE>@6qbU|FQR$VNrJ9zxXh8 zNOz}nOV^+@(jXm@N;eEK45HG4geWa3T>{c59a2hnE8Q{FxksPp`~Cg@@6L7uX7+KZ~HN>%vr|aVNkr+j1{;gl^`aO$qFP>-U+OTNz zJp9NMH^nmz#f=v){=qcXCSB(3-BQb&Qz`7$Auj@8VK0LxcEag6^;Rqv-5|Aq$m+GJ zTf;HiF_+(_YVc2HJb0WDBN|u(T$_Pk*dJi(lk~b2^ONNfYO&>4Cn8%^+71IbsaP%= z*hGY?1cw{%+)-e$r8}tv?q=cKd%x3aQ6{$`=oj zSeIkMKSxZJFy8OzT>4Gv`28a~4#TOh9k6E@!x%e{&T_kFKrm60*<>-k)Pu;O{-d=P z{X4R@+5`Pf!!J@5GCxLJ?+bPxy$k0u7-xJo2Lg$}RTbp*&xZw6h?@D=pye(>iEb8y(}k?deicH_5MFM*tKcul+mDxd5digl_Q zlyQ0eD@2iPS+#}oy2ru?t<&Q-dEKXN%qv|lGCYS$Bp!g?lO5*b@++=6PT0o0gSeBYQcfH*=*ox|QD1<8ELSKo5kPc*uJ?oCFRwYzF zSqQLvoTy5tm-nrBYrx|LH|ftVK9zgtHHa=TXWsjAqTDjP8qWWy_GXI1*fsyn!0KRH zhZ{ESV3y1V`V0A4>U!?!!00~c%`0E0-)hjpVUPe>F4bO?HnwPSzeTX$_y%5R9$C@; zUMu-BEe3>0i6~el87>lFNBw!YD46Ehdv6!yWf$P((oS_3w-b2VZ;BpQFmo%%LS2Wq z$mVB655pU|nBBif>|p}>5@bG$zV?x^h?qKTW&5g2Z(jL>GeigOn*S_^GwQ{ItEaEO zw>lb)C3>q)rsO#rSKwkmCX}&`>|VfYXAsxo@K|_1V{2oL%DnhHo*aZFOi89qCg#&7 zDz*302fFERQzaEcUNuFVgEvsjuQb4QDh@*|^UG=N?`JB`7N1P(-xgCwmsVaQ3WELa zj2^Vj`fVOdP6~Z9>ae&Z+|&YLz~yN2;1D@*vWQs0%!1sn!M&gxlf96Y!Kdqi}yq8*1ltz+|Gl?!ZL$s_s2HJ?P8p1CRm9z}6#zcFd{6SM8Eysq61=z(qbFEV5!^`Ky+7?T1 z@j^|6#TpT7yzH}?CHJ(u}>h{f-e zD`fa*kb-2zu^1jA-Sp{)O?#u`wAQ@sm{2OwV@5piE+McC1e`>`D-ybee-t5*&x;PfzUd?fwF26Q54=0!JTRgm8^6O2vJYXyRe{I(z28b+q<{+&CjEsq zJGPWv(WvCx!-1?UgFpmECDHUArEo_S+_rYLP!aL^Dm9d z#I3}g2HjsAE}J#G*f^h?Gd_?U4;ePaw(PIaZj|+0v;QrPsCX#gy%01$UklsJX*M`? zdNBz#lC6oMdMEkaOSp9RD<%pPoC~OnmPiFfn^8)jRQ6zsaH+ zti8s$OLq%b@Ou=F^NZYbRidT1Q~mQBCM_SgclxniCE;?OKffF(6lZm8qgtf>s0bOt zjZ3sC&D>9U-;tOnn_C)XM)>KQA#Li0DEM(cKlDM?JMPqq8-uoIH|jNV0-&+H=*9s> zNb6MnqN;6Ktp`&<^-aO)Y^)!Bmg4D;^Hmuf^sU? zSO4_f^KbKA=?tu8sBO+Nquwv?;a|ug*u25E!pN2*NDqZvp><-3$G1(@BM`fj1}D^O zRqbre5O*CcT@wJu#EbTWObrjdO?cn=l_}vfy#5 z=W~ll;p1o0*Utb|Q&@dz#z+{~KC-MYb+HMU3*V}OI=ukX?D-y?58T6P3O+LpWFOO; z2$K5-x1W?I6hs;P_$juX*!Uo8g1dFYBgJD=@Ypf6pUrN5T}0#95qeC!{2vu2%z#s( zgr}pkWWQ7j>#%g)d3~(g>uOi*`2okE1J;@}`oLh28i-L`H%7gL&1Wa7SDYH9c6|6e z-1~^&DDkxFKheOb*asz6wU4H;jC|+@(USTI{p+PL+S?hd++&J@6rT<>bU&Zc-?C5b zZZaK_wm39V+CJ;&hMvSrHXnW2?uI%6G=A>Bmk(i-3@spXzi(VpMFcX$2QwU4fXv;C zt-cq8B^7ND=vLdO8mH7f?S5`iW_a}esUH<@3G}Dm<`1unKH_#$P~VY)3*(XoBnI9w zl!KU7KG<~4Iv5I@S|MDL`pqL*|ALH)jZeh`GhY=dJYNFqW8vfARST#gzE({F*@K9? zBKskXa8L-Tatz3+*5^<>`&S%lfGpMplP!Orx`eX9&h+*@)+jZ=UDwy`#RRJo5(0~P zqTnYEETHmAwDinOvlES^X0Cwxb_=CYskn6Y)=$uu{=lxwzO`fuk22(Pw4_uLTIdAU zCnABT#P;AQNs^Hn{@m64G3^DqeKcz44}f?4ZuBD~)@S+bOL6!)w$T-d02t>Pno(GI zEpXV(Xr2Qp5?Auyz0F>EA1#!T`_zX%b#8sV?ho_RUReEyj>xC0L&(Jisr(#Zl(Ct&R4Ck$14 zRct92#WlOHldYLt!%a@(>CPDM0{}%Y0!zNtlW3{SX1oQT-RWZN=a;j%^{v3S0aDf< zm`^c+IXM6~1D(#un|l$BOKM;Ffie0;QOO;8-DTJ~Xl#b-3G ztVG?QYBVZ|HVAK1>K_-X`#P>##7&w$^K+cpa8@ljo-ouO~(#SCHkd z1?fi~Ieex0`DH~+;WQ|yCJ2JrPcP^#KHeILVIbSU5(CGhMwys07`Vk%yz_bpNT4PL zm#Scy0TidfBo}db1*8;&RiDH*N-Dy8DkOKW^e>OZB*&R&BGs&D?Lj#?4_o($0r4}x zHFs)}OcqOBrh+357a6bIQVuin=G4BfN5OZfzYL)0%Pbi&FDQMHcrElsys^LCgh&|F zfRN*=suTeAOJ0Os;CcsPs-8-U@X4la71AjUT|@2i-)_SUWm`zbZ};(XzIGTLdKkKU z$9-M;Xj>Mc2yeIz=X!epWMUso?UkE2Y2@{9`noAe#VshG=C&!F?M|LA$TSGAO8-DB zy(gMGLvVR7blq_9bGjnM5Otg8zVqWzsi<4B7l2|s#IxDX__XIE(Dp?1XpoW4iSH=*)f?mS8iHdJDWeE|sq+@cj>?kAD* z>N=;h!B^kU&6_jA9dvF2rD@!6*c4)wst~3p3p_16>1lg8DrwfpUL6cp+xYB9!>4(*w63(vIFR7-RhB696%jZrMjL;g*~w zbU|PuEhYjZMOP`?yW@Z@32QAFk2|L*VgIOGfe@6YIO9U<_BALZqa0Un#m@0ZYHyS9 zw@}C%q=t`L<@0S-59sYyGF(Gs`oU0Hd(=v2A2cnd{Q`OC$HM|J95j7J>Ob7!MJMO)sSXosjoT zlsweV)?=yS)6pv#)SkM>emjw8$&)7f_g$!+RN|@78Z`iMu2*IZ+cor^PRW`3F0M7? zN{temMXx%9JEbcg_GsEN&oR093Km`*e#|p$WkCT-p$(M}>oY#l^gR7|pYRt5rS$!p z&scDJSIVQ9oMI2Wl}g%WqPX=hQY9hn~EJ1MHw4Fn$2=A|x(mSJ26)-o@kSZQH70Y_pH`iI z3Ru#aa}asYa^V}c^Fd7KCZtUbV2XydLc3j3dqjSbFHgu5|LVC1ij<~n*z2};HUY=6 zA7b8!cY;Ge@xSR0T*9eWFi3u$H^(F8Soqk*s}9@2?xZf?ieo@Ac<~!-#T|zD)q@@=B+|AL_mWb7qhI)-`*XlNLuqFQ@hhmtsR5+nQrKD_^OnAR7t#!@2WlLC@KcEX`QUtZ#bYBYY@gh`NT@ zI4vlFE6w%06Q*dVZ(Vch;_Yx-Z|iQs!uKFu(e5#Z<&`=smuj-{H&QiU=mu4W0nw$w zq67g5dt+_Zu-j%KA1jx>9JSm2J3GJE#E;lO^!?+B*J<&!6L(1~5+%atWS;(KU6~?@ z>B{s=_cXWZ;Ia1;7`3HtAB$SmtL1S0Tz&+E%mkEK&ybA)qgy@ejNE5U2e5Z`N2 zzaMNhXII`|^yx46vIu@laVRsWmKE1?>AyVvM#j32FWFjUqglMLLA>VZ(mZOE>4fySlRZm)^8U;rhc2-y$+w>5{nkJVf8*WyRAI)NLAN!VhwtkCJxL)v8 zHp`VCYBr3tcxuOw$qk*hDr)E(TT!GVLW%Vbhu2sSB7_W{`T!A_N1eqMimC$?BVh& zlZQWF6KcW5pN3Sv?lb&2eb|bQdd3yMc_>6u^|DQY%Tn9yb3E;|N1R;QW895n47Cc9 zsujP50O8Ym_JCKNi={;F3-5cH1TEB)GtPTcpT!rxM4BP@ksmvrK5dUKH5=8=k~a&d zA0PRgpTr+ya6gln^4Vy4z19>;U89xl(FN7NoFi@SO1SyR)%;Qbgd^9Pv2W#*71p;B zcQZxd4Sj00+4P27o-w`sTCBG<(gCGlk1Ufy0>Y>WrVIG>!J0tZ=RUUn*<2jgB4V%o z`O#xF+>em#8nm4f{$)dPnhY1xvQT(5;LDpq+*4^o`;%n)sB39OU;*H|JPmwqM=o$E zwBl_Cjkxh_a1~aIJcFkiNEjqR_oX?)#pTAhIP(OT8K%X6j|N#{0iXF826?|A#PSXW zw1p4CZ<;uvlvosikZ9rFvGbwB7if2b%N3vcA9Ku}f^NR!18(CqRrEu3>#|yUgOH&` zB}?e|!*h}h)KGD>bedaYcB!KmkQ{(vtWhM%=tPxIOgPuoUo|a_30Jx` zy~0Y9LpK+Vf5(i>y?s+0r$`HeSI6nNPVw>2OnHCEZzuvuPxotB$Lg)GW~iXte>Y!&S6Qha;% zu=w%xZm!BpNcIxi&ea~LKf!2ADN(x<+?a-__lLUG0bwyM?16D&{aPIMO+=wG1so5H zG!^c3$CG)u#7Qu~wdczna3sjQ)+1A3?IZLWO8c^^B}i)gH_4hV|Te0978trG5}KH;K) z0cQ&f9+rnkwDf$mf2c`!x0$34_prjnF8=$&c(`L)LNiJ_$i_9j_61p0}6h zgT3hTkZd~ekUBqcOVi6|zbbu;<&6m=6aZO&E5M|8ADgEQY@l@^XfS+n&$y&KQ@zLkI%m@`k?{bO$+hS|jR!6>09Yty<# zP^&3#?tB7KJ2gDvp8s-_)H@37+XLVXdC9aL%R>a{43J0FY?F1~f*z8xT6|-tirK5F zXZaqshqGb7hrrtS+Itp9Mr2?bmlz} zgs9njWL%eL!V=P(_82!eXo&AzjGcmFiYd&DTfeGh_q?+UPAGxK#&rdqoX|Pio z_ff{i7wuR{87n&Cw%fdtEW-ohhEv0lACJyz4c`VILW>p}$jB@g5Ox}Ka0b-iH(Xf@ z?;;#tj`{`3t#%H$ZoUEg1crfnTT(;}jZ-fFE>D=;uev2aO^(PntpeT`Y z)WG9~CfmDpoNE3icpLA*S-W@VS_(+6zT)xpt5P~&W~XF>rZIxe28UkRO=nRw`?`79 z?nKCH%@nWpOB6zaRIWDv{HSD8D&(Tb7sR=JpLKP`GF9jRKeGwkt@0|Y9~LG3qyFrg z+Ca9AWK>t(?xB^#L|fnObkSNf!gJtAzoId-l&q)LthE&VDPZ)W2CzdlGVXdIAc`&Z zxVIlWi1oOwV3P2?n3%Mjr|oO_4C+v^Ookt z@%>b*QJT8@E-K?*L%H2dn8Yo8fj9~ts?8dN`E+ZXA}ATRe8OmUjIFd&nAwAE7=DY; zt%*zzVF_m}ae{??%`T`3ni8*ia!adPviUhH^?g(KwZ%TAhp~?eh+0JCJ`0a$-RAfO zKYFHVD}cR31XpE|j-mRqq-qZi!_>3u;Zz6`A0B>A4LF{nSbef7Rde>!ph zqU|${+l=so7T-qg8WGsN;@cHkN7|EnIf~IQ*y7zx+Cw4zK;$5{ZZBlsA_U-IK{)55 zZ+#TAdu?%kp-pdhX77k#g2VB@K9IgLJTy&nR!ZjISDGl4&G>F`gZ;v5uQ`lb`Oa;L zI&o`%hz05mqKE^G@&BA$sh>re1pZ%_=56m*_gN`?O+HsXx<`@y!S3SnmZC7>G~c|b z4yskpG1GP@GQD}%SAV&+Zg>u>Zx_QPZU!LqAZLXkTp77g4F)fxVel$Wu-6xGF?5>Z zOA*LGhT8Vmf>#_w8K_;C>@yJit11A)!4c;qKDW$lC9B^HI!Il%v3~Z9iOj^ z2Rc2!%XKe$of9*qmK`@HRuvS5$sv;fa z?On_5Qp)>#e#FVa>vpzTmx(ZqehR!23bP4*eD+a*7ZKg6Udu%A1ULcsIdQx)It{ED zIx-0*`@+MTq}4Cmi-AIe!TJ=Y5#w+8ZBAlZB{KQlsa)xa*uu*=jYy?8gXUt5Ozw8| zGJOq^a-2MEp|b2e0QQmq67T&&XaDecWgR%laWGAKhUOz2A{tbUFi4Of&cX^mRci}89UV8I&2egP&*Mm> z#V&=#sbM`;mbZx~B770{kTpC%%q&b&*EuUPjc;-0nXo zfJzug;TeYfS`w|&U5Kvy(|8JeZuc9q#-ArC2JpZV?uj?zf*C=`2T1sVV3>b@X4HNN z0H&JwuU|s{6mJK$yMfRke;zdzAen-VNoS6MLI^@Wl%R`ye_Mq^umMMmV>vr_;GdR2 zsGzogiV<=!0Y%wpy}haaX~_z-B=)CspfDRN;A$;ouX57?8==II-Fhd0%0~sCb$}vJ zaE;~v_MXiFaGcbRb(G+5*T|(U3<#c4FU~(?C;}c^HU~>2?B4<5A)z0+^z~<`gd8}) z7!;{gPf-6EgEin^5u%b;zxc};hz=n29Q`Ue4F3>72yB#wQ&z^4{Zl>)nHkklBEI?C z9w?L&7!h)F-oLCP1v-opO8ABO59>M^0m3kNY|;O+Av6c*P&?_Zg4|zjLKu;|!3C|D zxc@0n`U>bUCx#V)@()RZNIm?2Ecidnf=^w&(WQ*>RN!a|{sJmt`v>bEWCBI|mN(CU zi{90YT2p(XwYvLfmpM*IQ6^tfc&o)3MpW)xV1 zX<~7Etyiv%dyU&FccFUF;U5#Eg_W9l~vX@_ZUtrBz|okXF~6;|Lh zrm7R*dO!?v)yD6@t;8kItOop&!bvs4!d0czBt8jdk~&i zqS@SvysATkMf5Pr%Yq4T2vH-D8A2w%aO{XNt>YIwYAQ2?UH5Uu2Q<>fN4Xm<%|=)v zU{oyWy*ope&}VD9;gC5l3;wScxz0 z3!{vcrzDD?KHUS3w!j`B=9KB5Z+nuYpQf`FDMXUv2`oet_R0b}G|iAZrpn>Bn(^co z$9U#66+1%cRK{=5tgL`nE=p(uV}%meqcE3LN&>yl&wZ0C zX>2QM-HA2aWsjJEb8Lv?VzE`s9j2+t_2adB4a-m%I4=fy6rR3HPQngUSe~`AeE9w= z+i9Bgx2;E#0MMQR$k%&InXL3s$F_P#E-Jb@AY|~pAOkf^anHw)NX*q>=wyc0=d^$K4a36|&Z2V7k1>|*XTf}Ym)1#$5o(PL zG6lP<2wNgN&-wRf>b=CcYQVZZf<3e(j?NL%8-Y7IN!c8$zI)yCO3F#0u{rHwTanff z1wq)0nP(!r&itWIwokd)r4;LGO!K6DC4uWpuZ!Kf2i&yrbO2i`3V0sgfoLPJL^#LC z%BB#V_FWD`MP7;}4q+_jxFXtIO8Q-nRSvw*1OskPsmHu#ROC6Tt!98s={J9- z$&2Xdzw*EplFWOY1nk9+1;7HR3#=PY(`SvTP!#B+E9gq?a_Z~29-)8vqDks8Vy~#P zS3K{6G5-~p#^6?dH%cf@=+Q?PWkKqdpM|I2kiv}#aC*%q9f#kJ6qRvH7Ug*daR*ax zU#Ywq3nNDxN5~JX11CVCDum>f!Z+foH{_51RHHzWN?q|yP0Dv?YNR#N`gEpH?z7c5 zsvM3kj{b2{?q^&U_wWV5!0TM&?sK9Yc&{tZKAZoU9i%PJT74p3G-+fLs}h{R>3(UQ zbu}H7_YK>Qn2lD{hN!?yLr38f^R(xI_+X`R_{;q7*#UEx9TWP$Y%u*K(gD|l6lplE zV{G;Unbbsn?M>`tb3C4Q(KtKXe}}90M&9ql^+VWE zdJ@rrhb~5N9s{4qg(ZoyxxN3$xcgdWV?=ZrpkOT#i1P+FzmPrI`oyqxh|1_!=h?dh z=cp{wD-^vEufc`+q#ZWO!Qz?ksr_jDw%6H$ch4Ae$*{gNT8F5hxdZQ2b}a^1AbSv% zvc#CXP#Ux4yO*e;)x>~a8Y|1@-jH{3QLGD~lPd=4yv&jI_FV!lj&vEqf5|z|;iH}@ z!1lW^?>i#wsMq|m=qpVqEG)Q|V|_G*9ef#~Da_Q6dGe7#OxK9%X$^O09n zlsVa9Gx#&S+O{~`4%+j&^gu#08|ey>+R)<8Mg!-zi`)wZ%w67$vQ8=@g3<9&PQ*>p z=Lw=b=dc)5PKLaQurb>Wrcd+P#+c8=O0^O&fd&}wfCkn=@NgGVq4=%m3xQ(iyA*O7 zHV}KX73T+QVj2};#6W#Kkj^*xZAKFpF@P6q_$8)S7=LM~#9&-pHI)2qa2d_S=+}^A zrT7+u^T(I?JU&6Nrp)P2;I$9G0p{FANqBYgKOAE(iI;rU625yzmQt?OJ5u7jcqHGaua!Gvx}pHWX8O#vDy$mq9s^uf|t zjuD6T8JEl_CY|!9Qg~|f^24k7F#dd+lV^~vn4E~P7__#c+iYLOiEK$WI^@vAfl1O% zuTs!5Lp!+#7R2$kXWZLq_n9=OK-_=9q0uJgLDZ-IJAewE3-(_As;Q+Qvxi`LeBKCN7zq6?A{ue47zx#7oVau@xm*O;R1>~`8ziSzw%8B#_+ca z)^Jnj-Ro(77Sz$`TgLOKpaM|DfW#CUVU@Z2C_3rYqw(c*SS5VeUC+5}urbT1u!K1t zL&NZ>>gNjZ?CGfA98LWLMRLe$43AE-6~WcA5C#%7gXJfA7SJ%#sx>hNRA85lxhE#Q z4+f+kW8FvV60?@ur%OvNuolcBv%Nq$5Y@(f~nsQ z4ihxVVMzYR`tC!*eEPhp+S>-NO~;WR1WkdW4n%{MP1V^_0e%(|6w_h-pQ?y{7W^cc zJct)^N7}CY06H$NrUd?0j-e!)30I6Jf3@+Py<@7%W|nh-hg(g&H-1FQ{R118&@&S# zK7(!0rxn9T?G?EKpzB^ndbB8Y0Ngx!L@8u&byH_TD;*|ND`sKukKV!1I9CK%zEydSm)D?~Ugsr<(BN&{|a1UvJE|V};ZS^CI%;e=Ele zl6bRMc=}&H#mm>oz&_yO_f&?Gt{RYgAjixGjJeIm5UVejPd4!$bj&>O_)h_2d5tu*cY=e#1hxS({eichn7moP z?*%N%a^dORT5G?YPmX>O!<<$(Tg>b_?mpscnj!P7HoXoP2>@+K^Z=%o4f?ampQ@EU!x<1vf(y} z!&${4Fny>+8c51s1M*an&>34<)0|f~9++=!eL>-H21&B{xsU#7usC8>x;S2Fml`zI z`gpzPxncijsbfZ;KfwIYd@<#dqumwq$)7AuVGd?qC(LJl+(X)s5p0C^#aj@(G1eVpRuz$7@g8L`QxY^Io= zMEov5;p`KB^j%KELs>$O`+$0N(N3D3tI?xJFpb<}SF=nCky4W=XMW=(faVb?oHnA# z5M~RZ2J}f5h$ee`#FI7Eprpv_kn8dzRv#vcpgCj(`!c&I8FYH~Wacry(KFPiTJ=FW#^$vNtK!1b;oCweAMTAvISb-E z*kOA&_j{}41u?k|7zvU7XgmW5((^3?S@Pr2AAS#}CObANfB02S;ze7k74}yoW$bT% zMkbOsEKv~nV8-}BAX;C!$3%|OjofMs`V(?%V*!7}5sdkT_HPK!0%#Agr29|8BlICM zgpYWt!2WLt|Ihndf6^8};(_$>wr8X0TKQS5)S7)XCd z+M@T~KOz4sz&*}J?wtEKi-AmFuN*#f{Wpt&2F&;?N+oabKUs+tV4LK>DIa9khY6X* z=oH8y`G+JzdKjLu7UsLHGZ+8v?!G<_SJb!lHD1u)z=u%$f!pPZp!hVNf!-iA#rDg3tp^X|oX9*^zOh(?H z>=_6vNC8sOz|a*$n(#p8gwL|P&-3Ty1w8Kj(r7TevxunuD{RtJB77T=fb8?0k2uCK zD{68DL>Niib5JEe`9^l@qog)!6jxMuB4V6vb7c?_XmddEhszMG-r9-X2bvW<1t^UD zmgV0)&EGx3Ly?$lHhGtuIwURDk!r!k08E2>njAeg@Lv9P`=D3L6@^?e%F;Zu^M51i@d^!Ta*}?H z8*lxOm-PPOqbT-$(B*&q%bA+nL z{+pQJ?=H363B(#ljZOR-F!{h#Jj;M{xwPyR^H18IGfmn^u*N|TIMY>u-c@tOc;qNO zHVBl-g51>hEj1<|7~B?LjEfEUcYXMc1%Ln?G7Ze~)LOR3hL7Pl&zo_n5D_$1P5kdp z2-(yi7@fw1l~tq=qQ)N7r|LGgFRkhE!`|QGF03@OM7*I`DY@s?Z5#V zqQMRKw`+}p^?s*8MdqqOiac1TR!g7y2^5pR+&)`Vw(IU|7y_v@Ll1t3YYqfa0!A09 zd=MUR0Nunx&pp|nl=1$;&hJDzObm;FE*b8%U5h_{wR>CjtAQ)`X0T-01?p48&=?yj@Wx}Z1yeRPg@%`1bm;QqO$XOGeS3-O4R8zS`7KZ0kVofJe4eMQ26ur-gsrPkGe8#!H;kll;o6Phsz?&e{-3T1hngE!V$NsnCl0@NDJTb{pUt>mNZ14t|x;e5L)d=NLv=km^ z+mPw?Y3tc2-Q!rYP5%VZ@3qP{rKUy%xxU{-oQ2$6EtF)PU$q7!v;t)e_AQ)%i-MhG z_FMeU?_~CG&lU8UMHJAnC8L zsmICPZ%jgOC8Zn{n=FCv(rwWZPrs_(?wq&O|84R!I9xlMz&@O?LY;z4Jj>E>)9WmU zF#}1#ae2F{Mw~C?DtGx!Ru%3{t)?x zR(D#QlaD*%`Z5wSV!=1g{f7Bx0~M!qe+KRTk<*=zU{V>lRWi{0SytkL*1uG{Ta*1l zos7Ks$*|Qe7CcWYy1yZM`gXGJ&x9O*Z1 zZn!E>L~36C2;r=MxtUqF%-VMIhm4_QFmNk{tV%`LPkk5sAFBejJ`8_H^Jj9}B>*NG zZbH`7Z95w)lJm{F#JXnH46d9_C!7D&uhUsFV{kr~ax=ZHYcB3$3p$ z4V78f*cR;1e5$brf)Fan9*BPNj=|c$^{sWR0tWS=Y4XoeRub0g#pE#G54 z_r&H79N5*WTBn~Z5gRP&Wz9$w%B(S6W?k-mpOCJa(}E=&?=2V{d!ASO<^m^J1`mc6 z^7HSO-ajUgK4_m0^U4Z7_&Ve+>$4bqKCg){b#_w}xZiRP+^4Z1S{bWeF7e1`2V zcE$=KO&fPZ8M8^s1w7Ml4s%o+LA#>q`5(@n{oyeqNkk`K}=wxo@adhEUmqiDA9xwbe3UoiM@F@Pu0P4cK5rp^u|hxtcjt< zFr#*0M#_th-|2q}S}?~50qBfr0y}3Tx^~(nEo-{de>R&OZ_a|JpiM z;IY5?)N&ogUH;`YZs~@wJw5@}Uc+W)TDKIgtYmqbYs={bjoe|Rmf0P$0^+>&yoCX_ zZMuk94xJY^nU~_D$8ygf4h=YiTeX*T!05kRG7nHL-qm+F7(9j@b^3Do%DVOs%)euA zbNLr{MsS=zLT*u;&|5g!6+#g{g3(=LD>RmZ*G}DWpz9uz9OFfMZg&oJ@dN18pc0f2 zEk*CJR098wV*?sjW3e$8xbD747UpDb5?ESOW0CBpb(l}>;WA$$9^A`&qw>N2O)|ch+H33lJA5U8SXI#Yl-2R7xMuF)kaORe=4H?_`#+1ozoKJ<%P}(u^ zOY-?&*M{%jwJ%y0%iDab)Hog^%Pt`-FGQ!!<0Sp`A~B4)H*;Y z+R0a2=CPaOZdRaH+rnl{+h@#%jhc%0zUG>mwG)-f!QvOzk((|0yosCXY=gH$36?Gs zg>tZvue==2zq$LYSX^*2fqvroI!zXo^04nP7fme25BIuHLu~%!R_-!U?y}=hd+B`f_N;zU z-2eL9BYt}P16*tg?@2%GHTj@E2D=*p5K+K?FpA;@n0|)uWy=XYA0GPFq(b*aH^RiX zBJLEWJuCj#IH2m7dhH#Hb>S^x8q=ohgDt;CmFU%uTMx|B&LFZ*WwRCY55i$X)qZ76 zn$FKH`&1WOO}wUzD+Wz#hMvH>B~U}I$6pY{E%F{L9O7c#E%}9<``yjcEF8Q(kF|W< zYbmjmLg;x3VPwGYznHA13+AQdUOjPgRg^vccqCNVc2C)L_FoIW)X7zO<+$CcHX=rk z^RprxfbemOA4e3R3nI`0%0bU)+dNWrUxMl9@JFp}iiGVkhhw|0SOua7jE&v}PSu&8 zRd#1~r!1ODJnOrwkPt4tS=G@;g&RkH3UK#~oc7LD=89R7m>e{e=-h&#t z7`Q35csW}UIKO>+Fo+r|rA$YFcF_Ws#TzL%Ia(e(axX6v_t+RqDKSqe2`>F>p8kTQ z1L*4(&F2p>DAW%W7HBmkkz%%ia)e6AOL5mQU}(P8B&?`B&=8N}AIf)`T5q zlVwUjJl(MOC6PP+Jsj}8(#5fEc_h%(V$Y@sBVFVw-QLx_B7ecSCN^Y57PD+Xrfgfs ztF!dFk$fO?`+CNUE@e*i#zCfRprt&`An-!?XzBJWXnR++e8Q#4A+W6G#P|26v!{q= zt4L&@)?-W4?atB800|=j=dRKpsbUjRB@+JD7d{xY7poOSbJ8%|CG*u`lGg3U?ef5$ ziaSI_h=1N5WeUIm4-^J8E90hbdkEoDPX|Ft?rp#L76!5P^J=O8xSyI4VESL0y}M^F zuG)-k^!BZou$d*V5r?PWe^Fhh!vl&IPeXe+v;Xlw_@L-V@qT@a&WlS*=ttWh5#3V(&|ehn8z`WCkpFOZk;XH0%}THXzAk}o zdss@OPq?&1+Rhly)>gAd3x3*gi@0f8%XY8>U9+*-_BvbZ&~Wgt$zZ}jl_870p2or7 z!=6^g>LKq4K#neFmH3(~HR4yS^$WNX{EnUso=!Ix9>BH1Sq#^^hm+{H6_d>yB5kLk z1VKwSxk-x*?HzE$Bs#`Pb~p;uXtBF6ocq#x#z#WJxq*|gF zNuWEyl;Hr`7}t>O2BkmU_>Vh_jF9-Aqx)K#n~&8`i`BmZU)Bm7f3;7+ymbr)9blRc zx~c)THC+cDmW(MzU>ubgE>#saHRD&LoME_{-`E`9FIXtD&y?(+c4N#hCQ@?6dbYIH z9A>gSTMtNn@g5A20Aj$vc=t$L;e&C+EA)T^G5Xix!mnIKQx) zjs5GP{cE=h|1NHrLuWnSLfPsH1r~w@Ogq%_I`GUrEBwqQ$kDiOUfx%(d|_kF8&9Fv< zS86op2MzVL@Ej6^NpYX2w_Z-;dF~AdS^rL~Xi3-e2z04V+Zwd-%37JW9F%!mgYP8k zw8r`bO0~*=I!uo^Xd&*PnB-gUs-nGKcA6fzAPUt3miG3;qLca7U}6N-`VPlM4guUvy6{7 z=E5ezL7fY;l>|XMHVlDRO$(>xA(zN&3&pydz_Nm4(s*A8W!N?klaTSwvt~B%sK@JV*)`p-cv+IXC=vmmlL#xIqVXN~ zFjk#$f!u)UbBtAGb2{hQyCqc9$c6KRY*(95s770uqS60iZ|tPuaUH%nibh_*@>Un4 zo7C>$KI-lU3`%3Dr!(ln{)`DCWo_K~VVCa*Y*LrTJ_i3EcDD{ObmsdFIK0Y5R_U)t zT_8iW+gg--8ctJT3lA(GG)P$4%ZYc;_yhlX&jf?>(6y|0a#q?ZTp9NAlTVYk)uNY9 zhdu|x`^3#pf^Eym6}i%Tx#a3vPbFi)GzPzbgD3+jV_wkfmljT*=UT6O!-{;&^nX3z zyEXhgZ@9_%%JwYNtfoWDo7lY!7uTOVxkl3sHmM*F&5+OtWlfAv^Vs`qkQQtWku*~^ zXc2r&3ugSh^qsu(Uoi8b#~}#OcqMF=3n@NDIrtsbtFIMN$pq`FoVP9OHE)o+8lz$@ zBmUgY-yuk}ffT!%|D>H22h2Z-TPos&noYuzn+L93qmIn{t_;d3+$S$E>LH{nJ(LnH zTZKy$?HFy~v^{m7x09d=^!s(r%e}AeiuGFf<49dx^G57M)KKFh3rDeSx{w9d z)9m{ksz2Wlb!BM^X|`os&xipN9Cr*pwCzas&%XbN7r-B1^YNbLE72FjnGWRdw+Mzl zm#0V=i_7lTW+2Vtodv1>4}#QHS>wGzvelHB*dz|pojk@BrW0wo!G!ll+u%JeCzeRZ zFtY2*&YDUy!dfxd(FQBROx*lYbXxJ1DG$K_ZloqHTnbuK*ozH7#0AU^JH-h$H1OV~ zm2bwz`A5gVf8>&2yN#eBg2-@Voh7J-2wf<_)hbtC_wjdPqZ(^^9ojzx8`dKX$nO z2m6TwE_eW?oI(QYcl~;N1VlUC2H>i*NRY{=t090>8ROXVU7-B;-x^xi#DQlfc%es= z>rs<9JZ3%0#DzXt;C)HEkB6Y6%6Lbwn~eh4({0^6yxsOZm1%e0ir~g1L1YxDFsKA} zLmmJkd!=;Kl{sbxUMrW83zEM?&kSl- z0^WDv{VjaG`F3^>tGCSmIgH0ie+5X9LC3X~#^>vc8zVpp0mhz;YEv&&Ry`QyVKw;v?8bO{t6kagzzldou~$4&~R2Gn^$1z5?vVdk~fNV6@k( z{yStZ=lEPZ<4P4opQcc}k4vx{xW6tN=IfITX{s5^#X2`wG z^@fPm15GOc8=pbyW^e}@GHzMMU*xknAIzJMyEMQ?22BuccMrVm@q1xOoB4PB{`B1y z<>h|E+Q!KNKz5^SHz{ft_p~-eQijZU(FUcIcla}A8*5IS7MImuJ@`L;*PO(*&rRxm zaPYWnnQ;#0$Up}wBC;y&Iy$dn2;*DfU^a8&3>4vJTxps`&d(J%kn2qi+ zv>QEl7(tiJVZ%RpmqR`ZY3i6iZB>Sdg)HG&0Ge)%ywe-4*VXcPBgLIG?Z8{U;n1K7 z!x6{K(nilA_udA_XhSA`s;RvG|GkYXdzNoUw}e+XT%QN%l-^9$8j21ELDyu<@rr{W zEr>sijCbMddnBB`nOv+5&8$PM?r=lG$5e~6PgG$}#szfjEn;y@$Gsq0TXvQA3p!F) zTI868D9^L>2vY!WDylnQ{&lEdMpT2hU!ZDq{ufT-xVdYZdZwaae@+QwxzxgSUSIsD zJz2VkFqvbvwMGIk?j??v57F^C8PQaHE34s0-r{4!(N;Ks)YaW z?1;}lZT_Ro)3V}G^J2*a*ftA4?WF~KI=tSJ2Qri%|E%5*^7*LX0+uZ5ch^xg^LKQV zIMbgcTCd*uC>fT?9doT8z`kF7-Yvd{?fuj(ogpbD3x|1L^`GHVaQXJJZba0B&mj`V z6={ii=QPYQV%Aqe3e@hoMgnDGCR(8#gqi%j_&xgD&`eWoUjVF0BTYsF!M1qiEgWeE zMwV1lBtzTSGo4ZGHKeZ=n!dhvjj=nE&{B-Oaryjzn~`DBsSShcE#z<5>o?|x5^T7s z=hi3Uj{`vB!>zqh!kY4ZIF=?qfVfH9Fa8d_nO12HaqmcGM0H$LqN|Y@3yaEzCBY+3 zbb^cNPrkH0y$`gikzPum*U-@g!3%l@!)>LmK;b*o%2ebm__9mg^8-p5H#kYQ&&-^y z@%K*8-%UPOu=EaSMwa%=k#tV9I{zGkunIn~1gcTGEX8uL{%bFcnYzAuy~X{-BlUWk zpTnPFs>?5x$_*DQ-m0uM%e#kTL*u6wN}_*Uv8<3iRZcf$Fq1s^!+ZEwY<=C<((2!T zXbdhwG2&Sk$_ia+HMq7e<78@sdgy59BpoGvzCt(FdM#cu!y3gu4>1c0;|{y!!nHot zZReo6v}{v#5o>>qw1rh@mm%b{AGkcxt2W|ID(u)kF;=|o3FjuSX8T>g9>4sT-Q@O& zc4Nwvv2J3hNhha~MYhy+DrC)OrjCSi&J!W^VfH1+@q0-6mD0uyy@e~1Wxq4Te@BDi zpUtn4!Ny&RxC7!-i7LA*Y4X4W%nRS7a_;f84*uGm%_~L;yvH@3z*iVbOGy66=%i}Q zlasUhhgpfjxd$$r?R`S@9?ezfFW6ukk(I)fv8y3w>UwISb$8|^;xT!}^$yu&n6aEo=5R*Ip7%?BT3zG|%I4Wq$ zZOjGDz9FV0*z7Y;;(;OU%_R)GH24N9?x?$&ggIbhwX#Zw)wng`+hn>~3xfML{;e8+IwRoYs~7XEd(#FzDqLV>^V z+?Lg?56*3gV(uCKLeJ<3^hak+%!NP3Pp9P_^MT%<))+VpKYIxu_0CcDeje6gAp0qo zq)NHEa2J`2wo&(=MyIR0VnnG2lUc-v@r(UhF8RfgYz8;Q+tSz)O#RY|xAejy_$vQZ>SRH z(C>F8k7#nmO+>e>=T(;iF3;@&l<3~JiRZn2K zQ{w4n4;!g>P-)>AGhgCB%$Mm9`lRBwcU=pZU~l-fshVf!Ll0mf68f35MsTfny0fw^ zae^pwT3L4KY7H6*vKSp3%d=DTBGynpwCPP=J;wdgO!*VTUbZG$p8Xn!UC549berws zcj|S>yCt+Hon5?mNs~{7E&wWg{WYg@)e*h$&%#s>1@k+RTk|5bmU|>MZ#Oi+FpT&? zGPuR`7kz|dh3BpIAs_VFa`S@$QWVE&o(uc$$q;s{%hLr?{)g91up9IB0$Oe+@rLJ& zcNx8V_L5jLe;6Ujbe6WEpf9jEVyPs@lw4}3*liHqZBw4rU@B?*H2M>EU5|H9V#(Ls z1On2B3>oC3tjRHRzyA`{NU|wytl$oFP(r$RpG73eI;%!oYA8MkVr~WHxp=wtIq8)* zNPChI>)r0U@^}SDH{y<1xaO|TdnKKVT(LKJ_t4Lt9R`S0Po9bIPaNe8q1W<$cfZb?yS^pn;|G;4T?3{uqSv(X!r=!|vg{DZO{dH_62>ANN9Y*y zAzrI4^X+_SoK1ZFEu9JJM~<7 zO_YKwO?a{I3d(e`1tqe5P9ueQDTJ1czx~||ly~G0VxPa^+}4`Lk%=eFnlaXV%t(>w zR|g@+F1ZEouNon|@6L`~hdXH>-gl5Vv_8*g@O;)7k2~liV-dkoxfO-XY3Oeuq3FoK zT2YAA`E%Sv3lD;KQM{K#kEZw_dTHLAyiRxNNwV$r^$p_=j@#RS&%`-iatl*Q;zn8< ze;6A4o_!h{sG1KLBVVAKmD@f`Z>*13w14=RR!QthI$2w&u0T&5AVC&IcO_?u7DFzM znZw#&17hDhj;E?8c-jftM*7lPIwpN=y(&`Zq*wDbL_MmP@A4P1V(3AyN!tH0CIJNM zn7m~b`IY#>{MH}8)9yds!L~;42&mPBf9<0gr0O-uxxPFbfcu`Z+_5F*2mNo5A7das zDF@p)I+c%VirOo5HoB@(=TM2&M)QXnOVQ5&`F?`FRu@OW)03GVi+w)G-o!i9$gGN! zmkO?bvP6o(Gr0GUDC*bnnssuJswLoZUmQU+rLH&3`#O!oQTu|CFx7=#!}MP`cF-N; z3Pp93791~dr3lcFQPxZyL{+l}`TqL$wRx)ED)Pf)aF1Kr6?_3awUVp0PVljIBo%5X)-h{M?Z2xPbz7%4`n# zQhnRPCyxy~#XZEYd86i7*uu$4`#c}qE#6@aF7O^Ul<5PE;bT#hBB+@&;R2XVs5nFGEuL?;AdBg+%sO@>#vzMj_`S>>2j0ABQ_ZOv0uM;{h zD#{w?bcFKSwo(U7={f7Xw5c5gVdBftRxk1K{$B5#-hI-YZoIhT+7Xwl=Ts4xUVqWA z*{ZuGy-XjeYNUv}-znoHWabL#yx?VL!IkNO3aKoaiX!-|DVlrCap>ce$tG?Ma>cgE zWO-oovN&OO{Cf6ArYBQ+k8@zb%&EM$Q&>N?Bdp)fXQHckoMIn2II( zwbmlgMw!cnkM>=T_k&6D-4;C8r;5Q5o&j|B{qSZf?H84TkYL@VgYrZc1c`^95h zvD>*`ShK)#6gTnCf%t>`frHWGkt2*DfAyb$C=nHpZO$+=UV7*EmsrJ)D~~t`)0drf zs>2E2{2fF9R>0DhKHbHWOSyB~^DY@mvA?U@`U?*cb4vPVCgN#LHrJ7Uymn#IzwF1X}mIM#`et>+ zo8-BhdFsxC%o1olonU)m$5TkBd8dg}>;GkCkG7cV_Po9mUX=R=z(t(cvt02oznC8o zoHYjN*jD~8p;8<#R=uOCwhJFAn)Ro(8q(YDvsP^f1| zw=LvdS7@c}Q}fQ9yc7jupqPBCGRi2K5*ezvVVOl}c7BvJw#%8om(HI?#dg4*)~By% z{1Xn~8de4_QB?y=H9%?8-x2R_GIVcdy8EYOlK<)1O$WEXv+jEMiL5 zBgb1M6_;qerN4@HB(-O{0zFq zIr75#%Jbe1J133ubb_tV^M5v@nutBXG&f!pi|!8ZgFW#YWFL2w`|P0>(`wT)i!#bg z10%x%rL4=jD7=-8cK(hD#g7}(?a6aIrkj5TeA7qRj1+9aeho@gB}x+(*;#n{Mh1mR zms=S4r*^b_p=~m!XVR&Q-B}oil~#NhyggFXB1vpFxP=O;_3}{c_BH>|VW#V9IkD0x zSGKddTu~ayC`IM~|fhrwTBxZu8Z?yJnxRY)`pEOF9rd-BJmPXr9I zwAw3lVTpc<^v*>Qyddg8MbRPS_y&hIQMCzrp@@vD03cpody zyjB&28TLQp`Y-1@yyvg@P@_-y<`)Xk27?ym**tkOe*MFbkLl*JL6bm+M(YMjHfaQ` ziVLQn1@|_aH<&TrI<1NkhZAf!*D< z9Y@cghDwWuAN$00vzUQiaiP=RSig<|Vi%3v4DY&>&2WpHbQi9<>GG~NRn;1=3Ff~( zXtEWJDv&)x>egflMI9|00~m@3Q&6WO>*D(<;S_4D0#becJkgJna|2hRg}jqh;6Qa z`D%Lwl)bZrdGcBrz{0jUj@UNUZ^JyFFFBWf-=46RLb%XZgHM@wSUX@&mR;+%=#1$< z8`srN(|Ehbl=ofAZRGD5vn2$QjJ(>o*oAy}ZONauW?gjB?F2bt>mtf3IW|_2+}cwc zfg)8?dkb<}#rdF_07bDcu2DX)i@MfEBg=Am8mWcL?AKJ6IWvT{8AWD@tbe!R1q1)9 zcm2j6^KEX!;m;fYmEm@5nb&QN`SqyZ=;kbI{`x|5QrG88gGuRfyUCw(d0ehml=!iB z-V=MmK~^oag;;ZYDQ?8WxbwLt2$yWd?HJWS?R?3eWXNMf3$|PN{YZuzeV2O^cULAg z@_r-h*ieck@2vGWG|rww+EE;u`_HIWYc%h)#}L>2Cn3nzJs z+W&KAl07yzADGw z=d-kZdsc5X@^L#-?F5RcjN096{3CdQ!Bc6akUHAKr%pGu(C3{2l8kRsw-$1q$9g%`q7=|M;Fu@OWPlWXPm9kg3};yxbCZ&2DdJFz+1USq4+ic-{f;uZ_TuSXSo1 zXzV9841A@CA&^%#_#MoRk$ZNpU5P)08KC9l-O>C&f69Q4?!|@ z)L~)bSY8&TJ2T_nCE^_dkNqfvgso&aL|vKYn)q6F zIxoG$kJcN%J{DF2A3_mW;wI@m8c9AxSs0?cdJ@}KvlaO8JC4 z>CgWp4>h2XqlM(X_Kj}_Y39>YP>Ru?iOIV|;9fO5jh(*9rE}#IS=HsPtdU(MXn4nE z^je@B!>z`p{{^c+6q2DK-KQH_p3#1L76K`jHW(XakF=72&`z+Ood3-&f)w#AJGNpz z#obyKk;b^fF6@9ZxF*;ofo~B@C(XGEb;{jpZNb=Mo54!nzZzVN#7@C6$u^Txd&+MK zW`;FWHx96wNkI)q_}5^u-EI_-Hz$spy>0SHXViL444JXIqd8eWNeaX*Ql`YCTI!eo z_t`E0>vaBf>0`i?Y3}~+5agqe`H5fHh4_=Y*>lRVpkgIuIj@*AxvK2P?iwl>6?nRw zs1{(%G-=r(%>)nVVz9hBUucSbBWHM^(mO2ps|k4 zf~Ru3^NRr_ktkIB1EinW#8BsZuebTD^YcmS5LV&&z|kJVWLN>?3iRlTaM-Q>=Un&t zbT@0UZ*_TxHUL|;BMVFe|IIi{>itgFYTLkA5|4h!SsvT;R&tf3N+*Z+LvyZ+n za}j*sm!UTv*?F+UU*Ha?X*n>`)K;{10nj<)uZ5~F&PWe~lC`QG&0rA4vuX6=Gx1@) zO1JXJfAviuIHWSWQ&w2_eagDs1@bhYm%rP4uSvsMn}_K&$krSrQVj*Rw zLF$`gQe{sRO(5*m>mT~5@jcJ&U9<9%+?wSeo-?cS5^$_&H{uVC)SaK|7ASyU_W-jweOy(Iwc^d_rYK+bv()0 zhUhJE#`Hu3Ui7ORpE>X4;;VzuK)69)+a&4d3x%jTAZd*GtoZAqMO5w)FDbfhvOPdi(-H#sNM zWuT9evuo`8p~3sT@GExy5AMiKO$SHfWCKNLHT;q#GN`iDF5@cPjF+d@59*#sQBbOm z9+M*)b`)*NyLUfwbPkix819jMt_PRlcLIu2pp1Lf%FNPp9;maU2T!OAh>LJL$_M;n z&RQDBD?kdSjBz$JoOqt4|H@6YnJsRgC-R+BZ#0q3xhnS4GYbD#Z>ZEaec=p>J7lXk zg&*+kVM4FpKb#%~adjc)GRGpujmLYG2*DLg3&Jc%b;om;dPnMPP_~DtG!xs{*p5Z5 zJaFjX?&FFOJ9~YW3thaE7-#x&xIZ~TtUZ}dttjd80+#B7g_id+b9!~tK9XN$`VJjM zFdKUqUgrpkrIenw5=pB{a;a*zPXm^-&Xa%fj}#t+)hr-(=V`uz*1&B!&$hSbjowHio$hU z-Q(CC4%4miZYE=v99x)neNZgq?O;oqlvm#|L89pG5SX4TG#`}*K+XR&5h${s}J5ISDl z6Rhj8q&aKH#R%oqjlaya4>1`kY{xx_-rDpMeqAM4u2hXYRB^8@lrgepnHHU>g>&1G#P8COGU22{a8W) z_#Hg3-#eqa4YOgM*jssNnBnJ9jO!lRc@Hegy(Y#UJ4$5yn(r*omKiY~z?X;J{yY%y zNn+cg&PZj1_c?X<2qFVgQ&4DGgLj^nq6Gtug(*d$vRatB+lE`0{UG|fw5>vy1_VGN z2=*o=i@gN{)5L{}XoN@K{xTG?9wHmQc`;aLH8#H z)UGMMW?wq<3@cq9WP7OmACRnT&F4_DKmum>7t`V7Qmi=s=ozQ$Hx{n`IIy|2Pgw%hB0is6vd59OWlcZ(oYi{x z@&Eo!wx;Pd_LZx)FzXxg4?9m(?^>XsUPSL3BSwi7_ni7#7q8~3dWvnFaspyubj`Nj z{n{|#hNAY6JS}|3?d*q!wBDu9Jo1L?s#La=c0mZXAjU7e!?+}>WBj2KGDNh;x!6}m zQ5L=~BQF4v&sWjUzm2X{^k|a?9o1Kl)yS$ugr?1 zEY1IF(MpUMfCa5VAC(mvdo6C~os0}si6&s$6Ew7JdU&nTo6%#Rbairyxs=axaXUs#tT!j3~ z<~4)vlGp$I%d7y=EF$vu$~W86lk?i-8Dl4q%I=2!X5T~HT;>|X=e8q>vsgOCZz&2+ z?3y}WQDhe3pi@DSB# z-aQjybm7u?l^avrg@HtMJ5#1bpB9h-OlELvQ}@G|ZTTLeiF6TIGN&z>;%v%nwr+B` zqbNht6S;o=q)vPsXs+xX0<@@&q7R?7@^1Z??__^mp@xOHy?qw;?&XNz4BB7MSu8n{ zjU4+*30TrgmzdjsnlV=>D(@gj$O@#c(+5KvH}hgM&ZN0Ka(DLa{u)`!cdHc~TVK4q zHG{G^;wZtyLaGIt^JGPrYITa3av+GnQki$2jKNppEB5vKT4@DN=(GOq-Mz1R%tiG& zFUYzxh;RIc)p{??_9e#4*&w*r9CN;xIgiuI;&q((E31-Z(3ZE#B|mSoTfod}Q5&)g4~gTcbNt16s=3rD{-k!%D{<*Sur{6&D4>Gd6(io1YSyk^HW^DP5Hh zdT(+wUJ4*%AgeH}hG{D^BzpgRO!U@YpWY4<>a~tv^is3qSPFBrQ;E~ZqQ-A=@e6eY z-r|C(ncV(z3E{S>nh>0Sr?TOk?X#n`z$cw)D}#Uk0=NnyKay1pw*g0G*-N@`MD#!l zqnf<4*FR;*M_GI>Tm^51#{OjwJL;O}pJPikLAY5RbA)`-fzzTJw;-u zj+)kaI>GEDS+$z^uJ%)(wA90NGsETCE3ECR5p%KC@x1@z)Skbs4+MDLAwPq)`3k?h z>812s7g;tWN?fyMo-AIn_Q|}kR=-{S>}lz7JIgyse9~EZCXIL-L#>kT z9P8jTc2#@k&r+tkU)}tmh%2g`ZAI6a#YW71D86eEjEszlz2JaU$93(ONGUA>M@X7E zbC=87%t=J;gXqOl8fvMRh=00X3N*70YVv|y?6E1uk?D=i-UKc?dD$ zjy})r!(Zv^e9_({E+Bf0t^WyA{W&;P1ef9~6c2+nhKW4VB7v$ln2COm6tSCUXT9;i zL%3f4*2;g_I}@wi>htIyy#k1gU#a(eV)4yg=E&C1_53yK`Vr5meJsF?rYLd(1lh}_ z`Rnw$wq;wkcaGb66+Oo`v^eQ+&MO2Q7h3z$>!41FibB7 zeLeP2zHrw=s_|N1bTB}Oe5bo?X?v>u-3m^>Zx54=&L4Sxi-Ezn-1m+$Ai&+XrsHmb ziyvfX*SIipdULovK_0>$DvNWHTo%)D zc5?PjTYf?6D!2z@X-AGAi||z=Ff!61w<6En7^@A<@V=xBfGE%QwF4Y9enVRnUN?Kx z&BK--DXcf-16=|jODCdfdT0&PpSZ{NTylLi8|i0n4SgZ=DMO?Ik=~KMP3G3+Uix=A z7s#GGI)wx|eomcd4g&gQ&G9|Ur`i{RW+KtVhFaS@sp#a4xY0{( zaQWI0|4IAn{p6F_gS5%hi(npfzSF?TE@cR4@MNPPe|jnZICpmPan3ToLJ(}WT-ey1 ze95!S=6ng2p(uq1+8m2gP11&s=4oD&@8sXND=$^bGDZy^HyPpx|!w@a@KvRU1!U-%GQ>xAXot{UOoiP z*T6Lejmm+r>WN_WAZ2Q#6FAZ_0jXQb*mym}R4|ZQpaNJ(MQ))%hawwxCAhe(#XJ7~ zmd62I4#31T*Um2FZuTR#dh7YG(n%{z0dA5>hjwXtzX&?6yvXj=jjdj$?;G-$I0D~q zgDdf>(OFbM>`F+sblS@(o@<_tUfFNKb9t2^OafsmP(WeT1p$W0-MKeeajm(A?x2{rX939h5uEmV(6dSM55kcHng`hO zTE%5r++ax)00gE-U+F%WnM($}H}Q5Wd%5{4PP+|nfAeOBoAlklhahfHlQboAiob_G z68NJ_y35sg5-n^g@VQ0BK4v*ax-#K8%}ruONVx%-nKev}CK7}JMrD)_+;*!4%&|j7 zKWU>dLZ{;L)#l=RQ7Sf_t4b3-W|36g0gIt69PGhPs25g%Nn0Y{#9C5MJHsi)%`69A zL!8Aap$c?Lf_^Wd^K{~7(Z)S~y%()}KvUPz)SNRLuIUnKF5xG(O6lEex|&WBBq zlm!h@nh}?qBbJhtT@FQz>%Lgnn#xOkEn9U5-C0>AZ&Pqg!O@=6ff6ejykgWie6d%1 zEjtb#-Qi|M7I6);Oi9F6R-Vo9Hjb|QmAfRZZJB^vLuo#4-u&z7wq*fG{8PrzL#X@- zNA=1~`^pok9^vSoeJ(x>T6$;saP#XV5M*^Q{WTr(-ZG*4+`lW^?Ls1W0~`1Lwtc1W33HgVY`Vb0cCEbDtxKCFY!J-nb9%Yv#XOG0uZ;pxn~`*Dc(&+^z-F}kXz1? zWtu9+(6{IP6+27p;jldtzWw^ z2r%pNR;RiFJMp{t6lx6j_r(41pbo>CFFFU#mD>{~zLrHD-TfT0w`+K}L#HlSOW@!u z>Gy2A4q$hc$RqF`l!-gGY<~qv=A^w6a_Id0vq|r^*p^KC&tqG28?m8g>m6Q8op~xu zQx7dllYF`&GkW|V-2MJ1FE{8-KO=I$4fp<*j7XJ0O>F6l%UiDx0*Ti6 zt?LI{%l+hEejreN5!P|1GxbTKX0*k;cA&L!E%2N_V}y+gbkprL&butOmKWE^r*nVw z8BLap7}M8=gm<$kWrx|9mztzgHwz7E%DnYaV~U@27d0TqJw9bC`zf(2$wSdnovp0; z%{^R>Wj!7yAB8FN9GS#{qaJ{2@FRbD2JrWvcZL=)@QR>?BGzb~0|8%&vQm}>Qz-43 z^iLgSEvlO%;Bhjav&Od~4EQ9mF2mV+oW`T>NVvCnn~n0WcHCfG&~3L=8s%6EhQ{#c zr>Og3nEe=P+qi9PmW^o^O4;k|Ar&lJfL5j=CV;L^QGsfps35K{2ugo?r+P~VI8YTa z<%>I;Q4e_3k2mugJlWQ!<*l0fxZavYGh^ym`zHq%KYdrWb2ArNTYHd~VcUm#tAM7W z{uZ)iPfwAjI)j@V(lEJI9!@i%0Kn-Y3;YFG0vo_|DmP#oE2PRd(~L2axYFLMKt!f) zyp9~44vo#BS9_RRW&!8vNRGp=32`q@P<5pR&NXoV`TCv4{XGul_A)n0*~spC>b&c@ z#hhUhBd3*D^;hq`|K#5hXS9s#G_K+1d8C6!+E!S${k2y_c{#Go`VZ3~-2K>=1q_VfMX=?WMvb6R*s@9wQwgH$ zmAjD#+P}>9IlJ*fGACMrtDAjHCx^JJ>%fzC3Ai*D015{+iHS_{WmrthR%Y-rG7JSo z6A=4=OVvr=UbkWnMJNTo`f*KyFkYg!70;Sq0f@h4=0oP4$+$PtgmIF7u90KzVt_|e zad0ka!8ZtUYEO}J+gPwDt<_Wo$8{8Y;rnR~VbgK25eT(G?dFEV(u1!(228dgj^^8p zo0oFsBS#3fMkq)wgGSbbeJ^*9bm`MaEuz>358MGaog&;gx5HdVu1QZs30LFD(E>lYoX zXvFu96HShPgNC@4-d2HLFjptZm*<%b>A0&1%l7icj0AlGV}8F-q+7hoHMWYx&fif!xKD3s!`!C} zyP}QaKL9m}gs(D_kj7rBwt@8I_cLNPgQm}n8~^%}clG78njS zmX$c2Wvhz`ZJ0)u_i1MthH(WC4D)3vzMPv!3S$k$w&6?fJlxZH^aeGO)$ag<+Q%Ha zhb?f-M((|!79ZY=Sg(s;nJ=PhUpwH+)GvB+S&7uV(N68_R!jJrg0@x)Lq#Y9%RKUG z*&>=A3Gn~WjAT!k@wnXf}v8e}}SQ+dFdF+SI13HY78*b|kNFruB~4)aX$l-ucn~AaB0) zT;nr@OyyN`PYk_Vgu?}ew9hlXgZX3Ue~E(OS;EGooKBHBnq7K6?IfdL%%^l7jLxeA z`kS6)Tbz51^_rq}ZVczVyGFWMirMG}F4@X(!3?aP2K|ElCr?n}0Yu(LhF+f>`FpEB zeyRC%yH&OqvjWUHNeYS`osUG2lp~8wR^(gqe8YlTANSD7 zyuITHw+3$@!HqcSY08_jrUt=;1;j5qMy8g|yp5Qns@|+1#igMGn=1(5Jm{(=3=DcI zWP79Z(C7Z)&>bNYksWL~LZZ9Bz|06SnwJ#Trnv#aN9gs4XYW!C z!^xA$_f1Rf0=shp6j`o~wiP)_n%>LgFVB}(a!*Q4HI*uEeu|mOQ`duDZ=tT|P}hAQ zD&FW}>oXvzqQAT&4MNdp@Jsi@0xa?I|71OCVu0G!r!&(d(Mzizew$$YsWllr+_!x5 zgWjQ=*Bs>M3S6pk@uCuje{L+9;1gNq=n*PRgNWK}%kS6DKcs4(Qh~TKh21^cb0^ya zy?D~Mc3%+=VpHbGy=+66W^jk&$}~W#@f`lHCpie+H3pPF@z7HOC$MwvY;WabAE~uO zkYMq63Gpmldo{my{tt8+*5@YN8FTFyN^ZTxwb6l?C zVkVC;Ng7ow?S9m?sh3GUO@t+sx;xU0dmw06W=52`g-rx7wZs@)OsqK?mDYOP}^1`Z}%{n;oNI~eJ9YdPMq5{ly7LDu9#a{6WKhda6M*wg z7S)bhIIf^JPCvj+xu_0r>Aa=^p)#T+vSzz`5RyFTNvK=Jp0wff2l4X)9KzS20J>O7Ofg3_Ju6Z=T{SIwGc z{A>4l@^n5jyLYJp-4@hrxZ-kT;4%;oigFL{Fd)nZ#Tq9rz4O&pw!9s!Y3FPhZ%m^b zA_gd`nsU=@$lNu@w@RwR|0kr@{IHpGH)a(*b=b@a8E5JHDsuL=`Wu&gk8 zQ%^CYgsU2&MoOSA|36Wm;$tWcgY0|j^_9^(OptG;)hSpv%_3)kX<;%3zoF~_xi z=El6!b&jaHW*l$}2pxPq0#;)c6c(sbR9m1(GeyqAPdJ-befX<>ws4-JpJBCj3QvRl zH)6Zo>qA({m7iKa|E42(Vk6dYIQ*YQ^Gh)x|I{2u!Wv69xo+1U{x55wfWCtGv7ZCqIMz*Kp7fY*c8Bvp^9gQA~-!=@K*1ew3n-M=%JbOO94v$X1?q|fV zYfyg$P5z&9Ds3csgLO?(&|>MKW;-f;dsuN@e$liMPoDM~00&yXZWKIXAx5x|KWXIq zCJFsO8fZc(BVNcYu;ZKt9fxQ|x2UU+EXb?_ytR((O<_wT3+i~IX6e9yrke1%-%4fa z$i{f^uu(nopN=u=!sa~OI@kXycQan*YlOEov7AW8~ZN@tX#FRxbB5W1TP6p*}xOU$9H{gQXQo7+OX$UI;|9xEFiQQdE z??lh1s@huGsxP*WhSiMW@8i&+i>~PUFb;4c1_kg)&bhFNu;hiHruj_7`qOMXFCbLr z&W|-Y8_vZ^7vATbKFlQI5ng_x`9BPSW3>s_F5zaT;(C4l{bBbLSymAQA zp5#D%Vh4S)Ro#a%{(Ua{gK7mf8K>bAw$l>I8|b)IScge>b}A2pJkUnOxN*Q0yt;Y9 z5G77?FM)G_T>eJiy2AJp@%DKDHF0wX6N!a)C-%V3pqR%G?=`k9AKz!~nrli9_3th- zCHTnNREoQ{bUf?ot=gP>*|j)T0y^V; z2U@=TiOKjrfOYxd;X4F>d`Mo4n0myb%#JlFc2uJ~0#}Qf&X^zCC6n!z9Ht069~vpy z#X%{Gb)}E-X~L(t_7vg$e)jUdU>x3mb%&VH{yG@qh_b@6IBS-Hq}xe_Z2xcPzfNmP z$FTR8Mp=r_Ldb-XXpbW>$!flNr>X&RJdnT*nW(O8JaInFUolkVK*nE1V>qQzie^#! zVHYz{jj<#xKaASef?8YsO^m2S2@nhYh=r|a`BP7ApKZZP8q6dr!vsipTxkA#gUQ=r zczr|Yc-UdQdi~JbdceIMCRx4ckAK@s60c_9${kU zkj&^?`j1QE`k{+#be(I2s6zTnBfY=;E92(mahk4nIEy~e9n(J_7MrX3p2E!}Ck9Ez z=IMKRao7{c)_JU-w4X!bzRbKV^Df~`3WxT?eN=D@8*&*Td+}U>2Zcd*b|G-M&4WYb ztDEQKF1M z5v$_!>#sqh{390V#o<}e&$Ypg0xvXNWNFQ7u(_U+n>RPKU+vMr6-GYE6@2UY|%D>)@$64T+s!Jbf?9bmrmR6w~(;E3b7Mt zJioG8nh#oAUPvLg9f7Wlz$h!J@uCq9MUj2$u4{T~wEo%^GhZ{^fsBC>w0@23qxZiz z9!t57Jc=<6qy1yxHGHyZJm#*tY}WX!%?<4j9+&#NeDu-drLA#lR;g*o>*`KGcce+W zp>v4m#lAy?+&tTy!lq(tB_oXWEhkDIWdtk-Qwp~)m_3Jawpml4=5Uh+g^X+11*`MA zqdekdn=Mu82b^96$71ZUSyH~@|B?0P0ZHfI`ncKRG&M2Rl$jPare>OCj0>e$pJt@8 zWXj47p)_R@cXB~Ntfnz@t4vW*XvWmcJ;W^)OT`71a^G?VRMb=y5(NCct-1Gp@BRJB zf4ttW<(%`J=Xp*p(I3VZmGG7pF2@A%K2o(tV!t+Fl1Zb*7Ddsx=Kgc^ax{#JCOidZ zJuUw)9F26)#0aeF_s4vs%AEUHY^2vG#p??qibtEoyzWhJxFWNE`BsweC)439mZhCq@nx~7 z2rV(5M4v2$tTJuA*v>7-{XabjTrK{r7Z#z>n<8o$JMNDM`@Q*VW68E5a~N+9;`0O0 z>;W7kKk4w#n&Qqo75c*c@sdc!-B|G1koO~NtK_xoT(WYB<=JH!ib5>@cvE5(tHHkU zRizHZ#56bH5}KTDd=U1{WHrC`^R2_o1;2m95395=v$%H@A}+3@5)x{3AV^r1ms4@s zf7qFSYDDQLHVE#?b_EFarBS`&SFkVN(<+wvJg*|&?E;x2i`To~ZAYA;Q1p5=k*;Xy z7|<>j`r}>3agw99W|egdC>J%-Luo`Jj7E3FPke~CcIirX^8sR zxN>MUc`n#Wk>sIkYh`r8zqnuicrKF4?5YsT>l5_g3>ypo`FMvIxK=9O-AKXf;MAG! zMLU62ZjUVUC%uZ&um$66-je861Zc~;_7kCKV@b`(!d2GVDl5EIa#)4+p*K=x*nDx; zmGhQ<-w>1q(yq(0lbK30_@ z_|t*d{a^A;S90pSFezL`dwB|G(i!JFSDBj1uy$Tzgg6(-KAan|#ExiqTpq~#7z~l9 zTfIu3YtZQLBsjqwed8+Y0VjwbSG;1)zTvbh_0O!nA1k66@AGe{ zFYdWUGbVtPH=7#)2L(={veb9Al){?&4I*QI{0wm58aEKX8+{P5VUD1(E|a~u1{a5QK6dwV8SoBmqC~sPJ_k($Tv|IHbFX*ONr}-TcHJs&8Z4MhEKZHpeDZ7vC$a%g;B6p8ulVGtW;1G7L4ilrP31VUn+TajGVZtu#OJy zKr1)Y5z6T%HRqQv?Hb7f%V$%<+R%v!6{i}@okAo0$MF8<9y+Eo>D9}8jqL7hD>!*; zt$Tsf5&*!qrkP4_9+Xk!iv@og(8PII#RPb@7`*Ch?QON`{L^n3>gcX@?lVf2USIQY zJ<|;VQme;rB}Hc~IC@Ac;B@fPL2Kq;*c)_L!$v>);8_6C4fsg@kp6QlC*13YW)qLE zE3=X<{rk=GD`sz@4JUix0VU0QPQPkHPj^DxQVOjA0-D5rO^8v@mD5&=Y%bU&UbA;LUBzOW zgX>mq&x#M6v(Wfupcv`}$;kM6Oq}j%UtiZ+(qGvGc1~lGWHfM zG%!tABj&3wed+ZbX7MiX6YyO%P$pGkJP~zg=3oPpp^=gcP^EojiIZC9iGbSsIHU+` zL$m`;-ayA* z33>q0!%68rVFszNx#1(gk|?4cy9e{H!`Z?Vl!#H`NP#o!_vBhOO%CV1>mhY1_6>GA zvL%`E$tLY41wEuk&X58f?)-*P^ERSUN&%ZUu)Z2 zOb~avqYWVWa4n({rYp)ZUS~3<)tS1lh9l408z)UMDSVhQk8ZdTwfGLMF@rNu0|?5G z^P?F66H`!Z6d=5!$a_Gya1|MuoFA&XQJ}S$*QP~);Q04vsJYB~zhm4!DbseS|BgYg zhC>ph1^<_#$$n(m1kw72Yg@8El z^}sZ$y5hAC%eqL;v$x;3sKJ(RY1ly9VS=JS2m>BiV_A%roJ7pFrhouLuJmo6t7di3 z#(qV}a8Uww^dTee6u? zDq!q*qewO7YDth`ia@te))lJ43H7Updf=T(k*Cl}_&8F! z@nCP>$XVkrPw}7*gVibUOJq+MeErZ4ie5Pa!cAtZX}=zB$UgjF0xtXxWOZx+cf-zD zQr8lekii7s2zQO@j64M)NILH8A*x*4cNYf9PglrvA^`LSQ?=iHm}HLiu-`nf5&DYb z4nFZEf^J^JbSMN`VK*DJ*^M=mmh)2nqP;5mq|=bOQ8;dFX{-Rc~l?hj>MqiBVOL=93xN%?6R zrOfrBI#iH1QkvT4`R)~v;(Z=LOFWYHDZSc6u9CxhsbX_aLu`eb$0&At63Vs5i`CV( zQ14Ma8_9n=WmLgLYti6=T1E4K&&u@*69RygYn0?Wc<~9u#$rq+(FX1C=I$!XV>{>v$DRC=6veVptyfr%)#mdBJ&zpA zo^xS-_#_jju>E!7{51!V(zTwx1fwq<_YGg7t}TAmL<$Mn^m%3O{N7*Cu^Ql*;tJ18 zK7YAiUi~*Ei2VJgvhc&<{XuvBg*V=)iZ`FSRBUl(?W1O12e!QMB*-`BfovzS{7%%`LLdq>x+7Ik!n0%C9 zISQ_FzMv0qQO1(%0Ica5!cusJ?9&A&q6XocZaxR8F1Ro@uKkaUdi2Myw2DW)nP1nY z#Z(m+{f7+txoTgdnQ5f>VI@3CheirM*|_wSP%#8e4r`YC%K{;*>HP3H{PX=DNJXWU z|Lj>0XXJ=Hb!Qn?AUx<{OvFI}2Ko;24Mc2UBI_qkqX%~=fy9)&>2WaNT2wDH{lvvE zE=pkF5hMP+0NEO^;s9#@x!s^xxSL^7KmY4#a5|+r?YeQft3RP;fc8;fW~98tt9}i3%>ut-BxV11!gFRl;o0_36O^(FW0CukTC@86eb8DK4IJp|}`CI{kalJ0@9QZ-O) zKuOQl2_0Rm$5=?4$j0H5riILW5KskYxnsWgqyb;;tSSK-;UGB;Qd&t zIHg;Mn*trK)Uvclc6wXV8@QBrAugOrh!+e^RQ4(EjI~Uvs|0}IDn)dZn{>RMu*R@( z7;nx7`MdNynK-PX?g0Ps19@HY$1fx+W-x(s%--*C@Y=Hseo#c2hVUtF?ZhpAfLqn$zCJavys=F_hZe%w8^b$L^$D%NBJWWRKQ zc8XN%@3uM`_xWVJB>#E;O#W;g?AY8xWxzDJ&4i%+$$^+-UjV&eE7XQ7P1;T2GtaC7 z=kiXsU_sj8;_<*NL174!p*$bSZRjUT>?$Nz{KpZ-qdp3TmI-!%*JRRiE1V$LRB6st zdTQFc)jtIWX^u|`Oev;t$-1vYthT@=BJyD9l$ceKXI8TqyViD9RDxFZOAFsx`%|bG z_@|cl+-zT9RJ8CB2Zq1?d0S6a_}v7q+G5rDSK49&90+I+!Lsi-@1BOYh2knwev{nv zHPOZ1AaxHvwDIb>W)}ITC%K=HNR;e5PVkL2(-Iu+|ToptLOhBQOh}Fr$$;&ch;^j%3)K&PJ+gl{8S$UqAf|J-_9xsI~N&DcGqudLO5aLP7_)JYyh`zN_OzLmvi=xGGi5Mj$&>T(Mk?ZM%km&-pZZlVcRhY3a!s_1$uY)}BIBLbCcw6D9C9xvhYH zmhS{z!a~LYHp&tEHa+qYGk>u`+r8uL-+l?Z0493#9#N_}+*8*n5VW`dOJ=v-Ka3T9 z6?LLL`+g>}{W~PB@{Q;no@yV{FWObh+VSEC0q5R2WpK~BMu4W6Au9@5ccNJ2e)$m< zZmO1b)aS9+HRT1;*KuS`-!>{tReF=gtWPBPU-+aZX4;$= zSZ+(F%{D5z|M>LuWfd?u=HeL4MDxfI{6WD+&Z(4hampCvuxTZXm+JhsC1u2-e_OIC z;c6iPAt{izJ}s7Hu?EJ^8x>0~$L%b0?F*zrD}?&F1(z*C6_^cKBl|Cg2J3(rDy`(xPzEk2GM!N!by%>;Vu$ys1R&QOkoWphPWJM*Q#K)?KjxHwj9v|6u zse#YQ4H!I#8!9c8CK7hwr|N87*8Fu~44?da5CwBM6;fg1E9>HWwdixrZ?j+0(k`DO zdqL3sB7^3Nn4Fx@vf^kV863_j|P7y=hPHaZAq7ozvd%b%)Hz_J9#LiPTj55 z&BBzrt;A}>q3oVSoW86y*w~FX&LxU=Cpfzyv~Z#X6(M_d*J#1p&!LNed)(7P#V6Kk z@JJ<(=-00dR56-E%hkoByXH5KY$GKuIE+X3jP>qJQuh4&GQPM3JTA}gl@Q+SUKo3) zc7XrtG3ZC_IQV$0{$H*8?vln^uDBSxl^~v3n5YNEHhAdRZ?^~}2wuVE6&)BcQ!601 zb%+r@woeb()_}#gos{rE{v&#zb-3G{ON#%^ft=k2BNk04$4)J6viKJDt;~}+kb|{= z3IC!_Hm7Ph6CBTd8tM~59btm=7R6mSTen$t=js4vTjbn+Y1$9)HG5n$l5||XYB}56 z#l7b_Hc!hR;@Vfid*B{ZkwC2+dM-HMY?$|VtA%hn7jP9g5q4G0Y=@(nvXXZV^;WQv zt^liydO%FnO2xeUI}<35#yB@d%x_W6T+?bV@19auF^he9FM$>T+Rn=d?F8Hk|ClMuu75`?YBq=M;h=;XAbKX(VnFt! zK1#c|&0Wjl25<;{0z8bP^hVNFT$onoJ=a=HD1_%L-A~z3)5sKnK2qyqV$c7>SxuAF z`7FU-!)~dGV=i^=>yL-UBo_XJ*q;qb37d&q?S-7aJ55mwk zxSWP96qUV;(fcdWSa|*5NniQ**m`ZUEE&AbB9PJiTaSZz&l3=W=D<%jn1JdA;ty4y zk*36p?iX7|m!4d@SNz1$&S)Pe`j<+$PBJHTz;AZXcIP`ja~lyvV;1c0Q*K`?_TWTO z0yX@u(F=ho8=tCvkOO_>y!Ih%Wsl*~y%sLKeqpzp5$+IP2duR^2u$K&4mEc}Zn(Y6 z*H+t#^y%hz*VIGXQ5T6lOYh^;8I3i7PI*3TZFOWVF&;=XtZM4vC0@!?XKFV29VKq8 zP#5bSXboIx%L+V-=!=ahT@RK(uphmts@Ud1*5-XV(_K6xFvFcVLLF(!-SigMZ%>I# zA(u6MjZ7&Kl*g(gw?m^AZV_)!>}Kh|JGepOzzr~PeyKN^ohEi$Td~|2I^KtHOwkrI zQHf?kR=`P&>?%duw8cP8ANi^OnuS|ef?HM1(>ytE>fCGWylXuVc{ZYMNoPZNh3r@s zc*wm9uA_VkB9F_b*8*;Zf6PUTUq5)R0eX>tY4*_QLx|u~Yx1$Nre3U8sWY0t@Ln}W z%WLjAWOPl8Tw6x2O#=8ngIvjzAvpqa@WPz?lI~-L{Eg#4r0=VOLD`P;5aLtDRvYrn zw{^cqMnpRo0$*VLEjORo8gd~uu}y9MGAf`crP(o^!Jdm>%Ap5>x|V)+1D!9PMOf{t z3}auAzmm-&Z{uoa^JS&X-WskbFQfl=ZGUm=9kAXgf8 zpCy7PcQ*jc!14SsyJxn`zc zk~88RI%cRBxMh-&gp3P_ecNN@&(5M5_nf~}Eh{oGop@{yi!QWS-D1Y(yoS5ScK5^| z>9H6e5am9%_aA?a%p1RxF^N=3E(@?WcMuh&t5t5Z6?Hvb=ub>Ywh+1JnGeZ3$qU4- zMJueO$ndGi@aYsRP5R;4cqXR?-!BCQzDw+ko&$O2kN@VG3CU+zD&|r8L2+MqqKLoA z)a97Rofx~8rNbzcCfPMgGi-lHs)?DH5$S2KbnIL91T)KAguAH~K~a|rV6|`Po->Tk zUV@ajLUytZt30Ts#f8yJe9OC3aLUqy&P=knExvww$&cWkf++|J06hYZZ=_?OH{Wna zS~Qf5p`A*kOD^dlWJQ*{*B5h@^5Bw1AW^UfalaVWIA9aOe^?tV=d7Mn}|1uJq~3=t1XIuzKXv=b;_`5Ftwa*(dY)o z71GnSVH#l_p*_v$t0P%ijNd-*Kiz`F@D`tK&KBe|MTRDmO=j;shg#dw)|CqG_-^h> zeebg4yx?MvEquA88OkxKYi0;I@}6G>uLE=EkQ=&A-N9ZO@5%`Z2lpe`z57-KzrWw9 z4lN7{Sm4{J5Nr0;md(zG)B#+oF~9~{bFFhcG^D?3)9BidwfH;AX|gbSCKY*L`o44T zce!b$UxRe*!&G2n%6|t3gG+&n-S=fHZ}WXM9JnBH8WGItmZXickBZYX^O(#;T0E`3 z{f!k4);Np6Buez{9SMU28u30#W=Kc?H2kZ}9cq^5QG$=bxa0~gYz^6vD3v7pL%hJ~!?E^R5XBzM5>T+<%|75hmwaR?jB1EkT%#f|44fJx6uWHrQVk4M5Z?!hLCWk_RT_7KB#i;d3bRw({ z-@L<{LMjjr?2>O~mr?7cg0pb-wS zr?_cK*@3RGxl2j}-Zazm4Nt#p+WBUw&R8bQo`iS6{Ylr2@so~$r}mn&;| zhh}V4yovFalD^Yxz=#EVRw%zEkpdxnMoUT|8;%Y_HYES&TQ~sjvX6347^gPtTbV+u zowmKXJbJmIp7gsq@~yDXwZ-DycQ$JmrkCm1SA;*tDGBH?VOS<6{no5x+o9G^=)h47Z^YoJ92|KXn`}PJxKHN3T`8J zRSE=~BSHlQgihMDMj@Qz;*URN=e=~a0by~XOg((&X7oG4x^zaHV-o?f5;bWTq5>vu zBKnaVKint3nYU4yTmJiP2c+j)>46Z=QJO&o>^F`7CL4Rki z*4!}zmMq@2H|t*P;;5QGDp8}zhkO6POhU*M< zVNEHYD?OFVGn^sbkCC|cmZyymN66|b;iRoaDCLM~-TI%k_|?DEX~;gQ&1!p7CTWnO zvQ0c-bMLhqL#9(ZrX|Axq1x}Pp5IcTQvL3aq}gvFuw!?V+G;{;I%ue?$aXv}%hXX`d?AfCnlrD><=`f2bQT`S;u54#{4 z?k>xZf&^A*-?1RBZThsr)RK9|k2eYHwjkq}v*%#K>oF^{*Dcn*KhyKk>KRkr+@y3M zz_W&z6MvgMt+wPsV|vppXQaH=i!P}VD{3Yj`A0bD$4hRwez>E zciRb|aP->%=fPdq*M!r30;<*f_-^*XzyRiYk?3<`nYiIlVT*Ubenyl5#9gw0#*{`=*-Cebp99el(?=${$_a@OTS39>vYLJjB zN-JHvAvu|AS(o0R%c}C`UzlWkE+Am#8i3j@aoKwwebuuN?Npm!fN3rFjK&gO8$TkL zyKK@=Nr-8wjj?TntQv20I}aw5mNwtYQ_r|;+~uc9HKvBXQnub2ZjD6y&&DKR2vND& zf3ohx3L^+n9zKHN!hy(e+;vUjpUw6jkeuF?D@M|l*-usM-tx;q>}>QzfHkgaKZW$s zDm~5!Nr0uw{CG}hwPi?oo z#{sw8R!8@=s>{m#8L@Y%+h81Q+Rzol8jZs6b`$u-2OL<|W;cPuh#Ktn=XRCt)z)(t z*+nv%ZEb0LEap&@c-B|SGT!xLep74Kp8h^by;N-!ApjaD>;CFiu z6rd*RYd=*XY{`plcW)|}TjX6%bKZWZW?4rU!RpXTbY3jMkp~2$+w-ohMPWhg8;1U_ zZO3WMcO{ItQ_m7jMyYlq8>Tl8pQj)Wy3XmicQd2fLZ=uoN44pnk%Eh1f9GD7 z&NT$i&C4dKFaKXGXtXqCJxqJUTNLm|pkJgBe;4pJO?|d_s&yOwp?MF|Io-k}%XOf> zycNc1NQBnF5*H9CMN8|pB=bt>L$gyDey^4Q(b87sDk@1F@3GbTbR5Ylmo(8GL?0~6 zLYNH*m}g-hTMz8w(@>220pF!8!efp6moyCYbZSt27Fush_+#hFATReBi=G2cRIM05 zc_oey(1GAH1~bY#EcE$to;xQGHjHZ57|mz^S)}*k6(eFZLjCmb=!N*@%N9bZhEtuq zzTG2%8N*1z{_b&bX{VdZiP9i}HP~@plHyF#&Ch&JF|E`j3q=hGQ_Hs}A&N=Df=+MRO_6nF z9}uXQTF5J)wXxn2X?t*ue-vLw#cJyrf3vl}*NZ!s?ah^o>Rso&eqgo#k^dE+8rrfu zS@Cm-rdEDD5Yt3qFNA%8OPWT>tVP+H@N!gm@0&s+km*``m#yfw4jXe-hyh3ZP z8lSdVJNw}vY3%2E4GVp5!#%V?it}F&?(c7$N+40G{+_f)GXM= z-bFe624~fLwvj8so7yL8L?Tb)ues1n7BsOKs59}n8vKT!yFl9TlxBj9$ed%zK$0Om zw|c52(Et+KV1Pcm@N z8juLDiO3{zE=C~*2DDfyzu3%@(Gol-JiK47`fB+&xTE@&TIj{QN%C_u3p3ySccF+v zjxGdC@T5O|!bkK*H}+qURDAtZjsNwj3i^N#RoGA{ZL(K%)4EZ0xHwO)t3lxayUkD0 z_>?gOB@Q|vV!w>_MGEuuvR?ibSo=Y-yDVlb>)@H#b>-mLy3q(`_4K;E{fAv^wQm$NK=t{nV&gXNmIF1UN~3rG2NbKV zpsg1|y zeTEph!%1ln+P}|5dAkR6Kb=M(ovjo)1@QN6#xg@smx-kgq(w;0rgEZGbPlXsh@>k4 zbxR7Xl$Tt+$^4IC>3c|M;LN#7YnFN33F*Jj{Qp@&*VdKMHYq}V%L)H-;YDyeH#EGb zFmTBN@PZ2~G%kDJ9`4Cygq!07?C1^G()O8Fc-FLBek;n)2MRZ1hC5uYJ^Y;}-zgU( zed`yMPn;W|t~hP4v0xad7zE;*>pX777oD3I7y5-5U#VbdjrT&eJWbHf`sCZuhr9XO z23hI5Tn6`fzf=!ja*fW!SYlL%0J-Ov<5rs&G|B54jJ5D6vfnx|O%^|~In8Cl2L*ic zy~674zyI&z+PrM{f_gJPEW)Si>uZ2|xwVU9O>?2|qMrhF2rs%V7IR&_U!U{MP`3Y5 zcG<)e(@ksWh5BmRFYTPfUdP|?8PNWGCF}&{y|% zS`*AenPVw<9u$-oD%fupZI*;;HvV!cu3X#ec`!TSv?$E63=BKZeGOR}Ep$Ez!;%lE zU}`owEE~*+jjYxz=O9VKPd4&y_emR-aN{NE-cQx9%%*P^e1zQBz7)>+mfsoajY6JG zzLEM=ep|)*0h{}6!&X5@d!!dhKNguMOevGucD6&WMxwvmfemIX-%U$#GQ&S=3(Y}c zQ$k|9_3X(^{yqVA-?%QyList$k08{>n4H ziHg9-n%{(4xP44G-N|?NYU9d}dBFYW(wNB=K;yx?n7DN`bHqYcq^=OH4=ctf8rN39 zENs*qMP*0DH)x~p#Jw4ojqjn-w_pD@0L}mv(4}6^kCG|Tv+Nw>6>A4}+FzeFPL?H~ zBxUFHE@4TN6_*uPXsyi4aT<|Bf)QOktuKbzA#D^>SxwRYrT_8*_+yLYKXF}c`bibb zhZ_>7ojd0cae>xB0MwRSj|HC>JH~`(60Y6=mpUI@+ZA50KcVKeZ(X|ou>t@PuFnRe zPGeM$#Enq4Hs`}c|3JW7+if-|qN^qVm5h9LJ#qa42}D=TenhIS>{e-ckdy?efnC4P zcx_p?qe+qZbuDRS>vhGFBr1>vKxwrP=@Fpz7OnH}^AEzJc7k2d)((QIJ)yKVXkR4u zBm6il*KW1{8u|I;D=4=-w0WQlAq%!V$Np#aOBVy|7rJX=Xez^L#TtKDjiVLW6NJIl zl;l(PIWiL+FSMeIETb#o(`o~# zpjI0=q3c~|_}R5>zU0+GvUEC|t{mO9_RPJPqJoy&UA^dhU>a~?w*6;)hx`UF16cl0 z5cm%G6|k!EKXy0Se21MpoRSC{P^%q{9=bP^bcVJ$$48rRP*!uj+OACE5kGj|&9d%F z`>nXVN#aS2FaS|3D}5?SN6qv-fcwvO6(dM7MOQ4xd-ocfP#oqSSR_&_5`1^ar@ATr z+LltmdD!Efxy9pyEis7R8>!f~c5`Vbnw|*67eNo|VHNF>l!SA9zRG z(}LO#(*gmfuXyu*`}7O3xsyn%N{T#m8mTq%UJ8F#VzEieq7W!Y zFNiX#!gGzyswc{*D;6|bD4P+a2;sT39Yku$7K4u5^f z{dz;z%exOFYF~lon_S)6a|=cWQbNi;{=!+!5#7&6m3b$)FH10U7LAUQYgiAk+`Q+wL07imUd1?TiP~u7-(78%sA&@5R(@KzFK>*5GuG)nWcpt2o8-v59Wx z;-DxtpC~GNC)SV6xmsWmmQ&@)Q8QDM8N#ItrujRqX1Z2(TES!p*m5&6ZmBEs5^F`* zP$5JKT&7TxMS@hV&RS?s?gsh+R`O=Lym_(!RUvw;)9At(=Id<`6@J(EeyVNuyM&Q% zxW_CX0H0baDRY5#Uw7bzUQyeoknajXb$$J%Q z>fS?N+=b|E?`zH35w9H8$ne!I<7;4~RIdr^06RnF&Pb?k+z$5Z%D#I`o5^UU!Xip@ z3-MOZnr zoxAN%@M{EO`4YAGSzZS?Zuo7z=^=T^_&vh9_v z2gkGx!(J;t!bY#rN;_=G%;rc4L^dTqtuihi*%UGjj71ahb!t1~0mJ++Mq@RbMmxeg zARA=Asepf9#|Li~uJ>FdvWaQISA@3q^X`Rvgr8tb_qfCi3+%oA_-Cm?ocb{m_M^7R zD|_6)q!S3*z8%BKER-CsxvhTKX*_F~Sv* z&b#hh`;moN23IMV!K}&bA&XxOsQ_#PgbTI&#mx190pQ`i>#>`pxLx@#)_L;YWlH47 zhB`Hz8_6Lnh6tO^^=`^p`HhKK@?&SDENPz9Sr^j>0&^PSE2B7is4xdh4;hc@HIjaVVLp7#&$mI>v9eomA^eZ^ zkZ}5PgxV0(WGU?L=IHZ$Pdz#;0oSFOMF;TidBWM{`l88xh7sm7(UvSUr>fCrh8* z=X`uRC0&taOQy~ym~S-kJRtJ$ZMP>5RtnlsxMEQ}$Cy^>Q|x`4)+_CE7Q4e?uFab} ztzYZ;XuT0!q=yQga5GQX2h>(yyP*Y!)qiZu`E%k~cI+?KHRRCrv@X7mX$RI~raO5j z#?Y<)BwR7tJl3jB4v6t@7Zmu*V#WA`#@V5js^#cAb?ag(<+vVvF$%jr=^9?#^_JYf ze#6li)fLrRfb&sesAfqSs{fZ3Q|6^=ri=^b3{1UO_g7VJshR5s+V_0_0B_B0zP+J> zgAK7Kq-7U}AJcq(Ynx~f?pfLo7sZ|krH)aF41BkmzX7L(#{yNesj#FEZ) z5#IjGmnZMxuW~AJCSy$*pU)%nB&7lyBa4b0J?u-(2fl;mSo)-{>0Dl-$u4^&D>N}6 zH_s%ut>J|6lCHI_|6O9=Z0Oc}l$X8Wgz3yn%#ck!%=+Ynb$GEi0Vi+$yWkg}BmAQV zYD12~jhr6}jyLXGOjF+%?s7>+N5lj|a>mBon=__O+6t&9-Zbr0JK z-stXgNG+<#`yG~4mWP)xqiK22&XpZ=f(RWdf0}39eXt>>h-pr&KrBWzU%o`ThPb3} z<}ORi4=3)aGpj?u#~FWBAa>DEI*Sq&_JcR@%!;A}19*Z7oPew0If7dEod{f*q?47k zTPXB!^Nhr_F2s<_iGVhddpz&b;PAWH!iv$U2W6!^_hAiIz@r1VG< z*V^4!<}#-{sqm6kb-0IX(-2z^Q=m>dLQULfJj2rHgGozh! zSkK*+lx+pDlOvBP{y5aq)6;H6E+%mQ<>h#yEAAwY3NdyCbldp-(Z5(5R;1(#MJIh; z>UqTM0!N4AvoW?U{nF8EbV6IsC7OTFlLs!OfcmkPPBm*~$;WDyiQxW7)RBFt8{!9J z8?hXa>2NJP0$1L&Vj*S-j-MH-)eW(-GuxIf!^?jt2 z(_Gbp=2xiUp_zcdt8yGhWEEO z)Q%RxdXXNGVoUz0S9|V9)&&OXysK``{7G&6&IA|^POMngL*rvt>bv)ajJMRcp3@2s za!J{Zk^J1-7h`67Nx$GoBz!3oaA^*1U?vKF*Y&Z~f!_@h^n$W{4!*32-DpEQb+wv( zhsu#LQh66J?5EM!jlJBK51cF{chgB8BjY_~w(QLLP{B+pYNyx1yN=AgHI?;Ggc+%V z=NU)n#q3)dZ-S%Qfc+EtKr?OQaX?t;{PsIPZVj;Bo6`^f|&-O~f z2N&r-x)oE}VRzX(De}?&=ww)o%^l2nSA-=MVYFxzm|0H9+w9{TFlXZ<+YQz0APQb} zm=oBycbNP5FYN=x?I^g`hz&P(mwf;#QU+7NN%khNuPIv#%oq1`+UC&2^0ap!`eE3G zn7a7mNsHsCWnfHDCxxP7KMV{ZRmdQU4oEdlA0OB+-4y|<#d_TR^3U+g2Nl-fq5n>{ z(`1|E4YOU_0`Eni-avK}nE8X_lK(1aU5Ji4ZA@OWzhB5d*>2I2mmkMPvGo@^{M!sncg^SpDgvc%ztsqn0$;B5H1ZyIiIPSbCTZPWn6=+t zWrTalbtsoXjTFtsksbSHTOU}C`xynbK?LqjRCx-*<&JL(65QcUPmG)^y%B4C1Ep_U zxJMi7!ZbBDA}Y65Rh*10Ua8OFbXarK1UozbnpEWs?LlgOLa}2!IrjkblDRsEmzBj$ z_4N&J)Jaf7|GRsQTdBmU&j7-Q_wd1S`1ema$*?s$(ZzYx8WRf=Q;pP;3iS_sd0INv ze%yaz7iZ0MIr~~9MKdiOvYB{TW!*;!75)W)m2&BdS?ma-Ylfl%TmH&G9Q06CsE(FO zkA7J?q}06>tYpvB+0KR3=W8up8%nz<7q-;D+DwBRuU=Bd=rs1_TK(PBEwyf61XOYU!3j9pk0L4R&Tge#1zr;Q4 z^>VQ(27z3=w-dutyE{h|oPAx#P4^$aIc0PgKLw?09sINUyNM;&KeWOFU1JcHkM1>I zjSE?sL+XRT+lEMww89hV4#NI;l<{nywhvLP5sz`X6Z6brDRYOFTNk!mdes9xv8Wdp zi@fyKRpLRi(p#xG=5z42OZew*im_}qUVd|2Q16>osiiZ-3&~2|IH=X!JTNNa9aQ0{ zuW1$)z)G4Y9->-_15I6wpnRO+u7fsFwpIuiNs)dykh^6No3Go)t+@K}j31PYP1)Ty zrl;-PmmAQUX>t32=+T#d;&&hnFF?k`2ZxB{nYsp6{^t1Eh z?tYSkyANZ?|3Z=;>qQLKRA|I|z#TZkJA?(PjRSR@@5=Q!&v(t{<~K8R3jTDmxy^J_WvjMc zF)z8SCC@GV<*9JDE@t9rkD6PyOW6JS{nFZ@6mIe{(u&TOYQZmR9q#cO(Oid$ixW>= z&j%{l28+2IV?^v8#Qp~*JJj`O>rb*Q#$80X?cqfzHnv^ZYkFg=52^*Q=j6K%X28UU z`;8R(Gm}TvFXT~Nz1;;Wc*nwva`x25b85)#7V4I7o;~oHPozpuS_5;lAG*P3ZiZd> z>6{>Q$lPx)p|28|s=%qjV<*)SoR(se=sUvjQC?udev45jOL&GuKwB)O;{jmX9 z_{1~NUvrbuKW*$)SDqeLO3KKh9KgVE^y<70rvS2H-`!6ox><2|W8rE4O${?oTrX7Y zG;n(PyBEx`eq?+>Wf1A6DprGX^#BWGcd?ikv%J$f&p>gr517RAn6m-V>ubC8ho-&1 zmuoC|G4Ixamz9ebEBcJ^IP4Eap7u0xJr3@#qvYLIE;nCb!8}fe9fr@fW)%DaF14KM zECrX#p1U?*_#|)1vvY&$)wJ4?*!Q!ME_V(Fq;MlAV!8{Dv~xgJRoAFcozR{}|di5nu@N25Qz6W|~3ULD?7<}3JU@;N*xqj?au!5c4g)pqN*xKb$45TVt&aQfW@2K zleZ208YR`Nh9B9N_Iy-B59HW;6w8nCS~3{BT`+s+C)N+vajh7)ybUx9f8&>-f_=A4 z>_ukN3?e&LcEZ|mM$d<4GX3SP~#GIs0(z6{M}~q^{VcJr6X#s9^wdw!|G#x0qOtI&5bazb`2NZzKx#c#r0V zu#c4Lh!pka$?H<~VVoBeU=(cab#fIg#@+~D^U`!fra%K{ZbMvaygJ&;yV4V?j*aPJ ztW5HA!COrqKXt1@;U8)9TRu`Gd2vJDN2GbzrBL}R3&0r03E_N4>ka$ybz3HsQhC)! zq3lYEybb)pS%{U8Jl6rSQa~1JCSn0T8Y28lF!_r*#i?pjdDZOcq_!pKT5${@eW>ex zTJVv4`+s^E|Exb4dZ*fLgZ2W4c{xw#hC9DiKHhBg8jZicdX#_wrKDi5)v2}e0GI|F z5T6?_qwtul6+7E=_q1Y6TA<)GW{amOip9y${T8Qm0O-XG}w zxSuz|L@yzORo{lA#m}C7ayKGGy*uFY$H~ah*xmL%BF?$b@7v0s(kd*Xu?H5Bni=5L zrs24&l$D_jEg7Pw-V?&UK9rm`7Nh;;XaFTGAdwMD4J}xdFKe#h6-OcR+S3F@9jCXVA z;@+^|1C+L{R`^@gb1CwtX#DLOo^OJ0EJH9@+J3ZA_Y&(Q?r(c7YMWM9?9<#|XwjiA z?5wm!(LeJKt;nipwjW$AZaf(FMYL-aZ(o2SG+g~s;64wi9pwL@$hQhi8#Qi?R)0gQ zqAraJFfim1Z@uZSR33mAW_piUp7n(o(KFl&<@1|sb`Mf&(iaP=H7JvZA_-S18OXO6 z@yE;-V=0BPmka}8H}^Cakm5s|%$JTp#Ci6s`}?C(8be!nFBqfaW`ZB97jx6D93=fZ zirhhI&&X@NGSN$HcA1DJ-UMhJE-B0p1_g7d;s##!4+6f{r$nv5Bbwo^Y-q5;wS}m^ zus-&sQMnSowh|q0A!_y!`-4kSAv7Zo?7;nbAoMF03}9^w)pI7A9>;NF>#1;% z^7v4vxQ5SCXD(r8==}B-^CEp|(`3Cko`ix%i0p#}YuIcd_qB1+`d~m`t0lD6;Kh0zooWL)1c58@3O^o6qvv&Ya|CYG^P^R3^Uxqv1#tAvnCqfl)W6 z_P@xeH^8hq9Oe>REG1Oj8HNjRVc4h<+L6fCreeu2q{4MtMt0|pMMdO~@4aBurO!Hx z8stB_9XsOqwq`z6x7N?C&lT;Y0_B9^M=MowqCS{@v3_KbLWoXGPucBgX@21c&yXpl z@AGXlF<`w&Xo5KYo`g))$_Y#wZdI?RuB5p%o15-^9cXFGnph?IiO(v`lhl^&!!vvWH2XY7~kZH*lcsj@p&a5B~9n8g>W#*;U1uws#g-1r8P zJh$L|n=iR1=E}~4;EyPG{$q+mA#}{NFw$%do0m;|z5D9{RfKu*? zt+vr2Zvf?$xKA_r28?<7$tfZ2&}zur3lm^19U$laitANWhv zh@Ej~W^mno;VOl+dir|CVfskBLVBQP1Mv}NU27tZ9QY1Gy#exp+jN~I*NzU+zsUHV z!slBUdR&C<`xz88|CWNGslia2FI91Y%NDy6u3IJ|Mlbe28%MJ#(&Y43X^Usx-tWJ$ z9}q!0-n!21#a2tUlJ3ewG%hhciSNw)aV=1((MV|QXau~AOwv4EZUvXp5Y*7iJ?TG~ zRJAo+2uOxM-$wt6(Y0p|Ww}bg-(>vw9$)#ot3yR0*rwxw`n#%Q`9XsU+;iHc6vpe2 z^x};i&*fJSYSdJ#7)YY#X|%GUdL`bdx1+vV`FVoad`}1hIdFX)%|>*H=A_Zw>tV&o?NJm0J7lZKsmd>;o%1Lywu_ zmP=&lVn$0+kfAY;ihuvH{?cMjy@wQI=ug>DYN zXK&Qo;2Bnbo3Lh&K+(>?$7DS-kkL9!kI&aJh?Dss1C7PDn??G)M%m=rdFm$(9S`s+ z-E;`Dxp{q|0ZD6z@j0zVJ4*mTV?s6g(v}85!{z^We-9spJ`=Hn zgiT^$f!@aeLu^Pk7Pr(i#ubFYAXUofXdTwQjFIDIkP*KLZZ%npEdeqEW5kbmI4m)i})2M&#KYP!!6GynVA@0|V}^hb$r zwEAxg4N1KFgawmK))+%`Sdw`v2u$|rE*}I|O4>FZ0AeIcIn@UtNRzA@l-FAGJ!`-y zO|H5=*N4@*B%xqude(^iI~r+r|B+E@@F)*a8|U?B7bB+9={T&6-Sv*RPVniSqfP8y z`^*1U=rIu#AfU?!@xDglb`}5&nt=1{M;fA!pTTU5?LfVLvl^cx=l>6TIRdDKCuJiS zK_m30&0{e3>zj4;``2b*tUany!>(X8lra~&GZ*TfyY;n{ds75c z8v#(2CZQ2?hr!K8b{p|Zy zE5>ks5KhfcP*DndGHSV;GcvmA2IWvcNWTYG8_uZ%ksw}EZ{96uk~g}!GOP(_)KK-# zVR42Lb9sjEF3g=_`@hWefd?+bg%=F6oa#Bg5jC*trt7IkdPzxXZz@u7{xmetJ@zx2 z!+O@3ZGtW03!ShU_`vd(83&V*{Elwm8GK&!)vXS`>uQiRAFV1l;*&D0b zX$!|{9oHwHed9V~fM0wvMC5(`lc?y*GRw8bT1mvy6Tzc2NDlghh72)AFzU-j427wIj+)g%2P?4>SH~qJu1tx|e^IccB zuVi9RfWp`VHXedhFOc8%cHaw9H`KXnlzwOPWz8S)~@?Fy`*5C zVBEp3(Yc%DwYFn-X5rj((9&GJJOhBzd8Z)bPK<0aSlQu-Eh6Y7)>3f1B9i(xp*2YX zhl_{O;qT>&?+fCy&`)Kp<^v60~-{eI%l?lt=C@((J(XVma@3 zrrNDNU*%$EkjcX)H0KU1wgh;_n_p;cN$VWi6rmi9OnezJoX#mnUQlQK4fpT>tN67o z$VyF?=g5-NG(%frEw^<`h_O$|-FE;tgIDQB4Xw>@9A{dnsp4(PkvL%E?Z%?DIwzo> z+vT-0qzOO=nkFleSoB<}AX2n$-ukAzGvfwj{jm~TvI%o!x-AGW~5`3n7e*FmL720R%4QP^i@-6L(+;hp=Kmf`u zMP_6Nc4?N;$V>{k1v2HSzBA>Pv-3GB{F`(v4p;*`xzmz;0>Jn*wqsmbpMrY`NFN7Q zuChbc;oX0tX=S5SC9$Eye(KX!&$ky*n9;cOAYd>dMC0y3$hkwt}< zA5C^Ygr&cm({0;nqjjgcY78E*v_9>XV3sLo?cwXLKYJ!7%GN>Ik@mRbnrFKT#b#S^ zI?JA#gTT$zWDa&F!8PQ8;3|wdlB2 zjps!eaUx)jNW)Th$9-!FB7$R1vU@V6si%MtW)+iTM=0CcYZ!2idZ|~SSF*Of?R{bs zDpSBC+oxI66PhvIK5EWHZT-b`PeWluKgsdrx&R{M7~RD6my(2$B*eKxVaU4YbilT=LGa(e@HE^!vc4xdR%a{NMM6#X0&wA;ijj zl4|x%Dh4#xe)}BF%9kg_T{tx)PdgX+i8~1RZmwn7$mmANVYnq()nWGx_w`$A?Q$E# z{6J=-c4is9Ezkww>C#-%L$p*C-{#KY8|XTYZW)`}@iN=#>&s325oQa~{QgROC@FJ# zcu@{c%^ym0Ko8zl7?0w7(RltRqQGZiPV=?|D%w(RE_*Um>Wac>RA~KAflDQ=6M`j8uBbgt`z52NLo@DrP|EC4j~SHDW@>f zr-?B>>1!MEO>oWL+)RM{{5y!tMhl^-1ffg}x+fE}SO&0xzb?~YLqi2U8mE+(-i*V9 z*Zi=SFb%wgu0Y*|r}$B|F=FlxR!Xi;3Oyra7)90Zo;>?+BR%!U?J0K*w#w=1^6WRQ6(D<4 zGIM}T(VyLLP&foj<01lSwSi&aHBJC&Mp&}&9rH2f>!Y~;E!g%iB6mtbQU7A ze)$a}-o`fc8)lfvALig;I8=WU{RU27?`s`3D+-Xc0v#NLzt-gCxU(t(Lj$+1KA>$G zAV7yhf$U5P?V0;w52^vajDYVz{|&t#J+#*{6gNmsy-mvg&)fq&4ef=5!&W{a+m%o7 z?2zsLvN{?+V0rbFb75-PRUMt3{u0_b+PkAx(mS#_Gl00|-u6v=h{{+y1?$6D&^&S8 zr*feDd1Y^H&V_(NotcQ}wUKS%1CjA}7RtGkEPYRr$-jU%gEMl$NuB=i62ooTE8?VXboDVQLUx;NO3Cm$E5PIKvFy6DOk{n|T<2~trYD!srADl~X(rog6?oP~>wRTKp=&{i^ZY)(kC`XR3__$YG{e_JwEXNgTIW1?z49qVxP2r zedw+LV)jh4SXZ@r6Pl@FBnFo#Uu=iekYYIY_V!t0o4RQW-)RDWmHjP7o?4fi`4DF) zYhqnh$1kKvE^8BU2U>(szHhfP2Y{X%T6;{AxNN-O?c2#|fi8 z@3)Y!3co-$sYiXBE&;gmQ-G0kApbB>0#N|2Ul|Mp5~O?}PmoGFV@2<`}RZmS^NscSdz z7@df|S1KLVKi#cMy4xVI zgImG|fwb0ZPqZSf*^V(>8%8(4v)yZ*RisqzBVANJVPp_DjlejM*>>3TuJ_iWrX%M< z0~l;oQR<{G*)SFZ7&@|tJFeTu!eEIE6A_pQ=de}MN9BJ>L!M2C#(0x% zo=tBzkcE<6vGpP7vPf$DLa0vP4^zolFm6~Zs!`gh!f#jo(+kHh z?)Ac)Yujgl4%2Pp@XmJ;qeA|2Wwh}1dS*$M#eN$K#TbYx{RT%+rDpdZYUphKg`)o0r;GU( zo-O%Dy(lbi(XmM4vh1>-c9{pWz~_4XokD81S?B<;Fp7*sa=Q;mc4pkt`jAM>3aNY7_2){U1_gBgLX(!AoMik#PKgTn zY6o3aG!W6O@%v?0m!XwwbvMO*$2n1>C-wiSue-VX`OjuDKv|>T%4@^$S<|02&el-d zB1dfPyXtOto~IOkHWaI?X(`P?8;*XUEXij^9XwnFhlu!degjOpby(4l-i1;-m;+uI zJ)V?!li7Jc7voDTK(+n4ErUaQcUM(ikG`(?wSM5z_INoqtNBgv1#eCA;(aL5^ z5Vz$G#;W;4#5Vek4NXQ;wL%)r*?AgXQc3fl=wMDDN98}Ism_n z7M*f+OlLaJ7d#;siy=dW?OFHMe*U$Y5d7aY|2>M!Z9rOIAd_`Dvcn8oTPP|L0bNL_Ul zj5t$2M_zcoU)mD3qu)pisApxuI2$=e0-TC@!+xify<`m7V$Bk~?IN{G{()43_UV}Y z<@hLM?Re{TNFAffH>1Krr84G6xsgz>OY7_w?9am+4Wq?;O7S5_aC;qM3Wb z1<9LG-(%J;)2B{b>%F=Ot+rRui>t);Vk_AHFH5y zVv&AIe(15rn;(}BjgbIP3G32PPBHr9f5FFz{nxReVxCh}T~{7Zf@b^#2i&>p?u|~Tl7L0zY zDk`4rgM1l`v?n{e5uDmvC>LRvjXwcNb-o_#8iCJ>8 z>Gn^d#)1VY>5f`Q{(5fkf^^?$^Z7|`vy^$rl2BxnsxsLmw29ei3Ul1ZfA=v(zgMez z?Y|Mp_p-3Wj)4|<68A38So@*19~dq0esQSaRv_slaiC=SJ^G5iIBZ^T+e~nNlz`R^ zUd!s#CciCG$UHomX5=z844YwW0=^03*)e*Z9tC>D{6v^*bW@QGn4Z5rLVB#+(%p18 zY$@0dt(_q2Iia=NiPhz$d1PwY`ZltEfz9&yd`SMJ%_$T@NrSy$a>OCshJ6jwD!DTy ziJ{_m`a*e8CQlsq**k730v3LgQJAD}&MNt!QUV_UBYZm^whgS`?d*Wr;ZWeVUd!^i-SEBlGIRFbmo%UThW;Bx~o~!Ql(Atq0 zeQ!`#;(e#CFJO9^TSthmXDN(spb}-6MFX|~T!W~!g=xJX zp@PtkPBU5+{%k~gpTaGTo#x;LbC5pgTdORX+!eqanUMcqtIQLQ3E8$EzuEK!?Xxp; zT8`Iba;Hpq0FCs5o$ilvbxYNcz?vZxzG_=Q{g;gGB0$~fgR@SpPxZvTo@T~xo-dyn zZMGqhoaJNhg4U0jOq^E-1oG&9bNckL0GyTK;+-Hei##J7gJfj@JLM}RQKTn}#!P`7 zw)RfOq!_8KM_W~U)P6oB)Jb_5X%Wg_Zw+OpPx9$-4TtKD`FMbJ+b_B2>ohg8tM<|O zzvi2U;Zo^glEhP{nUOG1*oD)l3Aa$&zZeTB6S@&|AL`3KE{oc31I8S){c4jT?Tpr< zk}T-pjIkc&BGMJg7*JYLL**{w2f*;?o0!7fLR0nXs>-jK6HjJ^lB?k;( zop|m|t8Cp_fNt9t1oV%^Ilx$>p>Jv7=bFO3NaG!MdP;0@zLQtmeAAsd?98Rs z`gz=gNgfddFoH%e8w9p>DKNBJkHBVaRT1}g)He&n*HUBo3s(t(yXOV62*QH2{7n>n z&N)Dd^7tTPF3jjv>NH)hrGWdSUJmAg?7HZ?U|lpY$1=rLUs?>W>RPx48nb`tGYs1? z7olL}8i5#NT|0B!d}kW8GrcFdu~z5$qYin09b{(LeH3q8!G+4&)2UV*o)$xw|^~4d5HaDOR-EZ&s z`cN&usLi(jG>L=w;VxcYVj`NckbP4Nx&T!xTOf9_Or<;z%>FA5I z?3{iqs)ZR0aVb5h0C-#;oOOos-%4e`5xF$y(AqzGF!e6xbqHDmrg8Ok)J5;kuRKyKld zd?|tIQV2D&TW0em|L0Ag;6M@Psa`xbIN(+PF<_vqNZ+r&D<@ikebOtT6Os<_#<$Lo zZtBfOkVB{w0~MqSiiaNajeA4DvdLKO7wQ+2P~@csg_){;JIR-sDOgM;^OGYp9t&AF z-)S@AGF$-XojMaJY@fHA5zyxferc2}a5Z-#s}}FnY~yq$m%nj%ag96XjpEKA_c9lC zGsmJe(A+OcD04e<*~8ubF3oo<3T8DGop|&gqhe@RFTmg^f#Arpb4kvcq2KY8$Mf%W zejwZ*)vdaP%qlC)%GBFPHBLpvshB4hqc*8X@y`!l{Po8VK5i-#HwIq zGpTn~y5zp`*x~B(+Jfn=FsQrW20#$<%>gN-quGoBoseY&Y`Y8Cpt>5|WwDEMWhIEH z3XX+ku}wtY1De0$Ibq`xyd&xtyf;3Y@=pOn=Cx{JO; z>Bw{*SN4NcZ2cnYHM#ousCEuJj*%Mho)V;tQ=q-j{Jf;tHlm`mqRzh~hP5Z)-eDS|N+D~XzKw+Gx4nY;0K&R0U~HvbPKf@^FuZ#4P+QMdR+b59-QZIeqZa%vLm8j6@3!8$H9K{E*{ zoT9o%N-ka5KTTc(`25|Y_JEx%Ae>GE!FWBntt#hy+^uJb6+en&Nbk%b(!^2Mfih3u zq6}juyfQ;;_e;gmgQ}=pJL$8I*%>^6OXvGl<=HPCMf@IbJ#(i1OS3F)+kUaE%Par|(1Pe#%fpG5{;VP3Q_-?`(r ztwd8~CqV?xW%j5xgC}@ZS-=a6T=!zQv_Y`!1?&4n?6E~!h_gDy-_cA)_={|}tca2~ zoo7|BHsCedu5akF^OC9LA01d=qL);h-f8?SVvH4DS*9AX$?EGfJuUjT0{_T7`UBLXB!Z>@3uES@unE2>ug~ zScYf?klw=GyX>ll+Q7+CKS=*wy0o(YZf+LQe@&qZI1Dn{sW;446QzsgB=R z2Ap5EuK`*JOb@W&$FI02)1WtvdV(;Nc3Yvt{+?2h=6EZFM|+Ym326>*IuS-AjvBIDv{0{6X!`YqI7;C0(4fy~828iQ-c|4t6zlmt)t!wrl7Zcz5W( zUI1%C8e%By34raAv0XI$gR|1?#)H05+5dqnO7MQ)TKuk$BAn9$_LkIVtFKK0sti-F zU?lI>IqsBfA85pdc#mH} z6Y~o+Q>ND{-|3p5+S9}h(2VvU8%TG}NPm}=;WsEYL2wn2flFTZfn`8AhVB83l|cB1?@Ek$b{^T-SA%3bHT>sOQ<}^(N$=zm&<6}chafa!jvyQIF0_B4hOk;oM zCGko)O96KiRGFf`$*kMJHvoexj5`;0V8_eEXqQ}CfjV?$F$*g?RUjO{DVA>UIf=cO z`f_+O^~8!ZAYbDvebDzG7wmKLf>r~%8gC3h^(nv}*AT^tG(f@2)HLJn`WxFIwkBh^ zOeOTs?A?zWcUH4-g)p>MJ@4h{i4Hk>*HC}L;?@i7-x;*?Bu;9954F3t`O^bCSOGl| z8wivya5D{TH&DIsHDa2Z*>d3 z8sd1wp9=_KVV}{npZPi9x=Kwa?)J|O;(3l5yFka2a4h|C{o9|FXIBr2WyvONS$91)V60D|xLIWM(Q>7a?ExWE~n@mI|uCPtQT)zVv{fg23 zo+0OI#?2^m!;k(6Exl zdEDF>;Snf~->*4`Ngq&WJ%)og_KdTd<&6G=tiSR4f>L&_i^ev2SIA_*?-=jSg9L3B z+eX5=fOAra3tR^%ZkPS#74u?C`~IhpsM3ABR zW<>W)Y3C)Y7(l(oDqS`S7qSko3F)Ap4(}sl-dtvmzz5?aKE?pnAO$ZSgBy!d__WDP z&SrxEFgs`A`Bc@0D(ZFv)&aI}ZMy%q8`$sNB2WAr@=Jp!QP>1#4DXi+B^s6?9Ue=n zzL^xe*IHBq6Iq&$9J;{X-#xlN@C^H{4jUpK=m5>I4uLHNo$w&fq%P=y*=XHX?K*eB z#&jZucf{n9XZw=$=jc_u~&Mu}L z>;5iXlV!QD_6VnFl~*La?i?2S_#z@cQpNwVB8K>g9kG~|j2?;D`8XiW<$tpW!|vXj zS_OE?ht}X7-3<~`u12(94|hn1PFwx2kBe@dFehx}J*A^@|C1A-p=slG=2IB}9i*pc z=5yR(9QI8!xeRL12gUhr>UFL4%G8e2md)>pEUb+cdmQ zMa}m^MA@bHfL%AEEjOk7n7WA_>V;!#$ugX(DX~yBrQ+xj!t1g{ghjPovuM&^pkT-D z>mb_j1Ki!=;H@*`eRh$*-UvHaS6}ufF{ln?`Gd-@qy}&+@jZW1{yK(u| z#jrEhvff{R^!`EYKdO~BXGmW_am9Zhx~>ZTLu_ADSDfATeKCLicKG8B6W@iyXgw?+ z>Xm6eP_c=^G;9^>-^-cMpF<4>Jy{iuPu2lStI1#n9|x;rCu2_a5j#amQ@?k9eGWeo zNaS`Low-qUgK{NJ8mcXoDZY=N*C<#CXy8((!vtSK=3_dSgE-Ayc{TzqwEXrHDX*jAmd~TL>tTP#>9fegT(JE zPF+v@)Kw^U-oxh|zggmMTyUo$?e@;OWi`Y*^~Hipt%^tRRw?7BUzIU~oe6%l8#69fU zecv!0Z@+ggWmn?-cHR#VC&DMf4VN3~4iua^(7btzGqr&FO@CV~?09`j-N%XWd&^-u z*<(K$H0BkWL-goxe7`=--x-@bx2(Et=1@3NHsLC;tOdgki@WqTBsUCZWb~_PZ1wl* zDS(;PsglEa#tqzFD}sf(1wM#qr|So>J`eghtvpa1PlMs0RVz^nRrUPl{y5njPY;e} zLzTS&>q9K}i$@4xCRU`T;cIKmd(p7 zYU8g6`lBCqiVuREGUqs-a4)U+6+v?)OuWmQ!L#l{6bOM)}?$T}^ zqyHpi@aGEW0nfslf+Fj!nKb&%hWa#1yHL{U(~@nC#u)C%;sl#O^1b5v1=!0|hbe?C z_0`fZop1xa9)M?*V|-=c5{yz(yQp*rwiFdb31hP6N41fPC0#F3lP!lQ`$S14$zi;2g=aPAgpVZKn z+ZP?ph|)B-^)A}4hk{diUs?*ravW|dcY_E$BQ2-4PtiEwf7o+E^&qW^zd~Ril&BN^<<|2U8x#jAPMz+PUoYsE?@5-#VO*$0=Di|t{<%Vm;hmhJyg_$|;oXw7R&U>* zX=m)}oBQoT&wobCU3LcW=F7>> zm};xc?1l<731NgDoOdiuX7rhLpPTP@6%@+Z+2nhos1`t^+WbYqNIYrqF>Rj|S^tH! z7ws6rr}0UV)orKEk|grj4d2gF=7uGmt{Ir@j6@*k6is7}QN-UHZJm-{NW_8%f1a$J zxh0^#Q7uX&7y(-7I(1;a=N9v14r5m}6(Ntcz;Ay#;cF-{%Anu*V^*g~X=ECV{y}6F zw^cj0bW#%ag`X)3kpblYb`k3{w|qeR#-8@wUKQ*a5lsfpM&o6e>pz4Up&NBJOUMUg z?ByeaB)0%)&HylCb`?Ht^`}m}6@>JO`LkB_|Hl1xSg)hgY9k{cOy11%4_U^I=bSNJ zb~f*cDN-_R#qq-^y6Ce~Y0>?3@s#^>fAjjhVwxHH9n?AR&le{zfeRL@wajYipOjeP z6v&_}P7V-xR#Ba%e4XJdoe9-GHzG0Fm6v=FjpE(-EU^SY52|9rvqL4gc%p6%`m7?6 zM^P727qjG5D~dE$(xPUjRaIwO5?mbLHOb{QOOhcZrz}KHzjZc0d1I=ZaB%Hn80`2O zZ}2JpuvHVd{Pwlz~UWy_G5R~&hImv*ANOsJ?gXqB{8YRilf8ISkN8U78{#39mh?O0z{q1)&E?IAb}0(3v{MsI;-;m`i;nQg zvp8_nhFrSdiI&gLX8n4)by*80HP2-8-F=Ql%zc!Afr{=4=vJRKPlLTBdX6XLHxr8X zONnbnrdWV_hnYTs!ZGJdl)R>BD!v1zx(J1DJCcoy0-6&c`-sp<1FpX*}OgD3__!gA~kO)sd{0 z(NAbN(+HEC`gO0uLG9QdmMGT*mac_x0n>3#6mWca-70!@`%Cd)VbhYNDBWQd79?&} zA%>c=8$TE98ax~xa`diZP4|w7lLp~BdEDTu!Pg}bouVV2NZAWDJbJSj=UH7L!|^_v ze8N&k0kx37oi=lf(*B?x3~Rv>r)|l9Yn|XOrmeNS0bb)P<-%*G5=h%4>f#mpPio7L zLG=^#W$3vIfXB;^s)H$soav4}aU|B|3anf4;wI8YhYq4=DbKwidwy4&`hLS&2U-P7XC})Kx)%5$A{2tVKOJEx=Mr zcr5?{?v|ablN1eH2XpC}z87`e*@^dB{oT>~&X4T9>vH|#olLad$;^-#zkh>VtD^|o z0EqfEVq?Dt&906(9r1c6&5bsoJlrJV3K&X-eg)m&+7)A5FGU1WBBx24y%JBr1J=5! z`Mf+2#i^n@dT!Q^9ax+E6TWALVTxMDz=k6uKh&_Mpip-cQjQ^|>bSBIO}~N`;azb) zq|-T!HsgT8vB+(6Px?)Jhg68~j0@nXOEF8;uYxqH;!x90Q7376E}FErzF*-Vlxm7|1hNn0;Sii<|% z8}0w=5PCym$yl7(SOHqx(%Nbe2D2bTzRQ-l$aZK~(1AKJ@oKR#@1Qcgd~RUJbC_2_ zpSDH`z&YCa0JKhHCM#_BRdP^)RMiJu0Xj8^rsi8{6~gSr2QuhlEaETa?jg+kB`>S| zmlG=e9>WV3z2}{62;~@8`VW>fCZP;KoSjmjXj(&mV;<8_vkT?fn-7nquhWy#k>_$C zx-ln00fweOin<<5C!iDn!hgHRS z#gzFgN}SV=$NeM%{{8Ziup?+7`{nnFdY(7DXp^8*HZozV_9;3p9Xe}ut$cGRudD83 z$o5ND2jc2rl0wP3<*P_L-Vo8Ws0xsy(xk5g}6=!g4)H(zp}j zG#V+VHaT`{>roLk+Z>qe9v^3K?<-tdvwavG_X7cpwM1w8n`p(Z8m8epBa zw)2#1>`GJk$rU=KZpDv`1~wJ$cE9yk+P7BoUA@>9y~)9~XA!lQ=T-Ex{HDAfEH3R3 z1O5tdDg`1y`YHc8y-{HRs8a&qMX@m7&Frr_g9gPwXY(j=`gZw1cvM@DD$J|{KXz}R zaP;c4?cW%7&qfMW77P5^gcoLXrlR<@7gsIWpOGq_*<@N@|Gtt`uG`_{eILSnW$i}z zG*GAvF#EE2eZgFE~OPtF5s8)QJ1}(U*;IG+r3)u*83;9R8dpY z4Ief%BWitaz@rfAy1DSzJ{(%$RBNQ8o)Wc74aNtSCS`!u2*CDpZbVq{_@X0gjEap| zxf(Y8_S1zXu`oQZYm(npaTI~}N$G&>Pr+)1tUD3*!|w(kNl)0u3LBbr32L}k#(?1* z^50D7%N_W-1stBNICb!{mG4lfCHk`jPZ!Oxed1n&nkT`7@%`IuKi(0$N<~Uk^*1m*PQV024|o@ zU#*@?oL8FH>(mT^i|DQ%bYlMe^X{L2fk`fstNSa_oO@x?wR9~4iuHzm_?_Hoa}b9_ z+PE2CKDqW$yxlDlqsLLWU)fUVEy_$G^(W2eNcI$5qUzO)La4xVY?)B_RxGfao z!ob}}e7s1>tN+*|bn)vCn-tAyX`1|OmommMk$G9wwjTjcor<<})H#!D<4gAd4b8nW(-@9nQYL%z?QF0z2nN_XU*MlOa0hp3o<)-nlfZ%iu{_N2`*aoGf%DU zoMrFJ4*@%`gIf}3xIc^FBZE&tsendncUTBjL{koxaLigJ1VW<-6%AnMyc7GNDm`)- zwC^hi8YI3c>|d^Jm4wxA)c+gphPF%w56>&=?&>#2=VU2~oQuf}5r{jKs!D3)7fUa; z-A`T!j!LKky7T3JUtor6Zf6*L_7SAi8CW)QJj?49AvQ=?ci=4uP|sPW)Q=%Z)8=^o z;C)Un9u+@1b4uC>QSN*n3T#mDvoLoAmMVa8flL5eH3bEYT!@h=MH119k1L!v&PJ~X z{h>5bEkrX^XcZIw*We%z5v%-ZoI&=l+)Ewv7hFQf`P7A<(#0NJ`@wXog zMv8<)5E3AOl%iW17JOX;Ta2N-FTFqZH4!VQk=&xhHatr!6q zG6a8GHf%giP1-IdC?7^@lTDCKuU@aRqW?ANQcwNlGnnD1=`FEV;N|GsvHll%S`iQN ze)>*V8*));zk*@VQ-5KVv+Eo-X33WdWvYfU3AkPUT!ZJC@JNw>JM9+@sTI_ziM4!X zMZw9i%=yv)Cjgxgo7DcS&sJdkU$^Ql;lQs?nh1{=6!p}v^Lg*@W&dg8Y#(gvY{N{x z6I?*VZM-EginR$z{(}b3WtFj4{}W?n&+D& z>0-k(R-uLH^WABe96g3#GDr8;EL^$h%*jUJ*{PdGiiFLV%$#k140DSR%q9N{Tw30or zcos(MxTii6$|NCGgf3%GB`!Ehx(B-0^Y!l6Hh=AMSkHyn_T9BtGiLV1nmHOr0aW3h zVH5gA>vp*W=u_4y&({`?$o>S)XA72cIr{-aPQ`?zoam1_j$XcBayMnvB@Y?nE^SMa zf|$K#xT;1VOgPjkafs2+4wE88pz?8v)^1Wel7W0MAu_jU6Nl8$(RD(>lwv4`{D929}Dm4`j*itV29i^VeG7>D9 zH@E?t+5aB(Y7q2Y+MlUII#Wn<@$KGTTU<9!{+rA>&?oVY=MFIDEz9-d3?`A@anssFEf@SwHek zZcjVR*Hy!g--*Yt-Zf;yU+uLf_uiuUaW5Q`b+D2t{S}ElY0!Y;55S+8B8o!2$@mZ`~(^6 zxcUcJmgK!AuB@$Bs~ko?I5jR(t2XsM-7{!a6Sw|)PEt|~3jUMzL)d>p%9OV4!#)w$ z`$7ZR^1;M}*a-k8M~#N}HRNYj6zY2E-~g=Hg)$5h$*9mss$ZW7uUi(;iJUl67O(T> zxJmHqiVqgP8Z(7?M#1;kC20$z!xI66*BvYu&AIo3|A4vVIn0vyGq-}D72>L>FYh_B zJFb?8IMZckJJOk|ts_#(<;0B;c@dG9ns2vIUz8~& zM2dXLC)5Y+z{QMqx#ZCKDl&S-_c{3>C;w#EvhdYDehdOo(lH@Qie%tc!u|&({aLyk zJ8a+$eHtcjDtT~8dNi)mhSwsI_LSUSFe#uN4dJz}QJ3D=n?~Cvur=(&A|n+#nqz$$ zQ|mp?5k?AXzC&;e13Gn{nR5$TF`xZ3c(0{flXJ}7GS9N_Eu^*G!$w`u0Q(fVwseK} z!(*Di`kD_NaTzSUZQwhPSZ5DFEXTkw`i*g|#DN@-t`Vkh-9~QCf4pe93cgVY->?9V zm!w4BRcJNE!t_u~%-y+hQGRxqiALSi9no;1xC+WFGukdAbA{%ppyxzSdAdJn-|sW@ z(EWCPA+P^Gvc5a2$+P_*q?)#3VztT!EeayCWduUd@+uBSl_Hxc5fH-;D-Z%og(6F2 z&uCd9gvbb+1O&ncWraOM7-57F2x0vm?Ay2BbAIRHoSegdckX#1D1N4#yM~DkfhJsnV<(_+CUG?sXsT zm5c+?nE_ADHU^G}KbueT{vhx7KzBUy%2T_Ecj@1Xibugiq0(p43g{Bvj&5p}#-D4Z z`V>Zt=I(ynH)GdY_z(cp6Sho`UhpuM^3mb|E#VVlFwCy-0b2>I(VN!j$V_d!+{}UX zO`#%Rmpg5kNbJ;ERG=0ln}2a(1moFE-5eup7-k;K{9*`Yh%~629}B2#PN3L2(!6q( zHuGd#!(7D9(H==n=+-7-N@L`}F!!g1SkZ%7&SM_1Cgn^}G~|1j=lqvbM^1M9+EzJb zzdIxw`+eQnTsxh!L1#8@WoW{0pS0ZGB-ZlHxq;MHGrFb>wg?8^|HDL*oE&_%z`*@v z3aW7TbZcPpY@aaWm&wte_{dxd)3o&4vW?%eC72`f4;K(+IPgydrFc{a?K6Of6oy4F z0R4ZXRC)Y;LvBl_;D}0v=uCmEvlpr<+ri8VlgWKRFx*s`;@W^P3z*P6^M*e_^)~(h3grwg>Fk>jp;IbC;;gAZGj~t( zh#A_}oDBl;CL(Y ze}%LSP6GjG$J=^?65WDVbDds`RPpPrHl|(@1GkMV{cNP6$o+0#=;P#IxUXPL?^~f@ z%CKrknz6PTxh+N788CU}LefcMg9}DhVs|?mj7;W6>G`R~sY!iBV&`0k7?M)N7XkT7 zjN6N`spQQDv>5V8Z(%{UQ(9NBKo+>r6!i!J4xIhK>yY+Orj}kB9yiN0$-mgFnx(*tVlB3C5U&N(@Hja z6~CbClZ7Z~2TF-DzSP6uv=YlD5zB8K|KDKmP2K8h00){}@(fD7<7kt90vGS}6K z(2=UNzVL(O?!%3o^s36-Pj)mVfwx%mXfuz8J^{cG;#TLKML#z|0;j{oYlmSOr;B6! zl-hPN_grEUv)%M{`#HUjOkJ+x8Nu zzeAK%0T1CcItf7rkj-gEvx8jtv?ZplBYvm3BCMRljp?5#E`d-#--pdSOvHP%>CCo^ z&da%+Y}eRt+svD>^h|$V;~k%@!p3TUm{GTpe;cgHhu79iM8VXm$OH8fl+_bKbGkfP z_>+pT?FkY(;cJAGl&#^Cm0R8=Q0K^c;%W%Of{QEL@ zC7Rxza9FM51x}|ZjO1cx@yM6l$V>LpnT+wfQR!4VTqU%^zfIVwUGazDDh<#<<5%?O;09fuSr(J0e7{~|uYSX3cbG=DGg}Qmx^A7Y09Z9L zUpKItF!KFUA3EpXG75@b*u4$V&;+ns!@Pm}N{2|-=4I1B>IeUge1d2Ldo|QkqO!X{ zS7#6hggobhQN{MoSTFsZs{$hM5{6A&?yNxm&iUDdX#Fv+g;(^GMw(Ix$qfl4CL&IT zU8ebFlZB%Z2oK8|CHab4z*_xMr7l@DkVG3|BFfvl%{*s-?MWNJ!`YjWPdqwuOVx+t zO*bOf8p|b1h*WnspFd^lp^YkaeK8(=Y)R;*3M&ThbL<_$qxEw6;a9+tu@QJQc(F6M zTIahYpS-{Yu|b=oUZA$63vT*<*mk!DM0N@{YKSHa;5;n0eu=Qc zybJCI#@~MJBq9%#Y8YwL&V|K=CN8ATP8*g?XYBq*|9Dq0G9jMoV31e79Y8=f+ zV&F=K^7dQb`$mP8V`#2L5z=hHUcR!w5arABa-z+6he6nDG**}H;fvi>1Nn-zxJdUcu|oRHzv86BP^Zaz9^&+a$O4Te&gw%Liv%=8f$%P{Vxzv%238#ej8LDCxQUv zPE}w4VD7;~KKMTQJS*H>+M6mQE0BzviQhSWBSN&1vsy>Ha)w{Lx8@FXUckz&ezYuM z%JkUE+F&z$Yc{xs3CxYB9d-uIAwcs$sr)-oDoctz3p5qJ=)+0-r-V8@7ldB7`=Z{j z<+kDzlzPYYc7F^wU~n3vdv*2Qoo%!2*sZH8b_FiPRzv1?oiP#3aAs%DmQy$L%57A* z%7Nl8XAt&*1a`AWMOpE>RX4fCn1O4wfHvl6Ea-NRQcWH8XJ0qy&7BT=T9w!lkKOm^ zbs)zjJKXDr0VD!SDnvfRJ+ECLfByr{IZLTc3DLevNqv;T74Ax50i&44_84(|Ku96{ z=|Ni%8IZ~QA24|u8bT}s54QsklaG|#?5Outpqf(m$?(011~Wo{oN1?n+)q)zTiO7p z6{rljgtR`T&cDJx_!qQLdF}&QIqGUjU|-`DFU*b8A~U6K$VUeDgcXG%laK1mk0e|4 z_cx?mAMD5H6VhHw%m4{g{gUc5cZtUYQG(zMJCcw;F-n!`#S2!1EWO8z~IcXl)vs#lKoH|s>4NUtUpI~~8;>D**GWUnyb454n7|G4|f z=DAQln%}h_Kiao^*EW2**GLqdoKaSxWnDh-rVN;#%{8lKZN@ZfWLL%`D{xQ4`52n> zt-Qcs(a42Xz3x#}`wj;y#xLFl8EwHMpX-=G(zLz7fr068pLAWLGDH^W#$(C^+jucH0N`=Gs7K~HK^LlDP(+gMXU5~2eYUP;)V3n$COc{s)a z5*-! z+?YQD9B9<60^H2xQ@q8FO0*v}6D4VhD!HtQ(a9Njru-kX@O(*@UR4r8aaqr}Qz(7FhJ%5wOY= zKX!i%fLQ<6;w{;3_;mCovtoSZFdkYCi(0W%r-1^hmln~A16pdw7--Rf;9r} zpkK?SmNya2h8OP*6d_jh@DC|!#kN!id@|C2!~Jkmq}6DzH5S6t2$fiMsQqAq!f(uzAzgGXRxv!dFbLz@utR>r>AWCUs9>IDDk!+wup!wm>}o-ZFmE zN2^y^2vW~bZ5GUcLE91_{DETQOON*64HC4MO_rtMJE0|{lf*PaK)?F3Z&=N3bN|Km zONqper1J^5O`!QxK?vj-&E`S#(~BGyGo`?W#*(x<=}A?&i=n-r>nwHUF+#&0Ma&fL z`PPnXvVP&R8=+osIZlh6oOuqRw6yeow*clLl~Bc817-ohVL7Ol`sfTeS{P|_xkBmj zFnudX!5+MGN7~9u{Me}Xi1RAu2$WhnLg9>chqb;jLz6(|Xy|nTf~}RAbNKgs+Su^w z@d1{<4$z)oQ+uv?^C!k0B-kiTdx-6Uo|JAq8C!Aa-u9RtTpH9uC|Xu?$R)bb*fy5p zBs}3$Y1(kJH!~E!bLAHRelmF+4x(n2x25Qy?W2?eA^@2{GRUgh#&s=%0L%lxZA+;K z*vha)LY?JUJ&)9-HnIvQU;rj5lnV}AOcyYhJyOWLHShjeAY;^uucOwkrb3CM@m+ZZ z;7ah?LvH;7+h4rH?vTqVm0wiLxu+q@GWHu3*x(I%3n&2qj^vQto3T|Y08UE{f!45} zP3iJbVoY0=ZRaDN6ElxM4BiDm1OUF%TH9g0a@5z`Kme-*Z=F0MD5LO*6c5yz?0i=1 zUg%58vv3OZ`82xNw^j**Y=OeS#_9~_uamq!UM{!-^7r%UH`(wE- z?2ChJpU3@LUnF=6xaWp=AqUL#>uNDyd`c8%vF+4(%(nDR$oTaEQdpVzj>et$=|L zms+7dAd=Qk+v%wb2FaW^8nUPcRK86OMd$a8-AATcObiLLDJEx5GWr<5F%)m(M-#3~ zWy6569@=}e?BHBy{^EE&eMeF6sOL--mwUi?-$j{bkNWz=P{)~wuZ0gO#oQwHMUrt> z{ZzXkB#>Fv;L0X3lyrK8ff*D9NQt_ZXaZhi{FGb$ae*MBbpX46Lb(MJNSBnTbaz`b z4!(zjbDRW81I7dlKh?l5TJW?3S6N zo?F0(yi}pfU%f8dtbwGrTi$Y%DCit6>b|`%t+V}psA#+9shQkrUMSuZ&Z)K!r5rSe zAf&339+s(kKu!QUA-UwezFFYYB+6a8@%MwIQxr1wtyUR0ErIwd*|kkt&%APw>>cMJ za2H+KJ&Kk+k1M22UwXuJucg0}wn4H?ukCP}sl~AA#M#d!2kXywvle*Q z75G?@xon;~*E=nJAT+#@>a+#`qmPRDL>b(pwg3HSC}>We%1UKZg)GIQjP>El=ywf{ zYs!pwi~hAl(k|T3d!D;0vn+&rz1^zb9aYOtRuMnF^t7)kzt+icTKQ4!wDFFGm5n;v zx!oAbYAp|Gb0tXTQd>;gj9&v{R=e5X98h(Z*E=ppTOIg|gbS#vId5F)%ucuR!ZJJ* zxSyIjVz4tnO7_9k*i0MfAR)#V(BwqUK5<>2ea7SiqxN?FirUt0F?F!6>*zB+-l%xeQS3 zm$km=@IAh)&~7ewmEve3=Kr4s+V-D7twQh3LX)65sT|f zL%-mtQ44eyH^u0#em^N@(YTV`>e}S?!P6+7NGQO3lrsWSrnpDNbv7)!;-RQ{DBNvd zravD6%iceR1`;s2?Jdl-v`RGR81+V5I$tiC^IM(Sx^j_1?PiajjsG%9y>@qO^&tEO zj;6>oT30by%vHZy%j7Dj^=4}JXnlf+nH|!~ASbskA1P=5e!A>IH5Z)-$?6|DvH4)V zjN*9a1>{ov)Ir>IoAua?+b5m9Q{4a@q!Y_JRW9NITprRPK72K^LK_r8MUu;a{TQo0 zUpoQhV(8oGr{UN%TO}80%Q)X&1)E#xJFeZ4-nTA7

zjI)y_DGvXov{)#-{}uQC{2sbuh421jP({xbBriSqEDk!({T+We5P3n-N-V}k&L`vSa)+tlHGJB!(RkUE}T7iR=?fl**{)c7|PvZ;_L*)7O z7AiVm35j4GrEiOX)G3HQKLMWiP_=NOhar;epz2|*Ph7Eih4FsMZGY=0-)scZ6aDpX z^vRe%i%dQ+5%cUCo1nlh~mo zda|?<%}mO{qhG~zaVXG>Mno;BJKPseMO{)rN4V2dPmWCJ0ck8df(+$DLAZ1@R!OhQ z(u|uAZ<>fAHXU!@|9TcviSWci=`w5C@)T-Y-dkTJXCKErHdn&qtN1v86GjV>JOMsT zuyolOj0J3b61Cq<2BSVVgmUo5-;Mh6Lpg%Oi)hx*g*E|UKD9oN?KJD^2>`71&$Cg? zH{Np9`I!3auEw{a8D%vImuNSIjCY6I14IvoCDI7i+`2Hebgom74sKpO+@=-C{3dn)=vvanlZutP!dxp3FlsDhe~ub+D+dUDq>a>}l= zx#=+4N3-Gi$`Bp%gkaCNMxxr49*r$|VA_<$U>=j$Q!`m8mjjGGOvu%zB%P6{Quf;J zo$lfbQE*!{qFF)*{bi#^tKb-Ggp6sj_MG&7;Z1obnz2PbJLf+XK#ED`o+J7;oeW{M z-&N8-DEcaDzi7(`lVG0edybUr8u-(N4PHWnICq^T=6pcwA|^o5VL*A1^Pg2buN#h1 z$Xx-jB2Q3F%+s?bKFG-kJD06U=$)Qar!DjCB<&%RHbE?dV7>NbC`@GhSJUR+aj*8J z#)%rQ3VFUmI70o-LA#Iy=@C)nr@Ux~!OcFnlV92Mkycc|)`-3_l-~A0I9&f4n|=vm z7@p|ckCJ!B3@L!^3QcKwWtflGUE{ZO4}K>nC~PE4+EG7d=Gs|qV?nFn?gDq1718Su(UTGp6WDal6uZnP z&I+RV&uLBU6um%iEAHoHUMf{JbX{2}u+zxZ^UCs>yyo?o8`xR$`+pEQ|APf5oxFlX zn(RW<<2-7gG-dSkIxO9cTanzoK*beDPcDos;An-M#i9412Z`YgM*M*@{+#$1$W^XD zNo@HbY*H?{B_9x{&d}&UQdaT8(Vh5a;wqC+&K9aeU^vkOYvTGBY3asmrRYhP;SGXMCwWYiz)d&?Clbs_nV8HN92(U)%wQ{EzZZ zi1}r+L;k<@i<@B40suDs=wzb9;KK`#7Z|!f`Z|Y;@B2W0)~z+%y;g1CeBjGD8&p1C zVa18@?*bp{=_qM!1|52yoDe>qnCJDAG`fvl^}O1qO$M>vH!EwctMd@iWHD-|p(=q9 zoLsP!3M|ZZ0dJ&O9v1h&jQ8lDGAKGLyr&Nb;mY1lr=Sc)Jk}XAxl#>C-=mb0p|L6< z(xBQV)DuBXqnt>@r^4D%$Gsc?8@!yJ&EcKF$3lnInj^=b`Mb)m@Yy$ZUZDd6q=Pwrvl(xY|Qc85qQrAjewCFrSKgu0hykeZOtBSaXT|c8o zObWG+3_oA;P80Ht5@7J|A5Fxy7d<|?qd0Q z9zC}mJkBosmY7R8yl{VOnmp=bYwSOAS7KmggEjP?N%6V5>_|QvxKTD#RDMe0G$)%f z&MMj(C84ed@`e&huVqASb>?h>S5CtvsQSM;^w*y=m# z0zG#l{J5Rj(Ol|tKtS_aHj-wTXOyRantt=~6r>sqOca}a91EiC8q;X6zdA&aE=7$G z2P<(<)_ea+e*&M01Q;U&@!faeW?#kJnvN$CI|Y1c!8(v1Sx@G4gERG_yY`PPsrdCj zq+wG^x?SM_P-7XuD`^>fMsWQj+-FMxSo7cu?AJoufZCke)xW9vTqE5W{cqRoKvoQ zUo4UM$Ysyi>uf{8?g^CvE>TBUU_Sfm;kUu_c;U}0 zqEbI_7+uDZab#)7AoX#4R@Bpi!`x4WI*^?%V(KcJ%SO-Y&^$ z>|;h=!D1&3Kb?o{y*stV7>{2u_NQ%m*1u|4-O>rzT?pwut#R<4))7TnO$^mJ(}m}Z zYZjbM*1YB{`BpL~&Jwz*>-5!2JrtUoRoP)}Cp%!F@tsn6i8%H)^_`_2s+R6B`f~<3 z!7xK}wld@(Pg|;-S}m?4z%VHWDV)GCla2IJY{z$!W^eo*3)r6(pOINRw%Yf3Kgx4F@ zo};u4nk`qFE;f5lAeBbO=7#&DGsLO@1Z!6=b*3?QoO~e5iy%*xo?gtf*?zp7`;!sx z3aUfF1~c4JbkU(hA*1FIS&1LEeUE&e=4H{t_p>|H(yEAFnc?v|)79J@ZP;WYuNJ%C zubq-h{ZqE{qR|L;{oyo{Q>Aj-aN4%jT@E{aZ%3w_85>Y0mjjKLp3>h+O%jxgkgoz8<6VEmwZxdJ-TXO*Omzg9AOpm`H|J z9?^&0;7!2KGqg|k{??TPy~sV!3$E7^W$uvG6NQ4ie;A)`Y0gFDx%OwXi%q?rcLDN5 zabK-NCr;L3dPHnF)(?>E)g09on!+y21B9_3lh#e(J08BAJJ-BCT%~o206|(ZVoWt* zN;tNM)A-Q_T6no|>~*Yhz(`T2&gJHHp$7Ix(!5Bx^Aupc>!7`WPcJerD*jR(c#6aiT_bB~is-1=BsW45?>d_ZqF#UG2s=Yz zKZ!+7iUk}AC_jfQkU4D^X)#Yc3~kHAkMXmx^9?P*fk4O?WC<{{ZRPU;7#_}xOdL5f zuN}#elmSJ@C)JvpeMIZZY1ZN&`IK|&jQmlPV!{yFEVW{*u*KgBuC@24G}u72c=@S# zHJWphmzdH$$}ws-oeHK#L?-CrSWygx!(KyE27TY%J52Q%6O4M`ZQZn_7MMebe>)UcRH~( zn}|4I1C^z0hDK5%e{A_rU*4q!LnUk-^L+qsZjadDo@rH&-PZI!eHUL4=|@|~4d$w)#hg4?*n8NogGUN4alw7yED zU2$~#v|6=Y+M21IV0<{Jxu9n>vUg6T{dm_!5N;rLP3UByQ8I4xQAR<#=)IZd^@Z*l z+qOrAjpt|8qI=9BK~&k?=k@BdKBq3D6g%YLmt_;#z5D!Ef7`Lgq zvY#|e{kA+_zqgOwcdL72YaTeJBD#N1(HC%kj0{>yq=y-$vjY^}0rk)L2DBT~WpqkL zK`ck&`-&RIiu!1^_4e>AE&9Nb;!N_o%VPVX(bFJyk9M2x-CUl zgkoIK_6S^LOf$n|Gjdx4aexFKFwaK0eEsW zEZn1N;Fk<&ta?thJX>S(p+X5Y`_x3h<-({wSC^;UucVR_zJ&^Ud60!VJuEQDc7r8< z0#SGduZg?ew%HGYusl5G6ZvqP^DOEAgod7@`_=({1^#d&@Sywf>l@q<#8`utp#oH+Mx&N~rjs(RmPp?!a>yM=xDsB$kfw9l~#4B#mZBW+Lwb2dH zoT({;%EW%VGFONyo-@yMXg;K$D$M8__MgkTyowtyl>Uqlm#48~CA(pC zhV;SU9hww%Z(>7xVq+ALsdDpAv_QV2OAP#V_s81@lKQn=1|0ykC!M_C0jB-bu@w~i zzn5T|3Siw=3RQnIJwEvPuD&*)qRgn`#a-F12xGfaqRGmt(ocWmExLwP*PzHbmwOs zCFXCR^LHX{eJ+8o)48q2-K54hjNg0$Xi_VjwHdTH$bF*@Ef@<|bjpU?MtGh2^l?}A zd-#8X(9wW}U^tPynQbKc`vHF#<;NQrp&)eom-6FFw^!?~dI8^oS$6(c)WSa?rJESb zzAv?-hS$Ww7^9n#dR=}WP@DvsY!*aoYiw7Mbs+~`L&N7FBP2UR+(K*#G7yH9uQLer zwlLhPhz-CP7~QYntFt13*HU^?WHYwR3Mx>J4o>&GRU_F!*#@IP-)y9xj0%o4zz_g( zlBpI=zU9uMzX=`^_UKV>G7_&^+w9?$$}n4GEmM5kgpCYXW1*-^-4oHEc0Z~uJt>_1 zb;`lUNhw?Bg)}ulFcvc<4U$Mw;#ld-bV9nrCNw<7zZV6JFv=>9k%Om9F_qrc5 z8|c6O*9|1d5z7lU`9|~jkH6?#z2Z;)9r2IS22lBp0_I$2abvP-Yt86B@F(;fyEK&E*k1TcZMBV7-mEO(-H+vOFozK|$(m5p_ zvCVP@uUjGqKn&f`1POVN=Ot8yl$8|I?N7aCh1~VJ){BKJDGi`wHtRKW+N;u_KxX%` zGq*pTO^w;|TlcB~N+dd` z2aHsGo2pAcYv6Ku12WyZ$#CbH=7AVWglPVg2TQ+OaX*+_I=XDX|Bi^Y z^$?cLiTqhtQ(0Y5tv9#`7C`-cQ{Bc&KUD*D;=Z+EQ^!;aL9|h0QY04IyDBU?DkMi1 z4Omysh5XR?hI)#utFsCGEnSp9ymp~8$BaHGYPC^>c`{Hr4cNq%?gJvp_~rKXfUo}` zjer@B#_M{I9i9U9WpHj@H?AK zZmcZw{N05#EB15i_$XrKGFxS=eTujv-LTB5?Y?fHk^uq14h90%w04>Rte^z{XnzGA zTyaB5Pu%Q#-U*k&s-K}AivssW#6}-LC(Vr(slPkI(Ur|@4GAObmlK!+HN&kFQ7+hc zBy>_v*sTD%lNT$w+?Uu23A~!KB_^+Go``DEWxRnrqSbo~$ z-lVEP8BK{++qc0|!1fb#r@ow1j23nBLVZ41Sv^?E1>?2cnohSPzMFh?qxX$5+O1oU z?Dmj0VYgam&a4{3-#N73KSIEYm6-2-EGBfppZYcg$4XvG*v_9_<#0R1nhR zS8Ldl`3ju1?oBlElAXft_zUl^iWq?#;(H*pizK?`Zo%UIiyO;#%C}38dZ3K5a_OV2 zgQG`7LaVOR7VM%ZHf|;rqJX3e0(oM@;x728>Da2v^1>Id2K@1w&EZ;9!#5;^t>6H} z!svCXjv{)8cw$`xANnae{;~3X8##7lPuy2O#VhP$iJH4d)Y@#s-I)TujGaxAEkPGQ z8t3s)3Q;&%th~`L+OOs?O=apXno0o}OHCBVQj!+q3J$n8-5a{>b;F^L)}mRp6OU(9 zgFjSZNNbgaJ)?t#Cqq{Fc&EQ~8Y5X+9aF=Tg_m!`s+fZL&IfUe@H@VMU2xmzh=!64 z9h7XKi_Y=}>R0hAA0qE)LxGBaaO0@?^&g)m9}&{uNNK=d*qeZqhnQ1y5!aBBXN}+Hu4HHlb?o_*`d$;d{(dFy^4ER%6fVYK882y~_?^XX81*$393^`}%B#UO&-^a~*`d9Ixws&)ehT{?4Ls+A^u;@Kk z02lRVyQx#yMllAa3+M|?Kj?V1GX44RF$X zxCc3K-vwb=f{)21JRKTd^tG90qjn>k5X>7xx9#81sdzs@>Yu^p(r}jRPJ-*s6tLoL zAuH_p8%%4SKa?y$hp_ovviMg(p_cXvTzZ&|fAwnje;{b8n1*|=o?2v~*dW;VY}GTq zb)Z3=yRC9G^^e?w*vWrvj3!jSlCxw^>Fv+o7@Lvi(Z%7;O%7Hg)KbMLC>sj`lsHpN z0=O?m%fSa(6?>s{joiIbW8%SP|8QyK1N(@`aOxk*n?%cH zBGbTiR}-KUQAgdaHz8j8!QXFsm)0lmujhbUYKyW2yBTfO3Mk?Sg(so2EpybqJmT>5 z9W2P}H~$s?++DNkZdw=EdLt=4#8q~M9vP^qwdES<9f&Tcah8--`O(Q;_R;R^3G%yW0>Yh^@w&db#cbxIeg?bluJ%Uh z)&t-$a)ejRJ6alxKbumrup(M^UJMi$L`+tO#!-V~Vs%Mof4J`TiQ+*4s5ha}3pNiw z*Xu>N4>L;S!A$<;zA&#y`U~j^L5<0RsXFhfE#O;_5EB26C4FbznrGvBLn3S`mmKqO z_Gk5uLg01}IMP(tuDXAd>i~kCC!hiOO8YWz`t(o{WS{!0i*y0NKDVZQ1cOyV)zp*n zkScLPC5u(NW;tC|l;y^Oy-@KT$?FB5{cZ80?}_eo=GuOd-#{tpn|I_rsY=MTJ* z37uopvldIO?2QZYX?@M>Cg8H2FUcbdh|akx#>a!_4G8<%4pXL=LG~yxY=}`;CN=YB z;CCfA`)RsIkk%J#Y4^Q;wG#`&j90P~Z0(=J&w?h*oRRTinJOJOYf#)?Uu>ZxSR*V| zSEt9KLne?s$-2zkp6u3Ss3l^TfV4vTa3W=Ic1NB^c=gEy73KOz#`LrDtRgu?vmeMi zn=f_ZviD_cqn>|IuU;@fm7*R9tGwGBhCzMIGcwttuI^2 zv+yv=JDa)&C=wgWy@!JBL&Z52Q+>*U4o@=nK1(|Qu=w5)EbemOk;HiJdNEp%Iw<1g z5b|d$5#Tt~6$Gm=p8!IcBPbf-QTJ0Uekaz_i_^6kmaGtf^t0|YV{L}TO0$b<&UIVK zO_&+FXKAi6?(ns3tji~4*xvNg0j%sO;UH57)%5IXv&O|LCmfyS_fu>o$Uux3+$<2y8IlU9dk2sM2)f+%y zA(!^SbP#wu+{C>eFRwH01z^)Zl*|OK1%e^G2e}*1=H?C_RX*9YSN4&mo^mkUc??#B zKBg|}eCVlNq2dPQcRm8-QH8XQ{|wy}uA_BOCeUSwTZ)AXrHEUu%l+Jz{*=bB%;-}Z;#F39jxgoW3bXcs-0PuM&ih*N^j1H>Xu=z7 z3LJ_TEzJn(&Yu2B70}MmMj%7PG$W}pAfMdhHG47AM5%lMCvg#aAg+K{W`08QUk~w0InJVP{5lXrbua&aCI1lUBO{Z5YqJ46jYLbYGJfiq-ar(Y2;26<)yTq8^BysjFXHvKy*GkqGdm>jITw z)@pD}-vd<9KuXDQp)BPxny^`&(=%#P6@uAxkoSTP-=lrGouZdaUY;)u+k70>QBy#y z)t6&rMYX9L5tP>YW-%XB5rw?Xf|o?M>*}p_DsYMc=+A)GM>#`~rY8+Hmrk>g5WVeD zq=GNAayqekjK}!p+w5f=QnfCNT`#> z1s$vwS*5i~Bltj%_RZTUXEZH&pYGkwS|r9xGLL-b>4ewty^Dr|Q9O z^0hbqUF0`s5!~hhNB0O5!=|=8%tvdqAjk$qv~t=I3f+8{4H2&doZm%442$vsipBl* zM2yPqv7}qD9pfHNdXi=J<;Yfci9|Ax!HzuZa0>axqi!L9`^B;Wdk;w$P6TYtQSjxC zc&{K8F;z%K5;T4xct&3|Jw|ERJhZ6o+X#@)b=AH}xbs1CvJkGCQEDkTVECv<#DK6b zR(5_3_@5YMR;w;F*_zdI=z?3(IgkkPIfezkjKP{UbGWfX;jf^I2cEvYR~V-VWia>4 zI8SHa{=&*mRVii)vZl6?P`_W4V7BN*41bv&rFbW`Ur;s?@>s?qO)2hQxWmprj;B{J?-t+zD?uRkL(viqJW zveLSpuim_xBIZw1=rF`GjMUpoa6xv96W?1sRHAsaev*n5?UH&Tal`+%wRqz-WU{uA z`=~62sTjrXmz7?&(`Y4XG8MI-*~2$A!@9?lh}1CI&fw*gc~yCI=1i`d`{kktVTBXj zzD0419>s9%G?I3O7Jpx~!K%&6b3flb+0^D9vT>aYoBk=9GroIdZx_R8h|b+^F>KPx=1&8izQr^{#Wg_tw(c zX8Y!e{qU05z}+QXp9wmJ1HGx%`Of7TMVJCy<-ZBHWY#jZ}2l zMZlbA;wRlo<0m7OL`F5B_qcC}scd~F^AdOhT9$AChzrJdZz=eFodJmlo>7DxZhV=# zFTPZcW_4?L0OFhf??@c?o@D7t=xBL%suS@$p(@jB(fbo6$itQXQNq&lXYJh#pSn~% zfi@94#l5J$vwYneUK*+t_xvj*E{pdq#TIau`_Gn92l6}zc}p}H&WYm{lz0kA;~l)} zYNWVp5*s}gPb)?(74J)%dh~bZ5}XL>gMvn)3mp~9^Nr}!Pv05mdo$|QRW~I8QaP(z zJnV^Oc;(s)J6yoMnHV4&l;&}2pV1Xuw9`nxy0)ve$xy#7B46409>Fgo5LE`F3mUGZ zsh;rfP%sUgeJ#m;0NOa3MRM30G=@&vLGhfnjCIosxcE0@T-|fD-%W=HWB<#XJA>qX zJ4zf-+Z9g8n3=$xoS`C}9f?pa3R{O#IyK+c=Kao#FEvR$0V(o^8R@XzNY&t~*!OSd z39l{qME5C-uUAq?vW0lS50k07t(Q^Z@4b``+_&8a6cJ`g^k{nsGWE5;sj!XnT6$YY zXkogaYB`hMM@$&OReiwcV#dxe#q+ z>D22?m8El4s0(5Y1N=_idiT~(l87kGX0l}lZu>7CTCX&1)T2J}YouOEY(*Les9P!U z%W1NO71KW%`49JstA1cN@VKj}iBuILrPZWW$=4bj|M2?Y^KK0IF5ZnLM*Y1V3VsI~ ziz-|1dSpgrcFs)Te!|e$>P|Lr0^T=$L}O8vWSyR{Lj*@etZhkvwYnqOw=g`TX3_Ha z2-gE*J3?4xH3UAczF6I@gPUU+1| zm1}sEOLjU&FdsAT%NXfvWs_uP?N{gu`KchX=0pF&H121MLd5<#B6PDlL=DpyPqobl zDl2>h9!h_)R;384*lB`!%68r_&@C)V*2CRD1If_!*S7#ERc1gVdhunNZ=rj4>kgk! z?mP)fE4f0w`&0!E&{3O4~V8h=k-mXU=U@H?!8X!Aea_#9H`iO%M zg*jU?#HywSq=^8ktm5%MZNnp%HZpB$UF?f&|$n{rFgbgS3F4m&Mpn7W!T12Rh#Ad#2=+A7N`57sHy8&aF?O;=mLW0reJ2!Vgc)QXWEmL^V;k#? z<@fga{+{P~J>Ng!-p;wM>sh4Eef032W>6#;GUm=JwKO|t+R2lxAyiXXt zg;<2GpQcY?3z%oNH}0M?X6qkUR1U;{C*G-@Vn6Zw198mZs)p4)P@7AUcq-eY$YOy` zFr&;ZhCGbf_}2bqdLnjpoD(&ksFo$$jkN9rythD;J^j1Pv&OzQQj(m>V$9X^4EtS= zvTp{v9G$KOUTV6d@3{_9@g9+o2zwz$|LD=z8z8-}xnJG7(-BDaBxz6_Cmna^CDmBY zK;NjlA{I|sU^1%Q+CPl1Q&VR=(*AinSuBB3VhHL-QEEJ$J~i_;%$9S{_MbRuZ*e5n zpVW{43C^DW?ma7~zeRUkC$4!1T-Gl)lP)fD+c^^9a(cPaXT`2edLonZ3tSo}hx#BB zpCEfL^bS)CwpjP)pzn`}us|g5``()(@p6CWGIvEgg(Xgg&=3zI3(Y??2S|`6h}!a- zho2aLtI8Ovao;_bHUcs8r>!a&#r z9;mVOG2Un3f*fT)oojVO^O6#m)0!^qNxq(vQ}?i@5T)BA`OT5#`skr0BvmTT1>v7+#9`sgVGNgZu9VDyE-Esgk@V6MLk^GUh-Y`s1nvWw_L+ zmBk&LpeH6)U43#WonCJBH`A{|8A766;&;L|1h`H|OoVLLjoIA}zE&z*#%L4U&{t}{ zTf*MsRJv%jaZdS@d1lbuO4uD&8=FoMs@S;KT5Ak4G?-2hN6~m!^jskHqNjqBkCo$` zm%Uy0OI16Cx}k;d8P>||eZ`?8T9+8u^GE-MnU*}1l-{ON|1N)e;IBJPx4OMuhatyQe-=?ZoY&gJFM_$<6sC zx@A^6VCm)0a_KcPwW~W9v@;2@;SWUw+-mQ7Y8sQqW%c)ct!_*I$uLREq!NwCw3s{= zKWR7kvf8ThGW$U`0s{q^xfeEZ>ANgFdN?}NY&)jMU_FKR(SJqfG8Dn>C#qFBGw$kc z2RD+3T5BhR#y1Sb*d41}NkwpolgBS{=M+H&CxsB)q$htIqrCeoF@(mr0oS&DY&LyB z@l$RTP3*FIPZ4@NT+7|zj}V`ziF5s!IWXysi#ZZRk)&!}P~((n9d1099ku2r3TKD@ zWH`7G@>5TC2zcXJq1#~XY5aw}mQ~$k8pk;|)yd5+?{EzNYEqDN+GlEEF+pAaaINDZ zPo1(BWNXxlSWjl9H1N}<|d+%y~3;GiQaQL=>#vt;|sNtER zg?wPx6Tiik-LgjNcVW!x-?>b3wX&W=EpO0npN50(70}7j{Ld*Tg_84J=~Kt1?>_fh zZTsAkFufA1q8VyA| zL_dn7`P8rK*nUD?^XD|@%nFk-(LW4eDT?Iq-vQm{4PIm z(1o?!UuKBSqVAv)eXpUI2VCpeFzV9>UQ(s02kdBa9_mTw%vaPc`TbcL@2m4arpx;& zci!A^wCY#A8}VY+daOduI;8#}g>ll@G3x=+8JHJ*=<8f-SmbniaOjeevR66CSWY@E zkiQ)}o5R0jrG;?}iTd_F?*2YimwLpcyN0&I+Rk6~xaa6psUG|GvaNd&axP(Nyhv^A zOxZ7)XZ6Ju>E?d-<86kF=Iso5Ks&xyx{Rg;a)QtovR`^)X+Lp)M!tWsWB(8vg2+yi zt%LuZJ{ste>63IEU)!nh{=PcDf-<8jj-i^>KI*m0yl8T|qNPqOG*Twx38QC|BL*p3sc+%(589(xbR87IYedQLv?R# zv(N4EJ$sm*#ntR;RV2-etK9Bs>L2KNvtXDD?F1WK7nOLBMWM5+#V&E^q{om=r_X&r z_Tf1OD`l6z7mJNtBkN)w>xB8rCg?dc-sY7WV-=5#H!bGZN4?jr<0X+QkzPk@_`d=X z&C%m`JMLSO-s~?+mIlU(`F0R_HAM3a+73W+qbY;e0b59r~C*MpWm zB*^Bmls2@z{=zTGv>f_ElDsg26)fu!9Yw>$@jtQ@aL4R&=xkF%6y5pW|iaVauiF}xNut>$z;URF?2 z)03=wO$PIeoDmkZ<7bLRg$v>L^F+_1n!0rZOl3WDr%7y}bR)OI$+hwBKg}vrDqUP2w4KLK$H>7Q6eU z$s*|I-{(wKH@Ww3NXodPKj|l@3w2;WeGdK?j)~w_u+-%P8x)Glu`TOzx$~!OZR$>N zb`QaS-sAOiaN$&&jgRuRLww6l@_Gi~H<=X$A8%@${<$uw;1EV;8pabBq!AzLqp{gZ zPu=YRmwA@SC1stL4~AJYD;;e@pBfSzsV+Xk(J_b>ct2XSnJW+%y>fQ&H?Ru5K+Y=c zQ9cgIe{37Wqe5y6W<=8~vBE+{w)}Ky9o%$BzJHh9pr8{JK%7cG7Iv8(!VbI>P#Cq4 zi|3DGenhsEaIc^helh);6c^oenN)TRVeG(FeRr4+eJq}|PZ4`L7eS}8swVJpbMt%5 z3d+<2LiNol=A1vs3B$XYH*36Gv(|6}|3aalhn2{m(?M^{rGV}sJFFJ)i{SL|lY*b< zY^>loYrY^tN|mi-k2Xw?2k7vN30TwpjRD0ccr62?% zB+HD$d;HPX9tKYjdj7ah5{=V}gGs$VuRa}+1i3ywqAP_{rk~PehN+h8n4+OOa!lB$@Pw9tC-GPXK?M7#>_l`RBfTT`a4 z;W14xkE4R#o|TqYz=Ot%yU;d%VFAA*@j2`jPB)w3_60;T58ROJ3w7(ki#z9O=`AHR zO7rI)upfOF?G^twKA0{V{5Pb!el~~m{+%Gu4O!xhudQA7?nJe`H^d$>>i!Mr@M}?g z*sI?mOWU)0K;fa=jOE*Hl4V1e%Hd0;kVDWrsLS%Wd&F$&0o4wqmE&X3GNc0(bovGdbUh`v6d$~&#kF- zAr<&+a&@?{lIHfuq|5+wP>7jl%-J&-lBUTFdQM^5rTUMc6{3`ne+9GMFXbCEqi+m$ z*O}a$J&10Ft!MlR(J*Rm!Ld9hUaHKR7O@;m^sM``wGhq6SYFy;@zeMqFoU=>Ox#drZaDTkIIEc~3$PRFQ{pzkq zxzVzWh(9Xk6r8>xc{MrpIV!OaEz@g0sTZImH9G&JDQHzJ$3~TRvWC+w_PJH44!8T3 z^*M4ZVo;-7yio&dWdm7-20e@KS~g?|97rBR%xZLRg(OJYKmS|svU;GusSOekosVgY zEqIb0xIepJTwOUxJ-?iD?VaLbiFhjT5N@A6gik{&>Htr(Tx2LSW$C!QS$J5J-CD^Q z=i2emW1X_whEDbASfCCD_IG0MC^bbyp<6@RGtr2)!>(>NNTaPpmvg z@jACZ$A5N9iEKQ%CHpYKecbejUdE9+`RC2g*kVUUM;o5WVwy@hoU;%mr5kKcl;WeL zbG322C{?ElPIpUT`&L@Ax*pw^{HZ;NuADlTiG^? zBgD$|RKeKbtg+Wcd?%O#Z~BR-N%$*)BMt&!9D;Z;yiM9oq8iJZ0ZZ4KaT?_=)g+v1|_MB|F{ZOEXS(J}RPg z1<``dkB`JHI&h=DDtPCu@puT+xQ>$J@23oFbvkNrI_H_ml57b20@s(GAGF+SqxxQP zT*3D=Ns~rEqPSjqSj1oHg3L$=(pdhr&7zhe9ZXJ72H*b&jOz&f^_xShqnEW37`2ka zb`1P+Ur3o*QYrNKpZCCi#@Iz#xXfq6jBEF%;>oz{9T z$UuR(@>8Nt_}JPmhcb9I!5{uT^%J$Qc}#2^y>|DeGWS};kF-8UF4APW@fu>;e3r{% zIQ!GMLpSVPkj(r-NO78H#Ve9#4|M7kJWdaj^6&vvr?p(MgmXaN3DQlP&#Ft1Yx$+m z;Q36RDP9X~AP})DLFde=d%jXuB2CU+`4yDmwo@5kv@E}!BZEAL;!cSjgLpWvsW@m7 zIpr7j#jqF&$rms8g)1PNJ?^0Y&_gNA| zc1DkFS$U(7+gqoB-r=+t}2{ugh^{94B7PY1ODh)x0=phB1>#g?h zf>DkI(2$syLLQ#g{h_6BsRs{{dr?|{5w2{v@jcb!dkR9r{Wz5t@gM;Ws70`$UH0DR zo85H2%aQ{uYU9vbBID!~asLxifYjiPKy;F^*jkd{HCOO}s=Rv%j~ubH zxI$+6+0;t@`3M<8N^hm)6%{_*KSXvQS^uXR_iau}w_rpNdHXg=nE=vLQ=l09M1dcv zjb!cUU~Vo4-C`%E5VWS|8@+aFo&49TQ9r=9H#|eWOC1@X2(@bd@Pu0CoKYOD@CN`c z5-nxW^PW+HtgW-s!}w0cU32!MhK{C`$alT?#dlTA*#Xp4oruUX-)E#(I(au^De+!= z{R=IPSExNIak~q7L431BoL5Ttqps{LaBQ}3vqOJKB`f;XYC8uo$YVuzsm%S097-|S z`TV3&kd);_zFqq*nQ`qh9vFGsBmOFAId>pt6@@t55gBlp2q-=*o+GeT2Aa?W^7hgQ zfgNB8UMpA$S}&sRgwf<=U4->YqZmEBW(3*RP>CCo>mEk7FWU3d;y+0}lbA-7ucq)h zj+adx7Ujod<-hF6Qhit{dDa&OnMTb1FBH^=R6bTe<=5j4KQ&};7-vOvPn-`DZC9c! zgvbA#EUmo!Aji`*Ky1F`XRYg;j~9Rff`ZZ3R>(e@rLTHwPq^4Cj8?Ec6^nUYgED}k zd-Cej*mt<1yRN;3zk}WBHdh92`Hc{^Gy~^pw#H{!Vc#E^8=_82=}jnw@SchD?IRW}Ap0LYR81_o@bUJ;#i4@} z|HqS?%1T!84>^Fd9#9p$b7VU63d*M&S`imxGMU~*h=yPI-s0Y-(l|sT-Y=Os9uB{p zJsmvduB`x5@LtNz6&6-BLMr&W;n1F1bE_nw3 zc?oo<_NMyXpEC2^QTlmqeI}3bIb3g@U-R?165T`?#uRg^Bl-I?_NE(84JS8=HpjR6 zdIyn9*RU4^?~fGHzb5SD558q@An>aEn%8MHdbo73cIp{g>EC7#X;pN{yG`# zrI1loJ~|H`IwD|UD?g7x-n;uZA1>*IwMPh)8C6@8CL1kiI-{QPFc9zHHQ$J&P_jdN zfk?QS@I!`UGdLFcs{*enragVSui}ZPNp8o`G@@QQ1-zVp`1$s6|F5RSf38ukT9eh4 zg5K-R5Q+BPy`kpQwDv`A1ulknRs$Cv+;&b6-6KAJ?N$q(Uej3&&8VG}+sX?;!;j!i z4^}sRWc#%jGy6j%b7X%MV|93OfGgWdV@r3aZW-ez(8UyDN zappULWi(MVUfiSq)VMu+>>vk+tmmx%8D`*hxjpB1L%tg_kp(kilHBW>jRb6=WvQ=e ze05)vepZ6JS!x}|O3E!x$rHHj{H>^b5=GSIh`P}cy2nbx%^B#fc>0gw`q{O(e!I`= zEc!iQ(0hDb<^Ayr-%6^}med|{e~$gN;i>39b17u1$w#s{&iUAf;LFFDdAhC|(ptI7 z-IeC_5$cfuB}vY}Cb*XV4196VXULSxJ4P;4bF3Zo%v_!_JwG zu@WOpCl5%`LZaGJM>G;wSZyf#H$)TYN1?henelANo$D+?_@DAx4Ex3G8tHcGEkX(55W-H0I zv3ZhCi8EiWIc#Y;%`Gun-wep~Ok(;b$FUcL!wcZx6&e(+d|=9^4%ECJ+%OT~%+u`_ zJHY&lKO9=F@XM4f-)oE&;YCQ4Yy7_dN8a4l^c^*oVAaAznAEfBoyCw{-#LzzUuV0Z z{)y%c)v<9Dt)Gknce_AVC86?C+X`uxo;q)K;KxH}Lt<3r#WAx@R3wCJ{oBDGH@AE@ z7kDTW{5DMsmF5_6g1Id&?|0Q5Bf^9a}zROj5u)T@4q7-~(3)M)=x6c_(#c7Gn-rZQKP<2kgOutv$INB#gY$ zO>4s*8iCZzpa|Xf$y)ZrwbDAH-R5y{HqZTOB`NRM2luJk zuU+9auFz^qu*i@(n$(^Om^RHx!i-0(KVUPN$ok^Z>ej+wnP<-qKaP*wN^Fr)pg!%~i%onX{>uY6pn!&C$lHF>f)^lDcjKwM4euGy z9*E@4UPg~7vAzBbml)wo{VU-k{N^U{XA0ymzipU>O)<;!UkW?57JeM3#G-ZH4qDN! za`*kp$E$6@4-{w=)rQ=de0j$VW%8&pv|f-hMbT)#Xs*wgmXu;SV@Rxc|7TmRzk@YX z+$+gk-&3=;Hm5=48~^eLNH>EWf*f#05((qKwjboAk4}!E+N#`+N=o5g8jFJUK{~VX z3G7Nv0S1iqDyYdJCP2UONd=Q0g_ylK%Hs+e`{(_SfuXyTs`Ps(!6y+&;4(D2R=G8Q zH4g`A=J&B1&4Ln|LH#wy=JF?t#!8z-2Z%JEFJ#E#gkaEK)R4mI2v->5eaUybN3=~h z3WPvX%(!!Gv`h0})4ci)LpbzH{CgUycaB@H2$+0L-wO^DsH;5v*9o;88hln_S!w$H zs5mQZQX5u(19sddmLp5Yp=-e4J~GHzHBC>=76aLoQ;QjH+X2S|VzZPdIbH1zZmdww zeF$k2P~$^rRYZ0J(Y9`Iaqj6Nkxa zSqHPv1&2?C_-CG6nfO|xX*_MT7m}Q*$$$BjlC7a%#Vj@Q+?z&|* zp%%>DJK}7}nl$8N=)?Jy{A}=MwP3uIM$hou0w8yRV|9ydZfM@|aE>jA^DWN~dUnv+ zZ0@mea9xe(Ktbu9{CX1(mp?>LB^uWG^0v$G@|Tpzku2@PX{a-y0Z!|cQ_Fq93B6O^s7k6)_-;i=<#`6|Yr`NV2>X23mP2R6 zBV8ZUDA4>Z1NJG?dn2^!T;I%&?#Ju$=Nyam$&?;Qh9FYh?2h9EA#>k$lRF5MpWGO( z%p4o+J&NLIwuE-9k)d;$q^5CQ&SEZZKAm`Q-7zqK#YUy1zF7Bd+{D z^)~E5sCp&L_?iWHWE&q zs@b~=&7{|{i0t2KkCg^L|7>;6IEz?mhjg8Y4F(}D+Nx&7#ipOktz8ziTuNl^fXMN# z{)k&I>L>~!K36Ss@zhRlN&=6kwiu~Vupy(4vL=)J$$uXk;%(S#yRX+f3YSiEk1Lf! zkovR4MEg`e`&kUpuzMmW$Z9@o{v4h=iQM_?GVQjw!4-%^EQ#y(RhdV%@2|PfKULI! zj_D5vMQ(Ki zQ-+IwFP0l)u!6-ez9#PIS{sf`f=Bn9%G9H>xTI5Oces^Mk26YM z^0_|(mgZ=~i>#?k;(8wkgM(Ab`rEDb@SsST7T0kZ0s`zYCw8?8*>Mg zHEsX}V)j-amXPoCA?)Xx77$OG8iZP{O}%N^z`zN!=`7L$5!$E^V3=5?(cpbXx9A>& zooxBa%WGpC7bV!~_P+yN+(qGbg{D|S0 z46oazNq$W=!emTnu-+Z&pevq>E1r}q2WF?9a#{GcxO_{&iFY!-BpmJQGHj7EYT(&c zBxsx}=@mW;q#{pAG4@*B2dJ)>7h{G? zeaNTTzp+z>_SFO+Ijxwxz2^kL2e5DhhS9x1t0Kjd-u2U}1B;r8tK)O5oCt0%cwyl9 z_QEBL44*y!$DX_6iif{&A~V4zZ5OXtRQphZAM&lIO}=RE9aAl@uTCgdp-Yp}*wr!Q zbFy^;s!MXC8_It+P~QR%8q31zJej86{duJIQCZ%dhvR!3T{A1Lt;7a@wQ4cm0|ZrEQp=vb?xk$BwLOrdgseL^ z{$DLkR#ZC}yNa{e%K;hkxizT9BfIhr!7(ry;(*HitF>w@=^GxvFc;l1d)g7L`Yw&&!adOdUk=w^!^@F78!n@j9L{fD;1o z!pcrXao%SLW0X213z-K!|7G+HSrE_`4riy65O5bYr<4uKl&f%mLqpvK#|hn!U8;N7 z5+F;7Dh)B|uN9g?Vc#(Ch^3kx&!M>@XHVS1Lw52EburM4`4uVQ1M`5)9QdM`-UDQ$V^ki6ZcEPhSZnm5kDgqHbMLg-fN5R(JljHiW%U zas~jT@f%xWzKSgoW6Obgh8&i|TRgsZ;Lxe}NU>1?mC~I+Zo8%AUc+|VbDXDObSA$j ze2e{8z9(IF0y-4Clpq_Gmkmr5ZuHrc6xdu5XG(%CM&+Y5;zHvK0am#dORb3tgKQ;w zVb;Vke=cKoi-a7tZwJ3m!hG zv$e9)WID4F1}Vx%mEQUmBgngK!NW|D&}-PIwHCg6`G${QWv*J&by!RDhLu>ZzFy zUiF0b>=JUrCc0_EJxxc1!@aTmt-$#s!+F|f~ozV%?0Yt+i zd^eciob(E6K8^Suxg_(DO?Dx_E{I5@R)&=oeg>4j7`cK7z#z}vt146dl{Wlo&7Zmm z4!R1f#TL$^8O)xwoZy{WCQ9tAJtBLPn`(wSH`9N`Pn01^hCGIlb2~%RD`LQ+kHXHd zWq(d6!CZ^EKJ2u~l~-`tcb%udilN5g6= zc9L)7F7vs*=@fqZNaHG(Xp51dn6tt=)7uYRIQ?w#2QBNb19;}IITA?_*16wXnW4~B zIp{NkQHY(@5-JbQJSORyW(NN5AJn+~BR|3TXZnu=pt=#h7Y=$q%Td`eD4M2QWw1H4q zLq?a)oJ-tg5{M1{9XSO}bz&!Sc)!f~x?bG!dgJ;$hT3e$`fUqUW4pQd2K(HDIpvcB$-F+M zCSC8S`epvSOz+cKOXk4E9o5PfUo}T#>u7D9T&4voBA*C3 z>}2L&vHIQFPcDGc#9eL^cD-0n7nT2?fd)NbIotO=EGC%JN-7r1^6_%JM`N}ujP+b zZ@-`P$^3kL>u_7NfvIZXB_GAt_Z0+rGl9@8rbOxL(}RrKIzQu~Cx9c;_25#^cq45Y zcJ%tUp;Mn!0?X)I#|t!z-HsgFkU!^2?S-v%rO4Va$;hy>F^2~yOIj!AEokO1P<`CI zMb#xpsTao-h*yQ2q2~~$jWhpU&0EVJ0?_=J<*`xq-HQ9SSOR&8j+l!8*a(breTxfE zf_8}Ojjs(!D;WnY%3elSp5cu4AmiYpw}IP6k?x_H((Ln1c8K#iUc&KK50aRh)a%wK zsK`gsH&?|ir2Hu#L_T5^rC)qNuKQ|c+Z+q+$X^N4yhn-Sy904$@P))aIv#SnCsM*J z_BIasP-A=o;uNdXO4xL?@Z{lN^KCC9SGgyPkH46Otyu&y7Y9F7v%n3jJ)cU? zgghgBVUcMl+XBZo2^BX-s!z?UXzo5jRa4emaZDkv6=Xy;K0ca&IN#4he2IH*HPgUw zrdIcFexsxSRr(w7Py(-3+??meXm zqAK`5WcdFDT8#3C&~+7RZ~5C5dSBfW^QSJN`GSS&Feeirc>AuXj#uG}dVw|xy?sBV z< z#-O0Dla=c|EX_PVo|Uwr!C)iUN5a=xW;f3 z#TJWuVE1!K8+o3~O2Shy0{nNK9RAg?)f<_vo|7+t_GmhbUASz>d;IZS5l6&)ITiFM zFpH|09`X=W%yvr`~Z z{BwP^mJ%sXi_baHSPHBE7?szY=Lm1+KtXP!lz#+{Y5sq%?C(GPMV}JT0R(@Zy&4`EXV(dB;L)H7gsQ z<;QUMeDt3EhFT5NdpFHG#w3`mgaOH(r$^b4n{-7>2;9_T?piC5Bg3U8?>3+!4|v;c z0Wi>tiBq!7H$&Ng2M~KgX71KPz4V#O(3eY*d#NJ+Q~mGQsYIwY`II%%tl>#spE1f7 z39?AI=~L+1>z2$$N%i}@`sT}=0ruM zeX|;ZJq_%#jw-J3nl~=_nDnvyz96$4)g$bj*m8izQOo!*Euhw8GEe*VwnArVPUJ-& zxXo4y$E|o*Of)a!&*9^ZCP)7a`l4f=A6nYX1`!xOjL8l8etR!CP6jWJnuh3Fm@{Q2 z2O<$jS_>uFD8w7a)CMM!idei9vYPo9jS;t9RduD*!6YolVE`IfwLkp|Y&-S9w10|*WCYvqZnkHllID`xY;M%2qoW79exiD07xPxX zrbCwJKL8G{@w++4ZvB0l34GpB|L_T!r{h!b^j;Ys2+?;5`k`jUGF>FR5iXT-(C{Uv@y&`lZ(Ve)y#2dY}}kpf}&Rfgu)%7ch#{rFy+~l5w<{l-hz5_@T?Fh zL!%1nWZ5WfU1`Y zg)~F6F4B1Y$TUnb63Qy3NeFTPmp4Zu^ycpE0Eg*F)t~EGLDpHBd4JgbHk#Da#a53G zm~`(CF!rrk^D%4_I~k+xvuDY>mgH2UKN0s{b`DW>Rg6@*G*Q!CdC`p_ls<_`rZ6TlMUs#@urY z`)^&BXz!1$d(S>FSxbDk=jveLPM)!-M;&z&Pt>HIJPBY@KK9)Tg>5xc;q0ww<{ zIq|^Ue_7_YKjxBXF1>|t&`o>9l6K@HzLveHyl-&Xd;j=S%hooVbPDeK=4jf%51DV) znXvF7a-fO{4t#I5zrYU5^#(-ix2=tJ9Un~unFsX2vIc$}b?QvalsF1wIg+=F(F9|+ z-sgOdH>7MwvZD3nJu;JxG_0LWl>(Q32gHt{1N#zux8`Mr429fXYtd2(@t{A{A#vYb z)~5`)U<8upyzy#ciVc+VzBu!W6w)H~YKW*upeE(eK z_Zr)_i%nAoxWj-1ocG(vtnAhbW}-zvsYUeD2>e_1K}iov2BkB2GItf*`*I#eb4~CbBE%MaoQ;1(0e&xVS=(tH&Touek$%=6jgz@iEUx6d zR{BwE`irEaSJ}ksRweyx$5EGh2;riRJo!&nX!{wW3DjMtK2x-3fQr<9o3{Vrb2T-Z z9Qt>A9XTV@E;F^!eQ6UrBgFPN5AIa^er5y zUn<@9L>9gQc!gB|cp!^%ntSoo8Esagj6Q+(kV-Od6L2zculGkYZrq!-?L9Sf{aU7J z1JMW`n>_Q|u%54jVOv;O1?dh_Bd!{k7`2ciTa13i7?{7Grli)>sCIv@YqJ;e;^cwvPWFV6*h0b%3=?=>e(x zKq+uQ@@szJnEjT1s4G1HN*I+o?V+9GEIE`MZR6V6-UIcmnfCRWp#ySt9%+7dBxkFp z(v`hY<6;0|B3#6+`&&RAHBELP@@wUxRU^n+?PjSDQ)gt*2K1&DzC$yP`TSAOy`l#x zT{*2*lzoUP+%OD5m;Y&s4-@T*lM1tb9_>dGU(>&?7n`XZSk$RpyBc$5CQh;~{%`DW;Q~ zhJ4dq^FLwl9c{Fjb}5Wi#3#7O>8f-Szf-n+#iclr4#B$Mz+V?@H3eC7GB%F@Cek}5 zV}jo+RUwtC!7#JZv9+=I^&iR(Zv9uxmVOsri&+w4U>_QHT`is?*Np=~l&K&0k}9+5 zCk^$fp!rVviJ{BR%(i=%TS-EL)lw0O5vV|H?}sMsDMb0c6He(YHN&wc>#Kn|OZ~16 zi28IBxc$af|4vjF{dpkl$N>0h1bHTb2L0LIRF=VonSNu=K4~KTF1YXi>(HJsScXx4 z`q29^T1<0U`5&|oDI6;10nm;AgXEoA!!*h+O&eLV9b+cPA6Oh3Py;yQ9+3xxn*(@!21Sc`M6ZD6b-UI@F~6Ah9(# zYVg8A>6O=9e$3yxBMB_=3}Yxo=nnUkNfn>3s6@x%pM%lujkI(|K2A_ojI;2!<`B(? zIb&~eW3ZzY6Nc5owawk>`_rgasx|1lsQqbt;LVS)jg8MG)i~ew-I+p<`oD~QK{+Al zm~au+WJ4PeAJC0#hfvGwW{k6SAq#R;23lvZfW|n)?W4ej$hW9Gn=#P*iVbgeV9SevuTXV?9^G93;Hn>VWYs6b+_MvCU z9xLUeNNrXg<1ln`NUR#6$grpn1>rPBA)M zIt(zaD{yOXvDr{K=@r{Ai?-WHG#@r*2JQ(;>h~1}oym!f88T<(y|Y|KBc|=|7jSQ0 zSc_X!PN|Gy8p1LM0+Lt?vruhg`~6XiD{#81_vj~2r&?AXj3i)1w3fAO&{iG5)) z;}wiP6I(ojf!KI_(lnWSKRrufGQLbr>~Ck4+n>=ZDc)3Y*Ouu}K<&-2(5S~^i`b)d z89XwzjtAs5r?kFbPm@aZ()2ot4##vY77pVl>l%3Yz;(3=AVMFt=QFaPJ^$0yS9EDU z*n5pL@1HB^MFs45(0N_%i~RetEqW^l$0K8D`sz3g)|v;P6*#d7OL>E{lzRK)2w-12MIQZH}ipQB#K9*rVFGPf_d~vIC z*2aG8(oA`+66=?_6YYy!;|T@bP00rPauTCCM}2OeGY03HiG4!~;P#vI6|2k66))h_ z!hRHvOEw-`@jk-8b(`mLpSGE8x-OJ!_e^+xwpcaYuN^wvEhxxp3gXSp->S`T!P+%S zO;YTEpN$&brGK;_J#4>z9I_P`PnOBOPL{jv8K7oD|1o`S(C8U0L6lbQCTE016v2|SWS=O7fc90dfKI1PY zsS~1z7h-A+5-#e}f@49_kprAvH=4;&k7mv5Sw~zD7OO=H$`e`K3ClVPM=Q`CVMX>Zu$bqIxQycT4lWblBMGB_BkD z;Bcj^9kT8ohan>jD_`Zqdr4iW3xW3=ipp!yyvY;>ErNG}Wj4my5QfoL64cNaeAmJ; zLW1ubb9l_-dX3)*6_wV5wTPt^0d_9+rA)ENQq8Q?$UH{!w=X=IJT&AseZH1OB4`1s za0eV&D@DGi14CO68%_fg%65w)RjH&mQl3#~)15)4P|)N~6!*QEGadfyb-iL3&Dm-J zerAQFIC?Z7Rc0$`>Vl#L{vb}1#9OTSF&`_Rb03Co1)ANGGzCO?fzu(yxAB#u0W;&a z%Ixc-&AHZuc!&#c5)gb zN$o_BftGcZ9ABO5SgmN?W}=#1SyiPf^aLCn0|3JWrOPpUoc)Zx0Si5tohQ@dRH!GA z9q$wBJs+?B6oD;I%(4Dd*^jILU6hQIblBzpBS)xHBrOPsEdSbyJ1Ny-MID-6F3WrP%-7C+oPU)_8wY8o0q3aZL0bo}6xGf?jEp+rymkSeYplixjSd`st zln~fmYA#{XAyZDB9jLLKKZyOOr5-mdbK>GwTLxLy;c5=m^0bZt{+5F3iZO%uho~jTR?y9}GT6;8+)F?#$8=IL%va8c zoLFA02e8kF#xbU7$2lK$yMV1h8eTu?=jAOM?vII`TR~>Gdh97Jq(%4Zf3C@`x@6yJ zN&9Q$`RT%A8m%0P$dsSc7+kv(LTw?IRQO_4m}S!s;O& zA1c*jb*+wB?&gvW<8rMeE!s>X-o47x({$&miG=h!ulQJWf0Wz~%UnVoZqzjEGdA5M zaNrTwo$8d{E*h!Ddsh9W7nC?R?It%(jvA_ei~-Gr=kLOkg!csPVK1geH^^d8WhKl0 ztjqBB|8iA6G#7B%SL8e#l#ZE-@32T9D!aWEW zvk4e77zq>n6X44^KmJ=hHwG$PBD<2pELD%FssbBc?oStX$uy%j7}*}-Ymu%KIV2AZ znhZ)xdmM2qzdp@n5&i%x_WLV%9Y%FZ_Cptc`nAEX3zH(5k z2g8?PFDav>_mc{p1k?1e-{h!p3-AE_uNbPGO0!l2IJM=eTXo>KO~4|E1}@@CrWo`8 ze9>2;EunC;Il#EbEQWGd4EQCqj(zM-HgPv4q#3^0*0^oi6CRicJPx>b!#q@BfvrPo z_y8-fLiwze{?1CoFojz9>%$xXG-cHu)tPXU6(awcR7^U_!Kd5l-D#9{8?vo$EV48UE~N@3q&u*IM_wx9Z}$YPYd>K&IcKdP7)6HvMXj zx!e`_VOm#2bOCJ+h=%+JM zY+^RPfTNFk9a^G5|M`=NZK&Whu?^@1;os zQb6J-@Ie9PIJU}mU%?)mkxO6K9u^rL!EU5(jonz%aO71As$@pu4=@yv3sBj=-*Q-) zZC!Hy$1tt39s?6RJ3|ng$d4JL9CM%v&v0S`$TCWy(JnWMA6sfvs zlMx6^aqI`5LNH-)K1o%P0AQL&hNVe&Vq*hIX=Z}7x*+m5*x^qc+~g0C-M6dd{sx;& z&nAdndXohWxwq<$K3lbB`qB@Sqx2g45rY(N`hnV+AEyuOT>T3Re6=BFj9LW7t6wE9 z%O4epTuxIK3$B$&-%s!2lgz`E>u#DG(-gb>VxNQC0NP@+4psfNe-Z@gdAKhTgh|Sr zgLU^;Qs0=|B9PFBy8wX(XkQ89YnR?X`r*&>S<4`@wDV^t8H}jkiJn2<`bO5!C-Fur zcc>;ghk9Ttx6_GgJ0F8k?5Cgxw zey;;OvYB0ZaE%mxS7EmrZ7+QwIZrE6XUJQ_>%BNfyoS>#p@u~-fWx|Eh>N;CIjTj5?HF&alw&V|K z$uXzknCfCp>$wL&$ucKuJ;wHLVY zbQ#y+sEuja2Tr$@VkPH$(-ZY~b3_B}ah6$)hR%YX<0ZFm*isJ@{f@t*${h+SHzx`{14W z#4KCdxrT_@cS&~bZS7SI6m1?b6J})oO|e_k;lYo}3VcAJpmOjseAw`?xKz8i)cX?6 z(1vfjjMWJ~cVwUhKI?zSHXEu!y32hv$fcW1TD4T|PBD(Ezn_hf;m(Ao*0=)=Hx4ZW z!vkGzo?_m2O9oF;=P!zfM9}0eAv)JE)yQvOQj{aQ1Spo0@jT>Cy@v`Q8Xf#e51_2qpj%)zw%ZMlA9D zK{fv`Xqfc`&}TUqSDRX|aN!`oe&f~jNWb99+$LaCIxk>>t`%P`aGZv9Fh-c6l&Dqg z!feViXr()W#W zBca+>GSN>r4WlETr~|Z9g9tVbX98YRIEd~xS6xxJGp1d>Gph_;K4yX6mhH`0M+?vZ z_IT4N1<@*GI15&r5;NX{{<#L4gzJ0k*iM8QP2g9YwqvZVZ#4rizGy7U4$5CN5-rg@ zoqHnUHLs~(=5OLg?9BA%L*4#+8X-14$h1Hb@3^*Jg&rY0+86Smt-}&{dFnJR`!R^* zYtoXsFh@?N$b{ZOx#!Hp*~;0I9|iWLks236Qw4p!V=&c&8QpQFP)OIX%zbE=0W_*$ zejsC&7$`(y);r$_l~?PbFcs(mXaj%DQH9eAKvam(!FI(}y`Q`>UFUh)ER36So1-Y% z%`V;{s#B_V5ZNa8Sv$b`M}$73nK^zcNq=KOP@*Qew5B#?=}UHRxm@(*QiQ*ivLQ8g z;CO z1rnk~vz>YVY&3{(`a?A@9gFHe0;w@zBxaW+V4v^s{ zW-u^p3_>ov<0!hR=l$j{2V~!GB5oeOFaF4ER!J%LmhZLZnmXfhn04aR#gpI?^z>GJ<>SD+I3qF+wAB&2clV-PwkHwL00O1YGb z3z;rtN)lYKscSf2f5U+2l5iUuXicQWWw{h2FjqgWv7gvy$NHR?3nG-OSgL)0drI&5 zg>MJy(}VZ;)KE7k@3*@HDRmSo1`?vjKg<(Gakq#Af=v>0-K5`JD$mBVuP+#gp9eUa z>0kCuM9phCX6)@|pKZqgvnNm1fV#CDXRXKKznLy^hw2XNtFN$!8(?|balT!*rX7*Dti(Q`lBL zkVo%MuDwQ_-vgxqd1fiLllDKsCSvDU6ntP{79f+<8N<>`AVKZ~A$7&Fp{9B9K= z^R^!#m&m+avN*xzkTRcjKqSMFeyMKKEJ8r8Wp6Fisq@*{AdJw;T!f-G5h$RQ8xA%P z&H%^MgOJLj-ryGD(xk6JxFe2-8i&NzA*eRjAC7y*s1rS4{6I(L2Sd@^EquDXq>*05 zfWD56Rq_UXXyED-mYA;pm!A$1AeWKM4pD(qu*&evPO5tTD(hR;_`!gbiDaH5Ly3k z>d5REbPn|R9m_r-G2)G#C6}6a)vNIt8}YvpJ5Y-$(I?;Fj;d>PdM5Nlqb08%;2H)1 zLjYoe?)3F;k>op)9^31I)Vm4Z8wqFM&~x4aB4o34yLfK}0mg&zP5j>1Z#+RCJnVwY zJl72S%+-dda^9XlBlh2DgHbvQ#~k~BG7A)ZnClJ(SjyI{i8NR!5~`z8@yEX`|E31W ziI0j_$wW2_Gkn&<`a~Y8GN50jq(RtAp+1aL$xw)#eQ!?(i?I21|!wa@A&nt&cV*=vJ>%QKcLBmR|E{3d2$i3?OSM{MtOsekmUBggwAFtANiHn}-#cN@m zD`GWPVBFF}t;pwl+L@!o(wa5H+p*yZvCfXnF^A?Qeq#@lWt<@Jwbq2@FN)u<=8i1y zu0=jjeb@%B#fnu{<3;@YtFM5d=J!2Q<9=8xYjwbRO8pDFALdH+8cSpnPu?e3+LaQu zJxc|NaslOIZe+PX2Nm(;m%45HWG;->uGu9{ka~@r6Ucj{If|Bh$(g>wIp^LRb3DF- z*BA@opeVPR)^{)a4EuT|TzT8hN1?wadZFPTX_h_;v6DgmZJN3Pd~dUqnVym}zHy9& z@if(7>rrur2%hz9NDTHJo5h1-}RpIQTbnlHhN_vC^=?l%FK=cy5?w z%cdzHkVjUTZEL~N_{JVNmKW_0iHy?VMJ*1#E@Fi2>YC58a%@wx9JcTW)h-BoAE4Qxb`e^-F7USXPqB za+XG@C_@1U#Y5~zzj+tz>#4pDVz(b){hQdS_92qA$QRbIau%D`Q0aW=MjH+g4*Soqz-jaMv+x?{;(<>Xihn`yKTJbQ z{3Q^@X5hcy54FJ(b&K$PziC)i8|C9NnLDzXByS!lTs|PEGoj-9w*>)jSkw zDN>S(8}IVN>}3g5L{%ban793l=(GJqzANzbpo!i&phh$OBT(`HFG$r@;ePo>kqO*I zI`L1!SQ2$r25j4$EB)XVCb8#>%lf3cx!f36xO7P=HqDZrj$093y(UwpI`7{i&o!~H zRS=*xsL#z!uxig!Gr3BK1z$0;23nTDW%x(ydpoNDs5TBrSvHBkzxsOuXL;9fJp~4N zy|eMhcwjpbCEFFlB4Mgx&oyhkM>WG@wVEMgDQ<)J>M!y+zRoDZgHR8%2D=&)O;>R>A+}C&>~pe^rC#;8oihxbg~x2hx+bJ^t6w(AG|t zV0oI=lQe@6Wx0MaM;fH_>IckYr;*nf&s*9C1kpajUuAmTiAAyTeNstkM0&u6(rOli9Dp%yGBmecR`PVS64)_$SdMu4<|F>#Qt7{MdL~%5AkxcIbPuRq4P#taMXF_@+d4xo9({7Xew0h_MI}A1QMop9%SaT2s zI>u&2L>~a}*8Wx-PWKD9nn8ts3+HY9dDhLo+>^-eLx3f8lz^uExoQ}Ci}ftMM<6}7n>z#K zO&1vT7AmPJ2T;Zhw;Xk~~{QC<2a0$FGRtgJ!>e z{|J{iwe2m2N%RvLLG*lMsXHSTHr_g_M8=05k<1JhN6b>uu3vL_sB6@khHdQie#O2D z;>@wV(7eOj$)@;rd;M5}|A3rGq?IbmA`sQ#Ekd@yiM_icamm#gc26Z|jMPsH;4_u0 z?{~P3w;neSogPBN2DT?uLSDdxfk{|rsN&O!WtK|_2P%09^*%$fEzM#c{D%Xvwi)`M z@t9LWkD1yrgTs(&yGU4{o(J4T@+UT-Bv><;g%3bwUh+Z+;fjGBp3215yX|rUWF9BdZP2C7lXWq~XP}Ym-}Dta#A8*f zbg?=gL80helk0_B*TdaV@E`u^RM>KCqBy(tvsMSs0WCyg<*=&6K2PUyT#rEc^k5Iv z(z?_*U8U=`QQ!I1$o!=AgMF&;Z4k-Wlg5Ubs`A9gPVJTcI`?|7?(EF`PkpVgu=(00q zdu&LC+M;+r+6Cl`z2#c-BQ@7*gYE33xOC%)oS>*hApXiy-DA4eQ~NC~f~4Ja3^ zC5EhEHEy3!=PX@xS#^z&f~!uolwghVhvv<+2E&cd=IsaC5B?U$PR|xAA4NV%!I+x8 ziElLbyuEK#Ze{+tcgT^V^&Nwl30TCum!t&P`9}D&w%af*+;**%iqRO4 z@aU8vF>XE+C9<3Ajp!78zxvw`F8^(n9vAl@;wCN--g78A)VeJCWuQ~64!<;wKVlKX z?i6Bau5_NV=9;M&GA8_5dwXas%y46{$8lRQ>^LPRPT=durhZX}!0)pmoz7gI&40g0 zUu|{d6KsE{nQ49>0!S1+xiyQA+kE&d<0$_ESa}%6%$1U?cI-%%J~Q7S`og0^DZmtsFG_&!asw?OHXBj+i9P5A5`y z{k^mzFKLj)gXw+u#2iQcR-_=&*cIu;7*o>oSGK#-NjH)W5--uf`wjrWg(FI>0X0FO z0cQquu8vaGP^&}V#%QY5R+HGJ(eZ)LrghRKY{G+=eqGQ5_4hWrtVwwSj~zfhOyZ;# z*v*-EuI;1r;BMZByZClD`_-)*D~^%sG_Qev&m&bs<1*tAvsUAJ+p{VR{Onfys+stW z)ykKe?}M1}#u96DK+d&axecI7{_7C3G3RizqdQMdqdWvOjPb?Ji{4J6y>6PWeOp=| zpFXFSICW#Vejew&HgY>u&4F^;eB%aWv@4x=$r1!q=+LIK?&Lv628fi#OHiiHU(GyB zjZxa-7z;Ql4AQ|%S{GdFtKg@(&14a1r=^LP)a2;DL{F{Txt87x<^^&x9(a{OrpO}5 z>0=vHdLDH8EH-50X?q+-EaME+j^YoP<)c<9x6^sKCf8&cL`eD1C&QG1{|ZI{bL>R^ zV&Th3Ku53E7?#|8IhjzE2QR4*kzM;&qrE8owC3}|khH%&U-f9HNG$lS zusYDLN!2dBYkU@aI@GkCFB18)YlZ^CF2VROD%%a=@j*JYvr7oKc@3C}w`_ZUpv2V- z>GncTyqu$+&viyDhx_LJru<6b*nEV*+9BMS_0R}>_X!g!uXI48xT)wk_fS@p`ND_= z9oC-{|7-4cSHHU~Is1#xPp1r?+~-Pte^T?=C1H){WJ zKBW9I(06Nguh{$1!l3lUpLo^|r{=24>u|EL9(_Y*Hc3fJrc8pNQw#t2KSva*p-eFK zuh?9(tG`iAdRFK+TKR(k7yH*cILWJ`uOkM6-!3YiZNF4{-{^f*?9{NvHm5F@@38RI zbN{cz8Gw`69BKbi<4W>=KeUv`Z`4q`|J3}B?eoRLuY2lXm$o*S zGxpM}p^6tov{*({rZBaekdv-46!DeNq;1&vI+V1ZyT$7Tg#v!onDi~lZ*A7gU~TsB zpcUc?pq;qXKk1@q z|LhLz4Kd)>NZ-8DB=Zgke5WDfHIAaEhDyE!yGxS4ZxR?E)@1Ml2Ix1(%u9Krm$&T$ zo>AY>b0>7}s`{~$;bzFvzaBKPa$vraAm$NhiHt(NcqM2u`}ujOOZ9U`%Mc^pHSR?C znVG~Wn=Mkpk?sCWIZ2IkkkdxVpc|Ha+jx~A{82}9WSEiT=u;Tw#`nL!@#zA8Tbmmx z*vm3VjB7xc1f4XXtLAI~xAP^?kYkLe_WGYZ;evP+bb73YLd(14JznKwmo@yaW&p@6 zPf;`PS6gQgzK?hBKw22+fLtmTRSV4Dlxr*AeA0IhPf1eQ$5MRyRgHuz zazJE5hrt8GV$8x@&Kt9|9=43l;l7}*dpi8J!gpd_GCi30c1j(tR9@h9=gEH&k8WgN zhcOV>uRzB2SMz(N(d4lE+w4milgQHRPj#O+GWT9|m(-m4wvV4&OYpbt#Xb}~1wjk^ z&X*EX;LFCg!l;Jm>~p3~>5Ei10)>(^jx?+^jv4nHdI2b%5KHs^Hgcv|YobFHf&GnBx;31x+*RP_T;L*ol z=A+37{UK|!$HjZ!BO;gsPqQCtBO;jJz)9dU4QM!!51fj85c`Ol>7-g)AdRHDoK3Lp z+b#|eJp3ThwD)@d-S_@+oVP-@8wI4oa;5j~S(S7&Sd$o>F-m^da|s{px$nnKdrvT zJr59XpTVR02Qwj7^;~uyf?=1}gZpeYWnG!Vk~Pal;Yu!}0%V&=#I<_7XFyTFGwx@_ zvxVGUZDvLGksF87f664b4UEv?(ZNo5CL{{W?@3F4UzQ*J1uaJhy`W5TZ&0F2?$=u2 z6W5b)yaU&vmRaZZr^^?stpSt#$Oy#AT-!}d_SqLeuN>Da%AXb$!7NKpb1<+&{eTR= z6Bh?@h1C@sFWGxvNKC9Zhr54LR44soYJ~}7<8yQ<2@OAZ;jQlJrnla>o6~J`$#}}a@xf`@(d1eAS zzshFPgFo`zF7)@$)jQsV37oR9?cZ8Z6Sh@jX&X0x+hOa_<@h}570R?%8mPWL`9&Z$ zm}*^o15}tV2TwxBZK2WZ!^*n_nWgf5e{CjUX|cgc{>gi$;TfA;^izx;Ap*a0|8_Sg z=rycQP@1iq1M@dvN?TC4`l?*?Xj1B%v%6q1_4d?6BNA@VbS$jh^+uA#f9MQL3TRPR z3ENK40*aUTGPlwxlq_kPy>~H9&y*36gS)OoO9R3xsfmxQqpKi`Y^XL*FK~kh`J1mf z0n5DE=gCz5;#n$!T&@Pz{#^W$eh!yCou~~L$Y)}A`ey6TQ%PRGj-Of&5MxiayO1N4 zX&k3lKifz{T@pGcCAJmi;|Sz7mX%jiy6&035|Hr-AOkrHTE8Z67>{m^8f*SFqkB{| zAd>Je&wJ>0ko^DK$7fVu$(o80VRKrwv!un*DH8u4G{f84o&)b7jLeG3xJUrLl#c!l za&}?177fx$yVPCT&R-c+pcOb0X@Xf-G!m9PWTe(Fjl5B9-ZQ zJvpj1^l#KRL&*7EEmor>Qh}c*If%D9-&vcJDokrlzm0xp&H+D;9b5_yj?%?^XhUT- zDMkp=#QUHvyeOZ8aBL~D)kJtJmq@m zqJfBFaIWUXmpErzXEMHE%Q#YRt({6`sdjM6=<<>OezkjXXam!3XDGRsibqd>-a9z5{ZxoY!CQZNE55XtCN;rJ?3wpK&aCmMh+O;Jk12pJd<+H`pb#u_3wl&DS(tYKz zh;ygee=w=95JAEung-$ZmW z-;DUjE5Vi1$CvSA1P>eDF=svo`p1zu+?G0h>LcBBt4i{u+lByXBO*IPSB|!?2oeP} zy$*TFE)x1eBo5vXm_Na#y&7r}#zmW%*p^tpyP{V;?m{LNubTMUmu%1f{I5`t?Y1M@ zW*|l;tMJ~?Of3&+0baAXX;Jl#4$e{sb`$9S$Oi3~7BhQG+TU^B zSusdGZ7t^bT?GHICVGjJRM%;s{nec{S|Hv2#~RTt{yJloFOtTHX53I@06R z;TXsL`Xc7gG^yjNm;cdT-O5ko0j)*J%kYnMZVE?Z`DdC0p|Y>ZD#EczJ^NMD5&^82 zHm%V(%|8Ihh$h@6>6PmZ0L)mpsq$i2aMiTLMa-w5K0lFT41P#Rm#gUX>C-E-cfZ45 ztmF`V4Z8R4Kh1|v9^K=Y6Da)p;ODDPpFTZ_ePI;Nm@y=J-}Ypu&uhSV&Y5qj#mj4V zV2bU=C)3nQMY1jBb9$A=!&gB;SBavAZoN2%o$H^@zBGAW!TMKm$P!M^WHY`Vd$G@K zvoHG2)IfPVgtwTmAsYRD- zsEN}2VRM645~OqKAiT+ze-?~#_L^5l_FiRATcEdpK~(Y?wsa3BuUSz1AXj_jG>;HW ze0(f)vlZ-^xx9o?g-@AB)meJ$H)|~yNou|!#(s$v8Z4`g_fRV9I}S$pWTPND)}*24 z!GySnHq@-oR&KX$uJ72VQ0E(v)ERKjlbADLgK(6vPUG_FfkiT^;xIjn zebki6`1`R&Uz@K|M@02;fBZB^<;S%xM)~x3d|M?+LF*S(Sml#^@sr+{;d!1J4H`@7 z(hrV^Jy{Ft$Hb1T$080_nb;vI;u=fqCpEs*d?{tajId#oA;CH2Vq1q~Bb2$<{B|`- zU9mwl4fNzn=1QH&Yvz?vPOCk=&_HOzqJC27W<@`Gr^(W$9@TgOrbc;fj_}kHo<20e zX%FM`U<|^-@p(eoRIhon``@D~&LzH^+7nUOR*7E@T)`t|_uG|{$#BwX_eJh5D<(GR z;zqB!%%erJ8LNCV_kbv}pH)1fb}fr%ikr@2+L2G$m8WR0ajbI7#Z|4ycGj6De=)Ug zs&>r1f4_jL%ux~Sn6XiG(d}tNFJ#y;+blR2YHwI|C}`G3EnR37qr;XQFpIS4%jT^g<5^w<4o)iUQvvAr;_g7Yry(X4NUq-7!O}YMus@rH ztc<$SblFljjk$w$>5m=T++9u_Cru#gF&6Zk#lyAnVo^QMiT~HB7T_EkVU1u=pEXMXj1q$bCfspRrBpN1NcY~goo-u_k)Z#G=y*n8NZWbUuXqwgpqa2+l$&; ziJ@5z9yi0}Zx~b_r-&ApzTYCkE@qJYb3Hn)-P+6?4fX3(!l7jx<_zpnjBlxV6VR=M zRi4Xa(pvUVGQdm3acKA+JJ-nbYhMcf*G6WUHwT zTMC~Drgl6jmjM>>cUahX>Q4!UX5;}`ShJ14e+NU@YM2_g`P_usjnxB*d}w|yp3lgy z;1WEUC~%5Cyjc$$3H&W2;%oSmr00^k^hoit=S`RRD%%y6{p#-b(~72jH}UFWbvhHF z9zI<|z7|nkrJWh{@~<8ZV^x3_+O70xU(pG9dyBhwzD7 z)_&_1v*9je`x4M(vqkG<#$VflcyZ?#zV)Rc_ftw7YN}G0&m6ceW;b-X8&7->KD9$w z0;-d7tCCb}<#ib@C;C{)Bg9$9k=Gw$o*j^4d9|ki!lMyx$c-$c4)=dW1|$p)X-a8g z;H0`SLBU?=%D=@!<%3^2;IyNx^&@gnqH|(Y zIJZf_(+Kdj`4tLl4}D|X&~_vrcht`;A53wv-qZ?(e6$M`o$xP45eF$YjzVv^ZRa5# zqM6t8>MaCW8aiG>g&{*0dSGfA>ljCUubM^hwFPkLQFUjtA9~$8da7Z9jgI3d*-L3F zOtis^ggn?hwBq|OfD3Q=q%iXPMj7H82#$aZ+A;N&+}|_9RG!geB}nb3-j$o zkRo9Mv{9M(`&9Lx)(l_-c%wrCK8UHN)`jU_X3 z#$4IFu5ov~;6l2~zR`k?df*v0-Uzt~4x_k%f(&3B;p`?7emba40y9Z+-S8Rcw#f;U zBE?|-B>p_DJ4~d?GtS}!-4*aIdre{weUjY7d>p&BQyiwwX6S#}$Mi+AO|L#+TL3{A*H!T@p8E_=%h09Ns z+$WiB<(exY&j(kEOIY~eGF&f|X>RC7-ErI0cw@a_Bg~-xhmv)NK$K&M(UC54qasba7s;a>&(WbgVFNl42xkJe zM4!S0C(DCf{nio)`5zJ{85scsvaDucKW^k>$(#BHnuUje7iA3zV9Sz_uiWi^fvNb$ z$FUcosxZG!kaB`+Xo8RUXxd~Lc-_{?Ep_N?X5GTIr-)qDnQ~w(#8ptXiHWG^-wdp3 z6?C(CHdmM~V@p%hkzchKH6rwSBGfk1YL9wOB_%bC6Niw4qaCmP&&$uZVTiDr?O|DC ztfrTQ0yD?djdmYaooB~x?(QhyS5J@g?S3z75xkV|Gsn);wYySpTH*k1E4RYshTE4d z*Q>Le_s1M*8R5`+uYitJ5^M~k5KF1izvg0S z)xfOvBfe3SSZpng#w4Z^mywDTKR%=Vw|YfU6a2M(7DoLWw$Cy-B%Kf+wsqzPq+@4# z@uXr0xggSj(TEX!HrQfLJlR=n7?0GnzJ5f5axFT%vQhnZ?WfTp^TpnYWh{mP95`o3 z3HsZ9PK48DZv6O^E_Uh-5wh#=*@s4+j2>s%rS%)fX%SIxB~t3NmoI-ZVGE4+g^;K_ zrk4q}x|QMJ9xm1nHP#O!92vmAGjLQMJhFxVwBH2}5&Iux^^Rj!+Ay zM(Dn>7_1O;V9`r0@$`m&oR~xrUg?{rC&-KRLlqpq736r zyU|t|V3v&WB3qB35(IcEb(};IK#a=8D=bKs7{^v^A%R^Ln(xfNKz8Z$hSJ%w9)%48v zc%l@6s`C&OsWk<%ik-8H#be!r^&=DH)Q1ia(T9!y0#SSv(R2ZFmHspIMvm*!HBP6T zS$KH(c*$4`3b*TfC@0(Q|E#>wG-EQ6nL&t&N3L4GPU89Heyu=|{>DLNft(~W0at!3NGG#sT#Fv#%r+MbEe zH|Z>zTVN<1%Xhbd)I^cg>`ccuu>e5)2S03;C^8c6SHjzJ%nWIBYww+7tC*=H*hzSW zrde6-kDX>viM@6s`*B)BK?9PeB93Bc3)^fUn6S5KYc_dC$HQ_Gj}URLG7ySUUgZL( zH^FS(+w&1SwI6+jGOvE$OPvxVni!$(vQGxbufpl=(@~AZNolioRE^5;CPe>8y+`Bv zc0eUbs$fdAIbI_ha9@N3*oc5_lrk|5u82_dn2%?sY+L^0!b1EF8u)qSO88PGc0+>oTO^&NP23@L3MW! zEPaZPE&?4TD7>$QXadBavroue{x#CGRXCeAm0+W4JNIvy-!bXl*{lG2sO8~`rO9_Z zQ8}=sCs73pK*8~Qv;|B&30^q|`9AK&oJhA)grG5!xp&w(O&c9|RzvHxneTF7OI>G3 zf&~0>DQ4_#Eup&s0Byk$>h!mFTuK`If-C5eA4Jt+nGy^gpDD0T{egFV9fmpZzEHfJ zMPpRHF?`M7cofCGDA>43y)HU6OX7SJMFPt)CXgXZLkKB&8&{63o;Dz!)#J_nj-wM> z-w2%{7HJ>pqlT@=FZw#v0TXo^pcX z6KJ8aK8d%q^Kp12rwFXD+JcSZ?wFrr`=$AL45B~$VxkCVcaypty~*7z0DYf^7APDc zL2qIdIkc=uzgahPTuF+Kh`ro{#5Pp%Sw6bityQWiaEOvu!J52o!hL--#N*{`i9Vc! zZ!RcyI5dY&LA)w#XWhZH7abHs2P;YZz($IJuVpT}`A~dYtw!;-p|277PD!f06MRRL zNkyjJS29PBLZyW6C1b7SzqEXQ8(WEi*jgLwvxlndYYTXN8MkpAN1KAc0k2XW_68`I*N3#tS$3$IEFD>P>kkw>als?_kn(^Wi=?=yVE!0p0iH8MBef!!5RG zwyNGsg_9s5bxJ}dAM4?DRm$TimARk!+nu@bVr5WqXe}|PY+dS0pIHvW-eK>iF;|+z z#n6U})HZ{OlqAHn;9LNv$v=vIbn9-^DF`Q~6o5)t>XnZAhQ~_Tr-mw)#_gWIt9=wZ z;&jD2cQ=w-VSA+L1;ov7EYi1S573FK4tOo(#?39p3(X#8R3y-BtobI8fl?(ci$j1V z(&mh2UGWuHF)k+ps+B52Bp26shyL{ff)9|VR;!#T1$rU|Dtx6$+h7BEbiOr1uqUuz zHad}qfVpAe7(F5s@`Y+j9(R=`X#IWP2h-qide9j=TGle;&t?Mp#?V%0%`uEycUS^` z9iY)Z_hkCRUlej^2Mc zwBh3@U^I8G>KDPJ#;KyScK^=G=kWe;dc}qNT=;G8R~?MIPtV{6pR+y*bS>Acozr{G zFpJo2Vm`lMuJpp<;YNnMxzSGCv*(sK*~Oz0whPD-U2r`S2o?=;dX|62UrKuDSdRiq zEWOnRLZvhklda>!9Q|s0{riuiZ-L+A1=1jy*PrjK!<)RY*-NO%p(yztd3PAq@{ zQ|FVtaJQKD$WMGWm9DmLFnh#Fb3}kiXgPf*okl%dmqL+LT~L>WtY`1rHTPSec+^-n zTM}C;lK(kG_xu@R{yga zOjyg8w5 zV%u#&LF|5V;CCH~J(gHuCpmY7mXDpV<941DXWZH^ki7pOiTYHRzl6(|8g+YR|3S%y zD@g&AAdw(B*3O6nR+%k6&FA%nS(Kdw$}U}8Wye0%%5msjOPcCIy=nik04I=qNM#w| zh~W%z%JtUVO8+~yk z*cZYwUKJs$zn_T`P6XHISNY8Piv)Qg8}=Gu>xYwIkNKo+j2CjFbsRd|coyg4n_i;W zft+i+Qf%Vtk;Mu=1k6`%KAHM1IO;#W&G6{wlT5})^!wk50D&C{-9G~_WzGZ3e{_<~ zk7*^YNltjxh&`amlxm9Sl_p6?VV5<*LOkixn^qNyUsl-e{zOJP;ob^!<8LtQn%1KtyV`~LP**J^@%n!G%qz{?t!skn89Gl()hUYkAY zuTUu0l?GYtbeH69A%b1U&3~fiv~F#8WpE>cXbyWJb6F-ti)Ng|@L;1IgnWr?LUcp? zwlH;;8x^RDLvS)lT?7dYM*yRi^^Kz@$eQIyLMQfoM5&4x;xO*@=L$I8g^9H3|M~7m zlmgnnpclbD!xOJdb6=9+5Iso7);k=Ol)L%nr{I61Oa!m-v5*v}lsu42Ymm##m%5xL zQjSn1{ps$UNnCf&CYiKdpf7aum#JrQ1iZmONabW(8_8cR-Qn1{ycB9HOpO6fqLf=t zdoE^-ZTE_@?T`lRxrogJ*j`~$;=3N9PK;r{GAn0Ej*r23r$aZ~*xsZ`-d7_vnavH)}@UhX# z6kOl$6cfL)=29tfG6`gJNaccyRGB*J0l_Am9pM2myRF_w0Jy#CNy%ln4VI7YJu?Cn zQm^Gcu@pS1@H*^{mvXXlPbg)27e#K%c>?5@h#Q3;I66N4TZAm)b z`g=nWzV4$KN~SI0Lg@Y)z&-`8%eTqP!+$Rxat`@PZIa5&xdClLU5FNKv+a2Cai_tHr6>3V%f13UjZ*xM>XF(kIM0kx^Bq z-TVA>Guih>1J)97*+T8N$A54rqT?1zYopu=iDdy(TwII23&!mcQaq-WnxqoS78T!S zqcdt|D%{31PXoQ=Zca{Or$1m=f}NTL*NzNsjwG$G4)!0n5+`@U_yft>vsh~)Vm<#^ z>CpA9*Xlh@orBx!(_y`giMK_W_rrV+b$drjNxV+BD~zbWkaSj`fDBZGdh9eqXX>=| z#|k60_XQMkENf;$Wh`w0yyZ||s=7IP2tWl5V0HW+Y&3V)VUKgn8?><+_{xl)$mE@g zF3!i&>$vt-v?ni=^s-d0UrZy@&>__TrWER${xq11TgXwqAf!mp2)EK7@dbZRcpJoT}Mi%1T=0Y*!yFiqUT1u<&DEFP^^8n2hBQhM)5{JPC z4ygVfyBed?(IQ*-Vvmj5u|~NtDb`z5{Zr<)W{nk`Nr)G(Bgl;}rq|ib`2Ak6DN$c0 zTa9AA!p(g@Isf@jAfm5Zdyxaiv~RaOKem6z*<*~sB2H=Oz!Q0kd}mNeNwWh~{Q(r$ zUtnniU}YC@J2%xgrCI(| zl{)Glv(w&9f+F0~E6Pb-yf_&TG)4R6ByN|6jpzIPp^}dQMAvEP7BlD^gIgU>yREcdYUddf+z0 zuXz!Fwq3D_*|Bfv<`EzFt|iQ6Yp27q-B1_23*N7Be(&4M9Z9*dwy#wbC8%bvJo&nF z8g@w6R{UR}DCno369?;i6<<2Cz3Wg84`~9g?qIXZD8Y<;7lK$pqe@~Ln5|^O}JCf+bk5g zG}hQ|wbIW3K$nXehUj+h7U7@clsv~|i=eHe=oJSk^e=;0Pc@nSR zVFd&Dh6(_I{8`B0tOx5ZIn~|#Kw==+(r>TR1nq+%^jp&=fE-_Fu0O}J(Nqw$KZ%*B zbnwsl&^uDyI97c;$+aVxB7iTkyn(!o-lu3qzEDvC|A5qGmq1{ zXAXgU9svJ7v(+L}9tRDko*-mXh;ALJP|J9MPaHyURvEUkraiMrZ%-9f3l>4u8F;mQ zgy<)w0S9R7NPVJE;_X}4%QGwpxo85p;bGmw`l~aQtPQR7L3E5;D z=hD3oz?JQvmZY>TNAni-%px_+2epqs zGvNCa8;MoCl*$tq_8x7>^T2$j(xdWk;BZ=Rsvm5E)Ru_kZ=HE;_5( zs9=?lafm(moVooP_^943ZyQPl7Z@)ge5`_TBB# z9u=mIji&lZKy9wunG?w=eIhV`8S~dy2{X7RK|QCP3VmjRV`9UkerGz%N{qUzbQqVQ z-G3@U=@~+)5mE*?j!Ib7T4iCKJB-70V$;9kaX&gnr^$Bkx6s=I9k1U-@OAA?d+nI~ zDuX&=&KVM9<*b+|s8 zL<`T)xjdq^?#Fe)(3~5uS-bCI>MEu3YCIl_UA}2WvOe_y@b%>v#A+`WxCyssI`&z4 zI^-_dR8&uLB?b>Uls&6v;7yJ)>07k=DqLS(IQKLm(>0{*)_B$PpF6e*gC<`~8TrzB z!25jO(aYIpr*-i$@_>4Z-M8+0HYt={8{$z1d-<|J&SSN3g|&BbA>W7_;8Rlg=_w=k zQeKcYL0Dqs#Lei7qBhTXc1LgLs%0I-3H08$|nCAKE66I0EcpQ{%rh=wJCZe$t;46a+sja!;gQS+-2b0 zc6J@(xv0;C6j#p^o#^!dorf&d7X3?k<#mlHtMl--4Uy zNuGs2ww1n|^`mO76m6@w?#(kt5-Cjw!nvq*#rOz2U7?L7b-~s%@|HN5E6jB5UH4xw z(vR?S7L8uUOj6Q`bN>y9w+P!4*RoR`w9;@5%gfiNv}eYPO!d`ffNUVxnmUEiCSS+VEO zKYokS#(RNa&b9D&Ij^P9qj;be=~3N|`f1J^w=h~_ICA!W%9hEh_^RSI$0$zLMd|n~ z`dj7|hh@x@X^ftW$p>JHfgvX4Jg&~lCO>g zKzw&-5UQwIUPEfuH0*(i#I)xX)Wc_*6+n2xH9NZ z8fCP-G}w{#xXOll!M|KH8o2UIRF>s0miq`0+JfwlAD=NF)nzGHjgAcrK zK+_qg=IU(_68~g7U{&P#@_U)S_YK3e8{>l28;p?Up^`w|(b6}Znt#5ihBQcRBZD0D zt%s&P-#fmhWWLb8P=WvFImtVt(iI;j(~k{#q{0T4=rrLq)n}#Q+Fg2S5+b%YNAHc? zNH}VFiy8sgC7n<8@cd@6G{`8lVGjB%u;m~y){cin7FgRKwiMjOM*PJ%`C}1X{rKig z_4%Hf@rjEAQMN-0Zpd^#P<@OvMVxmALWwcPv61OVk=Ycg2?=ladKE!vP6BqoHNF?73^L zag=MxU7A< zqi=Q$>+m@CqJ5xHiKxI$d9)Beao)u%If5HOV zQ@aHb`ama=g2x6%18grs*SMcHoAC&jaBw1lrZe*Jwd0PI#}M|@XZEwVfd!-Jy;#JQ z1S-V~nAM0FE5W%{4I|p~n+F6ExTf(pxDC3N1mLlkkicO|7MgXwR@6=c^h2ctsw0*} zwIjcC15ZLZztXyR^8Qu4O|%h1#5))~pZMMUMc={CihK^IYS2PKo8gDMD?A#Crv zDP&T04F`csL$^twXX1d*a!n~^sGNWJ45VJs$mMADOV>jXiqDoU05oAPvu38PPshs4 z_P>F~fdWenPmryG-Y0V?3C6h0Im5kwi9$8Tl>XZyDQ*F#zW~DyoVt0^y%Y`{jsuKr zqLX$Fn8)94`f97j;St@Fa%e2?QAGzDOH``a&|n&&!5k1~di*;WLKWZ$-rS8jE17$^ zTw=5_+pVOlb0Sk0VOXEf4_Luy?tszUNsyN~U&2svob9MT%R1`e#qc^@x7`Y$u0=Dn=G-=8p zgT!D&Nk~SdE*YDsNu+ycCQdsT%hoI;!^`xFNG6AO=G#HSfGUx1JzgGTS{y!e;f*GtKv8 zZYJ_!)yk7(igL_AEpbVQNDhW^K!T}@cM8?Y8slINhB?{2mwWJ18=0ithl=< z#1>OgTCbc8Ehu*_p>SiRJNC8*0GH z@R6zN>2d!^U~hEDjodd_-z#L&zA#dQ?`NjHdHN&r2%1_GSnK;Sno0^}Pt}=ER>M^NIq% z(DJ7SKb#K4a$ODXWa;~sWmZ&ob3*-Q{q`a|+l)l=X<9jN4=#8eNt9(Oe zFH3QH=(&WQm!?qnNgtq41bKFxqR59)rf#D_78Y(lu91=8M~G;9PJn8>cWoRHyImkr zy}-|sKooP3sT$qpPCgntG5;QdRX?i#94#A-zMo7L!_;^Yj(kCmoZJQ5Q*fRzk{E*u z6A#btS}reb1NnK#fNJ&9?{ZHNLD$IYuzeJHU)BxmQj^5gt?G|H?=blkee05W*nY2% z2XTX!EUzR`D@44{lf(Xxfe-(vr>2D6kQgUz$rCz7=Efkqw$0>6asI##P0_%qR+Cxv z-=L1*k8j$KZoLU3?!PqY6R^WnDVa?C2=y8l=vNVK`78r=$*hgs)`!`l`eZE?sG=Q* zro`)XGD^Y#N#B5){`2bOB(e=5sG`*%jp4(51)TXI3D+&4%vc=ZknRGA_wjsRw%7 z)#*%3iaph5AxEWnz^4Z#6?d((f_NngJYH*1z}?6M!;KqTt>-^xl#-u^Mquo*(o(_~ zL7aNEF|6cAQciyY&WiwzX{Rr-$X_bI39x}^`T+s9x*%XW)v!eJJKs8 zwABbrPRNsw)#K~VpZ3IQcyy8dW^yCFDy(LgAXy3o#}r2}TZwX3PIv~{r&aeN1W$qa z(a2G~;0$)+u{2#pKtF#B_YDh|YYB^N@LDQlIrf!Sh{X4rEB4p>-VI{&K2Yc0dW75f zDuYeeD%R+XJk1umsUYw#s(Gzma)bs2?e#m{=$nI{Z#}gS?x9Xc( zeEc!-^!`rkTig&lPZOCyrmFHbzOy(CEzd;aSFU&4b{H2xO_1;e|pqvor8miV0x)Z zdPlEO^zixU@2wvv$+O>InXpMIF;`kU$?o-uIea!%wpW6AK%bwXicl6HtJ^-+INj5u z;1zd!;bUI8%TUh<>==K8>onN}2IUc3(4Og5Q)|7Gf`B)+=BmtLFRm!7&(I`Cj`W*k zU|Xcv>sICqB9yKonTt|-)wLC_bh-oXr!|c z+kcY4qaTDaM>MU;@K0-xy5>u5rI9LQw*mlJ9iVjb>!l%2v>zF2N)7X!I(oS$OR3_k z1@moY8Mp~`B(Ub~J|lhTrOrZ-=t=@x+#3`%9yh@i_QpTCPGy!`iDF7va*x3cqBqGN zIk{$}O~J#@2`E7k(oPiBqg z@$SzvVSp`mi(n3>k2CgO76y7<2*AVe62D>^uRXid##+|!fievibFKloZ*bgY1ITim*I;A*0rC7o?ab}3F1+Wy>*4WeE0gl6pF&-#OcmEAuMY*NI;m=pT0+_{+1r?{h zfx4VDs5(#Cgna9as_!)h@+u>AO2WxB)k# zptYDF-rUt>KRHNRQvDtI^Fv)GC)p1T$x}&?bcJgrxF7(=6^0^`8I4pdq&0Ld#LU)7 z-79eEZ2`?kLpMYNbA)#w%Ql6~HoU&tRw?;O|I^O`SMydYa$9~=_7;ZFlW}2CI~yzM zdow0|ZV6ckZ>Q@3thEO1R%?Gdk@3aDq!Mo;Q9zYxcWgmm55>iXO+?fE9JGWHKuIKp z3EB=_v3xzr-t1lkUaD3yl6t?RlkC`OEP;lH3}X*^8dFwr2%bC%MebCx#Y7MS0%)kIs?=nupVA)IeN%3cqWw zgBZg>>ky@fjuBQ2p&Vqy56XY2!e-a0j_vH%$}Lo!rp3>Ayi1ymYdg}5`wA%X>MLWL z90XR9L;{1zTk0BkfLdcAOKGQz=Tv>l3>`piuE-oy{6S0osIrA+@9kG!B$YbwyWfd@ zyt{9F=q#3=?PT)(vuf-sNZ%{Hm*g#bLQXs8nSyX?6J&0zyUb+ zDRZ}7UFq{BJdNXV;qC8B!z2`BuTXnXJmA=S4x>f{aWx=N z;(s{)*;p@S4sTc({^@AwxS)s?BmHpD=;1N(*0|{d#rmctVfm<%>E|seJ5mx9GbP+S zmA`6EKhS&2BrrKPDUhQFi5MaObY;tnP;4?YkvCnAnFjd6>~G<@FJbGx0_BM*(_bm< z|FK_H*oC*%rm-D--%ruwJd$?HOqFk58PubjNIfDU%8S-?K%>HCQcg>T-KR5^HW(^1Zwqi02LbDJ4Nm92mbmpZzG zNte4;&i4i3(s+KsEc=rD{#zwACK&?IyAi1>&I9JEa( ze`OrG?|cSAD-++ehs+1;`)*vs1VH7!Dp%EjDMy=2MI;)Y$4gEE>|P82uSspH<-A8L z-+_M}58If~Di=*t1NfLmVOxC370+~EwWnAV@tcz=vZZFM@a#?}@4bey9-0p<-CD*w zwApbAIDQ!%Vrq8~a5vCjVOF=`@v(6x@I17Z;#>Fk{lEEKUS{V@+iUA%KRWFyne^Dc zWqFXqfWJ-@Q}bwVRE3ya5&6sDG>y0`aSU6qQh_zWWUf zn0`H#-5N}!1-5X-J&r5rP67<-%DpWBoWVD@YCn5me47~;UKS@S zcKY?gi9qOqPc3%U9AEb79X-5efvc>UMqI^<6~#o|8-7sT7fKo1V_Sh+_f9m-JcD-% zs0qD15+23E6c1lTq#o!AWnit3-`1*$ho}fX|A5$VPkuG(i2^aE%Y^2sBRRszM=rJg zR4KL1CpuBxhPp9QdRCu#%vK@$%E|7deM~dhE&>}u#leBIbhvX#0ucjWnAowBa`oI zoKkmFh~bUJJTZmvN6a@IOlg$Ukcbli#HJ=|R7I+A>u&7E*VVB@Yj!$2HOVN1vl+$U zVMz9dsYc-_L^K>WKMs@AUk=CF_@&*{F~QzAIw-1XxfgPg7;b|Eu(WCoO@ZE~+199E zk(=ML_POlN##f1|*q#93&G!RO_h}6PRG~vc(IGC?xOJYTG1@K$=Rs}nX5|f>?lmEl z8%6x>djJ8w-PymSX|hE~VQa+!7oF5^+7-Q|XR3AmSgEjz#TXq*XLzi$UG|Pg&d8^X z$4mnW&!D8eu91^&-N$>Gi9k*{BlVqPB96a%< zAG@_oHvYtR;Y+Tb-!&e^qDE>8+tSx=mILxEY0a|-yuCY7c)vfLU28u|!J@ID2Zt8= zoyvDWj!hd#l4qQ>X7p|y`57`{OF^`ckU1)jN36`xjvAElTZeOr-H2x20^+0)e2}km$ z{^?IUS?-hhfgl>o;;TRzFnp6#&IZrtGWBkIuK>b&uX1? z;6|OAm3h9vysfWs;x79m4?wMs+Z*3$xHZ)J0qp1cS*O4xyirl{fJJh#9%~z>&&L^@ z6^o?0%baxfN;Vp6)D*J%=-tI0Vt~kuW8muobzgadR>d!!zotJ!J|681Fmb6KH*1%* zXqm{xCQIbcSLD^y#W zA*2`f)_k!zCDLc1hfZcb`XYd)LON+0&$4Jp9q&`9>gL2}Xi&qmArg)|kLoDXS8@tB zJVO7cf+0sOBr(E8PjRs3pAiXzd&ebUVX?jC!(SQUH_ox*jAM zv`GF#ew&dCmY3;Vlt?|J%UbNBiOLxAKC(9cX_XSy_7xw_L zrn!Fnc{qBw#J%?xH{d!MiFWptcH)zj=7<$`i^#QtLA|o0-EjK7yqxdjp3yl5h2r)) zY;hnq)rj1Kvq4WLVo|+@lG!o(?m#=IfT)q*_vV3empja~BJNYKU(NI5UO&coi9gO@ zdBUimYka-Fb@<>&L#V5tlVD-KB=kvgWBF*MquhKu_2>GjQG-8gRs<*W?C7lvB_aaK zrcktqBZ{einPYKkJ9RHBGw=;6r5rMK18nM0Cj(4Q=IahAhK2B#B+ef8gBzvX>q1=9 zwVILW>DoUZzL^iO4>EiKH3mu>VI>mCf75^)eWb0eFDnU=zl9*&y_n0q0pigY-$cZ( z4M9TrccF`^+x~`E@cy=1RG80xpxGwe1h((=Uuqk8?hfr}qy^Zl;sPLOqT$m?$%T_f zjEQ0*(Q8>f=Om95#V0w6QXLwEf8*GuR@5M+(V#|M)oKJ?i+Yhxf zq_T`Av%Gpu2^vfjL{~Q@C`WyRUn>sc&* z%RXk7EdTjjsr;G>v_kJBX#*P;$MYi*3vYE*r=b(8OMvargK?o!_%MrI^^{8+);y$v z(EM+K%pAHx=kJ`i==K_1+_PG^dDR~&Cmk{8@ zD$RQV_{l zjgVIpr=>2b?k6%x2SWGXd9ae9o!#6dRMbI6jey_2=AoALw=RHq6wcshG2O5 z8P0Fwm2_UWUh5dBYiL=oHmGK*r!y}P)~0-fewM($Ug!UrFA%(!h*{Y_HK@8QYGKh3 zUw%Qjf2&2+dTZ!0?o~f%og4_;Ul{&2u;tQ8UIJSfBb0r8wxX7u`t*P;DK>atohtEA znTzM#a%gyMkAy6$m6ObHH~Nor93!hQ$`b0qp1&Pt!5CE0oT!GlGhiE4>3Hd$pN}1n z=8c`Gx>n6lw52~R40&}+_bKS9M*bv&9 zN{$x%JJcFuRbZe#1Nj>j@a8%NZk_^`p6lqagP%V%@&Z%Ae}H}hdpA0K5j~`QfMF0C z;H8JUq8D@khVbW6^ac+D`*cr~HN?kjXr^kJc%5XHu0X!i;0NC#8TzMTavuhkg2DY&zQ#!IK6#3k*Z@Ai0$KAOM{h|O^YPX0o5x^&@ z#IGbhA8}_Tur|(`y`6Y?bgrl{#>Z~ih)n}Oh1#^hF_)cs>A(g!17=+>o9u)wp6o== zgl|KJi7w86g#|#;bkMxQ{>ver@r!Q`H0^aF;5)8T*FbP=WiDELqH#FC&wkP>26_|x zcSDvytCRV@GG=j7EUI|Y2}G(OK;ojFckxL97B>Q~iFBPUQpktBaoIZK5#@J?O+xO- zPQ6}WOFENP&&kvP6JsU;bML(mSXVNxU{uis*6}>0-bztTE4LG8|TwKtFAtLQQJe^RD~7LIc^;bHn~h9&=a)ns=Oy`YRW+sLpqy z$C80~u9|>P4^oXBB~s?(xe=LeX}Gcv7)U96ivi1TGr4pV%m&(O^(0Z<9as$=1yWmA ziCfc$e>#cajaEB}&S%RjJot}rp+A+?_`j<+TDq}@PeBKs8T1b+VTq$*lpw0o>ZfRg z*@v8_J2VTh>pJg#>1v&ZmtEIGm zpkD(WM+Md>x$FTA7)xjnEEz}jb>z9^=PF{g8pmbaz%PH2r-!tTb<41vGz@c|(lJIv z->`tMi9YKGIBJ|6tnvCyjq~*g16~%SAwI`TSid6@CP%aK>B5ck=cEge$(T>z+|SKG zlZ!xOy$02pEc|kiHS!T6FaQT=Vm^CP6);`w8WeSH<;0s60p)2ewp-;$+e_7Jz8Mdo-d1wbUL@5Yee5jr5Y0TuN`R!1Me3A_0`g4&A)G`f#q$C zIzA(F%5pT&oq&ReVsLJrx<>3Jtjv;m7yoLu;472m8sFvhpEId1Maf3vfXl zcq!PzL~lel3yI;}xf+0M^^N)fcs@{IvdSw~97|JpKjjSU6gNz*H{zy{v$=Hp3G^^C z%=cy`WAH^`&8iaGlvvZ!4USkzg(uZsYY)Tf>Z0Cucr+dSZoyjxd$?b5*~$5 ze6$wE7J4IY6fqU)uN1DZHvW*|>ruZKb?|=lPrv&JXlUq>(TeE%MQW4B7LPT|$hF-I zGtO3GQQ>EA{FWix9Bf?}DP*B|@~4fZu!e1Ghf_9F=9)_iue!AK=2DG*e(j&)gps`v zLSJ4WI0NDSC3J2C^5O$%LQ!~r<@r}5HM>3>RQUizp$QZTKY7KXzkuF)A)+}r+PI^v zqv}1vI*+}$)rx|*Bu|mnrBH7E9_DBq&XdR0cyyUhcm0ZER>N0PWzVj0ib=14Z>|&k zH)eM6`eqloyyq{N!}bD#CFRB5VP-G2+Ab3vlVy8I6Pf;FL0r=U32n zU!a!V7vIWL(W+UNK=0@44QmyaLkd7X7HWv&v2x~rS*56vgW_3DcE8UO=@|C=e#O#! zPsTyxG5gtqGX=ISk5uZ{41Sr8*Fji_(u;$hH8U0wK*Jzz8_Qs~{qz=M1}3CUbdKA> z`9xoTi_NTl>9O)#c^lmKeSApp3p+UoGbG9^Nwv0B|6!GiT`yXa!|e!bu4|^Ev5!)T zeay~=jj`hmASS=25v-pjSh3N?nm#T1NVgeZ{j%z4#kbTiYt82>`_lwXT(7c&yC}d zrHQ5cLZI#SN$cC$(UrQ5m-9ns`Et$gJM;+j?QBoJnNY+_#-{S{w@r+zz7@DSpi*d6 zE0ivqq6URn1go0?U;zvB-?8z(J11ttU;22Abs`$rwlDgw5V6WBkhOe9owVHDm4vSn zA>791ujV#AutD+V|I!C3xRgC zrwMX5lXpHg!1t)J`?dnp_mU%w$9IXwdZ?@S#!5hkwiHtxdqXf#uX3@ALRA#40Vq~H zFewdGM#~|Xl$|%TWX5?L;2*w>YhdoS#ar(C$;g{so_99!9mDV8pItZ9vN(E;8ii9v zM{K4gN7(;Rf1?`n%VjUs;>|{#X6gnL=hjTfUTH4C2Uim-(uCmA|pNT&O%M zgjV8itmdz-q&W2?`2}^#>&Laa+%gIJK1_E7mNPqlL(SzA$FVlXk;W^4paA}_gy%P) z9o@PmBWPE87L1tx{>1IbNmogoZk!)L*)x9)@k36H!(lvJAAGtKQZN7D2Nhj7xaND| z0kyj3ovU*B{pb2UXk+(dN)6!T%%MIw#~(hoiiJeC77ASNx)N^?;#T?aOr2W_oZI3x z<+B{C5$j%nh_{Pf`eI)895j%X=h~Bpm|{1_n_tXdn0%chmn0TGlQwewm@VS)!tmIB8)~W#&;E$$L85u!x`^D)eocKT@VN45u%g-_0 zh>mC#@Zkjhbuo>(Sd;?!#Vc8>QylF#r~Q;_{8SLo6?NCxS$utIFgelspTI5`fH#ui zCe6wR*@m*xTbA3Y4c6>cn>rMeZXVLdcXG)WU!yWKeDXNP_F-XLZ}(I2GO~qqz2&kK zPKmR*yN`;xK*yph^Kd5)$&a`JWdtI7_OGZ2I;6rmJhO}?5OHk*C{1y@K^^a$%4ff@=Y<1HT zfoJw%-^$0>n({xp-HI=*1pK;$U9^4uOSWH5AfwBZf29y~Ye0p zfDhaXxFo3F%_c^)6*4!{)Ug55L{NaF zMn1LejBTq!Y!Hi+uZ5APE%tW^AaEw^$A#r%Pug(0ld`E`>=|7^b^VJ!};GM z+8``G3&}=qC5emxDJ#;{u;JFr%QZhdquTQRjFrp}m8-B<^^f@t>ig$jmx5ml2 zN-y$jr0AgIX0=Ue+|<#N8E|@<$U7S)sB^4Tr7A}GZ&Vt%cw_@=_eet6ODGT85Va>t zZoX+i3y29^6b?bgj5_L(wWK%nhO?i1>!k3WHJR7+o)H?Br62J3tt8I&*%+5?ABTO_ z13oA)opgL53;74M`oNlI3d=g(_EmsY`6`kF--m7;gVubxHX(4SWF#6-UguQpcRl** zme2Zc9=MIhhg*0!+kYyIUk04P&Y-jG&VsNTcP|rx8qfVl&cV3!@#sogV9^2 zqc;eq2_?TvI)4nr%G@ZC?bVl?1emV%Y)vj#bQ+)hW>{c{iotFb5V72|)&K5AASP1P z*T1v1~_q3FBjz2-(|)o zrV>aa{LHdqZes)3ex1Ff$SW-l;m&5A0n`{{=!kUn+nwFAf!<{%tW}+Jsgr@5;yY9> zAR%wMM^Asw)d)TUdmzl%i|md;=j?Y@CaEg^ zm~%jj&wA8B;EwmJHZ z>w0(hxO8`I?q*(vxV+GZzh+5kM4b6UpkVKp=^H7Wi`c`k;FesVu z5kS)}R=Lv<3BNox&M#yC_3Ofc*vL2VgN#n9iWpB50ig0LY{NJbX;yyT?gpFSc{X5+dvqzcfLQxI%BTKY$SvM2pADMB4X<6B zlkS%++xiuJHzjLZd{o-`PM|b0wYC!L?6v);u1rooxYehA@%B94Z=X|5EA&xQ%37Y0 z`|B2saD279Y`_@(Tb|%I91BmU~WtgcNy?jYcfSJG9%4>%F7pCwy|`{ z2t4@$zCe8{BN~4X?e);Kd1bx?Z|mfl)Ht1#ylKs0|HN;VH@uY*2o-+4$)I8Ud0h^* z55~oG2k}beK-ks-Sj+i{{1Ey(|388C4z_p88gemUl2?+Xuxj+=7faYFE;@o;k+ApJU zZLgCK2%=ET3m|6Bo*;TX|L>y_h;}vzoL{?i?=!fYuMZBR=^wj$&@p$=8~e|X7vNaH z21)Tt=T!gy{hE0S$jM>Y`SaZ)|MhEMUstfmHQ}09|NAD;2O!nJ=Kmf5t@Zzw=wIXb zpB4Sj(f$`I01N%UX!>u~`Cr2MPdfcy%KR6I{4Ztx>mL664U>RM%WW=FXSQs}C_LK8U1`1}p3`x@J&Y@8et|*Cy%ceq`7PgQ>|#Bn{4$^9ve}@Ld8p$#bLC6^ zX~4>1f84b#zkEU;y;gW!7tJ31NaM?xgUYZ~ZvL_>GW`LzJyyu9{&bI0^5^xjxi<7! z@w2L>%&&YLktaHjp1)R&7tQA}V{&M@y1U&Q*;MtYWk3hbXOZYUSfpZT8YVY8=GYZ! zwVOZ5IPqeJWY{9v%ir(|-;`MWq1x!2Q_0yEp03;e@|gro;44(BBX#`+iheM9v;;`+ ze4M6{C45bJfZbcaPqdb>8b=tpj2SqeE}5_)6=7YkAI zNHQLqAM(u+X&Ce1oi{k*BSaBtTKt6F;S(AAY8z*D$$WjbEWMtH#Js{lJgC%q>e0ui2Q!rAPYxtMv0T( zJn)%L(2B8w(7Yw_QzW+3vacPO%2Uy2zd~L10%o(A*1K+Pt8Ok0_Z ze0i9hnB4u@L_x^70aju^eP;n7BEgc&0Aupp#5kTlgVPhHzK`X_kL*yO6?d4u8tlVl z`2qhQYtiCF5ulunu0Yy7E#4xl0q*S(pOddOe_DA0ZdIe7!wH!_x#6E34b{ihV^25c z{fPMmX$+kn2uAycJlk!-gk1CukvaRN@VqALVG@`q>_Hoi#idYws*_!F{STIn|rczH5+%V_P{FWn2J{ zF1GsJxLGpsystNL&ux4DyOh-D?GF_u*y#W!4(*8w!ejcmluFK>7Q*wvgPBf%nQG?0zXi@W5-{bti(>Q07kgf#u}4GmJqk?0QuHXwIuZtnew6`FlH2`7ulZws}&&QBU1_ey9zKISIx9 z+ZwwGoob9kOn7dqISv`R4tTm?)A@gVU{~?G=X=xD&&wJ1>2tmgmpS{VyHAD+3@6^E zi3xk|4O>j~1;?jM=uW5IQY$REQFliDd+_!4`3ONbr5@b+gdJMu>v%?9yAQXkCr|mq znvL68*d5|HMEY5AHfpx-JzOHC7j7xF9xBLjBx1;`B&6ok*Ltd>_WJ|vnH|rEj0do~ zBrMYn(>F`qA7AFPsQgm|fBFdSF7l1j8bS66jS-u8!TMstXR^*~*C3Evx#00eIH!8S z^7R04vlwz#d95&&t-CYtP+UoIqe*PZ1N#GuF1gcZC0>!Q7qDKBNP3|~1r`?qZt8tS z3A9-q*itOcM268u^w_;#E7~)u{V|grq8jCwg&!yNmSDe%&ED!&*gwt~C_JiQQ=ri@ zpheF+!L)d~{xVERHpp)rzNCZh00~#h@YzQ7Mx8&?9(uLclC2?KDZKq?cjYaEgW?G= zVAmFxF%ooePsQQrwv*1SpYM}{FN?*^wMCDvT7BuCJnYR-N!+%ZtgEHF^`gj8g6-d` z!yB;(+niD42IL4OCVr znqKAfcwY>c;G*!4D~|7$hD)-RdeRgG1NBG0*aRo#>fE0(2;a`WUgy5MJXNrjmF#V` z^P=gC&1g=?m*trORDy(aP9=yMDoNHBzCLSZL&}UgKko&@LzVdM(lfx~kihK(^2|hn z3m33%r)V_+)>x<^gk-jl0WT#Wj12PGEBr;yE85!!Ga*cMU+=!7-{nm9EEb=6C-jb9 zHL^2dGFy|guiACvu5!xs()L1^m|gwpmmUM69jnUprig2r?a}ooW@*(Y8Gh^V<7L>* z{V_)sv&hA|GV7tZNFE)q*^{C?gznRJy7qKhi1eQiA`CDiTBUy?lO2c^FVfhq0u`Yt z225|{DQ#6(cg{l|A@g=x$HTek_yWUfcP0H`c`3*IE-24zpB-;pjvOCi7`MMFLNxvP z2cwYdgqy|9qatVYHtc{t%3BwQ=bfVU(>i&V#j*fg{0pCoOub3_kQ7XXhNWpbCsFT# zhyS%qIp2#g8mUg8s(yrAT*q#A$!wGrxJyltdT-)7?(`^lsEH-SNZ>jVXeYZ)dJUZ% zcKL|rYUdL%{jMpH{7!FU-+C>JN=+q1@KaK<*PdRF3HR{F>W#~y&jbytoU&)_H-4mF zKbfS~XAmu0hIOY=OLItE0oWq{9)HyGg|@o~Yj!@?d+Xx{B{_B5os#ny0!I5zpI=3f z%>gRtT&iH}u5z}H?h}Vj>U_fvOrKZu9?<69A_Qr=0|1b(29ZDBGgueY?u}@1DrlNK z`!oCVHfO`mQeW+W9HG>1zh)!rg$(~ZYbsxB0^dIxGdrby_xh}sujZ4(a$^2e9sGW) zS(tWXXSW#-%_?K%N5_P8rLfsD zyO?^U-1O%M!94B{lkQhry%_n4i}rLe9ZH!V10j+ez7m5tJ`|QA#Wz^(gM3lY5Q2EV`6y! zs}SjV4|{$j;a^zn+wd58_!W7u!w_s+M;j01JT&4u+FOes#t&N`^j=ay|Iz3oxhxuy za1Fi9d;uhDaRHH_z8azRUYsfYNry!4&X|vg*_?Z@p@wa2fnUPkZ?Zr+fV;9;sI-D+ z{sR26nC*_nO8`{dl{m9yJwaaed`lz1ucyki4O{Gdp)WLRt?e28c*}j%PeSjvzpx~1 z2Vf|0KWQo@NMsJy!W2Y(#pXyYuoO55QJaz34C;<}i{souiD?>R5cferaaVL4&9X`HIwAs;s%nnl&NIZ^%tAQeIUX=bs8A8 zbcT6uHWECH?nn}R_N!=$kJz0<+O~W09=-EJ&VUe*WnDPFi_H9kU&y%lL5z5Qc@J88 zBZPF;ch4CZOyH@K>}@U3GZ$E5i*0GZ;MTI$o3%xKSbEyj2$Fcjt;`RJ^ihR6a1Mq? zN!aq>$3qWDrPte|9eYRlcPd_5PaXQ`-0oC>CW2zt!;ye}*kyMHe{cANYYdQJY}Cy^ zEv&T>g^vh)Z#=JLwI$B>jN&se7o*g(ov0b+)i3388Tm5p)Biw$j%HGL9%pmw#0OmW zQi1Ww%jYbA5hIcf8u{;UreNT^+*2l>s+J2R2R7=CZ8PcIcNV8JJR@%j*j;WepyQAd zHX_-mNV_1sW%5GnwMwFhBzA9Y)UZ-HX(J66#VRShf%7j^EavIHQ7xBd3guiIyegNq z<$PF|47NsmyIrU@V?pwxQ0L9BZ9GRK<#y;VPu=-a&6`~lO&>78Oq$T8k%?8wONFH+YIvto(Ezu|36vJwli6CqX zYeOjZkbvw~7#Xi} z7VukgD87kBj~ zYRRW8WRCUbIq`P%|DX20Gc1axS$jZ|C>cb_CL{<5A|eQ`pdcVYKtQsR!xEP$Q52MD zASlU2K*H7Yp8OcoNT+=LRYNEgb$W62$;AhsYpnZAe%QD_;Atwd_Xy?@UF|k%qLF2}ck$S-gSZ~75sQM1agS8!LEbSQ5p;r&*3cL04Rr_*YVp+rW?P<WN2w@0&Z8opt35h$?`Mw;Z0Jp8#Lcg%z9lV`b zJ8ZuZUny$xwTz(Zcj=V}dFHRw^d%<FEOnyREd0ESE>eeAf*rY}uK}%-QC4@2d?JZO;zgr=sE)fsl*{9JH7qtvgdfNGxW8tAn@!~F7_ek%?qWwLK3uRJ* zf%XJRd`Gv?K$3I2)0>lmr@+kWi+*f5iX^EI>e%yzy!*6dag>YJArQNGa1@Ucc*Bp!&EXAD2mS=mfE*_;w&y4tIEb$1s z$0M;G#8nbt)?F!6)PTYn>Hh19+~|U1AW56 zapH<&CKop-%|IaN7W&<%GsiV6HzQyGMk23XLgwCtmf^!CqSx}LDf4!gaczkxLhhOS z)f=gw;vN2xJIk>wUuD`9U8^M9Qd93qe=`dNR~Rl^r*o-lrkxoN7+BdQzSYM)j(S0f zbdw2VLux)aG^=rBz*b#g419FP2jNVFB3+xffiEuJnk#Jr#9*#kHo5$V-_5btF0bPj z;w2ul;f|lYVySLtR`SHSjO~Nlv1Kkq-}g23x5(atceO!`ntfyf>ICAJA6hFM?59*x zKQ7&jW3v~BP!nDN04cc)>dESUOKg{A`{!p4`yK#+AO2?^udgv04(^yK{N?cccEq#- zVjhDZ6Y#cJ4y zD!B`B^p~Gm$9){02P{J91~`vxT^PGFtab@Is`4vo`#O!+Y)NOBqKnoR3_ zR;c{(nh0=1Au)0Gr@mG`tR~6z*!bP;Hhn9kr*)h5VEIYv6aj!8rl#HRX#@6(Juygk?pJ9rTXuo{v~`Qwp<&CX0aiw2ZWI*QQ*Z$%zBUwE z%t?BEv4)O0&40QJLp4siKEjSScb@GTE4P`tWe;2qVJ$21kb`V_&oI6q!@ebVqMk2z znhbKnvOJ#2DLA=@{$SS<3g%c!V$kh-0BlNvC+#dF3;RvIwt5GnK@f;Zh>wVu^eibJ z2^9|>I6E(1B=Y=zyl99{Q%WTu0knSHtH0fM^mwV$^og=(r#0#nFVwoRqV@HPL2y;{ zfMg;y@niH=Hc^wh@B973F?1gUxtQ2~SL^L@Xr~HH`NorE+$6`k?SB!2kDrZy|=qO)*?+_FCI<*WDXD zU-wq?2Z-$~0B<|Gyz-#4oOs}v)p7itS+tH#aqae`vbWHUjql2h-8n`frcW?k=!w}C zrdwU5--kEZov`4*|^I?xT51PfS9+<#y1C`)c>;)@WYXabCx> zcN*^9?+F4QTJr}6waIy)c?i#Ad6qx^!BM7_2c`MvF`?b#brclmGz4x^w7#Ib5N)vi zi?Nx)MaS&Qa|5pplhRXGsWMqII_k8jtJj-V++zw9j_6wiGhN|1sl>jPRVG7l{N$yo z6Q5?wLA z*^~F(gYSp0eT&4}+c2J~|%UaV}82NQiiVMWy#D0C@c2wG1E*f||GjLu}y4SF`9a2WPXsr~3n7s*DAUN9c zlZj_?*H(T+;?>ojPO}4OnA$$OYKknmYZNaE-)VLbP`hw?jwOG`YZsvKgDGMX!WgMo zwD{)ZwYe)zF;Vj^?=PECw&3e;jjVs&0ATpw8jT0Jyo4Ncc-aTz;no8Vh${28OW+w#nSxU7_8p@68LjyT= zGsc$i1y4%ScV}{2dYaNAOVTmTe)9SanoZ`uQqNjPc+biNbL9mUar%NZK?XmouQawND?wcJ=FNe)z(%D=P{K%<+Vd=wIYl7?`KmVqE4*ve1JrABY+ z!z;QemK>$psRGc#G&aWPA4f*)K~=aCo6~AapZyatL7qv-E)G%|LzNfUPiYEFpm41T z`hoJ-_E4F_MHR0`!%+JaP%X~!(!>|UV9|h!BXuO%9>nh$Tng|RrxgV$n!8c_da44O zJ^5BmmAfkf6CR$|&GhArG!wanRXLP!U|<$fWMUl?CyJWSt9-BVO8X>sTlYy^QTurc zz%=cLn?2;02+;+*qww>kT4k;2LFR^BQXz_eB~m%{X}sI`yCH^vso3Yt z!i{}np+&!cY|S+gM@`^=$hCnClEVY_GJ`}09&X13qAL@=GMB@n!>Z~>&Xnz9UV`V# z>_e9*=_gFQm z*u-YPFMg!#-J!W3O1Gj}FzR-*5LbkA{+2G=g_O}bufAqt9V#b&3mcL@AgK^`-<~^M z@Ga>ouMimh^2V-;)hn0nf7PI+hqjkmFy`ayfwW;P%Yc)-^(bu+<#`+t@+icI>x8gd ze8WrEuHUyCt{8uN8OX^O9B)?GAVH#HQ>pl=`}Hus*7*5;1d6VJjVEUMwgo(9X1wkAtpyFN_A&aYT?A91uEjKjB5}CSF7pE)bqa0T z%s(L|extj{>nM_CF5?!VsAkHD7sGga%<&1hoDz&bAMjS6og}y@;1AJ0GQ@pu6LI6e z8wA$kCuV-;#oIlnJm<`F^qlZW zrGfazmL#?Zzm^8OcjsG0ad!^i`{&EJo@HwBxlqwx&s77m_g3-;S~YbG&`n~+D)jIT zoOe_W0X_JIg`nd1g5Y$Sf}hq(caeSKgJOrVhxdE3ANsx6(janrTXg)#jf_hP&v$pW z#INMt*j}hsu_V>hy8w-D;Qb;q_IpBQ9?V7T7DLiD&?vBiDaLzedK{M+w)#3cUc5^e z;{TF=1mVV5vZXiWw&5`L!`Kr*MP3)Jj2$M+`QIlI36xNiqsljQG@;OTB@k8<~Z{^W$|(IwFwr73I$SxYBe575V6Z_TlVm3y0#^@7SI79`ibU#15eRc&(u)J zTY*V#uRL)`l6-p$W`vOQO)gOXh*d&R7_xs!{xWvfJ4#qdd{#J7yiM{eK&P>gJV#vDHxi9o62uaUEa{j=WN3%(|*EF9I zD^8eR!XL+nd2)-w>!bo&>Mlr0z5L!Fl>lJF3Bn3fF@s94@(!ym%X@2f@t#|&6t;Ex zU3RFhp^?zXuJnjJUtPrw)YZN&u2-rXCD>~o^>FrvSQZifk9bMgQ7G|@^*;TtG6)aq z+DhUwa4h%GYM+z_{3|h9IbV&ww=1Rr<2`Arb>^y~JkCK@S1v#t()GuehRSf=Ym#;@ zMnM;Ki(0#1F#?WFGTZA834;xb+vqEqv$SLfkfT);99_6MKZz3@oeQm5RxBcdq!HfG zF82rgvMYDVbx)!$|3XiGePFf$0Am7=u`C)*6zjPM4TpwV{w}O{SR0hjhF7r%?Y1Y{ z-WIcBp|S+@^EJi=r~0LxwLy%IoI!P;r_;G2;pa{?*i(u1G+$ln)5}Ex5WNC;jnvgV zt$LTq_F8U%UIN3Y9P&04EpT-ahg{ibIF0Cxp*Rn2D`z6Z{cx0gA_f5-cI0d-w!_YC zR=+5_VqD#hl>q&7aia0v2x@IG|MGR|5d+)W6cO9dePajtjsn%X(;OKNkRm0h5I#Aai3Q*ywlJ?9a7YakO)(Sa z#SOyLQZ8k=B$~CvBWH9Wd!8s~(kj4=$8jckY%kW2s4rDrJC47B_yXV742&BEoJo+@ zQ{n-|3t5Eyr7l;a-3DY^vzNLIy!&NUQR z?9(aKnrAEeW=?LbxQoqzFP;tF;keFnMqDC1P*}L_l>gTPo2&Zx>97X zi0$P0xYh=N%9-=Wnvz>VI45AiP18@awxZ!{c`RbJ-&;o#(2gQ;mQm4VZOKasJ=>ye zdouuzivZ^>VdVf4A7V73Ag56tfdZ7=ILHvMM(V#lnyFjd-UvuEg%bd(ti29ZOaeie z>B7(#=gU7#2E-ujqDp#mq`JVxcL$bT8d!D**S1t4up-3?*lQHlL*Z{YkHiX@$WPw2 zD$|?~^B#RA8$1pz&?sGByv6>V<+Tjo-1F&sB=47`SX2{)m^a0(K^*rkaeE%j+&ug( zx&7%1mTou=`j(Ub$TKi^FCG=P>TC=?b-B*!6&yfacA8ShSZv;%d2u2BQr3J(;aJ-= zUf6ihCFM406@Y~yGVIthDT^2-pFHVInd?b<%D)eChhZ=pT1-K5$rcFTtYx2px@K3@huv?cc0>3TJBJO+%N&&ua-E@iKhq-06;$YJ@PK5Gh{eV zT*7^A4hcBbd+kr-4m4M#5;g|&`H7>z)uDYjrI^K?GuBv48{aPDD z{1K|_hFF53%jbqa{I0eY&?HV`#BCORfcXv~~9IF*g0ai6i z{ZZpr&rW!UwnphT*#dZCDNtb(q1=2Fao=fMpnjvB+3VGH3te z$>gX;kO*sfU>0Wr*na<_3#Y*JHUjK`3E+Z$-jd-kA9r;-f2zIgY*v}21arl2_A8d* zFk$t^n4-OtEa=?0&7HC#n33M=CI*lBK7{T(j z@wY~e-!Htk7WS){yIyF~QFpBc%&nMfj^ii$7rl2@x|-@jn86yJkyW55=QXb1d#tz8 z8*ivy2k>+dL$!`abRva3gElLT1qw3%dXwGTF?s5%vX{kh& z7hoU+f};P8k{Gvd`1Dmdr$AlT;b*BDh_gbky)-@BDdsG{yq;Tb?e~_@zj;V4)|~)B ze-1_%V~6S?H0@3cbgDFC1L*7%6K7L5*+y_@u2H41IIylcr{66 z%QKDP;>!o6&a+QsIkGA?r=o8NWNDtUblyHEr6CTz=3%VHzgg!!1J?F|yXG@DFlr*0 zW6Ap_807bxYF^N(#SvGY5Qa(eH=K$>Aa(D~_gUbr87;*xpju2nt^_?C{r2hws_fGC zjUde!p#$R^4D|SW(Q8l}G-g=78%-d2Ynuz)VhOQIwF+jvV`&%g`QMBsP_nvnKwDQdD$dC;xbo_%N%0JRxE)k> zp1WEjQ`=1;?CAlt11L2Z`nI}~fC3)PjIcx@U2~-08^1IDT7h5C-KHY`3Ded{UC3ps z>kB@`0K*IQu1BR>0~&ZH;_5UjR59pPwcw5MmfRy>fP)+-K1uL$L*W(y@aJsA%RL3Q z-dnvljoil@-0UfQYQCN&X7%Zz&_b1$_-OZLV{MyuRm zS9GP*<57}6Hmf?_rmUt;O>Zmh+FzH`_`-+D;i<>5r+AVN(>|o^W0pl)F$y7Mx_Nz}zEo_l#rO0CWzeB*>W^o0|h}T7#y14XAllf3|k8paJZL#L3bGra!Y@9 zKp*j`{CB?t$$4BVfG75VWigAssUHHIKRbv)>&yps z^UpcJlN10@89JkO`|zNL2Lcyvdng|s;=dREf7RoA=Kqpq}25 zNhlQ`ffT_|k@h?Cp)bzXyc8KVoJ(H&Y%Mpm>NMyFmakv@WeF;RuRnSX z;LX9sA+m_p`Qp+W;`B{GpSP6gJAO8hbUu|OE1K2qzV6!j_k>0Z`97+|R4Q7g`S@&}fME>J9&k^e`sGPx$+FudIsh+n#pA!>+XXu#x z1bhEVRoCah zjOCvn)DkZ<_w0s-@>iQh^e{?>IuTLASLJi2kasmGQPl^xIE>5;xbc`*F?{6jZseeD zwZ$#iPT}TfFR8g2h*osF=hrhT1gwiO0I#Japi5rMzcz;6Sv^_GHqgn~HAnxC+=+ir zOD6o<$4k0b3Hp)VYKz<|E!8S-m=$nlTcqG`{rqKGcBP#$+dyQqy$9s{a@ArYGh-zA zD%ORM@%726~;79?kutW?1WxdRA=YMme7x3$nEr37^mKa z!jN5@P#=NeQeMNy4ythJX_2REpy2$kR;<&u&i9*>)&E?<%|Al+l6bqOI(cFj3KcQ~ zWFdNa-dN?1;hWj^&N1f+iGkK}eUmb#A@I!U_IE}}cm%FaD%|~&HQjKrj{uGOz)B#Z zq!6QwD!0(2p7APeI`mAS*TFL=m&LnCO0!H*dX+)Qvd&pqd+kD2sLd%xspIrbGFwKS z!urp*&}cA!h#xqxrV6~V8|m>X?k-v==$u`2F7Hz{uqLEpW1bvw98+k>+hdkXBeX+b?S@C8(- zvwSLEVuwP#1Q~iLuP#?_JQF7f*GLEpEnFOSM0yB^BLA9puTQkv4wz?G`Z3scB{rCk z3_25bn=G$O^@{A6gP>DI1I*RWw~9p(1{W=jWu=8Hu+9krpX_2Qu;Brb!)Vc%EHR?5 zAv?Gd3FXCFsZ`I}=F^Ad0^B{12sbmeFFsxS>BN^fy-8s`lAlN6#cUfjZ1iEe;CLWa zfJ5(UH_l!p-ULqEeQT?A&Pc1cge{`GvwdO0qKBEL-VV_}@^B z`BD%`-or@o?AM3-?ETu6y@}(K?&F1#krr*vvU)IM#Ju$^GBEf3qX}O8f@Eptc>>?p zV19;=KAd1A+5Tt!vXlBbn4{DL4=+=iP_~x~sK&khy@(A*ce|>g^h* z9VnRAj@;~)@dlPbA&#-RW87rqYlG_6*ZQ3JvoOhm%4tx)Z$SNw2|K)wD^XOP_$hGG z)8c0--dRt9IHp2EUx78z zBD-jjIP;30g8HAH&JQjQ%$dETgHPpK`yg(Et5vTF zkMUa`qp{HnC=ANfiCtg}LoTO(!MO4-zzmh{_3ZI)-Kq(~d$l)h#vQa8B)cdbVwdvb2@ zmjTf~KrK~BxB^O7&Z}nRAlH5hFtM6--Dc?5&=u`oa*EwCuk2*_&|s%)hZtpl>~Svo zAUxf3EVK+{c#=?4`T;XA7z}1NPCL zaMpc2=ytt-VMK;R^GBn?d}Vu)0e)mzBrwxI|HDih-$u9E8tRCYDmN^YtO5-z3*jv= zSR`MK-O&lK?RAYLBLW@15TNqHr$Xxkg&i}azD&pGt(jtHoqBGi_ja)%R08>Ilp>jS zEYpAW1XdnVX?Bbl7#gv&dks5sdoR+6-u0=&K0J5J<23b7FINF_ zp+H!}2Lt*B|x5#){ZncWnKarpgL#P&Nk% z&LiKG1zcL<;_xiaJpoxu^Or~dR)R>aE9z&|OH&HuJz={R5T&h|Jux#V=FwZ1+X$Yj z@G#PmJk0=sZXJ{r<}X8b&8o`vtl&PkO6m|j&geHiESmuBLr9R*TfGe!nRQ2{ZUXDZ z2AnvnqyS637$GT>nF@!>U9^f(nYym4LBfiZ{cu_J7Virx_G&okdWb{vX}Pe}nh(fp z14d>_^kiCc76B+SNVXq#)N08=MoK6i97-upgdXC{dJdupFtL_#AIUz@&MtV*S2GId)J!$FptSp*P|LceGOS zg#F$+ya(o3k~r{6O~V+C1g5V*QNTSmr0X-bV!=LRLJNI6bXw`h$WeML55^!({^ZpN z-e(QPW9_Cl{_27XVjhdg~^)0U?B*kjqF;4g^y?E|9N-y^Sa zEL5QIMl@S5P-Wqwb!j_>lx5qL_7UBN>is7S?~e^O5s@6SDIbi+2R=SlXW%y)(0D=ez;Vt0*00gAtiVuw}Y*4n2 z<{Wo!?SJv-y>+ht`yF2J@j{RZm9m|Q!$XvXGLDUc#1hvkeI|aU?f#r5)r)(e-KrHYTftN9O89^LphM=R8 zN#OMcA`CwZTBY}Qqr~nznm9O$K}Mz)V$dxUM=O-AofxDBH$vLn#K=kvl78rbGJj}h z0wj2YtrH6D{^vpt#J`(P32{JFkTPTknLrNELkI=gg8z;XKX|!77LX~}LIp8F$00@V ztr6H_v$u~UWDb6L2f78(LUMbTB>=8U;NYSJ{=FuF!%GtQb43DwE@)r+`+Ddg0s#nO z04*oSNyxkH>?5dw(avI}tSmq4z&R#6Z4t@Fg{neGX&.frequency([ (3, lowerCaseLetters), ]) -//: `Gen`erators can even filter, modify, or combine the elements they create to produce. +//: `Gen`erators can even filter, modify, or combine the elements they create. // `suchThat` takes a predicate function that filters generated elements. let oneToFiveEven = fromOnetoFive.suchThat { $0 % 2 == 0 } @@ -167,8 +167,7 @@ oddLengthArrays.generate.count oddLengthArrays.generate.count -//: Generators also admit functional methods like `map` and `flatMap`, but with different names than -//: you might be used to. +//: Generators also admit functional methods like `map` and `flatMap`. // `Gen.map` works exactly like Array's `map` method; it applies the function to any // values it generates. @@ -219,6 +218,7 @@ generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate generatorBoundedSizeArrays_.generate +//: # Practical Generators //: For our purposes, we will say that an email address consists of 3 parts: A local part, a //: hostname, and a Top-Level Domain each separated by an `@`, and a `.` respectively. @@ -240,15 +240,16 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ ]) -//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `fmap` +//: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `map` //: to get a `String` back. let localEmail = allowedLocalCharacters .proliferateNonEmpty // Make a non-empty array of characters .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. .map(String.init) // Then make a string. + //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some -//: steps here and combine both steps into one big generator. +//: steps here and combine them all into one big generator. let hostname = Gen.oneOf([ lowerCaseLetters, @@ -263,7 +264,7 @@ let tld = lowerCaseLetters .suchThat({ $0.count > 1 }) .map(String.init) -//: So now we've got all the pieces together, so how do we put them together to make the final generator? Well, how +//: So now that we've got all the pieces, so how do we put them together to make the final generator? Well, how //: about some glue? // Concatenates an array of `String` `Gen`erators together in order. @@ -280,13 +281,7 @@ emailGen.generate emailGen.generate emailGen.generate -//: By now you may be asking "why do we need all of this in the first place? Can't we just apply -//: the parts to the function to get back a result?" Well, we do it because we aren't working with -//: `Character`s or `String`s or `Array`s, we're working with `Gen`. And we can't apply -//: `Gen` to a function that expects `String`, that wouldn't make any sense - and it would -//: never compile! Instead we use these operators to "lift" our function over `String`s to -//: functions over `Gen`s. -//: + //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: @@ -318,6 +313,7 @@ emailGen.generate //: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. import class Foundation.NSDate +import typealias Foundation.NSTimeInterval //: Here's the obvious way to do it // @@ -513,6 +509,9 @@ property("email addresses don't come with a TLD") <- forAll { (email : Arbitrary //: Let's put all of our newfound understanding of this framework to use by writing a property that //: tests an implementation of the Sieve of Eratosthenes: +import func Darwin.ceil +import func Darwin.sqrt + // The Sieve of Eratosthenes: // // To find all the prime numbers less than or equal to a given integer n: diff --git a/script/cibuild b/script/cibuild index 1698536..42448cc 100755 --- a/script/cibuild +++ b/script/cibuild @@ -110,10 +110,10 @@ run_xctool () { if [ -n "$XCWORKSPACE" ] then - xctool -reporter pretty -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 + xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 elif [ -n "$XCODEPROJ" ] then - xctool -reporter pretty -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 + xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 else echo "*** No workspace or project file found." exit 1 @@ -136,7 +136,7 @@ build_scheme () local action=test # Determine whether we can run unit tests for this target. - run_xctool -scheme "$scheme" run-tests | parse_build + run_xctool -scheme "$scheme" run-tests local awkstatus=$? @@ -146,7 +146,7 @@ build_scheme () sdkflag="-sdk iphonesimulator" # Determine whether the unit tests will run with iphonesimulator - run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build + run_xctool $sdkflag -scheme "$scheme" run-tests awkstatus=$? From 44ec84b341c3a8697daf961f37c0614398bb5185 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 16 Mar 2016 23:54:29 -0400 Subject: [PATCH 277/460] Add the shunts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lesser of two evils in my opinion. This is a poor man’s arbitrary-precision arithmetic library. Because the range of 64-bit integers comes nowhere near the range of values a Double can represent, we shunt all values in the log-adjusted range calculation to into floating-point land and calculate there before shunting back down to integer land. I fear we may simply be shifting the goalposts, but until I have more robust test cases I can’t be sure this is the case. For now, it works and I am sad. --- Sources/Random.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Sources/Random.swift b/Sources/Random.swift index 12550e8..ddd9a2e 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -190,24 +190,23 @@ extension Int64 : RandomType { return Int64.randomInRange((h, l), gen: gen) } else { let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) - let b = genhi - genlo + 1 - - let q : Int64 = 1000 - let k = Int64.subtractWithOverflow(h, Int64.addWithOverflow(l, 1).0).0 + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 let magtgt = k * q - func entropize(mag : Int64, _ v : Int64, _ g : G) -> (Int64, G) { + func entropize(mag : Double, _ v : Double, _ g : G) -> (Double, G) { if mag >= magtgt { return (v, g) } else { let (x, g_) = g.next - let v_ = (v * b + (Int64(x) - genlo)) + let v_ = (v * b + (Double(x) - Double(genlo))) return entropize(mag * b, v_, g_) } } let (v, rng_) = entropize(1, 0, gen) - return (l + (v % (k == 0 ? Int64.min : k)), rng_) + return (Int64(Double(l) + (v % k)), rng_) } } } From 5437163ac76229ee324a9bb8f6c000b50a4d33fb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 17 Mar 2016 00:10:37 -0400 Subject: [PATCH 278/460] Add the shunts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lesser of two evils in my opinion. This is a poor man’s arbitrary-precision arithmetic library. Because the range of 64-bit integers comes nowhere near the range of values a Double can represent, we shunt all values in the log-adjusted range calculation into floating-point land and calculate there before shunting back down to integer land. I fear we may simply be shifting the goalposts, but until I have more robust test cases I can’t be sure this is the case. For now, it works and I am sad. --- .travis.yml | 3 --- SwiftCheck/Random.swift | 17 ++++++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2704295..d34dbcb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,6 @@ env: - TEST_CONFIG="PODS" - TEST_CONFIG="CARTHAGE" -before_install: -- brew update -- brew install carthage install: true script: - if [[ "$TEST_CONFIG" == "RELEASE" ]]; then script/cibuild SwiftCheck SwiftCheck-iOS ; fi diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index efaac3e..dc0de58 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -178,24 +178,23 @@ extension Int64 : RandomType { return Int64.randomInRange((h, l), gen: gen) } else { let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) - let b = genhi - genlo + 1 - - let q : Int64 = 1000 - let k = Int64.subtractWithOverflow(h, l).0 + 1 + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 let magtgt = k * q - - func entropize(mag : Int64, _ v : Int64, _ g : G) -> (Int64, G) { + + func entropize(mag : Double, _ v : Double, _ g : G) -> (Double, G) { if mag >= magtgt { return (v, g) } else { let (x, g_) = g.next - let v_ = (v * b + (Int64(x) - genlo)) + let v_ = (v * b + (Double(x) - Double(genlo))) return entropize(mag * b, v_, g_) } } - + let (v, rng_) = entropize(1, 0, gen) - return (l + (v % k), rng_) + return (Int64(Double(l) + (v % k)), rng_) } } } From dc2f5314878ef5a4ac05736aa185195f3369b592 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 21 Mar 2016 22:31:13 -0400 Subject: [PATCH 279/460] Bump podspec --- SwiftCheck.podspec | 2 +- script/cibuild | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 5e1aeb7..f277a57 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.5.0" + s.version = "0.6.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE diff --git a/script/cibuild b/script/cibuild index 42448cc..33b5129 100755 --- a/script/cibuild +++ b/script/cibuild @@ -136,7 +136,7 @@ build_scheme () local action=test # Determine whether we can run unit tests for this target. - run_xctool -scheme "$scheme" run-tests + run_xctool -scheme "$scheme" run-tests | parse_build local awkstatus=$? @@ -146,7 +146,7 @@ build_scheme () sdkflag="-sdk iphonesimulator" # Determine whether the unit tests will run with iphonesimulator - run_xctool $sdkflag -scheme "$scheme" run-tests + run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build awkstatus=$? From 57f61f0f97bcd47549d693395c9bd336714559c9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 24 Mar 2016 14:38:26 -0400 Subject: [PATCH 280/460] Remove script directory --- script/LICENSE.md | 18 ----- script/README.md | 82 --------------------- script/bootstrap | 47 ------------ script/cibuild | 173 --------------------------------------------- script/schemes.awk | 10 --- script/xctool.awk | 25 ------- 6 files changed, 355 deletions(-) delete mode 100644 script/LICENSE.md delete mode 100644 script/README.md delete mode 100755 script/bootstrap delete mode 100755 script/cibuild delete mode 100644 script/schemes.awk delete mode 100644 script/xctool.awk diff --git a/script/LICENSE.md b/script/LICENSE.md deleted file mode 100644 index 8d92384..0000000 --- a/script/LICENSE.md +++ /dev/null @@ -1,18 +0,0 @@ -**Copyright (c) 2013 Justin Spahr-Summers** - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/script/README.md b/script/README.md deleted file mode 100644 index f66206f..0000000 --- a/script/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# objc-build-scripts - -This project is a collection of scripts created with two goals: - - 1. To standardize how Objective-C projects are bootstrapped after cloning - 1. To easily build Objective-C projects on continuous integration servers - -## Scripts - -Right now, there are two important scripts: [`bootstrap`](#bootstrap) and -[`cibuild`](#cibuild). Both are Bash scripts, to maximize compatibility and -eliminate pesky system configuration issues (like setting up a working Ruby -environment). - -The structure of the scripts on disk is meant to follow that of a typical Ruby -project: - -``` -script/ - bootstrap - cibuild -``` - -### bootstrap - -This script is responsible for bootstrapping (initializing) your project after -it's been checked out. Here, you should install or clone any dependencies that -are required for a working build and development environment. - -By default, the script will verify that [xctool][] is installed, then initialize -and update submodules recursively. If any submodules contain `script/bootstrap`, -that will be run as well. - -To check that other tools are installed, you can set the `REQUIRED_TOOLS` -environment variable before running `script/bootstrap`, or edit it within the -script directly. Note that no installation is performed automatically, though -this can always be added within your specific project. - -### cibuild - -This script is responsible for building the project, as you would want it built -for continuous integration. This is preferable to putting the logic on the CI -server itself, since it ensures that any changes are versioned along with the -source. - -By default, the script will run [`bootstrap`](#bootstrap), look for any Xcode -workspace or project in the working directory, then build all targets/schemes -(as found by `xcodebuild -list`) using [xctool][]. - -You can also specify the schemes to build by passing them into the script: - -```sh -script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS -``` - -As with the `bootstrap` script, there are several environment variables that can -be used to customize behavior. They can be set on the command line before -invoking the script, or the defaults changed within the script directly. - -## Getting Started - -To add the scripts to your project, read the contents of this repository into -a `script` folder: - -``` -$ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git -$ git fetch objc-build-scripts -$ git read-tree --prefix=script/ -u objc-build-scripts/master -``` - -Then commit the changes, to incorporate the scripts into your own repository's -history. You can also freely tweak the scripts for your specific project's -needs. - -To merge in upstream changes later: - -``` -$ git fetch -p objc-build-scripts -$ git merge --ff --squash -Xsubtree=script objc-build-scripts/master -``` - -[xctool]: https://github.com/facebook/xctool diff --git a/script/bootstrap b/script/bootstrap deleted file mode 100755 index d61c863..0000000 --- a/script/bootstrap +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -export SCRIPT_DIR=$(dirname "$0") - -## -## Bootstrap Process -## - -main () -{ - local submodules=$(git submodule status) - local result=$? - - if [ "$result" -ne "0" ] - then - exit $result - fi - - if [ -n "$submodules" ] - then - echo "*** Updating submodules..." - update_submodules - fi -} - -bootstrap_submodule () -{ - local bootstrap="script/bootstrap" - - if [ -e "$bootstrap" ] - then - echo "*** Bootstrapping $name..." - "$bootstrap" >/dev/null - else - update_submodules - fi -} - -update_submodules () -{ - git submodule sync --quiet && git submodule update --init && git submodule foreach --quiet bootstrap_submodule -} - -export -f bootstrap_submodule -export -f update_submodules - -main diff --git a/script/cibuild b/script/cibuild deleted file mode 100755 index 42448cc..0000000 --- a/script/cibuild +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash - -export SCRIPT_DIR=$(dirname "$0") - -## -## Configuration Variables -## - -SCHEMES="$@" - -config () -{ - # The workspace to build. - # - # If not set and no workspace is found, the -workspace flag will not be passed - # to `xctool`. - # - # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will - # take precedence. - : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")} - - # The project to build. - # - # If not set and no project is found, the -project flag will not be passed - # to `xctool`. - # - # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will - # take precedence. - : ${XCODEPROJ=$(find_pattern "*.xcodeproj")} - - # A bootstrap script to run before building. - # - # If this file does not exist, it is not considered an error. - : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"} - - # Extra options to pass to xctool. - : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"} - - # A whitespace-separated list of default schemes to build. - # - # Individual names can be quoted to avoid word splitting. - : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")} - - # A whitespace-separated list of executables that must be present and locatable. - : ${REQUIRED_TOOLS="xctool"} - - export XCWORKSPACE - export XCODEPROJ - export BOOTSTRAP - export XCTOOL_OPTIONS - export SCHEMES - export REQUIRED_TOOLS -} - -## -## Build Process -## - -main () -{ - config - - if [ -n "$REQUIRED_TOOLS" ] - then - echo "*** Checking dependencies..." - check_deps - fi - - if [ -f "$BOOTSTRAP" ] - then - echo "*** Bootstrapping..." - "$BOOTSTRAP" || exit $? - fi - - echo "*** The following schemes will be built:" - echo "$SCHEMES" | xargs -n 1 echo " " - echo - - echo "$SCHEMES" | xargs -n 1 | ( - local status=0 - - while read scheme - do - build_scheme "$scheme" || status=1 - done - - exit $status - ) -} - -check_deps () -{ - for tool in $REQUIRED_TOOLS - do - which -s "$tool" - if [ "$?" -ne "0" ] - then - echo "*** Error: $tool not found. Please install it and cibuild again." - exit 1 - fi - done -} - -find_pattern () -{ - ls -d $1 2>/dev/null | head -n 1 -} - -run_xctool () -{ - if [ -n "$XCWORKSPACE" ] - then - xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 - elif [ -n "$XCODEPROJ" ] - then - xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 - else - echo "*** No workspace or project file found." - exit 1 - fi -} - -parse_build () -{ - awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null -} - -build_scheme () -{ - local scheme=$1 - - echo "*** Building and testing $scheme..." - echo - - local sdkflag= - local action=test - - # Determine whether we can run unit tests for this target. - run_xctool -scheme "$scheme" run-tests - - local awkstatus=$? - - if [ "$awkstatus" -eq "1" ] - then - # SDK not found, try for iphonesimulator. - sdkflag="-sdk iphonesimulator" - - # Determine whether the unit tests will run with iphonesimulator - run_xctool $sdkflag -scheme "$scheme" run-tests - - awkstatus=$? - - if [ "$awkstatus" -ne "0" ] - then - # Unit tests will not run on iphonesimulator. - sdkflag="" - fi - fi - - if [ "$awkstatus" -ne "0" ] - then - # Unit tests aren't supported. - action=build - fi - - run_xctool $sdkflag -scheme "$scheme" $action -} - -export -f build_scheme -export -f run_xctool -export -f parse_build - -main diff --git a/script/schemes.awk b/script/schemes.awk deleted file mode 100644 index 4c94df9..0000000 --- a/script/schemes.awk +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN { - FS = "\n"; -} - -/Schemes:/ { - while (getline && $0 != "") { - sub(/^ +/, ""); - print "'" $0 "'"; - } -} diff --git a/script/xctool.awk b/script/xctool.awk deleted file mode 100644 index f613258..0000000 --- a/script/xctool.awk +++ /dev/null @@ -1,25 +0,0 @@ -# Exit statuses: -# -# 0 - No errors found. -# 1 - Wrong SDK. Retry with SDK `iphonesimulator`. -# 2 - Missing target. - -BEGIN { - status = 0; -} - -{ - print; -} - -/Testing with the '(.+)' SDK is not yet supported/ { - status = 1; -} - -/does not contain a target named/ { - status = 2; -} - -END { - exit status; -} From 6362767d28fcf3375b02f5f035cc9ebb62154a18 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 24 Mar 2016 14:38:26 -0400 Subject: [PATCH 281/460] Remove script directory --- script/LICENSE.md | 18 ----- script/README.md | 82 --------------------- script/bootstrap | 47 ------------ script/cibuild | 173 --------------------------------------------- script/schemes.awk | 10 --- script/xctool.awk | 25 ------- 6 files changed, 355 deletions(-) delete mode 100644 script/LICENSE.md delete mode 100644 script/README.md delete mode 100755 script/bootstrap delete mode 100755 script/cibuild delete mode 100644 script/schemes.awk delete mode 100644 script/xctool.awk diff --git a/script/LICENSE.md b/script/LICENSE.md deleted file mode 100644 index 8d92384..0000000 --- a/script/LICENSE.md +++ /dev/null @@ -1,18 +0,0 @@ -**Copyright (c) 2013 Justin Spahr-Summers** - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/script/README.md b/script/README.md deleted file mode 100644 index f66206f..0000000 --- a/script/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# objc-build-scripts - -This project is a collection of scripts created with two goals: - - 1. To standardize how Objective-C projects are bootstrapped after cloning - 1. To easily build Objective-C projects on continuous integration servers - -## Scripts - -Right now, there are two important scripts: [`bootstrap`](#bootstrap) and -[`cibuild`](#cibuild). Both are Bash scripts, to maximize compatibility and -eliminate pesky system configuration issues (like setting up a working Ruby -environment). - -The structure of the scripts on disk is meant to follow that of a typical Ruby -project: - -``` -script/ - bootstrap - cibuild -``` - -### bootstrap - -This script is responsible for bootstrapping (initializing) your project after -it's been checked out. Here, you should install or clone any dependencies that -are required for a working build and development environment. - -By default, the script will verify that [xctool][] is installed, then initialize -and update submodules recursively. If any submodules contain `script/bootstrap`, -that will be run as well. - -To check that other tools are installed, you can set the `REQUIRED_TOOLS` -environment variable before running `script/bootstrap`, or edit it within the -script directly. Note that no installation is performed automatically, though -this can always be added within your specific project. - -### cibuild - -This script is responsible for building the project, as you would want it built -for continuous integration. This is preferable to putting the logic on the CI -server itself, since it ensures that any changes are versioned along with the -source. - -By default, the script will run [`bootstrap`](#bootstrap), look for any Xcode -workspace or project in the working directory, then build all targets/schemes -(as found by `xcodebuild -list`) using [xctool][]. - -You can also specify the schemes to build by passing them into the script: - -```sh -script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS -``` - -As with the `bootstrap` script, there are several environment variables that can -be used to customize behavior. They can be set on the command line before -invoking the script, or the defaults changed within the script directly. - -## Getting Started - -To add the scripts to your project, read the contents of this repository into -a `script` folder: - -``` -$ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git -$ git fetch objc-build-scripts -$ git read-tree --prefix=script/ -u objc-build-scripts/master -``` - -Then commit the changes, to incorporate the scripts into your own repository's -history. You can also freely tweak the scripts for your specific project's -needs. - -To merge in upstream changes later: - -``` -$ git fetch -p objc-build-scripts -$ git merge --ff --squash -Xsubtree=script objc-build-scripts/master -``` - -[xctool]: https://github.com/facebook/xctool diff --git a/script/bootstrap b/script/bootstrap deleted file mode 100755 index d61c863..0000000 --- a/script/bootstrap +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -export SCRIPT_DIR=$(dirname "$0") - -## -## Bootstrap Process -## - -main () -{ - local submodules=$(git submodule status) - local result=$? - - if [ "$result" -ne "0" ] - then - exit $result - fi - - if [ -n "$submodules" ] - then - echo "*** Updating submodules..." - update_submodules - fi -} - -bootstrap_submodule () -{ - local bootstrap="script/bootstrap" - - if [ -e "$bootstrap" ] - then - echo "*** Bootstrapping $name..." - "$bootstrap" >/dev/null - else - update_submodules - fi -} - -update_submodules () -{ - git submodule sync --quiet && git submodule update --init && git submodule foreach --quiet bootstrap_submodule -} - -export -f bootstrap_submodule -export -f update_submodules - -main diff --git a/script/cibuild b/script/cibuild deleted file mode 100755 index 33b5129..0000000 --- a/script/cibuild +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash - -export SCRIPT_DIR=$(dirname "$0") - -## -## Configuration Variables -## - -SCHEMES="$@" - -config () -{ - # The workspace to build. - # - # If not set and no workspace is found, the -workspace flag will not be passed - # to `xctool`. - # - # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will - # take precedence. - : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")} - - # The project to build. - # - # If not set and no project is found, the -project flag will not be passed - # to `xctool`. - # - # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will - # take precedence. - : ${XCODEPROJ=$(find_pattern "*.xcodeproj")} - - # A bootstrap script to run before building. - # - # If this file does not exist, it is not considered an error. - : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"} - - # Extra options to pass to xctool. - : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"} - - # A whitespace-separated list of default schemes to build. - # - # Individual names can be quoted to avoid word splitting. - : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")} - - # A whitespace-separated list of executables that must be present and locatable. - : ${REQUIRED_TOOLS="xctool"} - - export XCWORKSPACE - export XCODEPROJ - export BOOTSTRAP - export XCTOOL_OPTIONS - export SCHEMES - export REQUIRED_TOOLS -} - -## -## Build Process -## - -main () -{ - config - - if [ -n "$REQUIRED_TOOLS" ] - then - echo "*** Checking dependencies..." - check_deps - fi - - if [ -f "$BOOTSTRAP" ] - then - echo "*** Bootstrapping..." - "$BOOTSTRAP" || exit $? - fi - - echo "*** The following schemes will be built:" - echo "$SCHEMES" | xargs -n 1 echo " " - echo - - echo "$SCHEMES" | xargs -n 1 | ( - local status=0 - - while read scheme - do - build_scheme "$scheme" || status=1 - done - - exit $status - ) -} - -check_deps () -{ - for tool in $REQUIRED_TOOLS - do - which -s "$tool" - if [ "$?" -ne "0" ] - then - echo "*** Error: $tool not found. Please install it and cibuild again." - exit 1 - fi - done -} - -find_pattern () -{ - ls -d $1 2>/dev/null | head -n 1 -} - -run_xctool () -{ - if [ -n "$XCWORKSPACE" ] - then - xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 - elif [ -n "$XCODEPROJ" ] - then - xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 - else - echo "*** No workspace or project file found." - exit 1 - fi -} - -parse_build () -{ - awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null -} - -build_scheme () -{ - local scheme=$1 - - echo "*** Building and testing $scheme..." - echo - - local sdkflag= - local action=test - - # Determine whether we can run unit tests for this target. - run_xctool -scheme "$scheme" run-tests | parse_build - - local awkstatus=$? - - if [ "$awkstatus" -eq "1" ] - then - # SDK not found, try for iphonesimulator. - sdkflag="-sdk iphonesimulator" - - # Determine whether the unit tests will run with iphonesimulator - run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build - - awkstatus=$? - - if [ "$awkstatus" -ne "0" ] - then - # Unit tests will not run on iphonesimulator. - sdkflag="" - fi - fi - - if [ "$awkstatus" -ne "0" ] - then - # Unit tests aren't supported. - action=build - fi - - run_xctool $sdkflag -scheme "$scheme" $action -} - -export -f build_scheme -export -f run_xctool -export -f parse_build - -main diff --git a/script/schemes.awk b/script/schemes.awk deleted file mode 100644 index 4c94df9..0000000 --- a/script/schemes.awk +++ /dev/null @@ -1,10 +0,0 @@ -BEGIN { - FS = "\n"; -} - -/Schemes:/ { - while (getline && $0 != "") { - sub(/^ +/, ""); - print "'" $0 "'"; - } -} diff --git a/script/xctool.awk b/script/xctool.awk deleted file mode 100644 index f613258..0000000 --- a/script/xctool.awk +++ /dev/null @@ -1,25 +0,0 @@ -# Exit statuses: -# -# 0 - No errors found. -# 1 - Wrong SDK. Retry with SDK `iphonesimulator`. -# 2 - Missing target. - -BEGIN { - status = 0; -} - -{ - print; -} - -/Testing with the '(.+)' SDK is not yet supported/ { - status = 1; -} - -/does not contain a target named/ { - status = 2; -} - -END { - exit status; -} From 999ba71a024f019f267992d1c8c9015b0364bc5d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 24 Mar 2016 14:57:28 -0400 Subject: [PATCH 282/460] Pipe tests through xcpretty --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a66856..5a93f50 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,9 @@ matrix: - git submodule update --init --recursive script: - set -o pipefail - - xcodebuild test -scheme SwiftCheck - - xcodebuild test -scheme SwiftCheck-iOS -destination 'platform=iOS Simulator,name=iPad Pro' - - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' + - xcodebuild test -scheme SwiftCheck | xcpretty -c + - xcodebuild test -scheme SwiftCheck-iOS -destination 'platform=iOS Simulator,name=iPad Pro' | xcpretty -c + - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - os: linux language: generic sudo: required From a9d840544ddfa38e6f29ca1e798f7f1819c07e98 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 27 Mar 2016 14:32:24 -0400 Subject: [PATCH 283/460] Test Rose laws --- Tests/GenSpec.swift | 6 +- Tests/RoseSpec.swift | 131 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 110 insertions(+), 27 deletions(-) diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 5c7becd..ff71464 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -200,15 +200,15 @@ class GenSpec : XCTestCase { } } -private func curry(f : (A, B) -> C) -> A -> B -> C { +internal func curry(f : (A, B) -> C) -> A -> B -> C { return { a in { b in f(a, b) } } } -private func id(x : A) -> A { +internal func id(x : A) -> A { return x } -private func • (f : B -> C, g : A -> B) -> A -> C { +internal func • (f : B -> C, g : A -> B) -> A -> C { return { f(g($0)) } } diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index 987b64c..8dfd772 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -9,6 +9,113 @@ import SwiftCheck import XCTest +class RoseSpec : XCTestCase { + private static func intRoseTree(v : Int) -> Rose { + return .MkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + } + + private static func depthOneChildren(rose : Rose) -> [A] { + return rose.children.map { $0.root } + } + + private static func depthOneAndTwoChildren(rose : Rose) -> [A] { + let topChildren = rose.children + let vs = topChildren.map { $0.root } + let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) + return vs + cs + } + + func testAll() { + property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in + let tree = RoseSpec.intRoseTree(i) + return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) + } + } + + func testLaws() { + let smallArgs = CheckerArguments(maxTestCaseSize: 5) + property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (x.getRose.map(id)) == id(x.getRose) + } + + property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAll { (x : RoseTreeOf) in + return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) + } + } + + property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (Rose.pure(id) <*> x.getRose) == x.getRose + } + + property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in + return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose + } + + property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in + return (m.getRose >>- Rose.pure) == m.getRose + } + + property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in + return forAll { (m : RoseTreeOf) in + return + ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) + == + (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) + } + } + } +} + +struct RoseTreeOf : Arbitrary { + let getRose : Rose + + init(_ rose : Rose) { + self.getRose = rose + } + + static var arbitrary : Gen> { + return Gen.sized { n in + return arbTree(n) + } + } +} + +private func arbTree(n : Int) -> Gen> { + if n == 0 { + return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } + } + return Positive.arbitrary.flatMap { m in + let n2 = n / (m.getPositive + 1) + return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in + return Gen.pure(RoseTreeOf(.MkRose({ a }, { f.map { $0.getRose } }))) + } + } +} + +private func == (l : Rose, r : Rose) -> Bool { + switch (l, r) { + case let (.MkRose(l1, r1), .MkRose(l2, r2)): + return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } + case (.IORose(_), .IORose(_)): + return true + default: + return false + } +} + extension Rose { var root : A { switch self.reduce { @@ -37,27 +144,3 @@ extension Rose { return .MkRose({ self.root }, { vs + cs }) } } - -class RoseSpec : XCTestCase { - private static func intRoseTree(v : Int) -> Rose { - return .MkRose({ v }, { Int.shrink(v).map(intRoseTree) }) - } - - private static func depthOneChildren(rose : Rose) -> [A] { - return rose.children.map { $0.root } - } - - private static func depthOneAndTwoChildren(rose : Rose) -> [A] { - let topChildren = rose.children - let vs = topChildren.map { $0.root } - let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) - return vs + cs - } - - func testAll() { - property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in - let tree = RoseSpec.intRoseTree(i) - return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) - } - } -} From 80c00a79a34a41318087225c0240237dc7a5b803 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 23 Apr 2016 13:56:45 -0400 Subject: [PATCH 284/460] Fold Check operators and Test operators together This allows us to completely seal the testing driver data types. --- Sources/Check.swift | 136 --------------------------- Sources/TestOperators.swift | 133 ++++++++++++++++++++++++++ SwiftCheck.xcodeproj/project.pbxproj | 8 -- 3 files changed, 133 insertions(+), 144 deletions(-) delete mode 100644 Sources/Check.swift diff --git a/Sources/Check.swift b/Sources/Check.swift deleted file mode 100644 index 7759ff8..0000000 --- a/Sources/Check.swift +++ /dev/null @@ -1,136 +0,0 @@ -// -// Check.swift -// SwiftCheck -// -// Created by Robert Widmann on 1/19/15. -// Copyright (c) 2015 TypeLift. All rights reserved. -// - -/// The main interface for the SwiftCheck testing mechanism. `property` -/// notation is used to define a property that SwiftCheck can generate test -/// cases for and a human-readable label for debugging output. A simple -/// property test might look like the following: -/// -/// property("reflexitivity") <- forAll { (i : Int8) in -/// return i == i -/// } -/// -/// SwiftCheck will report all failures through the XCTest mechanism like a -/// normal testing assert, but with the minimal failing case reported as well. -/// -/// If necessary, arguments can be provided to this function to change the -/// behavior of the testing mechanism: -/// -/// let args = CheckerArguments -/// ( replay: Optional.Some((newStdGen(), 10)) // Replays all tests with a new generator of size 10 -/// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. -/// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. -/// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. -/// ) -/// -/// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in -/// return i == i -/// } -/// -/// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) -} - -public struct AssertiveQuickCheck { - let msg : String - let file : StaticString - let line : UInt - let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } -} - -/// The interface for properties to be run through SwiftCheck without an XCTest -/// assert. The property will still generate console output during testing. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) -} - -public struct ReportiveQuickCheck { - let msg : String - let file : StaticString - let line : UInt - let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } -} - -/// Represents the arguments the test driver will use while performing testing, -/// shrinking, and printing results. -public struct CheckerArguments { - /// Provides a way of re-doing a test at the given size with a new generator. - let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself - /// passes. - /// - /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` - /// on the property instead. - let maxAllowableSuccessfulTests : Int - /// The maximum number of tests cases that can be discarded before testing gives up on the - /// property. - /// - /// The default value of this property is 500. In general, most tests will require less than - /// this amount. `Discard`ed test cases do not affect the passing or failing status of the - /// property as a whole. - let maxAllowableDiscardedTests : Int - /// The limit to the size of all generators in the test. - /// - /// The default value of this property is 100. If "large" values, in magnitude or - /// size, are necessary then increase this value, else keep it relatively near the default. If - /// it becomes too small the samples present in the test case will lose diversity. - let maxTestCaseSize : Int - - internal let silence : Bool - - public init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - ) - { - self = CheckerArguments( replay: replay - , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: maxAllowableDiscardedTests - , maxTestCaseSize: maxTestCaseSize - , name: "" - ) - } - - internal init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - , name : String - , silence : Bool = false - ) - { - - self.replay = replay - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.maxTestCaseSize = maxTestCaseSize - self.name = name - self.silence = silence - } - - internal var name : String -} diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index 3badaa9..3ac419c 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -6,6 +6,139 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +/// The main interface for the SwiftCheck testing mechanism. `property` +/// notation is used to define a property that SwiftCheck can generate test +/// cases for and a human-readable label for debugging output. A simple +/// property test might look like the following: +/// +/// property("reflexitivity") <- forAll { (i : Int8) in +/// return i == i +/// } +/// +/// SwiftCheck will report all failures through the XCTest mechanism like a +/// normal testing assert, but with the minimal failing case reported as well. +/// +/// If necessary, arguments can be provided to this function to change the +/// behavior of the testing mechanism: +/// +/// let args = CheckerArguments +/// ( replay: Optional.Some((newStdGen(), 10)) // Replays all tests with a new generator of size 10 +/// , maxAllowableSuccessfulTests: 200 // Requires twice the normal amount of successes to pass. +/// , maxAllowableDiscardedTests: 0 // Discards are not allowed anymore. +/// , maxTestCaseSize: 1000 // Increase the size of tested values by 10x. +/// ) +/// +/// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in +/// return i == i +/// } +/// +/// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. +@warn_unused_result(message="Did you forget to bind this property to a quantifier?") +public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) +} + +/// Describes a checker that uses XCTest to assert all testing failures and +/// display them in both the testing log and Xcode. +public struct AssertiveQuickCheck { + private let msg : String + private let file : StaticString + private let line : UInt + private let args : CheckerArguments + + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } +} + +/// The interface for properties to be run through SwiftCheck without an XCTest +/// assert. The property will still generate console output during testing. +@warn_unused_result(message="Did you forget to bind this property to a quantifier?") +public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) +} + +/// Describes a checker that only reports failures to the testing log but does +/// not assert when a property fails. +public struct ReportiveQuickCheck { + private let msg : String + private let file : StaticString + private let line : UInt + private let args : CheckerArguments + + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } +} + +/// Represents the arguments the test driver will use while performing testing, +/// shrinking, and printing results. +public struct CheckerArguments { + /// Provides a way of re-doing a test at the given size with a new generator. + let replay : Optional<(StdGen, Int)> + /// The maximum number of test cases that must pass before the property itself + /// passes. + /// + /// The default value of this property is 100. In general, some tests may require more than + /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// on the property instead. + let maxAllowableSuccessfulTests : Int + /// The maximum number of tests cases that can be discarded before testing gives up on the + /// property. + /// + /// The default value of this property is 500. In general, most tests will require less than + /// this amount. `Discard`ed test cases do not affect the passing or failing status of the + /// property as a whole. + let maxAllowableDiscardedTests : Int + /// The limit to the size of all generators in the test. + /// + /// The default value of this property is 100. If "large" values, in magnitude or + /// size, are necessary then increase this value, else keep it relatively near the default. If + /// it becomes too small the samples present in the test case will lose diversity. + let maxTestCaseSize : Int + + internal let silence : Bool + + public init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + ) + { + self = CheckerArguments( replay: replay + , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: maxAllowableDiscardedTests + , maxTestCaseSize: maxTestCaseSize + , name: "" + ) + } + + internal init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + , name : String + , silence : Bool = false + ) + { + + self.replay = replay + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.maxTestCaseSize = maxTestCaseSize + self.name = name + self.silence = silence + } + + internal var name : String +} + infix operator <- {} /// Binds a Testable value to a property. diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index fe1fda9..8c06984 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -12,9 +12,6 @@ 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D815B1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; - 826D815C1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; - 826D815D1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; 826D81601C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; @@ -158,7 +155,6 @@ 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81471C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; @@ -272,7 +268,6 @@ isa = PBXGroup; children = ( 826D81461C953D070022266C /* Arbitrary.swift */, - 826D81471C953D070022266C /* Check.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 826D81491C953D070022266C /* Gen.swift */, 826D814B1C953D070022266C /* Lattice.swift */, @@ -585,7 +580,6 @@ 826D81871C953D070022266C /* TestOperators.swift in Sources */, 826D81781C953D070022266C /* Rose.swift in Sources */, 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, - 826D815D1C953D070022266C /* Check.swift in Sources */, 826D81631C953D070022266C /* Gen.swift in Sources */, 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, 826D817B1C953D070022266C /* State.swift in Sources */, @@ -629,7 +623,6 @@ 826D81851C953D070022266C /* TestOperators.swift in Sources */, 826D81761C953D070022266C /* Rose.swift in Sources */, 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D815B1C953D070022266C /* Check.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, 826D81791C953D070022266C /* State.swift in Sources */, @@ -673,7 +666,6 @@ 826D81861C953D070022266C /* TestOperators.swift in Sources */, 826D81771C953D070022266C /* Rose.swift in Sources */, 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D815C1C953D070022266C /* Check.swift in Sources */, 826D81621C953D070022266C /* Gen.swift in Sources */, 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, 826D817A1C953D070022266C /* State.swift in Sources */, From cfc97afa3c185a360712a61ab2e52cb9e19efc70 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 23 Apr 2016 13:57:28 -0400 Subject: [PATCH 285/460] Round out documentation of the framework --- Sources/Gen.swift | 4 +- Sources/Lattice.swift | 12 ++++++ Sources/Property.swift | 43 +++++++++++++-------- Sources/Random.swift | 3 ++ Sources/Rose.swift | 5 +++ Sources/State.swift | 4 +- Sources/Test.swift | 8 ++-- Sources/Testable.swift | 13 +++++++ Sources/Witness.swift | 52 ++++++++++++++++++++++++++ Sources/WitnessedArbitrary.swift | 64 +++++++++++++++++++++++++++----- 10 files changed, 175 insertions(+), 33 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 6a9acad..16516b0 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -303,8 +303,8 @@ extension Gen /*: Monad*/ { } } -/// Applies the function to any generated values to yield a new generator. This -/// generator is then given a new random seed and returned. +/// Flat Map | Applies the function to any generated values to yield a new +/// generator. This generator is then given a new random seed and returned. /// /// `flatMap` allows for the creation of Generators that depend on other /// generators. One might, for example, use a Generator of integers to control diff --git a/Sources/Lattice.swift b/Sources/Lattice.swift index 5ffc7de..2d568de 100644 --- a/Sources/Lattice.swift +++ b/Sources/Lattice.swift @@ -20,20 +20,24 @@ public protocol LatticeType { } extension Bool : LatticeType { + /// The lower limit of the `Bool` type. public static var min : Bool { return false } + /// The upper limit of the `Bool` type. public static var max : Bool { return true } } extension Character : LatticeType { + /// The lower limit of the `Character` type. public static var min : Character { return "\0" } + /// The upper limit of the `Character` type. public static var max : Character { return "\u{FFFFF}" } @@ -51,40 +55,48 @@ extension Int32 : LatticeType {} extension Int64 : LatticeType {} extension Float : LatticeType { + /// The lower limit of the `Float` type. public static var min : Float { return FLT_MIN } + /// The upper limit of the `Float` type. public static var max : Float { return FLT_MAX } } extension Double : LatticeType { + /// The lower limit of the `Double` type. public static var min : Double { return DBL_MIN } + /// The upper limit of the `Double` type. public static var max : Double { return DBL_MAX } } extension AnyForwardIndex : LatticeType { + /// The lower limit of the `AnyForwardIndex` type. public static var min : AnyForwardIndex { return AnyForwardIndex(Int64.min) } + /// The upper limit of the `AnyForwardIndex` type. public static var max : AnyForwardIndex { return AnyForwardIndex(Int64.max) } } extension AnyRandomAccessIndex : LatticeType { + /// The lower limit of the `AnyRandomAccessIndex` type. public static var min : AnyRandomAccessIndex { return AnyRandomAccessIndex(Int64.min) } + /// The upper limit of the `AnyRandomAccessIndex` type. public static var max : AnyRandomAccessIndex { return AnyRandomAccessIndex(Int64.max) } diff --git a/Sources/Property.swift b/Sources/Property.swift index ae265af..2604604 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -314,19 +314,6 @@ public enum CallbackKind { case NotCounterexample } -public enum TestResultMatcher { - case MatchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification - ) -} - /// The types of quantification SwiftCheck can perform. public enum Quantification { /// Universal Quantification ("for all"). @@ -358,16 +345,42 @@ public struct TestResult { let callbacks : [Callback] /// Indicates that any further testing of the property should cease. let abort : Bool - + /// The quantifier being applied to this test case. let quantifier : Quantification + /// Provides a pattern-match-friendly view of the current state of a test + /// result. + public enum TestResultMatcher { + /// A case-able view of the current state of a test result. + case MatchResult( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : Array + , abort : Bool + , quantifier : Quantification + ) + } + /// Destructures a test case into a matcher that can be used in switch /// statement. public var match : TestResultMatcher { return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } - public init(ok : Optional, expect : Bool, reason : String, theException : Optional, labels : Dictionary, stamp : Set, callbacks : [Callback], abort : Bool, quantifier : Quantification) { + /// + public init( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : [Callback] + , abort : Bool + , quantifier : Quantification) + { self.ok = ok self.expect = expect self.reason = reason diff --git a/Sources/Random.swift b/Sources/Random.swift index 33a105c..04bf379 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -88,6 +88,9 @@ extension StdGen : Equatable, CustomStringConvertible { } } +/// Equality over random number generators. +/// +/// Two `StdGen`s are equal iff their seeds match. public func == (l : StdGen, r : StdGen) -> Bool { return l.seed1 == r.seed1 && l.seed2 == r.seed2 } diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 4b73839..6cc9544 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -54,6 +54,7 @@ extension Rose /*: Functor*/ { } } +/// Fmap | Maps a function over all the nodes of a Rose Tree. public func <^> (f : A -> B, g : Rose) -> Rose { switch g { case .MkRose(let root, let children): @@ -81,6 +82,8 @@ extension Rose /*: Applicative*/ { } } +/// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose +/// Tree of values. public func <*> (fn : Rose B>, g : Rose) -> Rose { switch fn { case .MkRose(let f, _): @@ -98,6 +101,8 @@ extension Rose /*: Monad*/ { } } +/// Flat Map | Maps the values in the receiver to Rose Trees and joins them all +/// together. public func >>- (m : Rose, fn : A -> Rose) -> Rose { return joinRose(m.map(fn)) } diff --git a/Sources/State.swift b/Sources/State.swift index d9d29b1..6539c55 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -47,9 +47,9 @@ public struct CheckerState { let failedShrinkStepCount : Int /// Returns whether the testing system should cease testing altogether. let shouldAbort : Bool - + /// The quantifier being applied to this test case. let quantifier : Quantification - + /// The arguments currently being applied to the testing driver. let arguments : CheckerArguments let silence : Bool diff --git a/Sources/Test.swift b/Sources/Test.swift index 1b7457e..299ea0b 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -779,11 +779,11 @@ private func labelPercentage(l : String, st : CheckerState) -> Int { return (100 * occur.count) / st.maxAllowableSuccessfulTests } -private func showP(n : Int) -> String { - return (n < 10 ? " " : "") + "\(n)" + "%" -} - private func printDistributionGraph(st : CheckerState) { + func showP(n : Int) -> String { + return (n < 10 ? " " : "") + "\(n)" + "%" + } + let gAllLabels : [String] = st.collected.map({ (s : Set) in return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) }) diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 4fa3a9b..46acad1 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -28,6 +28,7 @@ public protocol Testable { } extension Testable { + /// By default, all `Testable` types are non-exhaustive. public var exhaustive : Bool { return false } @@ -41,6 +42,7 @@ public struct Property : Testable { self.unProperty = val } + /// Yields self. public var property : Property { return self } @@ -56,8 +58,11 @@ public struct Property : Testable { public struct Prop : Testable { var unProp : Rose + /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive + /// property tests. public var exhaustive : Bool { return true } + /// Returns a property that tests the receiver. public var property : Property { // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) @@ -66,26 +71,34 @@ public struct Prop : Testable { /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { + /// `Discard`s are trivially exhaustive. public var exhaustive : Bool { return true } + /// Create a `Discard` suitable for public init() { } + /// Returns a property that always rejects whatever result occurs. public var property : Property { return TestResult.rejected.property } } extension TestResult : Testable { + /// `TestResult`s are trivially exhaustive. public var exhaustive : Bool { return true } + /// Returns a property that tests the receiver. public var property : Property { return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) } } extension Bool : Testable { + /// `Bool`ean values are trivially exhaustive. public var exhaustive : Bool { return true } + /// Returns a property that evaluates to a test success if the receiver is + /// `true`, else returns a property that evaluates to a test failure. public var property : Property { return TestResult.liftBool(self).property } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index 5918ae6..bb54ac0 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -6,9 +6,61 @@ // Copyright © 2015 TypeLift. All rights reserved. // +/// Provides a way for higher-order types to implement the `Arbitrary` protocol. +/// +/// The `WitnessedArbitrary` protocol is a *HACK*, but a very necessary one. +/// Because Swift does not have Higher Kinded Types, but we need to know that, +/// say, the `Element`s underlying an `Array` are all `Arbitrary`, we +/// instead ask the conformee to hand over information about the type parameter +/// it wishes to guarantee is `Arbitrary` then SwiftCheck will synthesize a +/// function to act as a Witness that the parameter is in fact `Arbitrary`. +/// SwiftCheck presents a stronger but less general version of `forAll` that +/// must be implemented by the conformee to guarantee a type-safe interface with +/// the rest of the framework. +/// +/// Implementating the `WitnessedArbitrary` protocol functions much like +/// implementing the `Arbitrary` protocol, but with a little extra baggage. For +/// example, to implement the protocol for `Array`, we declare the usual +/// `arbitrary` and `shrink`: +/// +/// extension Array where Element : Arbitrary { +/// public static var arbitrary : Gen> { +/// return Gen.sized { n in +/// return Gen.choose((0, n)).flatMap { k in +/// if k == 0 { +/// return Gen.pure([]) +/// } +/// +/// return sequence((0...k).map { _ in Element.arbitrary }) +/// } +/// } +/// } +/// +/// public static func shrink(bl : Array) -> [[Element]] { +/// let rec : [[Element]] = shrinkOne(bl) +/// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec +/// } +/// } +/// +/// In addition, we declare a witnessed version of `forAll` that simply invokes +/// `forAllShrink` and `map`s the witness function to make sure all generated +/// `Array`s are made of `Arbitrary ` elements: +/// +/// extension Array : WitnessedArbitrary { +/// public typealias Param = Element +/// +/// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { +/// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in +/// return pf(bl.map(wit)) +/// }) +/// } +/// } public protocol WitnessedArbitrary { + /// The witnessing type parameter. associatedtype Param + /// A property test that relies on a witness that the given type parameter + /// is actually `Arbitrary`. static func forAllWitnessed(wit : A -> Param, pf : (Self -> Testable)) -> Property } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 33696c7..8c5757d 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -7,6 +7,7 @@ // extension Array where Element : Arbitrary { + /// Returns a generator of `Array`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).flatMap { k in @@ -19,6 +20,7 @@ extension Array where Element : Arbitrary { } } + /// The default shrinking function for `Array`s of arbitrary `Element`s. public static func shrink(bl : Array) -> [[Element]] { let rec : [[Element]] = shrinkOne(bl) return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec @@ -28,6 +30,8 @@ extension Array where Element : Arbitrary { extension Array : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Array`s. public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) @@ -36,10 +40,12 @@ extension Array : WitnessedArbitrary { } extension AnyBidirectionalCollection where Element : Arbitrary { + /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. public static var arbitrary : Gen> { return AnyBidirectionalCollection.init <^> [Element].arbitrary } + /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } @@ -48,6 +54,8 @@ extension AnyBidirectionalCollection where Element : Arbitrary { extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnyBidirectionalCollection`s. public static func forAllWitnessed(wit : A -> Element, pf : (AnyBidirectionalCollection -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) @@ -56,10 +64,12 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { } extension AnySequence where Element : Arbitrary { + /// Returns a generator of `AnySequence`s of arbitrary `Element`s. public static var arbitrary : Gen> { return AnySequence.init <^> [Element].arbitrary } + /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. public static func shrink(bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } @@ -68,6 +78,8 @@ extension AnySequence where Element : Arbitrary { extension AnySequence : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnySequence`s. public static func forAllWitnessed(wit : A -> Element, pf : (AnySequence -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) @@ -76,10 +88,12 @@ extension AnySequence : WitnessedArbitrary { } extension ArraySlice where Element : Arbitrary { + /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. public static var arbitrary : Gen> { return ArraySlice.init <^> [Element].arbitrary } + /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. public static func shrink(bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } @@ -88,6 +102,8 @@ extension ArraySlice where Element : Arbitrary { extension ArraySlice : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ArraySlice`s. public static func forAllWitnessed(wit : A -> Element, pf : (ArraySlice -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) @@ -96,6 +112,7 @@ extension ArraySlice : WitnessedArbitrary { } extension CollectionOfOne where Element : Arbitrary { + /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. public static var arbitrary : Gen> { return CollectionOfOne.init <^> Element.arbitrary } @@ -104,6 +121,8 @@ extension CollectionOfOne where Element : Arbitrary { extension CollectionOfOne : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `CollectionOfOne`s. public static func forAllWitnessed(wit : A -> Element, pf : (CollectionOfOne -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[.Zero]))) @@ -113,6 +132,7 @@ extension CollectionOfOne : WitnessedArbitrary { /// Generates an Optional of arbitrary values of type A. extension Optional where Wrapped : Arbitrary { + /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. public static var arbitrary : Gen> { return Gen>.frequency([ (1, Gen>.pure(.None)), @@ -120,6 +140,7 @@ extension Optional where Wrapped : Arbitrary { ]) } + /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. public static func shrink(bl : Optional) -> [Optional] { if let x = bl { let rec : [Optional] = Wrapped.shrink(x).map(Optional.Some) @@ -132,6 +153,8 @@ extension Optional where Wrapped : Arbitrary { extension Optional : WitnessedArbitrary { public typealias Param = Wrapped + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Optional`s. public static func forAllWitnessed(wit : A -> Wrapped, pf : (Optional -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) @@ -140,10 +163,12 @@ extension Optional : WitnessedArbitrary { } extension ContiguousArray where Element : Arbitrary { + /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. public static var arbitrary : Gen> { return ContiguousArray.init <^> [Element].arbitrary } + /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } @@ -152,6 +177,8 @@ extension ContiguousArray where Element : Arbitrary { extension ContiguousArray : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ContiguousArray`s. public static func forAllWitnessed(wit : A -> Element, pf : (ContiguousArray -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) @@ -161,6 +188,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { + /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. public static var arbitrary : Gen> { return [Key].arbitrary.flatMap { k in return [Value].arbitrary.flatMap { v in @@ -169,28 +197,22 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } + /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and + /// `Value`s. public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } } -extension Dictionary { - init(_ pairs : S) { - self.init() - var g = pairs.generate() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } -} - extension EmptyCollection : Arbitrary { + /// Returns a generator of `EmptyCollection`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.pure(EmptyCollection()) } } extension HalfOpenInterval where Bound : protocol { + /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in return Bound.arbitrary.flatMap { r in @@ -199,24 +221,28 @@ extension HalfOpenInterval where Bound : protocol { } } + /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) } } extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { + /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } extension LazySequence where Base : protocol { + /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary } } extension Range where Element : protocol { + /// Returns a generator of `Range`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Element.arbitrary.flatMap { l in return Element.arbitrary.flatMap { r in @@ -225,12 +251,14 @@ extension Range where Element : protocol) -> [Range] { return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(..<) } } extension Repeat where Element : Arbitrary { + /// Returns a generator of `Repeat`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) } @@ -239,6 +267,8 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Repeat`s. public static func forAllWitnessed(wit : A -> Element, pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) @@ -248,6 +278,7 @@ extension Repeat : WitnessedArbitrary { } extension Set where Element : protocol { + /// Returns a generator of `Set`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).flatMap { k in @@ -260,6 +291,7 @@ extension Set where Element : protocol { } } + /// The default shrinking function for `Set`s of arbitrary `Element`s. public static func shrink(s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } @@ -268,6 +300,8 @@ extension Set where Element : protocol { extension Set : WitnessedArbitrary { public typealias Param = Element + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Set`s. public static func forAllWitnessed(wit : A -> Element, pf : (Set -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) @@ -319,3 +353,13 @@ private func shrinkOne(xs : [A]) -> [[A]] { } fatalError("Array could not produce a first element") } + +extension Dictionary { + init(_ pairs : S) { + self.init() + var g = pairs.generate() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } +} From c4d3edb97a481830b91969fc0ad1e454ecbb3f97 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 23 Apr 2016 14:08:44 -0400 Subject: [PATCH 286/460] Document the modifiers --- Sources/Modifiers.swift | 24 ++++++++++++++++++++++++ Sources/WitnessedArbitrary.swift | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index cdf109e..c897c29 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -66,10 +66,12 @@ public struct Blind : Arbitrary, CustomStringConvertible { return "(*)" } + /// Returns a generator of `Blind` values. public static var arbitrary : Gen> { return Blind.init <^> A.arbitrary } + /// The default shrinking function for `Blind` values. public static func shrink(bl : Blind) -> [Blind] { return A.shrink(bl.getBlind).map(Blind.init) } @@ -96,6 +98,7 @@ public struct Static : Arbitrary, CustomStringConvertible { return "Static( \(self.getStatic) )" } + /// Returns a generator of `Static` values. public static var arbitrary : Gen> { return Static.init <^> A.arbitrary } @@ -127,10 +130,12 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { return "\(self.getArray)" } + /// Returns a generator of `ArrayOf` values. public static var arbitrary : Gen> { return ArrayOf.init <^> Array.arbitrary } + /// The default shrinking function for an `ArrayOf` values. public static func shrink(bl : ArrayOf) -> [ArrayOf] { return Array.shrink(bl.getArray).map(ArrayOf.init) } @@ -166,10 +171,12 @@ public struct OrderedArrayOf> : Arbitrary, C return "\(self.getOrderedArray)" } + /// Returns a generator for an `OrderedArrayOf` values. public static var arbitrary : Gen> { return OrderedArrayOf.init <^> Array.arbitrary } + /// The default shrinking function for an `OrderedArrayOf` values. public static func shrink(bl : OrderedArrayOf) -> [OrderedArrayOf] { return Array.shrink(bl.getOrderedArray).filter({ $0.sort() == $0 }).map(OrderedArrayOf.init) } @@ -190,10 +197,12 @@ public struct DictionaryOf, V : Arbitrary> : A return "\(self.getDictionary)" } + /// Returns a generator for a `DictionaryOf` values. public static var arbitrary : Gen> { return DictionaryOf.init <^> Dictionary.arbitrary } + /// The default shrinking function for a `DictionaryOf` values. public static func shrink(d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } @@ -219,10 +228,12 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { return "\(self.getOptional)" } + /// Returns a generator for `OptionalOf` values. public static var arbitrary : Gen> { return OptionalOf.init <^> Optional.arbitrary } + /// The default shrinking function for `OptionalOf` values. public static func shrink(bl : OptionalOf) -> [OptionalOf] { return Optional.shrink(bl.getOptional).map(OptionalOf.init) } @@ -251,6 +262,7 @@ public struct SetOf> : Arbitrary, CustomString return "\(self.getSet)" } + /// Returns a generator for a `SetOf` values. public static var arbitrary : Gen> { return Gen.sized { n in return Gen.choose((0, n)).flatMap { k in @@ -263,6 +275,7 @@ public struct SetOf> : Arbitrary, CustomString } } + /// The default shrinking function for a `SetOf` values. public static func shrink(s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } @@ -295,6 +308,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { return self._impl.description } + /// Returns a generator for a `PointerOf` values. public static var arbitrary : Gen> { return PointerOfImpl.arbitrary.map(PointerOf.init) } @@ -314,6 +328,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi return self._impl.description } + /// Returns a generator for an `ArrowOf` function values. public static var arbitrary : Gen> { return ArrowOfImpl.arbitrary.map(ArrowOf.init) } @@ -347,6 +362,7 @@ public struct IsoOf, U : protocol return self._impl.description } + /// Returns a generator for an `IsoOf` function values. public static var arbitrary : Gen> { return IsoOfImpl.arbitrary.map(IsoOf.init) } @@ -377,10 +393,12 @@ public struct Large> : Arbitr return "Large( \(self.getLarge) )" } + /// Returns a generator of `Large` values. public static var arbitrary : Gen> { return Gen.choose((A.min, A.max)).map(Large.init) } + /// The default shrinking function for `Large` values. public static func shrink(bl : Large) -> [Large] { return bl.getLarge.shrinkIntegral.map(Large.init) } @@ -400,10 +418,12 @@ public struct Positive> : Arbitrary, C return "Positive( \(self.getPositive) )" } + /// Returns a generator of `Positive` values. public static var arbitrary : Gen> { return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } } + /// The default shrinking function for `Positive` values. public static func shrink(bl : Positive) -> [Positive] { return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) } @@ -430,10 +450,12 @@ public struct NonZero> : Arbitrary, CustomS return "NonZero( \(self.getNonZero) )" } + /// Returns a generator of `NonZero` values. public static var arbitrary : Gen> { return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } } + /// The default shrinking function for `NonZero` values. public static func shrink(bl : NonZero) -> [NonZero] { return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) } @@ -459,10 +481,12 @@ public struct NonNegative> : Arbitrary, Cus return "NonNegative( \(self.getNonNegative) )" } + /// Returns a generator of `NonNegative` values. public static var arbitrary : Gen> { return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } } + /// The default shrinking function for `NonNegative` values. public static func shrink(bl : NonNegative) -> [NonNegative] { return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 8c5757d..6ef45b0 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -355,7 +355,7 @@ private func shrinkOne(xs : [A]) -> [[A]] { } extension Dictionary { - init(_ pairs : S) { + private init(_ pairs : S) { self.init() var g = pairs.generate() while let (k, v): (Key, Value) = g.next() { From 678a5760e80c10417b4e6d5e8d1e96f32ae59945 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 23 Apr 2016 14:27:22 -0400 Subject: [PATCH 287/460] Code golfing --- Sources/Test.swift | 78 +++++++++++++++++------------------------- Tests/LambdaSpec.swift | 2 +- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Sources/Test.swift b/Sources/Test.swift index 299ea0b..593b522 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -399,7 +399,7 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R , labels: [:] , collected: [] , hasFulfilledExpectedFailure: false - , randomSeedGenerator: chooseReplayRNG(args) + , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() , successfulShrinkCount: 0 , failedShrinkStepDistance: 0 , failedShrinkStepCount: 0 @@ -812,12 +812,6 @@ private func printDistributionGraph(st : CheckerState) { } } -private func cons(lhs : T, _ rhs : [T]) -> [T] { - var res = rhs - res.insert(lhs, atIndex: 0) - return res -} - private func pluralize(s : String, i : Int) -> String { if i == 1 { return s @@ -839,27 +833,24 @@ private func printCond(cond : Bool, _ str : String, terminator : String = "\n") extension Array { private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { - func span(list : [Element], p : (Element -> Bool)) -> ([Element], [Element]) { - if list.isEmpty { - return ([], []) - } else if let x = list.first { - if p (x) { - let (ys, zs) = span([Element](list[1.. Int { func computeSize_(successes : Int, _ discards : Int) -> Int { + func roundTo(n : Int, _ m : Int) -> Int { + return (n / m) * m + } + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) } else if successes >= args.maxAllowableSuccessfulTests { @@ -878,6 +873,15 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca } } + func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + if successes == 0 && discards == 0 { + return defaultSize + } else { + return computeSize(successes, discards) + } + } + + if let (_, argSize) = args.replay { return initialSizeForTest( argSize , successes: vals.successes @@ -888,21 +892,3 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca return computeSize_(vals.successes, vals.discards) } -private func roundTo(n : Int, _ m : Int) -> Int { - return (n / m) * m -} - -private func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { - if successes == 0 && discards == 0 { - return defaultSize - } else { - return computeSize(successes, discards) - } -} - -private func chooseReplayRNG(args : CheckerArguments) -> StdGen { - if let (rng, _) = args.replay { - return rng - } - return newStdGen() -} diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index 46f3a92..c337991 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -78,7 +78,7 @@ extension Exp : Arbitrary { case let .Lam(x, a): return [a] + Exp.shrink(a).map { .Lam(x, $0) } case let .App(a, b): - let part1 : [Exp] = [a, b] + let part1 : [Exp] = [a, b] + [a].flatMap({ (expr : Exp) -> Exp? in if case let .Lam(x, a) = expr { return a.subst(x, b) From bacb1264bc9589bf76552b644cf434e52e3b30f0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 23 Apr 2016 15:04:26 -0400 Subject: [PATCH 288/460] Fix indentation --- Sources/Modifiers.swift | 10 +- Sources/Property.swift | 3 +- Sources/State.swift | 2 +- Sources/Test.swift | 62 ++++++------ Sources/TestOperators.swift | 162 +++++++++++++++---------------- Sources/WitnessedArbitrary.swift | 58 +++++------ 6 files changed, 149 insertions(+), 148 deletions(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index c897c29..7da727a 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -197,12 +197,12 @@ public struct DictionaryOf, V : Arbitrary> : A return "\(self.getDictionary)" } - /// Returns a generator for a `DictionaryOf` values. + /// Returns a generator for a `DictionaryOf` values. public static var arbitrary : Gen> { return DictionaryOf.init <^> Dictionary.arbitrary } - /// The default shrinking function for a `DictionaryOf` values. + /// The default shrinking function for a `DictionaryOf` values. public static func shrink(d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } @@ -275,7 +275,7 @@ public struct SetOf> : Arbitrary, CustomString } } - /// The default shrinking function for a `SetOf` values. + /// The default shrinking function for a `SetOf` values. public static func shrink(s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } @@ -328,7 +328,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi return self._impl.description } - /// Returns a generator for an `ArrowOf` function values. + /// Returns a generator for an `ArrowOf` function values. public static var arbitrary : Gen> { return ArrowOfImpl.arbitrary.map(ArrowOf.init) } @@ -362,7 +362,7 @@ public struct IsoOf, U : protocol return self._impl.description } - /// Returns a generator for an `IsoOf` function values. + /// Returns a generator for an `IsoOf` function values. public static var arbitrary : Gen> { return IsoOfImpl.arbitrary.map(IsoOf.init) } diff --git a/Sources/Property.swift b/Sources/Property.swift index 2604604..77d797d 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -370,7 +370,8 @@ public struct TestResult { return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } - /// + /// Creates and returns a new test result initialized with the given + /// parameters. public init( ok : Optional , expect : Bool , reason : String diff --git a/Sources/State.swift b/Sources/State.swift index 6539c55..847ca3c 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -49,7 +49,7 @@ public struct CheckerState { let shouldAbort : Bool /// The quantifier being applied to this test case. let quantifier : Quantification - /// The arguments currently being applied to the testing driver. + /// The arguments currently being applied to the testing driver. let arguments : CheckerArguments let silence : Bool diff --git a/Sources/Test.swift b/Sources/Test.swift index 593b522..2ebf8ae 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -399,7 +399,7 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R , labels: [:] , collected: [] , hasFulfilledExpectedFailure: false - , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() + , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() , successfulShrinkCount: 0 , failedShrinkStepDistance: 0 , failedShrinkStepCount: 0 @@ -833,24 +833,24 @@ private func printCond(cond : Bool, _ str : String, terminator : String = "\n") extension Array { private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { - var result = [[Element]]() - var accumulator = [Element]() - self.forEach { current in - if let prev = accumulator.last { - if p(prev, current) { - accumulator.append(current) - } else { - result.append(accumulator) - accumulator = [ current ] - } - } else { - return accumulator.append(current) - } - } - if !accumulator.isEmpty { - result.append(accumulator); - } - return result + var result = [[Element]]() + var accumulator = [Element]() + self.forEach { current in + if let prev = accumulator.last { + if p(prev, current) { + accumulator.append(current) + } else { + result.append(accumulator) + accumulator = [ current ] + } + } else { + return accumulator.append(current) + } + } + if !accumulator.isEmpty { + result.append(accumulator); + } + return result } } @@ -858,10 +858,10 @@ extension Array { private func computeSize(args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { func computeSize_(successes : Int, _ discards : Int) -> Int { - func roundTo(n : Int, _ m : Int) -> Int { - return (n / m) * m - } - + func roundTo(n : Int, _ m : Int) -> Int { + return (n / m) * m + } + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) } else if successes >= args.maxAllowableSuccessfulTests { @@ -873,15 +873,15 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca } } - func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { - if successes == 0 && discards == 0 { - return defaultSize - } else { - return computeSize(successes, discards) - } - } + func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + if successes == 0 && discards == 0 { + return defaultSize + } else { + return computeSize(successes, discards) + } + } - + if let (_, argSize) = args.replay { return initialSizeForTest( argSize , successes: vals.successes diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index 3ac419c..ff6805a 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -35,108 +35,108 @@ /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that uses XCTest to assert all testing failures and /// display them in both the testing log and Xcode. public struct AssertiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + private let msg : String + private let file : StaticString + private let line : UInt + private let args : CheckerArguments + + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. @warn_unused_result(message="Did you forget to bind this property to a quantifier?") public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that only reports failures to the testing log but does /// not assert when a property fails. public struct ReportiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + private let msg : String + private let file : StaticString + private let line : UInt + private let args : CheckerArguments + + private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } /// Represents the arguments the test driver will use while performing testing, /// shrinking, and printing results. public struct CheckerArguments { - /// Provides a way of re-doing a test at the given size with a new generator. - let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself - /// passes. - /// - /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` - /// on the property instead. - let maxAllowableSuccessfulTests : Int - /// The maximum number of tests cases that can be discarded before testing gives up on the - /// property. - /// - /// The default value of this property is 500. In general, most tests will require less than - /// this amount. `Discard`ed test cases do not affect the passing or failing status of the - /// property as a whole. - let maxAllowableDiscardedTests : Int - /// The limit to the size of all generators in the test. - /// - /// The default value of this property is 100. If "large" values, in magnitude or - /// size, are necessary then increase this value, else keep it relatively near the default. If - /// it becomes too small the samples present in the test case will lose diversity. - let maxTestCaseSize : Int - - internal let silence : Bool - - public init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - ) - { - self = CheckerArguments( replay: replay - , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: maxAllowableDiscardedTests - , maxTestCaseSize: maxTestCaseSize - , name: "" - ) - } - - internal init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - , name : String - , silence : Bool = false - ) - { - - self.replay = replay - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.maxTestCaseSize = maxTestCaseSize - self.name = name - self.silence = silence - } - - internal var name : String + /// Provides a way of re-doing a test at the given size with a new generator. + let replay : Optional<(StdGen, Int)> + /// The maximum number of test cases that must pass before the property itself + /// passes. + /// + /// The default value of this property is 100. In general, some tests may require more than + /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// on the property instead. + let maxAllowableSuccessfulTests : Int + /// The maximum number of tests cases that can be discarded before testing gives up on the + /// property. + /// + /// The default value of this property is 500. In general, most tests will require less than + /// this amount. `Discard`ed test cases do not affect the passing or failing status of the + /// property as a whole. + let maxAllowableDiscardedTests : Int + /// The limit to the size of all generators in the test. + /// + /// The default value of this property is 100. If "large" values, in magnitude or + /// size, are necessary then increase this value, else keep it relatively near the default. If + /// it becomes too small the samples present in the test case will lose diversity. + let maxTestCaseSize : Int + + internal let silence : Bool + + public init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + ) + { + self = CheckerArguments( replay: replay + , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: maxAllowableDiscardedTests + , maxTestCaseSize: maxTestCaseSize + , name: "" + ) + } + + internal init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + , name : String + , silence : Bool = false + ) + { + + self.replay = replay + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.maxTestCaseSize = maxTestCaseSize + self.name = name + self.silence = silence + } + + internal var name : String } infix operator <- {} diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 6ef45b0..e28b1a5 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -30,8 +30,8 @@ extension Array where Element : Arbitrary { extension Array : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Array`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Array`s. public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) @@ -54,8 +54,8 @@ extension AnyBidirectionalCollection where Element : Arbitrary { extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnyBidirectionalCollection`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnyBidirectionalCollection`s. public static func forAllWitnessed(wit : A -> Element, pf : (AnyBidirectionalCollection -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) @@ -78,8 +78,8 @@ extension AnySequence where Element : Arbitrary { extension AnySequence : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnySequence`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnySequence`s. public static func forAllWitnessed(wit : A -> Element, pf : (AnySequence -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) @@ -102,8 +102,8 @@ extension ArraySlice where Element : Arbitrary { extension ArraySlice : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ArraySlice`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ArraySlice`s. public static func forAllWitnessed(wit : A -> Element, pf : (ArraySlice -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) @@ -121,8 +121,8 @@ extension CollectionOfOne where Element : Arbitrary { extension CollectionOfOne : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `CollectionOfOne`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `CollectionOfOne`s. public static func forAllWitnessed(wit : A -> Element, pf : (CollectionOfOne -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[.Zero]))) @@ -153,8 +153,8 @@ extension Optional where Wrapped : Arbitrary { extension Optional : WitnessedArbitrary { public typealias Param = Wrapped - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Optional`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Optional`s. public static func forAllWitnessed(wit : A -> Wrapped, pf : (Optional -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) @@ -177,8 +177,8 @@ extension ContiguousArray where Element : Arbitrary { extension ContiguousArray : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ContiguousArray`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ContiguousArray`s. public static func forAllWitnessed(wit : A -> Element, pf : (ContiguousArray -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) @@ -188,7 +188,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { - /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. + /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. public static var arbitrary : Gen> { return [Key].arbitrary.flatMap { k in return [Value].arbitrary.flatMap { v in @@ -197,8 +197,8 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { } } - /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and - /// `Value`s. + /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and + /// `Value`s. public static func shrink(d : Dictionary) -> [Dictionary] { return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } } @@ -267,8 +267,8 @@ extension Repeat where Element : Arbitrary { extension Repeat : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Repeat`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Repeat`s. public static func forAllWitnessed(wit : A -> Element, pf : (Repeat -> Testable)) -> Property { return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) @@ -291,7 +291,7 @@ extension Set where Element : protocol { } } - /// The default shrinking function for `Set`s of arbitrary `Element`s. + /// The default shrinking function for `Set`s of arbitrary `Element`s. public static func shrink(s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } @@ -300,8 +300,8 @@ extension Set where Element : protocol { extension Set : WitnessedArbitrary { public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Set`s. + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Set`s. public static func forAllWitnessed(wit : A -> Element, pf : (Set -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) @@ -355,11 +355,11 @@ private func shrinkOne(xs : [A]) -> [[A]] { } extension Dictionary { - private init(_ pairs : S) { - self.init() - var g = pairs.generate() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } + private init(_ pairs : S) { + self.init() + var g = pairs.generate() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } } From 51c75e0504a3cd3ed20885df58bc257cc36fd244 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 30 Apr 2016 21:05:32 -0400 Subject: [PATCH 289/460] Aesthetics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A E S T H I C S 美学 --- README.md | 2 +- Sources/Test.swift | 2 +- Sources/TestOperators.swift | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index dab9062..88cdc44 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ let weightedOptionals = Gen.frequency([ ``` For instances of many complex or "real world" generators, see -[`ComplexSpec.swift`](SwiftCheckTests/ComplexSpec.swift). +[`ComplexSpec.swift`](Tests/ComplexSpec.swift). System Requirements =================== diff --git a/Sources/Test.swift b/Sources/Test.swift index 2ebf8ae..61b7fcc 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -384,7 +384,7 @@ internal enum Result { ) } -internal indirect enum Either { +private indirect enum Either { case Left(L) case Right(R) } diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index ff6805a..c2ff31a 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -142,7 +142,7 @@ public struct CheckerArguments { infix operator <- {} /// Binds a Testable value to a property. -public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { +public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { case let .Failure(_, sz, seed, _, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) @@ -156,7 +156,7 @@ public func <-(checker : AssertiveQuickCheck, @autoclosure(escaping) test : () - } /// Binds a Testable value to a property. -public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { +public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { case let .Failure(_, sz, seed, _, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) @@ -170,12 +170,12 @@ public func <-(checker : AssertiveQuickCheck, test : () -> Testable) { } /// Binds a Testable value to a property. -public func <-(checker : ReportiveQuickCheck, test : () -> Testable) { +public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. -public func <-(checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { +public func <- (checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { quickCheckWithResult(checker.args, test()) } @@ -187,7 +187,7 @@ infix operator ==> { /// Models implication for properties. That is, the property holds if the first /// argument is false (in which case the test case is discarded), or if the /// given property holds. -public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { +public func ==> (b : Bool, @autoclosure p : () -> Testable) -> Property { if b { return p().property } @@ -197,7 +197,7 @@ public func ==>(b : Bool, @autoclosure p : () -> Testable) -> Property { /// Models implication for properties. That is, the property holds if the first /// argument is false (in which case the test case is discarded), or if the /// given property holds. -public func ==>(b : Bool, p : () -> Testable) -> Property { +public func ==> (b : Bool, p : () -> Testable) -> Property { if b { return p().property } @@ -209,8 +209,8 @@ infix operator ==== { } /// Like equality but prints a verbose description when it fails. -public func ====(x : A, y : A) -> Property { - return (x == y).counterexample(String(x) + "/=" + String(y)) +public func ==== (x : A, y : A) -> Property { + return (x == y).counterexample(String(x) + " /= " + String(y)) } @@ -226,7 +226,7 @@ infix operator { /// addition to shrunken test cases, upon failure SwiftCheck will print a /// distribution map for the property that shows a percentage success rate for /// the property. -public func (p : Testable, s : String) -> Property { +public func (p : Testable, s : String) -> Property { return p.label(s) } @@ -240,7 +240,7 @@ infix operator ^&&^ { /// /// Conjoined properties succeed only when both sub-properties succeed and fail /// when one or more sub-properties fail. -public func ^&&^(p1 : Testable, p2 : Testable) -> Property { +public func ^&&^ (p1 : Testable, p2 : Testable) -> Property { return conjoin(p1.property, p2.property) } @@ -255,7 +255,7 @@ infix operator ^||^ { /// /// Disjoined properties succeed only when one or more sub-properties succeed /// and fail when both sub-properties fail. -public func ^||^(p1 : Testable, p2 : Testable) -> Property { +public func ^||^ (p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) } From 2685f259f5cf8040b793b1c6898a69f5f204a63b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 30 Apr 2016 21:11:47 -0400 Subject: [PATCH 290/460] Add more installation instructions --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 88cdc44..5d3e3ab 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,15 @@ Setup ===== SwiftCheck can be included one of two ways: + +**Using The Swift Package Manager** + +- Add SwiftCheck to your `Package.swift` file's dependencies section: +```swift +.Package(url: "https://github.com/typelift/SwiftCheck.git", versions: Version(0,6,0).. Date: Tue, 3 May 2016 16:03:24 -0400 Subject: [PATCH 291/460] Provide more efficient version of ap and zip --- Sources/Gen.swift | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 16516b0..90a51f1 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -142,11 +142,10 @@ public struct Gen { /// Zips together 2 generators of type `A` and `B` into a generator of pairs. public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return gen1.flatMap { l in - return gen2.flatMap { r in - return Gen<(A, B)>.pure((l, r)) - } - } + return Gen<(A, B)>(unGen: { r, n in + let (r1, r2) = r.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n)) + }) } } @@ -283,11 +282,10 @@ extension Gen /*: Applicative*/ { /// Promotes function application to a Generator of functions applied to a /// Generator of values. public func <*> (fn : Gen B>, g : Gen) -> Gen { - return fn >>- { x1 in - return g >>- { x2 in - return Gen.pure(x1(x2)) - } - } + return Gen(unGen: { r, n in + let (r1, r2) = r.split + return fn.unGen(r1, n)(g.unGen(r2, n)) + }) } extension Gen /*: Monad*/ { From adb3a3f7ef6c2139bcce01aece12a27731977609 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 3 May 2016 16:34:44 -0400 Subject: [PATCH 292/460] Add a test --- Tests/GenSpec.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index ff71464..4c1d976 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -25,7 +25,7 @@ class GenSpec : XCTestCase { property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in return forAll(Gen.frequency(Array(count: n, repeatedValue: (1, Gen.pure(0))))) { $0 == 0 } } - + property("Gen.weighted behaves") <- { let g = Gen.weighted([ (10, 0), @@ -148,6 +148,13 @@ class GenSpec : XCTestCase { return ss == xs } } + + property("Gen.zip behaves") <- forAll { (x : Int, y : Int) in + let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) + return forAllNoShrink(g) { (x1, y1) in + return (x1, y1) == (x, y) + } + } } func testLaws() { From c058909856c0c9d6c6e836d875e8878ce8144e42 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 4 May 2016 16:36:31 -0400 Subject: [PATCH 293/460] Insufficient coverage and failure expectations now print replay values --- Sources/Test.swift | 20 ++++++++++++++++---- Sources/TestOperators.swift | 20 ++++++++++---------- Tests/PropertySpec.swift | 4 ++-- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Sources/Test.swift b/Sources/Test.swift index 61b7fcc..c51f0d7 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -375,10 +375,14 @@ internal enum Result { , lastResult : TestResult ) case NoExpectedFailure(numTests : Int + , usedSeed : StdGen + , usedSize : Int , labels : [(String,Int)] , output : String ) case InsufficientCoverage(numTests : Int + , usedSeed : StdGen + , usedSize : Int , labels : [(String,Int)] , output : String ) @@ -432,8 +436,8 @@ private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result switch (fail.0, doneTesting(fail.1)) { case (.Success(_, _, _), _): return fail.0 - case let (_, .NoExpectedFailure(numTests, labels, output)): - return .NoExpectedFailure(numTests: numTests, labels: labels, output: output) + case let (_, .NoExpectedFailure(numTests, seed, sz, labels, output)): + return .NoExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) // Existential Failures need explicit propagation. Existentials increment the // discard count so we check if it has been surpassed. If it has with any kind // of success we're done. If no successes are found we've failed checking the @@ -612,11 +616,19 @@ private func doneTesting(st : CheckerState) -> Result { } printDistributionGraph(st) - return .NoExpectedFailure(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .NoExpectedFailure(numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") } else if insufficientCoverage(st) { printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .InsufficientCoverage(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .InsufficientCoverage( numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") } else { printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index c2ff31a..5275624 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -144,12 +144,12 @@ infix operator <- {} /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, sz, seed, _, reason, _, _): + case let .Failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case .NoExpectedFailure(_, _, _): - XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) - case .InsufficientCoverage(_, _, _): - XCTFail("Property coverage insufficient.", file: checker.file, line: checker.line) + case let .NoExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .InsufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return } @@ -158,12 +158,12 @@ public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, sz, seed, _, reason, _, _): + case let .Failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case .NoExpectedFailure(_, _, _): - XCTFail("Expected property to fail but it didn't.", file: checker.file, line: checker.line) - case .InsufficientCoverage(_, _, _): - XCTFail("Property coverage insufficient.", file: checker.file, line: checker.line) + case let .NoExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .InsufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return } diff --git a/Tests/PropertySpec.swift b/Tests/PropertySpec.swift index f3ab987..c151a03 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/PropertySpec.swift @@ -22,9 +22,9 @@ func ==(l : Property, r : Property) -> Bool { return true case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): return true - case (.NoExpectedFailure(_, _, _), .NoExpectedFailure(_, _, _)): + case (.NoExpectedFailure(_, _, _, _, _), .NoExpectedFailure(_, _, _, _, _)): return true - case (.InsufficientCoverage(_, _, _), .InsufficientCoverage(_, _, _)): + case (.InsufficientCoverage(_, _, _, _, _), .InsufficientCoverage(_, _, _, _, _)): return true default: return false From 6c456f39ab1897003e461c7783ccea270a52e8eb Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Wed, 4 May 2016 22:54:06 -0400 Subject: [PATCH 294/460] add default implementation for RawRepresentable --- Sources/RawRepresentable+Arbitrary.swift | 16 +++++++++ SwiftCheck.xcodeproj/project.pbxproj | 24 +++++++++++++ Tests/RawRepresentable+ArbitrarySpec.swift | 42 ++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 Sources/RawRepresentable+Arbitrary.swift create mode 100644 Tests/RawRepresentable+ArbitrarySpec.swift diff --git a/Sources/RawRepresentable+Arbitrary.swift b/Sources/RawRepresentable+Arbitrary.swift new file mode 100644 index 0000000..48bf1fb --- /dev/null +++ b/Sources/RawRepresentable+Arbitrary.swift @@ -0,0 +1,16 @@ +// +// RawRepresentable+Arbitrary.swift +// SwiftCheck +// +// Created by Brian Gerstle on 5/4/16. +// Copyright © 2016 Robert Widmann. All rights reserved. +// + +import Foundation + +extension RawRepresentable where RawValue: Arbitrary { + // Default implementation, maps arbitrary values of its RawValue type until a valid representation is obtained. + public static var arbitrary: Gen { + return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } + } +} diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 8c06984..1f6aae5 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,6 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 080BE0271CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; + 080BE0281CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; + 080BE0291CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; + 080BE02B1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; + 080BE02C1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; + 080BE02D1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; @@ -152,6 +158,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "RawRepresentable+Arbitrary.swift"; path = "Sources/RawRepresentable+Arbitrary.swift"; sourceTree = SOURCE_ROOT; }; + 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "RawRepresentable+ArbitrarySpec.swift"; path = "Tests/RawRepresentable+ArbitrarySpec.swift"; sourceTree = SOURCE_ROOT; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; @@ -241,6 +249,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 080BE0251CDAE9CF0043ACDE /* Default Arbitrary Implementaitons */ = { + isa = PBXGroup; + children = ( + 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */, + ); + name = "Default Arbitrary Implementaitons"; + sourceTree = ""; + }; 844FCC83198B320500EB242A = { isa = PBXGroup; children = ( @@ -267,6 +283,7 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( + 080BE0251CDAE9CF0043ACDE /* Default Arbitrary Implementaitons */, 826D81461C953D070022266C /* Arbitrary.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 826D81491C953D070022266C /* Gen.swift */, @@ -313,6 +330,7 @@ 826D819A1C953D2D0022266C /* SimpleSpec.swift */, 826D819B1C953D2D0022266C /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, + 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */, ); path = SwiftCheckTests; sourceTree = ""; @@ -573,6 +591,7 @@ 826D81751C953D070022266C /* Random.swift in Sources */, 826D81841C953D070022266C /* Testable.swift in Sources */, 826D816F1C953D070022266C /* Operators.swift in Sources */, + 080BE0291CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D818A1C953D070022266C /* Witness.swift in Sources */, 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, 826D816C1C953D070022266C /* Modifiers.swift in Sources */, @@ -603,6 +622,7 @@ 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */, + 080BE02D1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -616,6 +636,7 @@ 826D81731C953D070022266C /* Random.swift in Sources */, 826D81821C953D070022266C /* Testable.swift in Sources */, 826D816D1C953D070022266C /* Operators.swift in Sources */, + 080BE0271CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D81881C953D070022266C /* Witness.swift in Sources */, 826D81581C953D070022266C /* Arbitrary.swift in Sources */, 826D816A1C953D070022266C /* Modifiers.swift in Sources */, @@ -646,6 +667,7 @@ 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */, + 080BE02B1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -659,6 +681,7 @@ 826D81741C953D070022266C /* Random.swift in Sources */, 826D81831C953D070022266C /* Testable.swift in Sources */, 826D816E1C953D070022266C /* Operators.swift in Sources */, + 080BE0281CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D81891C953D070022266C /* Witness.swift in Sources */, 826D81591C953D070022266C /* Arbitrary.swift in Sources */, 826D816B1C953D070022266C /* Modifiers.swift in Sources */, @@ -689,6 +712,7 @@ 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */, + 080BE02C1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/RawRepresentable+ArbitrarySpec.swift b/Tests/RawRepresentable+ArbitrarySpec.swift new file mode 100644 index 0000000..35e1a92 --- /dev/null +++ b/Tests/RawRepresentable+ArbitrarySpec.swift @@ -0,0 +1,42 @@ +// +// RawRepresentable+ArbitrarySpec.swift +// SwiftCheck +// +// Created by Brian Gerstle on 5/4/16. +// Copyright © 2016 Robert Widmann. All rights reserved. +// + +import XCTest +import SwiftCheck + +enum ImplicitRawValues : Int { + case Foo + case Bar + case Baz +} + +// Declaring the extension allows Swift to know this particular enum can be Arbitrary +// ...but it doesn't need to be implemented since the protocol extension gives us a default implementation! +extension ImplicitRawValues: Arbitrary {} + +enum ExplicitRawValues : Int { + case Zero = 0 + case One = 1 + case Two = 2 +} + +class RawRepresentable_ArbitrarySpec: XCTestCase { + func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { + property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in + return [.Foo, .Bar, .Baz].contains(e) + } + } + + func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { + // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically + // infer protocol conformance + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in + return [.Zero, .One, .Two].contains(e) + } + } +} From 0513eea13da7ee2688f24bef74ab78b6c1909d33 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Wed, 4 May 2016 22:54:58 -0400 Subject: [PATCH 295/460] add build folder to gitignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for those of us who keep a local build folder for easy nuking 💣 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index bae65ef..2e900d7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ DerivedData *.xcscmblueprint Carthage/Build Carthage/Checkouts +build/ From 1696cefae2b06b153b1ca74a780769766cd1000d Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Thu, 5 May 2016 06:53:54 -0400 Subject: [PATCH 296/460] set xcodeproj org to Typelift, fix Copyright owner, & bump to 2016 --- Sources/CoArbitrary.swift | 2 +- Sources/RawRepresentable+Arbitrary.swift | 2 +- Sources/WitnessedArbitrary.swift | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 2 +- Tests/ComplexSpec.swift | 2 +- Tests/FailureSpec.swift | 2 +- Tests/LambdaSpec.swift | 2 +- Tests/PathSpec.swift | 2 +- Tests/RawRepresentable+ArbitrarySpec.swift | 2 +- Tests/ReplaySpec.swift | 2 +- Tests/RoseSpec.swift | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index 83aef26..c238d5b 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 12/15/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // /// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` diff --git a/Sources/RawRepresentable+Arbitrary.swift b/Sources/RawRepresentable+Arbitrary.swift index 48bf1fb..cc11d8b 100644 --- a/Sources/RawRepresentable+Arbitrary.swift +++ b/Sources/RawRepresentable+Arbitrary.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Brian Gerstle on 5/4/16. -// Copyright © 2016 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import Foundation diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index e28b1a5..6f9d82a 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 12/15/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // extension Array where Element : Arbitrary { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 1f6aae5..6e60515 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -491,7 +491,7 @@ attributes = { LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0700; - ORGANIZATIONNAME = "Robert Widmann"; + ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { CreatedOnToolsVersion = 7.2; diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index 604c07f..3f80642 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 9/2/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck diff --git a/Tests/FailureSpec.swift b/Tests/FailureSpec.swift index 63b3e23..5ea87a3 100644 --- a/Tests/FailureSpec.swift +++ b/Tests/FailureSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 9/18/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index c337991..ca3a210 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 1/6/16. -// Copyright © 2016 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index bd556af..c98986f 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 2/10/16. -// Copyright © 2016 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck diff --git a/Tests/RawRepresentable+ArbitrarySpec.swift b/Tests/RawRepresentable+ArbitrarySpec.swift index 35e1a92..897b3d7 100644 --- a/Tests/RawRepresentable+ArbitrarySpec.swift +++ b/Tests/RawRepresentable+ArbitrarySpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Brian Gerstle on 5/4/16. -// Copyright © 2016 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import XCTest diff --git a/Tests/ReplaySpec.swift b/Tests/ReplaySpec.swift index 96dac68..f9cd608 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/ReplaySpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 11/18/15. -// Copyright © 2015 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index 8dfd772..f411260 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -3,7 +3,7 @@ // SwiftCheck // // Created by Robert Widmann on 1/24/16. -// Copyright © 2016 Robert Widmann. All rights reserved. +// Copyright © 2016 Typelift. All rights reserved. // import SwiftCheck From 740068cfb37737c00e528527cac3a517299b0fb1 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Thu, 5 May 2016 06:54:43 -0400 Subject: [PATCH 297/460] remove Foundation import --- Sources/RawRepresentable+Arbitrary.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/RawRepresentable+Arbitrary.swift b/Sources/RawRepresentable+Arbitrary.swift index cc11d8b..dcffe41 100644 --- a/Sources/RawRepresentable+Arbitrary.swift +++ b/Sources/RawRepresentable+Arbitrary.swift @@ -6,8 +6,6 @@ // Copyright © 2016 Typelift. All rights reserved. // -import Foundation - extension RawRepresentable where RawValue: Arbitrary { // Default implementation, maps arbitrary values of its RawValue type until a valid representation is obtained. public static var arbitrary: Gen { From 8657237ebe79f0aea9bdaccc4299db951be4dde9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 18:21:19 -0400 Subject: [PATCH 298/460] Nitpicks left over from #160 --- Sources/Arbitrary.swift | 9 ++++++ Sources/RawRepresentable+Arbitrary.swift | 14 -------- SwiftCheck.xcodeproj/project.pbxproj | 32 +++++-------------- ...ySpec.swift => RawRepresentableSpec.swift} | 0 Tutorial.playground/Contents.swift | 2 +- Tutorial.playground/contents.xcplayground | 2 +- 6 files changed, 19 insertions(+), 40 deletions(-) delete mode 100644 Sources/RawRepresentable+Arbitrary.swift rename Tests/{RawRepresentable+ArbitrarySpec.swift => RawRepresentableSpec.swift} (100%) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 301698e..98cbe6e 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -74,6 +74,15 @@ extension IntegerType { } } +extension RawRepresentable where RawValue: Arbitrary { + /// Default implementation, maps arbitrary values of its `RawValue` type + /// until a valid representation is obtained. Naturally, you should strive + /// to override this with a more efficient version. + public static var arbitrary: Gen { + return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } + } +} + extension Bool : Arbitrary { /// Returns a generator of `Bool`ean values. public static var arbitrary : Gen { diff --git a/Sources/RawRepresentable+Arbitrary.swift b/Sources/RawRepresentable+Arbitrary.swift deleted file mode 100644 index dcffe41..0000000 --- a/Sources/RawRepresentable+Arbitrary.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// RawRepresentable+Arbitrary.swift -// SwiftCheck -// -// Created by Brian Gerstle on 5/4/16. -// Copyright © 2016 Typelift. All rights reserved. -// - -extension RawRepresentable where RawValue: Arbitrary { - // Default implementation, maps arbitrary values of its RawValue type until a valid representation is obtained. - public static var arbitrary: Gen { - return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } - } -} diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 6e60515..e1d718f 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,12 +7,9 @@ objects = { /* Begin PBXBuildFile section */ - 080BE0271CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; - 080BE0281CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; - 080BE0291CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */; }; - 080BE02B1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; - 080BE02C1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; - 080BE02D1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */; }; + 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; + 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; + 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; @@ -158,8 +155,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "RawRepresentable+Arbitrary.swift"; path = "Sources/RawRepresentable+Arbitrary.swift"; sourceTree = SOURCE_ROOT; }; - 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "RawRepresentable+ArbitrarySpec.swift"; path = "Tests/RawRepresentable+ArbitrarySpec.swift"; sourceTree = SOURCE_ROOT; }; + 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; @@ -249,14 +245,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 080BE0251CDAE9CF0043ACDE /* Default Arbitrary Implementaitons */ = { - isa = PBXGroup; - children = ( - 080BE0261CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift */, - ); - name = "Default Arbitrary Implementaitons"; - sourceTree = ""; - }; 844FCC83198B320500EB242A = { isa = PBXGroup; children = ( @@ -283,7 +271,6 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( - 080BE0251CDAE9CF0043ACDE /* Default Arbitrary Implementaitons */, 826D81461C953D070022266C /* Arbitrary.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 826D81491C953D070022266C /* Gen.swift */, @@ -324,13 +311,13 @@ 826D81941C953D2D0022266C /* ModifierSpec.swift */, 826D81951C953D2D0022266C /* PathSpec.swift */, 826D81961C953D2D0022266C /* PropertySpec.swift */, + 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */, 826D81971C953D2D0022266C /* ReplaySpec.swift */, 826D81981C953D2D0022266C /* RoseSpec.swift */, 826D81991C953D2D0022266C /* ShrinkSpec.swift */, 826D819A1C953D2D0022266C /* SimpleSpec.swift */, 826D819B1C953D2D0022266C /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, - 080BE02A1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift */, ); path = SwiftCheckTests; sourceTree = ""; @@ -591,7 +578,6 @@ 826D81751C953D070022266C /* Random.swift in Sources */, 826D81841C953D070022266C /* Testable.swift in Sources */, 826D816F1C953D070022266C /* Operators.swift in Sources */, - 080BE0291CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D818A1C953D070022266C /* Witness.swift in Sources */, 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, 826D816C1C953D070022266C /* Modifiers.swift in Sources */, @@ -622,7 +608,7 @@ 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02D1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, + 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -636,7 +622,6 @@ 826D81731C953D070022266C /* Random.swift in Sources */, 826D81821C953D070022266C /* Testable.swift in Sources */, 826D816D1C953D070022266C /* Operators.swift in Sources */, - 080BE0271CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D81881C953D070022266C /* Witness.swift in Sources */, 826D81581C953D070022266C /* Arbitrary.swift in Sources */, 826D816A1C953D070022266C /* Modifiers.swift in Sources */, @@ -667,7 +652,7 @@ 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02B1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, + 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -681,7 +666,6 @@ 826D81741C953D070022266C /* Random.swift in Sources */, 826D81831C953D070022266C /* Testable.swift in Sources */, 826D816E1C953D070022266C /* Operators.swift in Sources */, - 080BE0281CDAE9EA0043ACDE /* RawRepresentable+Arbitrary.swift in Sources */, 826D81891C953D070022266C /* Witness.swift in Sources */, 826D81591C953D070022266C /* Arbitrary.swift in Sources */, 826D816B1C953D070022266C /* Modifiers.swift in Sources */, @@ -712,7 +696,7 @@ 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */, 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */, 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02C1CDAEA330043ACDE /* RawRepresentable+ArbitrarySpec.swift in Sources */, + 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/RawRepresentable+ArbitrarySpec.swift b/Tests/RawRepresentableSpec.swift similarity index 100% rename from Tests/RawRepresentable+ArbitrarySpec.swift rename to Tests/RawRepresentableSpec.swift diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index df1a25f..37c057a 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -46,7 +46,7 @@ import SwiftCheck //: In Swift, when one thinks of a Generator, they usually think of the `GeneratorType` protocol or //: the many many individual structures the Swift Standard Library exposes to allow loops to work -//: with data structures like `[T]` and `Set`. In Swift, we also have Generators, but we spell +//: with data structures like `[T]` and `Set`. In *SwiftCheck*, we also have Generators, but we spell //: them `Gen`erators, as in the universal Generator type `Gen`. //: //: `Gen` is a struct defined generically over any kind of type that looks like this: diff --git a/Tutorial.playground/contents.xcplayground b/Tutorial.playground/contents.xcplayground index 6bcaa60..b85a947 100644 --- a/Tutorial.playground/contents.xcplayground +++ b/Tutorial.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file From ab7bba086f5fbf9a0d4119d4f197d8d94bfd05d2 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:04:13 -0400 Subject: [PATCH 299/460] Retab --- Tests/RawRepresentableSpec.swift | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Tests/RawRepresentableSpec.swift b/Tests/RawRepresentableSpec.swift index 897b3d7..7f55c66 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/RawRepresentableSpec.swift @@ -10,9 +10,9 @@ import XCTest import SwiftCheck enum ImplicitRawValues : Int { - case Foo - case Bar - case Baz + case Foo + case Bar + case Baz } // Declaring the extension allows Swift to know this particular enum can be Arbitrary @@ -20,23 +20,23 @@ enum ImplicitRawValues : Int { extension ImplicitRawValues: Arbitrary {} enum ExplicitRawValues : Int { - case Zero = 0 - case One = 1 - case Two = 2 + case Zero = 0 + case One = 1 + case Two = 2 } class RawRepresentable_ArbitrarySpec: XCTestCase { - func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { - property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in - return [.Foo, .Bar, .Baz].contains(e) - } - } - - func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { - // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically - // infer protocol conformance - property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in - return [.Zero, .One, .Two].contains(e) - } - } + func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { + property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in + return [.Foo, .Bar, .Baz].contains(e) + } + } + + func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { + // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically + // infer protocol conformance + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in + return [.Zero, .One, .Two].contains(e) + } + } } From 5e614103386f0217ab8c99ac9a19a9cb6b800dd3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:04:39 -0400 Subject: [PATCH 300/460] Add Monoidal Functor instance --- Sources/Gen.swift | 110 ++++++++++++++++++++++++++++++++++++++++++++ Tests/GenSpec.swift | 66 +++++++++++++++++++++++++- 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 90a51f1..41ffa7d 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -139,7 +139,9 @@ public struct Gen { public static func weighted(xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } +} +extension Gen /*: Cartesian*/ { /// Zips together 2 generators of type `A` and `B` into a generator of pairs. public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return Gen<(A, B)>(unGen: { r, n in @@ -147,6 +149,114 @@ public struct Gen { return (gen1.unGen(r1, n), gen2.unGen(r2, n)) }) } + + /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of + /// triples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { + return Gen<(A, B, C)>(unGen: { r, n in + let (r1, r2_) = r.split + let (r2, r3) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) + }) + } + + /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a + /// generator of quadruples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { + return Gen<(A, B, C, D)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1, r2) = r1_.split + let (r3, r4) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) + }) + } + + /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a + /// generator of quintuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { + return Gen<(A, B, C, D, E)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r1) = r1_.split + let (r2, r3) = r2_.split + let (r4, r5) = r1__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) + }) + } + + /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into + /// a generator of sextuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { + return Gen<(A, B, C, D, E, F)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1, r2) = r2_.split + let (r3, r4) = r1__.split + let (r5, r6) = r2__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) + }) + } + + /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` + /// into a generator of septuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { + return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r1) = r2_.split + let (r2, r3) = r1__.split + let (r4, r5) = r2__.split + let (r6, r7) = r1___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) + }) + } + + /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and + /// `H` into a generator of octuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { + return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1, r2) = r1__.split + let (r3, r4) = r2__.split + let (r5, r6) = r1___.split + let (r7, r8) = r2___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) + }) + } + + /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, and `I` into a generator of nonuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { + return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r1) = r1__.split + let (r2, r3) = r2__.split + let (r4, r5) = r1___.split + let (r6, r7) = r2___.split + let (r8, r9) = r1____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) + }) + } + + /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, `I`, and `J` into a generator of decuples. + public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { + return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r2____) = r1__.split + let (r1, r2) = r2__.split + let (r3, r4) = r1___.split + let (r5, r6) = r2___.split + let (r7, r8) = r1____.split + let (r9, r10) = r2____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) + }) + } } // MARK: Generator Modifiers diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 4c1d976..152c4e6 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -149,12 +149,76 @@ class GenSpec : XCTestCase { } } - property("Gen.zip behaves") <- forAll { (x : Int, y : Int) in + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) return forAllNoShrink(g) { (x1, y1) in return (x1, y1) == (x, y) } } + + property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in + let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) + return forAllNoShrink(g) { (x1, y1, z1) in + return (x1, y1, z1) == (x, y, z) + } + } + + property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in + let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) + return forAllNoShrink(g) { (x1, y1, z1, w1) in + return (x1, y1, z1, w1) == (x, y, z, w) + } + } + + property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in + let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in + return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + } + } + + property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + } + } + + property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && c1 == c + } + } + + property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1) == (c, d) + } + } + + property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1) == (c, d, e) + } + } + } + + property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int, f : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1, f1) == (c, d, e, f) + } + } + } } func testLaws() { From 7dd0be91f1ac0c61706c91c9be9ea8f3042efb18 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:07:29 -0400 Subject: [PATCH 301/460] Simplify SimpleSpec with new kit --- Tests/SimpleSpec.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index e1a306f..742ab06 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -13,10 +13,6 @@ public struct ArbitraryFoo { let x : Int let y : Int - public static func create(x : Int) -> Int -> ArbitraryFoo { - return { y in ArbitraryFoo(x: x, y: y) } - } - public var description : String { return "Arbitrary Foo!" } @@ -24,7 +20,7 @@ public struct ArbitraryFoo { extension ArbitraryFoo : Arbitrary { public static var arbitrary : Gen { - return ArbitraryFoo.create <^> Int.arbitrary <*> Int.arbitrary + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) } } From 1e0ff5da4d3378bdbfbb91b4f749042153e5acb6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:17:00 -0400 Subject: [PATCH 302/460] Declare an unreasonably large struct example test --- Tests/SimpleSpec.swift | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 742ab06..f1297c1 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -24,6 +24,49 @@ extension ArbitraryFoo : Arbitrary { } } +public struct ArbitraryLargeFoo { + let a : Int8 + let b : Int16 + let c : Int32 + let d : Int64 + let e : UInt8 + let f : UInt16 + let g : UInt32 + let h : UInt64 + let i : Int + let j : UInt + let k : Bool + let l : (Bool, Bool) + let m : (Bool, Bool, Bool) + let n : (Bool, Bool, Bool, Bool) +} + +extension ArbitraryLargeFoo : Arbitrary { + public static var arbitrary : Gen { + return Gen<(Int8, Int16, Int32, Int64 + , UInt8, UInt16, UInt32, UInt64 + , Int , UInt)> + .zip( Int8.arbitrary + , Int16.arbitrary + , Int32.arbitrary + , Int64.arbitrary + , UInt8.arbitrary + , UInt16.arbitrary + , UInt32.arbitrary + , UInt64.arbitrary + , Int.arbitrary + , UInt.arbitrary).flatMap { t in + return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> + .zip( Bool.arbitrary + , Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary) + , Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) + , Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary)).map({ t2 in + return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) + }).map(ArbitraryLargeFoo.init) + } + } +} + class SimpleSpec : XCTestCase { func testAll() { property("Integer Equality is Reflexive") <- forAll { (i : Int8) in From a2ad55ea53bf3554a87b4838fe0245ab7db625b7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:18:48 -0400 Subject: [PATCH 303/460] Test --- Tests/SimpleSpec.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index f1297c1..4ba53a6 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -93,6 +93,23 @@ class SimpleSpec : XCTestCase { return i.x == i.x && i.y == i.y } + property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in + return i.a == i.a + && i.b == i.b + && i.c == i.c + && i.d == i.d + && i.e == i.e + && i.f == i.f + && i.g == i.g + && i.h == i.h + && i.i == i.i + && i.j == i.j + && i.k == i.k + && i.l == i.l + && i.m == i.m + && i.n == i.n + } + property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in return (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) From 8cccf04b61a0399d7f538a710c422da9101b8553 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:20:42 -0400 Subject: [PATCH 304/460] Reindent --- Tests/SimpleSpec.swift | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 4ba53a6..3ddc15f 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -46,21 +46,16 @@ extension ArbitraryLargeFoo : Arbitrary { return Gen<(Int8, Int16, Int32, Int64 , UInt8, UInt16, UInt32, UInt64 , Int , UInt)> - .zip( Int8.arbitrary - , Int16.arbitrary - , Int32.arbitrary - , Int64.arbitrary - , UInt8.arbitrary - , UInt16.arbitrary - , UInt32.arbitrary - , UInt64.arbitrary - , Int.arbitrary - , UInt.arbitrary).flatMap { t in - return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> - .zip( Bool.arbitrary - , Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary) - , Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) - , Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary)).map({ t2 in + .zip( Int8.arbitrary, Int16.arbitrary, Int32.arbitrary, Int64.arbitrary + , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary + , Int.arbitrary, UInt.arbitrary) + .flatMap { t in + return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> + .zip( Bool.arbitrary + , Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary) + , Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) + , Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary)) + .map({ t2 in return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) }).map(ArbitraryLargeFoo.init) } From 09288accdb648d5d9938e98857cc4074690a8127 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 6 May 2016 19:44:37 -0400 Subject: [PATCH 305/460] Bump podspec --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index f277a57..d12c0ff 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.6.0" + s.version = "0.6.1" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From da3d0a94b6f03b6b7424db2fd884279a934ce8a4 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Sat, 7 May 2016 19:37:39 -0700 Subject: [PATCH 306/460] Add Cartesian and Monoidal functor law tests to Gen. --- Tests/GenSpec.swift | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 152c4e6..e9774fb 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -155,7 +155,27 @@ class GenSpec : XCTestCase { return (x1, y1) == (x, y) } } - + + property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in + let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) + let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) + return rightBiasedZip ~= leftBiasedZip + } + + property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in + let fx = Gen.pure(x) + let ff = Gen>.pure(f).map { $0.getArrow } + return fx.ap(ff) == Gen<(Int -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + } + + property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in + Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) + } + + property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in + Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) + } + property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) return forAllNoShrink(g) { (x1, y1, z1) in @@ -286,3 +306,22 @@ internal func • (f : B -> C, g : A -> B) -> A -> C { private func ==(l : Gen, r : Gen) -> Bool { return l.proliferateSized(10).generate == r.proliferateSized(10).generate } + +/// `Gen` product is associative and has a natural isomorphism. +/// +/// - Returns: True *iff* `(a1, a2, a3) == (b1, b2, b3)` +/// where `lhs = Gen((a1, (a2, a3)))` and `rhs = Gen(((b1, b2), b3))`. +private func ~= (lhs: Gen<(Int, (Int, Int))>, rhs: Gen<((Int, Int), Int)>) -> Bool { + let normalizedL = lhs.map { ($0, $1.0, $1.1) } + let normalizedR = rhs.map { ($0.0, $0.1, $1) } + + let sampleSize = 10 + let sampleL = normalizedL.proliferateSized(sampleSize).generate + let sampleR = normalizedR.proliferateSized(sampleSize).generate + + for (tupleL, tupleR) in zip(sampleL, sampleR) { + guard tupleL == tupleR else { return false } + } + + return true +} From 4d9bf37b608d1c08be91ef7a0e543cfc5d7a3be3 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Sat, 7 May 2016 19:37:59 -0700 Subject: [PATCH 307/460] Add map[2,10] functions Adds mapping functions from 2 to ten arity. --- Sources/Gen.swift | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 41ffa7d..d7c2905 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -257,6 +257,60 @@ extension Gen /*: Cartesian*/ { return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) }) } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// three receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: (A1, A2, A3) -> R) -> Gen { + return zip(ga1, ga2, ga3).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// four receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: (A1, A2, A3, A4) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// five receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: (A1, A2, A3, A4, A5) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// six receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// seven receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// eight receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// nine receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// ten receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + } } // MARK: Generator Modifiers @@ -376,7 +430,7 @@ extension Gen /*: Applicative*/ { } } -/// Ap | Returns a Generator that uses the first given Generator to produce +/// Ap | Returns a Generator that uses the first given Generator to produce /// functions and the second given Generator to produce values that it applies /// to those functions. It can be used in conjunction with <^> to simplify the /// application of "combining" functions to a large amount of sub-generators. From e81665a2adae31c5fa14bf414e5e8216a44dd99c Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Mon, 9 May 2016 11:18:30 -0700 Subject: [PATCH 308/460] Use mapN in SimpleSpec --- Tests/GenSpec.swift | 2 +- Tests/SimpleSpec.swift | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index e9774fb..467dc18 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -311,7 +311,7 @@ private func ==(l : Gen, r : Gen) -> Bool { /// /// - Returns: True *iff* `(a1, a2, a3) == (b1, b2, b3)` /// where `lhs = Gen((a1, (a2, a3)))` and `rhs = Gen(((b1, b2), b3))`. -private func ~= (lhs: Gen<(Int, (Int, Int))>, rhs: Gen<((Int, Int), Int)>) -> Bool { +private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> Bool { let normalizedL = lhs.map { ($0, $1.0, $1.1) } let normalizedR = rhs.map { ($0.0, $0.1, $1) } diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 3ddc15f..692e444 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -51,13 +51,14 @@ extension ArbitraryLargeFoo : Arbitrary { , Int.arbitrary, UInt.arbitrary) .flatMap { t in return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> - .zip( Bool.arbitrary - , Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary) - , Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) - , Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary)) - .map({ t2 in - return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) - }).map(ArbitraryLargeFoo.init) + .map( + Bool.arbitrary, + Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) + ) { t2 in + (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) + }.map(ArbitraryLargeFoo.init) } } } From 58ad046a8a671265d804cf2e679e479fe8513a3f Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Thu, 12 May 2016 20:33:14 -0700 Subject: [PATCH 309/460] Import gyb script from Swift repository. --- Utils/gyb | 4 + Utils/gyb.py | 1128 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1132 insertions(+) create mode 100755 Utils/gyb create mode 100644 Utils/gyb.py diff --git a/Utils/gyb b/Utils/gyb new file mode 100755 index 0000000..7db0fcb --- /dev/null +++ b/Utils/gyb @@ -0,0 +1,4 @@ +#!/usr/bin/env python2.7 +import gyb +gyb.main() + diff --git a/Utils/gyb.py b/Utils/gyb.py new file mode 100644 index 0000000..7a03d57 --- /dev/null +++ b/Utils/gyb.py @@ -0,0 +1,1128 @@ +#!/usr/bin/env python +# GYB: Generate Your Boilerplate (improved names welcome; at least +# this one's short). See -h output for instructions + +from __future__ import print_function + +import os +import re +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +import textwrap +import tokenize + +from bisect import bisect + + +def get_line_starts(s): + """Return a list containing the start index of each line in s. + + The list also contains a sentinel index for the end of the string, + so there will be one more element in the list than there are lines + in the string + """ + starts = [0] + + for line in s.split('\n'): + starts.append(starts[-1] + len(line) + 1) + + starts[-1] -= 1 + return starts + + +def strip_trailing_nl(s): + """If s ends with a newline, drop it; else return s intact""" + return s[:-1] if s.endswith('\n') else s + + +def split_lines(s): + """Split s into a list of lines, each of which has a trailing newline + + If the lines are later concatenated, the result is s, possibly + with a single appended newline. + """ + return [l + '\n' for l in s.split('\n')] + +# text on a line up to the first '$$', '${', or '%%' +literalText = r'(?: [^$\n%] | \$(?![${]) | %(?!%) )*' + +# The part of an '%end' line that follows the '%' sign +linesClose = r'[\ \t]* end [\ \t]* (?: \# .* )? $' + +# Note: Where "# Absorb" appears below, the regexp attempts to eat up +# through the end of ${...} and %{...}% constructs. In reality we +# handle this with the Python tokenizer, which avoids mis-detections +# due to nesting, comments and strings. This extra absorption in the +# regexp facilitates testing the regexp on its own, by preventing the +# interior of some of these constructs from being treated as literal +# text. +tokenize_re = re.compile( + r''' +# %-lines and %{...}-blocks + # \n? # absorb one preceding newline + ^ + (?: + (?P + (?P<_indent> [\ \t]* % (?! [{%] ) [\ \t]* ) (?! [\ \t] | ''' + linesClose + r''' ) .* + ( \n (?P=_indent) (?! ''' + linesClose + r''' ) .* ) * + ) + | (?P [\ \t]* % [ \t]* ''' + linesClose + r''' ) + | [\ \t]* (?P %\{ ) + (?: [^}]| \} (?!%) )* \}% # Absorb + ) + \n? # absorb one trailing newline + +# Substitutions +| (?P \$\{ ) + [^}]* \} # Absorb + +# %% and $$ are literal % and $ respectively +| (?P[$%]) (?P=symbol) + +# Literal text +| (?P ''' + literalText + r''' + (?: + # newline that doesn't precede space+% + (?: \n (?! [\ \t]* %[^%] ) ) + ''' + literalText + r''' + )* + \n? + ) +''', re.VERBOSE | re.MULTILINE) + +gyb_block_close = re.compile('\}%[ \t]*\n?') + + +def token_pos_to_index(token_pos, start, line_starts): + """Translate a tokenize (line, column) pair into an absolute + position in source text given the position where we started + tokenizing and a list that maps lines onto their starting + character indexes. + """ + relative_token_line_plus1, token_col = token_pos + + # line number where we started tokenizing + start_line_num = bisect(line_starts, start) - 1 + + # line number of the token in the whole text + abs_token_line = relative_token_line_plus1 - 1 + start_line_num + + # if found in the first line, adjust the end column to account + # for the extra text + if relative_token_line_plus1 == 1: + token_col += start - line_starts[start_line_num] + + # Sometimes tokenizer errors report a line beyond the last one + if abs_token_line >= len(line_starts): + return line_starts[-1] + + return line_starts[abs_token_line] + token_col + + +def tokenize_python_to_unmatched_close_curly(source_text, start, line_starts): + """Apply Python's tokenize to source_text starting at index start + while matching open and close curly braces. When an unmatched + close curly brace is found, return its index. If not found, + return len(source_text). If there's a tokenization error, return + the position of the error. + """ + stream = StringIO(source_text) + stream.seek(start) + nesting = 0 + + try: + for kind, text, token_start, token_end, line_text \ + in tokenize.generate_tokens(stream.readline): + + if text == '{': + nesting += 1 + elif text == '}': + nesting -= 1 + if nesting < 0: + return token_pos_to_index(token_start, start, line_starts) + + except tokenize.TokenError as error: + (message, error_pos) = error.args + return token_pos_to_index(error_pos, start, line_starts) + + return len(source_text) + + +def tokenize_template(template_text): + r"""Given the text of a template, returns an iterator over + (tokenType, token, match) tuples. + + **Note**: this is template syntax tokenization, not Python + tokenization. + + When a non-literal token is matched, a client may call + iter.send(pos) on the iterator to reset the position in + template_text at which scanning will resume. + + This function provides a base level of tokenization which is + then refined by ParseContext.token_generator. + + >>> from pprint import * + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '%for x in range(10):\n% print x\n%end\njuicebox'))) + [('gybLines', '%for x in range(10):\n% print x'), + ('gybLinesClose', '%end'), + ('literal', 'juicebox')] + + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... '''))) + [('literal', 'Nothing\n'), + ('gybLines', '% if x:\n% for i in range(3):'), + ('substitutionOpen', '${'), + ('literal', '\n'), + ('gybLinesClose', '% end'), + ('gybLines', '% else:'), + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n')] + + >>> for kind, text, _ in tokenize_template(''' + ... This is $some$ literal stuff containing a ${substitution} + ... followed by a %{...} block: + ... %{ + ... # Python code + ... }% + ... and here $${are} some %-lines: + ... % x = 1 + ... % y = 2 + ... % if z == 3: + ... % print '${hello}' + ... % end + ... % for x in zz: + ... % print x + ... % # different indentation + ... % twice + ... and some lines that literally start with a %% token + ... %% first line + ... %% second line + ... '''): + ... print (kind, text.strip().split('\n',1)[0]) + ('literal', 'This is $some$ literal stuff containing a') + ('substitutionOpen', '${') + ('literal', 'followed by a %{...} block:') + ('gybBlockOpen', '%{') + ('literal', 'and here ${are} some %-lines:') + ('gybLines', '% x = 1') + ('gybLinesClose', '% end') + ('gybLines', '% for x in zz:') + ('gybLines', '% # different indentation') + ('gybLines', '% twice') + ('literal', 'and some lines that literally start with a % token') + """ + pos = 0 + end = len(template_text) + + saved_literal = [] + literal_first_match = None + + while pos < end: + m = tokenize_re.match(template_text, pos, end) + + # pull out the one matched key (ignoring internal patterns starting + # with _) + ((kind, text), ) = ( + (kind, text) for (kind, text) in m.groupdict().items() + if text is not None and kind[0] != '_') + + if kind in ('literal', 'symbol'): + if len(saved_literal) == 0: + literal_first_match = m + # literals and symbols get batched together + saved_literal.append(text) + pos = None + else: + # found a non-literal. First yield any literal we've accumulated + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + saved_literal = [] + + # Then yield the thing we found. If we get a reply, it's + # the place to resume tokenizing + pos = yield kind, text, m + + # If we were not sent a new position by our client, resume + # tokenizing at the end of this match. + if pos is None: + pos = m.end(0) + else: + # Client is not yet ready to process next token + yield + + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + + +def split_gyb_lines(source_lines): + r"""Return a list of lines at which to split the incoming source + + These positions represent the beginnings of python line groups that + will require a matching %end construct if they are to be closed. + + >>> src = split_lines('''\ + ... if x: + ... print x + ... if y: # trailing comment + ... print z + ... if z: # another comment\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' print z\n' + >>> s[1] - len(src) + 0 + + >>> src = split_lines('''\ + ... if x: + ... if y: print 1 + ... if z: + ... print 2 + ... pass\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 1 + >>> src[s[0]] + ' if y: print 1\n' + + >>> src = split_lines('''\ + ... if x: + ... if y: + ... print 1 + ... print 2 + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' if y:\n' + >>> src[s[1]] + ' print 1\n' + """ + last_token_text, last_token_kind = None, None + unmatched_indents = [] + + dedents = 0 + try: + for token_kind, token_text, token_start, \ + (token_end_line, token_end_col), line_text \ + in tokenize.generate_tokens(lambda i=iter(source_lines): + next(i)): + + if token_kind in (tokenize.COMMENT, tokenize.ENDMARKER): + continue + + if token_text == '\n' and last_token_text == ':': + unmatched_indents.append(token_end_line) + + # The tokenizer appends dedents at EOF; don't consider + # those as matching indentations. Instead just save them + # up... + if last_token_kind == tokenize.DEDENT: + dedents += 1 + # And count them later, when we see something real. + if token_kind != tokenize.DEDENT and dedents > 0: + unmatched_indents = unmatched_indents[:-dedents] + dedents = 0 + + last_token_text, last_token_kind = token_text, token_kind + + except tokenize.TokenError: + # Let the later compile() call report the error + return [] + + if last_token_text == ':': + unmatched_indents.append(len(source_lines)) + + return unmatched_indents + + +def code_starts_with_dedent_keyword(source_lines): + r"""Return True iff the incoming Python source_lines begin with "else", + "elif", "except", or "finally". + + Initial comments and whitespace are ignored. + + >>> code_starts_with_dedent_keyword(split_lines('if x in y: pass')) + False + >>> code_starts_with_dedent_keyword(split_lines('except ifSomethingElse:')) + True + >>> code_starts_with_dedent_keyword( + split_lines('\n# comment\nelse: # yes')) + True + """ + token_text = None + for token_kind, token_text, _, _, _ \ + in tokenize.generate_tokens(lambda i=iter(source_lines): next(i)): + + if token_kind != tokenize.COMMENT and token_text.strip() != '': + break + + return token_text in ('else', 'elif', 'except', 'finally') + + +class ParseContext(object): + """State carried through a parse of a template""" + + filename = '' + template = '' + line_starts = [] + code_start_line = -1 + code_text = None + tokens = None # The rest of the tokens + close_lines = False + + def __init__(self, filename, template=None): + self.filename = os.path.abspath(filename) + if template is None: + with open(filename) as f: + self.template = f.read() + else: + self.template = template + self.line_starts = get_line_starts(self.template) + self.tokens = self.token_generator(tokenize_template(self.template)) + self.next_token() + + def pos_to_line(self, pos): + return bisect(self.line_starts, pos) - 1 + + def token_generator(self, base_tokens): + r"""Given an iterator over (kind, text, match) triples (see + tokenize_template above), return a refined iterator over + token_kinds. + + Among other adjustments to the elements found by base_tokens, + this refined iterator tokenizes python code embedded in + template text to help determine its true extent. The + expression "base_tokens.send(pos)" is used to reset the index at + which base_tokens resumes scanning the underlying text. + + >>> ctx = ParseContext('dummy', ''' + ... %for x in y: + ... % print x + ... % end + ... literally + ... ''') + >>> while ctx.token_kind: + ... print (ctx.token_kind, ctx.code_text or ctx.token_text) + ... ignored = ctx.next_token() + ('literal', '\n') + ('gybLinesOpen', 'for x in y:\n') + ('gybLines', ' print x\n') + ('gybLinesClose', '% end') + ('literal', 'literally\n') + + >>> ctx = ParseContext('dummy', + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> while ctx.token_kind: + ... print (ctx.token_kind, ctx.code_text or ctx.token_text) + ... ignored = ctx.next_token() + ('literal', 'Nothing\n') + ('gybLinesOpen', 'if x:\n') + ('gybLinesOpen', ' for i in range(3):\n') + ('substitutionOpen', 'i') + ('literal', '\n') + ('gybLinesClose', '% end') + ('gybLinesOpen', 'else:\n') + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n') + + >>> ctx = ParseContext('dummy', + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add an output line after this line to fix bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''') + >>> while ctx.token_kind: + ... print (ctx.token_kind, ctx.code_text or ctx.token_text) + ... ignored = ctx.next_token() + ('gybLinesOpen', 'for x in [1, 2, 3]:\n') + ('gybLinesOpen', ' if x == 1:\n') + ('literal', 'literal1\n') + ('gybLinesOpen', 'elif x > 1: # add output line here to fix bug\n') + ('gybLinesOpen', ' if x == 2:\n') + ('literal', 'literal2\n') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + """ + for self.token_kind, self.token_text, self.token_match in base_tokens: + kind = self.token_kind + self.code_text = None + + # Do we need to close the current lines? + self.close_lines = kind == 'gybLinesClose' + + # %{...}% and ${...} constructs + if kind.endswith('Open'): + + # Tokenize text that follows as Python up to an unmatched '}' + code_start = self.token_match.end(kind) + self.code_start_line = self.pos_to_line(code_start) + + close_pos = tokenize_python_to_unmatched_close_curly( + self.template, code_start, self.line_starts) + self.code_text = self.template[code_start:close_pos] + yield kind + + if (kind == 'gybBlockOpen'): + # Absorb any '}% \n' + m2 = gyb_block_close.match(self.template, close_pos) + if not m2: + raise ValueError("Invalid block closure") + next_pos = m2.end(0) + else: + assert kind == 'substitutionOpen' + # skip past the closing '}' + next_pos = close_pos + 1 + + # Resume tokenizing after the end of the code. + base_tokens.send(next_pos) + + elif kind == 'gybLines': + + self.code_start_line = self.pos_to_line( + self.token_match.start('gybLines')) + indentation = self.token_match.group('_indent') + + # Strip off the leading indentation and %-sign + source_lines = re.split( + '^' + re.escape(indentation), + self.token_match.group('gybLines') + '\n', + flags=re.MULTILINE)[1:] + + if code_starts_with_dedent_keyword(source_lines): + self.close_lines = True + + last_split = 0 + for line in split_gyb_lines(source_lines): + self.token_kind = 'gybLinesOpen' + self.code_text = ''.join(source_lines[last_split:line]) + yield self.token_kind + last_split = line + self.code_start_line += line - last_split + self.close_lines = False + + self.code_text = ''.join(source_lines[last_split:]) + if self.code_text: + self.token_kind = 'gybLines' + yield self.token_kind + else: + yield self.token_kind + + def next_token(self): + """Move to the next token""" + for kind in self.tokens: + return self.token_kind + + self.token_kind = None + + +class ExecutionContext(object): + """State we pass around during execution of a template""" + + def __init__(self, line_directive='// ###sourceLocation', + **local_bindings): + self.local_bindings = local_bindings + self.line_directive = line_directive + self.local_bindings['__context__'] = self + self.result_text = [] + self.last_file_line = None + + def append_text(self, text, file, line): + # see if we need to inject a line marker + if self.line_directive: + if (file, line) != self.last_file_line: + # We can only insert the line directive at a line break + if len(self.result_text) == 0 \ + or self.result_text[-1].endswith('\n'): + self.result_text.append('%s(file: "%s", line: %d)\n' % ( + self.line_directive, file, line + 1)) + # But if the new text contains any line breaks, we can create + # one + elif '\n' in text: + i = text.find('\n') + self.result_text.append(text[:i + 1]) + self.last_file_line = ( + self.last_file_line[0], self.last_file_line[1] + 1) + # and try again + self.append_text(text[i + 1:], file, line) + return + + self.result_text.append(text) + self.last_file_line = (file, line + text.count('\n')) + + +class ASTNode(object): + """Abstract base class for template AST nodes""" + + def __init__(self): + raise NotImplementedError("ASTNode.__init__ is not implemented.") + + def execute(self, context): + raise NotImplementedError("ASTNode.execute is not implemented.") + + def __str__(self, indent=''): + raise NotImplementedError("ASTNode.__str__ is not implemented.") + + def format_children(self, indent): + if not self.children: + return ' []' + + return '\n'.join( + ['', indent + '['] + + [x.__str__(indent + 4 * ' ') for x in self.children] + + [indent + ']']) + + +class Block(ASTNode): + """A sequence of other AST nodes, to be executed in order""" + + children = [] + + def __init__(self, context): + self.children = [] + + while context.token_kind and not context.close_lines: + if context.token_kind == 'literal': + node = Literal + else: + node = Code + self.children.append(node(context)) + + def execute(self, context): + for x in self.children: + x.execute(context) + + def __str__(self, indent=''): + return indent + 'Block:' + self.format_children(indent) + + +class Literal(ASTNode): + """An AST node that generates literal text""" + + def __init__(self, context): + self.text = context.token_text + start_position = context.token_match.start(context.token_kind) + self.start_line_number = context.pos_to_line(start_position) + self.filename = context.filename + context.next_token() + + def execute(self, context): + context.append_text(self.text, self.filename, self.start_line_number) + + def __str__(self, indent=''): + return '\n'.join( + [indent + x for x in ['Literal:'] + + strip_trailing_nl(self.text).split('\n')]) + + +class Code(ASTNode): + """An AST node that is evaluated as Python""" + + code = None + children = () + kind = None + + def __init__(self, context): + + source = '' + source_line_count = 0 + + def accumulate_code(): + s = source + (context.code_start_line - source_line_count) * '\n' \ + + textwrap.dedent(context.code_text) + line_count = context.code_start_line + \ + context.code_text.count('\n') + context.next_token() + return s, line_count + + eval_exec = 'exec' + if context.token_kind.startswith('substitution'): + eval_exec = 'eval' + source, source_line_count = accumulate_code() + source = '(' + source.strip() + ')' + + else: + while context.token_kind == 'gybLinesOpen': + source, source_line_count = accumulate_code() + source += ' __children__[%d].execute(__context__)\n' % len( + self.children) + source_line_count += 1 + + self.children += (Block(context),) + + if context.token_kind == 'gybLinesClose': + context.next_token() + + if context.token_kind == 'gybLines': + source, source_line_count = accumulate_code() + + # Only handle a substitution as part of this code block if + # we don't already have some %-lines. + elif context.token_kind == 'gybBlockOpen': + + # Opening ${...} and %{...}% constructs + source, source_line_count = accumulate_code() + + self.filename = context.filename + self.start_line_number = context.code_start_line + self.code = compile(source, context.filename, eval_exec) + self.source = source + + def execute(self, context): + # Save __children__ from the local bindings + save_children = context.local_bindings.get('__children__') + # Execute the code with our __children__ in scope + context.local_bindings['__children__'] = self.children + result = eval(self.code, context.local_bindings) + + if context.local_bindings['__children__'] is not self.children: + raise ValueError("The code is not allowed to mutate __children__") + # Restore the bindings + context.local_bindings['__children__'] = save_children + + # If we got a result, the code was an expression, so append + # its value + if result is not None and result != '': + context.append_text( + str(result), self.filename, self.start_line_number) + + def __str__(self, indent=''): + source_lines = re.sub(r'^\n', '', strip_trailing_nl( + self.source), flags=re.MULTILINE).split('\n') + if len(source_lines) == 1: + s = indent + 'Code: {' + source_lines[0] + '}' + else: + s = indent + 'Code:\n' + indent + '{\n' + '\n'.join( + indent + 4 * ' ' + l for l in source_lines + ) + '\n' + indent + '}' + return s + self.format_children(indent) + + +def parse_template(filename, text=None): + r"""Return an AST corresponding to the given template file. + + If text is supplied, it is assumed to be the contents of the file, + as a string. + + >>> print parse_template('dummy.file', text= + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add an output line after this line to fix the bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''') + Block: + [ + Code: + { + for x in [1, 2, 3]: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: + { + if x == 1: + __children__[0].execute(__context__) + elif x > 1: # add output line after this line to fix bug + __children__[1].execute(__context__) + } + [ + Block: + [ + Literal: + literal1 + ] + Block: + [ + Code: + { + if x == 2: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + literal2 + ] + ] + ] + ] + ] + ] + ] + + >>> print parse_template( + >>> 'dummy.file', text='%for x in range(10):\n% print x\n%end\njuicebox') + Block: + [ + Code: + { + for x in range(10): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print x} [] + ] + ] + Literal: + juicebox + ] + + >>> print parse_template('/dummy.file', text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + Block: + [ + Literal: + Nothing + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: + { + for i in range(3): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {(i)} [] + Literal: + + ] + ] + ] + Block: + [ + Literal: + THIS SHOULD NOT APPEAR IN THE OUTPUT + ] + ] + ] + + >>> print parse_template('dummy.file', text='''% + ... %for x in y: + ... % print y + ... ''') + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print y} [] + ] + ] + ] + + >>> print parse_template('dummy.file', text='''% + ... %if x: + ... % print y + ... AAAA + ... %else: + ... BBBB + ... ''') + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print y} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print parse_template('dummy.file', text='''% + ... %if x: + ... % print y + ... AAAA + ... %# This is a comment + ... %else: + ... BBBB + ... ''') + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + # This is a comment + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print y} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print parse_template('dummy.file', text='''\ + ... %for x in y: + ... AAAA + ... %if x: + ... BBBB + ... %end + ... CCCC + ... ''') + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + AAAA + Code: + { + if x: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + BBBB + ] + ] + Literal: + CCCC + ] + ] + ] + """ + return Block(ParseContext(filename, text)) + + +def execute_template(ast, line_directive='', **local_bindings): + r"""Return the text generated by executing the given template AST. + + Keyword arguments become local variable bindings in the execution context + + >>> ast = parse_template('/dummy.file', text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> print execute_template(ast, line_directive='//#sourceLocation', x=1), + //#sourceLocation(file: "/dummy.file", line: 1) + Nothing + //#sourceLocation(file: "/dummy.file", line: 4) + 0 + //#sourceLocation(file: "/dummy.file", line: 4) + 1 + //#sourceLocation(file: "/dummy.file", line: 4) + 2 + + >>> ast = parse_template('/dummy.file', text= + ... '''Nothing + ... % a = [] + ... % for x in range(3): + ... % a.append(x) + ... % end + ... ${a} + ... ''') + >>> print execute_template(ast, line_directive='//#sourceLocation', x=1), + //#sourceLocation(file: "/dummy.file", line: 1) + Nothing + //#sourceLocation(file: "/dummy.file", line: 6) + [0, 1, 2] + """ + execution_context = ExecutionContext( + line_directive=line_directive, **local_bindings) + ast.execute(execution_context) + return ''.join(execution_context.result_text) + + +def main(): + import argparse + import sys + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Generate Your Boilerplate!', epilog=''' + A GYB template consists of the following elements: + + - Literal text which is inserted directly into the output + + - %% or $$ in literal text, which insert literal '%' and '$' + symbols respectively. + + - Substitutions of the form ${}. The Python + expression is converted to a string and the result is inserted + into the output. + + - Python code delimited by %{...}%. Typically used to inject + definitions (functions, classes, variable bindings) into the + evaluation context of the template. Common indentation is + stripped, so you can add as much indentation to the beginning + of this code as you like + + - Lines beginning with optional whitespace followed by a single + '%' and Python code. %-lines allow you to nest other + constructs inside them. To close a level of nesting, use the + "%end" construct. + + - Lines beginning with optional whitespace and followed by a + single '%' and the token "end", which close open constructs in + %-lines. + + Example template: + + - Hello - + %{ + x = 42 + def succ(a): + return a+1 + }% + + I can assure you that ${x} < ${succ(x)} + + % if int(y) > 7: + % for i in range(3): + y is greater than seven! + % end + % else: + y is less than or equal to seven + % end + + - The End. - + + When run with "gyb -Dy=9", the output is + + - Hello - + + I can assure you that 42 < 43 + + y is greater than seven! + y is greater than seven! + y is greater than seven! + + - The End. - +''' + ) + parser.add_argument( + '-D', action='http://github.com/append', dest='defines', metavar='NAME=VALUE', + default=[], + help='''Bindings to be set in the template's execution context''') + + parser.add_argument( + 'file', type=argparse.FileType(), + help='Path to GYB template file (defaults to stdin)', nargs='?', + default=sys.stdin) + parser.add_argument( + '-o', dest='target', type=argparse.FileType('w'), + help='Output file (defaults to stdout)', default=sys.stdout) + parser.add_argument( + '--test', action='http://github.com/store_true', + default=False, help='Run a self-test') + parser.add_argument( + '--verbose-test', action='http://github.com/store_true', + default=False, help='Run a verbose self-test') + parser.add_argument( + '--dump', action='http://github.com/store_true', + default=False, help='Dump the parsed template to stdout') + parser.add_argument( + '--line-directive', default='// ###sourceLocation', + help='Line directive prefix; empty => no line markers') + + args = parser.parse_args(sys.argv[1:]) + + if args.test or args.verbose_test: + import doctest + if doctest.testmod(verbose=args.verbose_test).failed: + sys.exit(1) + + bindings = dict(x.split('=', 1) for x in args.defines) + ast = parse_template(args.file.name, args.file.read()) + if args.dump: + print(ast) + # Allow the template to import .py files from its own directory + sys.path = [os.path.split(args.file.name)[0] or '.'] + sys.path + + args.target.write(execute_template(ast, args.line_directive, **bindings)) + +if __name__ == '__main__': + main() From 00571ad722bbae5143eae434c1e7d7bfded16348 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Thu, 12 May 2016 21:13:28 -0700 Subject: [PATCH 310/460] Git ignore for python byte code and GYB generated files. --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 2e900d7..08490e1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,9 @@ Carthage/Build Carthage/Checkouts build/ +# Python bytecode +*.pyc + +# Generated Files +Sources/Generated\ Files/ + From 603f995535d7a86986c22cd14716b3b927af2af4 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Thu, 12 May 2016 21:14:09 -0700 Subject: [PATCH 311/460] Generate definitions of zip and map Uses GYB to generate instances of `zip` and `map` for up to an arity of 22. --- Sources/Gen.swift | 172 --------------------------- Sources/Monoidal.swift.gyb | 66 ++++++++++ SwiftCheck.xcodeproj/project.pbxproj | 34 ++++++ 3 files changed, 100 insertions(+), 172 deletions(-) create mode 100644 Sources/Monoidal.swift.gyb diff --git a/Sources/Gen.swift b/Sources/Gen.swift index d7c2905..dc87665 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -141,178 +141,6 @@ public struct Gen { } } -extension Gen /*: Cartesian*/ { - /// Zips together 2 generators of type `A` and `B` into a generator of pairs. - public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return Gen<(A, B)>(unGen: { r, n in - let (r1, r2) = r.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n)) - }) - } - - /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of - /// triples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { - return Gen<(A, B, C)>(unGen: { r, n in - let (r1, r2_) = r.split - let (r2, r3) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) - }) - } - - /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a - /// generator of quadruples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { - return Gen<(A, B, C, D)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1, r2) = r1_.split - let (r3, r4) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) - }) - } - - /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a - /// generator of quintuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { - return Gen<(A, B, C, D, E)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r1) = r1_.split - let (r2, r3) = r2_.split - let (r4, r5) = r1__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) - }) - } - - /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into - /// a generator of sextuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { - return Gen<(A, B, C, D, E, F)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1, r2) = r2_.split - let (r3, r4) = r1__.split - let (r5, r6) = r2__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) - }) - } - - /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` - /// into a generator of septuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { - return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r1) = r2_.split - let (r2, r3) = r1__.split - let (r4, r5) = r2__.split - let (r6, r7) = r1___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) - }) - } - - /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and - /// `H` into a generator of octuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { - return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1, r2) = r1__.split - let (r3, r4) = r2__.split - let (r5, r6) = r1___.split - let (r7, r8) = r2___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) - }) - } - - /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, and `I` into a generator of nonuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { - return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r1) = r1__.split - let (r2, r3) = r2__.split - let (r4, r5) = r1___.split - let (r6, r7) = r2___.split - let (r8, r9) = r1____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) - }) - } - - /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, `I`, and `J` into a generator of decuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { - return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r2____) = r1__.split - let (r1, r2) = r2__.split - let (r3, r4) = r1___.split - let (r5, r6) = r2___.split - let (r7, r8) = r1____.split - let (r9, r10) = r2____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) - }) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// three receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// four receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// five receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// six receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// seven receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// eight receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// nine receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// ten receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) - } -} - // MARK: Generator Modifiers extension Gen { diff --git a/Sources/Monoidal.swift.gyb b/Sources/Monoidal.swift.gyb new file mode 100644 index 0000000..46e3c3a --- /dev/null +++ b/Sources/Monoidal.swift.gyb @@ -0,0 +1,66 @@ +// +// Monoidal.swift.gyb +// SwiftCheck +// +// Created by Adam Kuipers on 5/10/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +%{ +max_arity = 22 +}% + +extension Gen /*: Cartesian*/ { + /// Zips together two generators and returns a generator of tuples. + public static func zip(ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { + return Gen<(A1, A2)> { r, n in + let (r1, r2) = r.split + return (ga1.unGen(r1, n), ga2.unGen(r2, n)) + } + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } +% for arity in range(3, max_arity + 1): + +%{ + +# Zip definition template +type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) +parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(2, arity + 1)]) + +# Zip body template +previous_parameter_range = range(1, arity) + +previous_zip_type_arguments = ', '.join(['A{0}'.format(n) for n in previous_parameter_range]) +previous_zip_arguments = ', '.join(['ga{0}'.format(n) for n in previous_parameter_range]) +expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_parameter_range]) + +# Map body template +map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) + +}% + /// Zips together ${arity} generators generator of tuples. + public static func zip<${type_parameter_list}>(ga1 : Gen, ${parameter_list}) -> Gen<(${type_parameter_list})> { + return Gen<(${previous_zip_type_arguments}, A${arity})> + .zip( + .zip(${previous_zip_arguments}), + ga${arity} + ).map { + ( + ${expanded_previous_tuple}, + $$1 + ) + } + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map<${type_parameter_list}, R>(ga1 : Gen, ${parameter_list}, transform: (${type_parameter_list}) -> R) -> Gen { + return zip(${map_zip_argument_list}).map(transform) + } +% end +} diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index e1d718f..7903aeb 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -105,6 +105,8 @@ 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; + FA3AD5371CE53BB30098B92B /* Monoidal.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */; }; + FA7865841CE581810077CD7C /* Monoidal.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7865831CE581810077CD7C /* Monoidal.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -194,6 +196,8 @@ 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Monoidal.swift.gyb; path = Sources/Monoidal.swift.gyb; sourceTree = SOURCE_ROOT; }; + FA7865831CE581810077CD7C /* Monoidal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Monoidal.swift; path = "Sources/Generated Files/Monoidal.swift"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -271,6 +275,8 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( + FA7865821CE580960077CD7C /* Generated Files */, + FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */, 826D81461C953D070022266C /* Arbitrary.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 826D81491C953D070022266C /* Gen.swift */, @@ -330,6 +336,15 @@ name = "Supporting Files"; sourceTree = ""; }; + FA7865821CE580960077CD7C /* Generated Files */ = { + isa = PBXGroup; + children = ( + FA7865831CE581810077CD7C /* Monoidal.swift */, + ); + name = "Generated Files"; + path = "Sources/Generated Files"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -401,6 +416,7 @@ isa = PBXNativeTarget; buildConfigurationList = 844FCCA3198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheck" */; buildPhases = ( + FA7865811CE57F430077CD7C /* ShellScript */, 844FCC88198B320500EB242A /* Sources */, 844FCC89198B320500EB242A /* Frameworks */, 844FCC8A198B320500EB242A /* Headers */, @@ -542,6 +558,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + FA3AD5371CE53BB30098B92B /* Monoidal.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -568,6 +585,22 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + FA7865811CE57F430077CD7C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "./Utils/gyb -o ./Sources/Generated\\ Files/Monoidal.swift Sources/Monoidal.swift.gyb\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 8240CCAC1C3A123600EF4D29 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -629,6 +662,7 @@ 826D81851C953D070022266C /* TestOperators.swift in Sources */, 826D81761C953D070022266C /* Rose.swift in Sources */, 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, + FA7865841CE581810077CD7C /* Monoidal.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, 826D81791C953D070022266C /* State.swift in Sources */, From 9e33bc84bc126fe526440d85e1703cc443d55369 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Thu, 12 May 2016 21:29:54 -0700 Subject: [PATCH 312/460] Rename Monoidal to Cartesian. --- ...{Monoidal.swift.gyb => Cartesian.swift.gyb} | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) rename Sources/{Monoidal.swift.gyb => Cartesian.swift.gyb} (98%) diff --git a/Sources/Monoidal.swift.gyb b/Sources/Cartesian.swift.gyb similarity index 98% rename from Sources/Monoidal.swift.gyb rename to Sources/Cartesian.swift.gyb index 46e3c3a..a7fdd63 100644 --- a/Sources/Monoidal.swift.gyb +++ b/Sources/Cartesian.swift.gyb @@ -1,5 +1,5 @@ // -// Monoidal.swift.gyb +// Cartesian.swift.gyb // SwiftCheck // // Created by Adam Kuipers on 5/10/16. diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 7903aeb..52e47d0 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -105,8 +105,8 @@ 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - FA3AD5371CE53BB30098B92B /* Monoidal.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */; }; - FA7865841CE581810077CD7C /* Monoidal.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7865831CE581810077CD7C /* Monoidal.swift */; }; + FA3AD5371CE53BB30098B92B /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */; }; + FA7865841CE581810077CD7C /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7865831CE581810077CD7C /* Cartesian.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -196,8 +196,8 @@ 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Monoidal.swift.gyb; path = Sources/Monoidal.swift.gyb; sourceTree = SOURCE_ROOT; }; - FA7865831CE581810077CD7C /* Monoidal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Monoidal.swift; path = "Sources/Generated Files/Monoidal.swift"; sourceTree = SOURCE_ROOT; }; + FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cartesian.swift.gyb; path = Sources/Cartesian.swift.gyb; sourceTree = SOURCE_ROOT; }; + FA7865831CE581810077CD7C /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = "Sources/Generated Files/Cartesian.swift"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -276,7 +276,7 @@ isa = PBXGroup; children = ( FA7865821CE580960077CD7C /* Generated Files */, - FA3AD5361CE53BB30098B92B /* Monoidal.swift.gyb */, + FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */, 826D81461C953D070022266C /* Arbitrary.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 826D81491C953D070022266C /* Gen.swift */, @@ -339,7 +339,7 @@ FA7865821CE580960077CD7C /* Generated Files */ = { isa = PBXGroup; children = ( - FA7865831CE581810077CD7C /* Monoidal.swift */, + FA7865831CE581810077CD7C /* Cartesian.swift */, ); name = "Generated Files"; path = "Sources/Generated Files"; @@ -558,7 +558,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FA3AD5371CE53BB30098B92B /* Monoidal.swift.gyb in Resources */, + FA3AD5371CE53BB30098B92B /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -597,7 +597,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "./Utils/gyb -o ./Sources/Generated\\ Files/Monoidal.swift Sources/Monoidal.swift.gyb\n"; + shellScript = "./Utils/gyb -o ./Sources/Generated\\ Files/Cartesian.swift Sources/Cartesian.swift.gyb\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -662,7 +662,7 @@ 826D81851C953D070022266C /* TestOperators.swift in Sources */, 826D81761C953D070022266C /* Rose.swift in Sources */, 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, - FA7865841CE581810077CD7C /* Monoidal.swift in Sources */, + FA7865841CE581810077CD7C /* Cartesian.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, 826D81791C953D070022266C /* State.swift in Sources */, From 93b1f030c592672738d4f49feddda08a36427ecb Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Wed, 15 Jun 2016 00:02:26 -0700 Subject: [PATCH 313/460] 'migrate' to 2.3 --- SwiftCheck.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index e1d718f..d729080 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -488,9 +488,11 @@ }; 844FCC8C198B320500EB242A = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; }; 844FCC97198B320500EB242A = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; TestTargetID = 844FCC8C198B320500EB242A; }; 84DF75F71B0BD54600C912B0 = { @@ -929,6 +931,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -961,6 +964,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 2.3; }; name = Release; }; @@ -982,6 +986,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -1000,6 +1005,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; }; name = Release; }; From 447520289f36394da0605aea0eccf17c8d5f5a6f Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Thu, 16 Jun 2016 15:43:33 -0700 Subject: [PATCH 314/460] Builds with warnings and passes --- Sources/Arbitrary.swift | 65 ++--- Sources/CoArbitrary.swift | 50 ++-- Sources/Gen.swift | 130 ++++----- Sources/Lattice.swift | 22 +- Sources/Modifiers.swift | 93 +++--- Sources/Property.swift | 176 ++++++------ Sources/Random.swift | 52 ++-- Sources/Rose.swift | 66 ++--- Sources/Test.swift | 264 +++++++++--------- Sources/TestOperators.swift | 20 +- Sources/Testable.swift | 2 +- Sources/Witness.swift | 34 +-- Sources/WitnessedArbitrary.swift | 118 ++++---- SwiftCheck.xcodeproj/project.pbxproj | 17 +- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcschemes/SwiftCheck.xcscheme | 10 +- Tests/ComplexSpec.swift | 24 +- Tests/DiscardSpec.swift | 2 +- Tests/FailureSpec.swift | 14 +- Tests/GenSpec.swift | 32 +-- Tests/LambdaSpec.swift | 84 +++--- Tests/ModifierSpec.swift | 6 +- Tests/PathSpec.swift | 12 +- Tests/PropertySpec.swift | 20 +- Tests/RawRepresentableSpec.swift | 16 +- Tests/ReplaySpec.swift | 2 +- Tests/RoseSpec.swift | 22 +- Tests/ShrinkSpec.swift | 2 +- Tests/SimpleSpec.swift | 11 +- Tests/TestSpec.swift | 14 +- 31 files changed, 687 insertions(+), 697 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 98cbe6e..b63b295 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -61,15 +61,15 @@ extension Arbitrary { } } -extension IntegerType { +extension Integer { /// Shrinks any `IntegerType`. public var shrinkIntegral : [Self] { return unfoldr({ i in if i <= 0 { - return .None + return .none } let n = i / 2 - return .Some((n, n)) + return .some((n, n)) }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) } } @@ -90,7 +90,7 @@ extension Bool : Arbitrary { } /// The default shrinking function for `Bool`ean values. - public static func shrink(x : Bool) -> [Bool] { + public static func shrink(_ x : Bool) -> [Bool] { if x { return [false] } @@ -107,7 +107,7 @@ extension Int : Arbitrary { } /// The default shrinking function for `Int` values. - public static func shrink(x : Int) -> [Int] { + public static func shrink(_ x : Int) -> [Int] { return x.shrinkIntegral } } @@ -121,7 +121,7 @@ extension Int8 : Arbitrary { } /// The default shrinking function for `Int8` values. - public static func shrink(x : Int8) -> [Int8] { + public static func shrink(_ x : Int8) -> [Int8] { return x.shrinkIntegral } } @@ -135,7 +135,7 @@ extension Int16 : Arbitrary { } /// The default shrinking function for `Int16` values. - public static func shrink(x : Int16) -> [Int16] { + public static func shrink(_ x : Int16) -> [Int16] { return x.shrinkIntegral } } @@ -149,7 +149,7 @@ extension Int32 : Arbitrary { } /// The default shrinking function for `Int32` values. - public static func shrink(x : Int32) -> [Int32] { + public static func shrink(_ x : Int32) -> [Int32] { return x.shrinkIntegral } } @@ -163,7 +163,7 @@ extension Int64 : Arbitrary { } /// The default shrinking function for `Int64` values. - public static func shrink(x : Int64) -> [Int64] { + public static func shrink(_ x : Int64) -> [Int64] { return x.shrinkIntegral } } @@ -175,7 +175,7 @@ extension UInt : Arbitrary { } /// The default shrinking function for `UInt` values. - public static func shrink(x : UInt) -> [UInt] { + public static func shrink(_ x : UInt) -> [UInt] { return x.shrinkIntegral } } @@ -189,7 +189,7 @@ extension UInt8 : Arbitrary { } /// The default shrinking function for `UInt8` values. - public static func shrink(x : UInt8) -> [UInt8] { + public static func shrink(_ x : UInt8) -> [UInt8] { return x.shrinkIntegral } } @@ -201,7 +201,7 @@ extension UInt16 : Arbitrary { } /// The default shrinking function for `UInt16` values. - public static func shrink(x : UInt16) -> [UInt16] { + public static func shrink(_ x : UInt16) -> [UInt16] { return x.shrinkIntegral } } @@ -213,7 +213,7 @@ extension UInt32 : Arbitrary { } /// The default shrinking function for `UInt32` values. - public static func shrink(x : UInt32) -> [UInt32] { + public static func shrink(_ x : UInt32) -> [UInt32] { return x.shrinkIntegral } } @@ -225,7 +225,7 @@ extension UInt64 : Arbitrary { } /// The default shrinking function for `UInt64` values. - public static func shrink(x : UInt64) -> [UInt64] { + public static func shrink(_ x : UInt64) -> [UInt64] { return x.shrinkIntegral } } @@ -250,13 +250,13 @@ extension Float : Arbitrary { } /// The default shrinking function for `Float` values. - public static func shrink(x : Float) -> [Float] { + public static func shrink(_ x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { - return .None + return .none } let n = i / 2.0 - return .Some((n, n)) + return .some((n, n)) }, initial: x) } } @@ -281,13 +281,13 @@ extension Double : Arbitrary { } /// The default shrinking function for `Double` values. - public static func shrink(x : Double) -> [Double] { + public static func shrink(_ x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { - return .None + return .none } let n = i / 2.0 - return .Some((n, n)) + return .some((n, n)) }, initial: x) } } @@ -299,7 +299,7 @@ extension UnicodeScalar : Arbitrary { } /// The default shrinking function for `UnicodeScalar` values. - public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { + public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value)))) return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } } @@ -313,7 +313,7 @@ extension String : Arbitrary { } /// The default shrinking function for `String` values. - public static func shrink(s : String) -> [String] { + public static func shrink(_ s : String) -> [String] { return [Character].shrink([Character](s.characters)).map { String($0) } } } @@ -325,23 +325,16 @@ extension Character : Arbitrary { } /// The default shrinking function for `Character` values. - public static func shrink(x : Character) -> [Character] { + public static func shrink(_ x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) } } -extension AnyForwardIndex : Arbitrary { +extension AnyIndex : Arbitrary { /// Returns a generator of `AnyForwardIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyForwardIndex.init) - } -} - -extension AnyRandomAccessIndex : Arbitrary { - /// Returns a generator of `AnyRandomAccessIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyRandomAccessIndex.init) + public static var arbitrary : Gen { + return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) } } @@ -373,7 +366,7 @@ extension Mirror : Arbitrary { // MARK: - Implementation Details Follow -private func asAny(x : T) -> Any { +private func asAny(_ x : T) -> Any { return x } @@ -383,11 +376,11 @@ extension Array where Element : Hashable { } } -private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { +private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { var acc = [A]() var ini = initial while let next = f(ini) { - acc.insert(next.0, atIndex: 0) + acc.insert(next.0, at: 0) ini = next.1 } return acc diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index c238d5b..37c4e07 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -19,12 +19,12 @@ public protocol CoArbitrary { /// Uses an instance of the receiver to return a function that perturbs a /// generator. - static func coarbitrary(x : Self) -> (Gen -> Gen) + static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } -extension IntegerType { +extension Integer { /// A coarbitrary implementation for any IntegerType - public func coarbitraryIntegral() -> Gen -> Gen { + public func coarbitraryIntegral() -> (Gen) -> Gen { return { $0.variant(self) } } } @@ -32,13 +32,13 @@ extension IntegerType { /// A coarbitrary implementation for any Printable type. Avoid using this /// function if you can, it can be quite an expensive operation given a detailed /// enough description. -public func coarbitraryPrintable(x : A) -> Gen -> Gen { +public func coarbitraryPrintable(_ x : A) -> (Gen) -> Gen { return String.coarbitrary(String(x)) } extension Bool : CoArbitrary { /// The default coarbitrary implementation for `Bool` values. - public static func coarbitrary(x : Bool) -> Gen -> Gen { + public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { return { g in if x { return g.variant(1) @@ -50,14 +50,14 @@ extension Bool : CoArbitrary { extension UnicodeScalar : CoArbitrary { /// The default coarbitrary implementation for `UnicodeScalar` values. - public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { + public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { return UInt32.coarbitrary(x.value) } } extension Character : CoArbitrary { /// The default coarbitrary implementation for `Character` values. - public static func coarbitrary(x : Character) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { let ss = String(x).unicodeScalars return UnicodeScalar.coarbitrary(ss[ss.startIndex]) } @@ -65,80 +65,80 @@ extension Character : CoArbitrary { extension String : CoArbitrary { /// The default coarbitrary implementation for `String` values. - public static func coarbitrary(x : String) -> (Gen -> Gen) { + public static func coarbitrary(_ x : String) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.startIndex.successor()..(x : Int) -> Gen -> Gen { + public static func coarbitrary(_ x : Int) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { /// The default coarbitrary implementation for `Int8` values. - public static func coarbitrary(x : Int8) -> Gen -> Gen { + public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { /// The default coarbitrary implementation for `Int16` values. - public static func coarbitrary(x : Int16) -> Gen -> Gen { + public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { /// The default coarbitrary implementation for `Int32` values. - public static func coarbitrary(x : Int32) -> Gen -> Gen { + public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { /// The default coarbitrary implementation for `Int64` values. - public static func coarbitrary(x : Int64) -> Gen -> Gen { + public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { /// The default coarbitrary implementation for `UInt` values. - public static func coarbitrary(x : UInt) -> Gen -> Gen { + public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { /// The default coarbitrary implementation for `UInt8` values. - public static func coarbitrary(x : UInt8) -> Gen -> Gen { + public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { /// The default coarbitrary implementation for `UInt16` values. - public static func coarbitrary(x : UInt16) -> Gen -> Gen { + public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { /// The default coarbitrary implementation for `UInt32` values. - public static func coarbitrary(x : UInt32) -> Gen -> Gen { + public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { /// The default coarbitrary implementation for `UInt64` values. - public static func coarbitrary(x : UInt64) -> Gen -> Gen { + public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } @@ -146,21 +146,21 @@ extension UInt64 : CoArbitrary { // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { /// The default coarbitrary implementation for `Float` values. - public static func coarbitrary(x : Float) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { /// The default coarbitrary implementation for `Double` values. - public static func coarbitrary(x : Double) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Array : CoArbitrary { /// The default coarbitrary implementation for an `Array` of values. - public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { + public static func coarbitrary(_ a : [Element]) -> ((Gen) -> Gen) { if a.isEmpty { return { $0.variant(0) } } @@ -170,7 +170,7 @@ extension Array : CoArbitrary { extension Dictionary : CoArbitrary { /// The default coarbitrary implementation for a `Dictionary` of values. - public static func coarbitrary(x : Dictionary) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Dictionary) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } @@ -180,7 +180,7 @@ extension Dictionary : CoArbitrary { extension Optional : CoArbitrary { /// The default coarbitrary implementation for `Optional` values. - public static func coarbitrary(x : Optional) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { if let _ = x { return { $0.variant(0) } } @@ -190,7 +190,7 @@ extension Optional : CoArbitrary { extension Set : CoArbitrary { /// The default coarbitrary implementation for `Set`s of values. - public static func coarbitrary(x : Set) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index d7c2905..537bd5e 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,8 +44,8 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf>(xs : S) -> Gen { - return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).map { i in + public static func fromElementsOf>(_ xs : S) -> Gen { + return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } } @@ -54,10 +54,10 @@ public struct Gen { /// interval and produces only that value. /// /// The input interval is required to be non-empty. - public static func fromElementsIn(xs : S) -> Gen { + public static func fromElementsIn(_ xs : ClosedRange) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") - return choose((xs.start, xs.end)) + return choose((xs.lowerBound, xs.upperBound)) } /// Constructs a Generator that uses a given array to produce smaller arrays @@ -65,24 +65,24 @@ public struct Gen { /// increases with the receiver's size parameter. /// /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { + public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") return Gen<[S]>.sized { n in - let ss = xs[xs.startIndex...pure([S](ss)) } } /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { + public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sort({ l, r in l.0 < r.0 }).map { $0.1 }) + return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(isOrderedBefore: { l, r in l.0 < r.0 }).map { $0.1 }) } } /// Constructs a generator that depends on a size parameter. - public static func sized(f : Int -> Gen) -> Gen { + public static func sized(_ f : (Int) -> Gen) -> Gen { return Gen(unGen: { r, n in return f(n).unGen(r, n) }) @@ -94,7 +94,7 @@ public struct Gen { /// generic parameter `A`. For example: /// /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - public static func choose(rng : (A, A)) -> Gen { + public static func choose(_ rng : (A, A)) -> Gen { return Gen(unGen: { s, _ in return A.randomInRange(rng, gen: s).0 }) @@ -105,11 +105,11 @@ public struct Gen { /// /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf, S.Index : protocol>(gs : S) -> Gen { + public static func oneOf, S.Index : protocol, S.Index : RandomType>(_ gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.indices.startIndex, gs.indices.endIndex.predecessor())) >>- { x in - return gs[x] + return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in + return gs[x] } } @@ -119,7 +119,7 @@ public struct Gen { /// Only use this function when you need to assign uneven "weights" to each /// generator. If all generators need to have an equal chance of being /// selected, use `Gen.oneOf`. - public static func frequency)>(xs : S) -> Gen { + public static func frequency)>(_ xs : S) -> Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") @@ -136,14 +136,14 @@ public struct Gen { /// than only Generators. It can help in cases where your `Gen.from*` call /// contains only `Gen.pure` calls by allowing you to remove every /// `Gen.pure` in favor of a direct list of values. - public static func weighted(xs : S) -> Gen { + public static func weighted(_ xs : S) -> Gen { return frequency(xs.map { ($0, Gen.pure($1)) }) } } extension Gen /*: Cartesian*/ { /// Zips together 2 generators of type `A` and `B` into a generator of pairs. - public static func zip(gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { return Gen<(A, B)>(unGen: { r, n in let (r1, r2) = r.split return (gen1.unGen(r1, n), gen2.unGen(r2, n)) @@ -152,7 +152,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of /// triples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { return Gen<(A, B, C)>(unGen: { r, n in let (r1, r2_) = r.split let (r2, r3) = r2_.split @@ -162,7 +162,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a /// generator of quadruples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { return Gen<(A, B, C, D)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1, r2) = r1_.split @@ -173,7 +173,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a /// generator of quintuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { return Gen<(A, B, C, D, E)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r1) = r1_.split @@ -185,7 +185,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into /// a generator of sextuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { return Gen<(A, B, C, D, E, F)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r2__) = r1_.split @@ -198,7 +198,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` /// into a generator of septuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r2__) = r1_.split @@ -212,7 +212,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and /// `H` into a generator of octuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r2__) = r1_.split @@ -227,7 +227,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, /// `H`, and `I` into a generator of nonuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r2__) = r1_.split @@ -243,7 +243,7 @@ extension Gen /*: Cartesian*/ { /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, /// `H`, `I`, and `J` into a generator of decuples. - public static func zip(gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in let (r1_, r2_) = r.split let (r1__, r2__) = r1_.split @@ -260,55 +260,55 @@ extension Gen /*: Cartesian*/ { /// Returns a new generator that applies a given function to any outputs the /// two receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { return zip(ga1, ga2).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// three receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: (A1, A2, A3) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: (A1, A2, A3) -> R) -> Gen { return zip(ga1, ga2, ga3).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// four receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: (A1, A2, A3, A4) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: (A1, A2, A3, A4) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// five receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: (A1, A2, A3, A4, A5) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: (A1, A2, A3, A4, A5) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// six receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: (A1, A2, A3, A4, A5, A6) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// seven receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// eight receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// nine receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// ten receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) } } @@ -317,14 +317,14 @@ extension Gen /*: Cartesian*/ { extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. - public func variant(seed : S) -> Gen { + public func variant(_ seed : S) -> Gen { return Gen(unGen: { rng, n in return self.unGen(vary(seed, rng), n) }) } /// Modifies a Generator to always use a given size. - public func resize(n : Int) -> Gen { + public func resize(_ n : Int) -> Gen { return Gen(unGen: { r, _ in return self.unGen(r, n) }) @@ -332,7 +332,7 @@ extension Gen { /// Modifiers a Generator's size parameter by transforming it with the given /// function. - public func scale(f : Int -> Int) -> Gen { + public func scale(_ f : (Int) -> Int) -> Gen { return Gen.sized { n in return self.resize(f(n)) } @@ -346,14 +346,14 @@ extension Gen { /// executing a condition that fails more often than it succeeds may result /// in a space leak. At that point, it is better to use `suchThatOptional` /// or `.invert` the test case. - public func suchThat(p : A -> Bool) -> Gen { + public func suchThat(_ p : (A) -> Bool) -> Gen { return self.suchThatOptional(p).flatMap { mx in switch mx { - case .Some(let x): + case .some(let x): return Gen.pure(x) - case .None: + case .none: return Gen.sized { n in - return self.suchThat(p).resize(n.successor()) + return self.suchThat(p).resize((n + 1)) } } } @@ -363,7 +363,7 @@ extension Gen { /// satisfy a predicate. All attempts are encoded in the form of an /// `Optional` where values satisfying the predicate are wrapped in `.Some` /// and failing values are `.None`. - public func suchThatOptional(p : A -> Bool) -> Gen> { + public func suchThatOptional(_ p : (A) -> Bool) -> Gen> { return Gen>.sized { n in return attemptBoundedTry(self, 0, max(n, 1), p) } @@ -386,8 +386,8 @@ extension Gen { } /// Modifies a Generator such that it only produces arrays of a given length. - public func proliferateSized(k : Int) -> Gen<[A]> { - return sequence(Array>(count: k, repeatedValue: self)) + public func proliferateSized(_ k : Int) -> Gen<[A]> { + return sequence(Array>(repeating: self, count: k)) } } @@ -396,7 +396,7 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the /// receiver creates. - public func map(f : A -> B) -> Gen { + public func map(_ f : (A) -> B) -> Gen { return f <^> self } } @@ -409,7 +409,7 @@ extension Gen /*: Functor*/ { /// values that you then `.proliferate` into an `Array` of `Character`s. You /// can then use `fmap` to convert that generator of `Array`s to a generator of /// `String`s. -public func <^> (f : A -> B, g : Gen) -> Gen { +public func <^> (f : (A) -> B, g : Gen) -> Gen { return Gen(unGen: { r, n in return f(g.unGen(r, n)) }) @@ -417,7 +417,7 @@ public func <^> (f : A -> B, g : Gen) -> Gen { extension Gen /*: Applicative*/ { /// Lifts a value into a generator that will only generate that value. - public static func pure(a : A) -> Gen { + public static func pure(_ a : A) -> Gen { return Gen(unGen: { _ in return a }) @@ -425,7 +425,7 @@ extension Gen /*: Applicative*/ { /// Given a generator of functions, applies any generated function to any /// outputs the receiver creates. - public func ap(fn : Gen B>) -> Gen { + public func ap(_ fn : Gen<(A) -> B>) -> Gen { return fn <*> self } } @@ -445,7 +445,7 @@ extension Gen /*: Applicative*/ { /// /// Promotes function application to a Generator of functions applied to a /// Generator of values. -public func <*> (fn : Gen B>, g : Gen) -> Gen { +public func <*> (fn : Gen<(A) -> B>, g : Gen) -> Gen { return Gen(unGen: { r, n in let (r1, r2) = r.split return fn.unGen(r1, n)(g.unGen(r2, n)) @@ -460,7 +460,7 @@ extension Gen /*: Monad*/ { /// generators. One might, for example, use a Generator of integers to /// control the length of a Generator of strings, or use it to choose a /// random index into a Generator of arrays. - public func flatMap(fn : A -> Gen) -> Gen { + public func flatMap(_ fn : (A) -> Gen) -> Gen { return self >>- fn } } @@ -472,7 +472,7 @@ extension Gen /*: Monad*/ { /// generators. One might, for example, use a Generator of integers to control /// the length of a Generator of strings, or use it to choose a random index /// into a Generator of arrays. -public func >>- (m : Gen, fn : A -> Gen) -> Gen { +public func >>- (m : Gen, fn : (A) -> Gen) -> Gen { return Gen(unGen: { r, n in let (r1, r2) = r.split let m2 = fn(m.unGen(r1, n)) @@ -486,7 +486,7 @@ public func >>- (m : Gen, fn : A -> Gen) -> Gen { /// The array that is created is guaranteed to use each of the given Generators /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. -public func sequence(ms : [Gen]) -> Gen<[A]> { +public func sequence(_ ms : [Gen]) -> Gen<[A]> { return ms.reduce(Gen<[A]>.pure([]), combine: { n, m in return m.flatMap { x in return n.flatMap { xs in @@ -497,7 +497,7 @@ public func sequence(ms : [Gen]) -> Gen<[A]> { } /// Flattens a generator of generators by one level. -public func join(rs : Gen>) -> Gen { +public func join(_ rs : Gen>) -> Gen { return rs.flatMap { x in return x } @@ -505,29 +505,29 @@ public func join(rs : Gen>) -> Gen { /// Lifts a function from some A to some R to a function from generators of A to /// generators of R. -public func liftM(f : A -> R, _ m1 : Gen) -> Gen { +public func liftM(_ f : (A) -> R, _ m1 : Gen) -> Gen { return m1.flatMap{ x1 in return Gen.pure(f(x1)) } } /// Promotes a rose of generators to a generator of rose values. -public func promote(x : Rose>) -> Gen> { +public func promote(_ x : Rose>) -> Gen> { return delay().flatMap { eval in return Gen>.pure(liftM(eval, x)) } } /// Promotes a function returning generators to a generator of functions. -public func promote(m : A -> Gen) -> Gen B> { +public func promote(_ m : (A) -> Gen) -> Gen<(A) -> B> { return delay().flatMap { eval in - return Gen B>.pure(eval • m) + return Gen<(A) -> B>.pure(eval • m) } } // MARK: - Implementation Details -private func delay() -> Gen -> A> { +private func delay() -> Gen<(Gen) -> A> { return Gen(unGen: { r, n in return { g in return g.unGen(r, n) @@ -535,30 +535,30 @@ private func delay() -> Gen -> A> { }) } -private func vary(k : S, _ rng : StdGen) -> StdGen { +private func vary(_ k : S, _ rng : StdGen) -> StdGen { let s = rng.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(gen: Gen, _ k : Int, _ bound : Int, _ pred : A -> Bool) -> Gen> { +private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : (A) -> Bool) -> Gen> { if bound == 0 { - return Gen.pure(.None) + return Gen.pure(.none) } return gen.resize(2 * k + bound).flatMap { x in if pred(x) { - return Gen.pure(.Some(x)) + return Gen.pure(.some(x)) } - return attemptBoundedTry(gen, k.successor(), bound - 1, pred) + return attemptBoundedTry(gen, (k + 1), bound - 1, pred) } } -private func size(k : S, _ m : Int) -> Int { +private func size(_ k : S, _ m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } -private func selectOne(xs : [A]) -> [(A, [A])] { +private func selectOne(_ xs : [A]) -> [(A, [A])] { if xs.isEmpty { return [] } @@ -568,7 +568,7 @@ private func selectOne(xs : [A]) -> [(A, [A])] { return [(y, ys)] + rec } -private func pick(n : Int, _ lst : [(Int, Gen)]) -> Gen { +private func pick(_ n : Int, _ lst : [(Int, Gen)]) -> Gen { let (k, x) = lst[0] let tl = Array<(Int, Gen)>(lst[1.. : Arbitrary, CustomStringConvertible { } /// The default shrinking function for `Blind` values. - public static func shrink(bl : Blind) -> [Blind] { + public static func shrink(_ bl : Blind) -> [Blind] { return A.shrink(bl.getBlind).map(Blind.init) } } extension Blind : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Blind) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } @@ -106,7 +106,7 @@ public struct Static : Arbitrary, CustomStringConvertible { extension Static : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Static) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } @@ -136,13 +136,13 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { } /// The default shrinking function for an `ArrayOf` values. - public static func shrink(bl : ArrayOf) -> [ArrayOf] { + public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { return Array.shrink(bl.getArray).map(ArrayOf.init) } } extension ArrayOf : CoArbitrary { - public static func coarbitrary(x : ArrayOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { let a = x.getArray if a.isEmpty { return { $0.variant(0) } @@ -163,7 +163,7 @@ public struct OrderedArrayOf> : Arbitrary, C } public init(_ array : [A]) { - self.getOrderedArray = array.sort() + self.getOrderedArray = array.sorted() } /// A textual representation of `self`. @@ -177,8 +177,8 @@ public struct OrderedArrayOf> : Arbitrary, C } /// The default shrinking function for an `OrderedArrayOf` values. - public static func shrink(bl : OrderedArrayOf) -> [OrderedArrayOf] { - return Array.shrink(bl.getOrderedArray).filter({ $0.sort() == $0 }).map(OrderedArrayOf.init) + public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { + return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) } } @@ -203,13 +203,13 @@ public struct DictionaryOf, V : Arbitrary> : A } /// The default shrinking function for a `DictionaryOf` values. - public static func shrink(d : DictionaryOf) -> [DictionaryOf] { + public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } } extension DictionaryOf : CoArbitrary { - public static func coarbitrary(x : DictionaryOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { return Dictionary.coarbitrary(x.getDictionary) } } @@ -234,13 +234,13 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { } /// The default shrinking function for `OptionalOf` values. - public static func shrink(bl : OptionalOf) -> [OptionalOf] { + public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { return Optional.shrink(bl.getOptional).map(OptionalOf.init) } } extension OptionalOf : CoArbitrary { - public static func coarbitrary(x : OptionalOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { if let _ = x.getOptional { return { $0.variant(0) } } @@ -276,13 +276,13 @@ public struct SetOf> : Arbitrary, CustomString } /// The default shrinking function for a `SetOf` values. - public static func shrink(s : SetOf) -> [SetOf] { + public static func shrink(_ s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } } extension SetOf : CoArbitrary { - public static func coarbitrary(x : SetOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { if x.getSet.isEmpty { return { $0.variant(0) } } @@ -296,7 +296,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying pointer value. public var getPointer : UnsafePointer { - return UnsafePointer(self._impl.ptr) + return UnsafePointer(self._impl.ptr!) } public var size : Int { @@ -319,7 +319,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi private let _impl : ArrowOfImpl /// Retrieves the underlying function value, `T -> U`. - public var getArrow : T -> U { + public var getArrow : (T) -> U { return self._impl.arr } @@ -335,7 +335,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi } extension ArrowOf : CustomReflectable { - public func customMirror() -> Mirror { + public var customMirror : Mirror { return Mirror(self, children: [ "types": "\(T.self) -> \(U.self)", "currentMap": self._impl.table, @@ -348,12 +348,12 @@ public struct IsoOf, U : protocol private let _impl : IsoOfImpl /// Retrieves the underlying embedding function, `T -> U`. - public var getTo : T -> U { + public var getTo : (T) -> U { return self._impl.embed } /// Retrieves the underlying projecting function, `U -> T`. - public var getFrom : U -> T { + public var getFrom : (U) -> T { return self._impl.project } @@ -369,7 +369,7 @@ public struct IsoOf, U : protocol } extension IsoOf : CustomReflectable { - public func customMirror() -> Mirror { + public var customMirror : Mirror { return Mirror(self, children: [ "embed": "\(T.self) -> \(U.self)", "project": "\(U.self) -> \(T.self)", @@ -380,7 +380,7 @@ extension IsoOf : CustomReflectable { /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. -public struct Large> : Arbitrary { +public struct Large> : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A @@ -399,13 +399,13 @@ public struct Large> : Arbitr } /// The default shrinking function for `Large` values. - public static func shrink(bl : Large) -> [Large] { + public static func shrink(_ bl : Large) -> [Large] { return bl.getLarge.shrinkIntegral.map(Large.init) } } /// Guarantees that every generated integer is greater than 0. -public struct Positive> : Arbitrary, CustomStringConvertible { +public struct Positive> : Arbitrary, CustomStringConvertible { /// Retrieves the underlying positive value. public let getPositive : A @@ -424,20 +424,20 @@ public struct Positive> : Arbitrary, C } /// The default shrinking function for `Positive` values. - public static func shrink(bl : Positive) -> [Positive] { + public static func shrink(_ bl : Positive) -> [Positive] { return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) } } extension Positive : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Positive) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } /// Guarantees that every generated integer is never 0. -public struct NonZero> : Arbitrary, CustomStringConvertible { +public struct NonZero> : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-zero value. public let getNonZero : A @@ -456,19 +456,19 @@ public struct NonZero> : Arbitrary, CustomS } /// The default shrinking function for `NonZero` values. - public static func shrink(bl : NonZero) -> [NonZero] { + public static func shrink(_ bl : NonZero) -> [NonZero] { return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) } } extension NonZero : CoArbitrary { - public static func coarbitrary(x : NonZero) -> (Gen -> Gen) { + public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { return x.getNonZero.coarbitraryIntegral() } } /// Guarantees that every generated integer is greater than or equal to 0. -public struct NonNegative> : Arbitrary, CustomStringConvertible { +public struct NonNegative> : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-negative value. public let getNonNegative : A @@ -487,13 +487,13 @@ public struct NonNegative> : Arbitrary, Cus } /// The default shrinking function for `NonNegative` values. - public static func shrink(bl : NonNegative) -> [NonNegative] { + public static func shrink(_ bl : NonNegative) -> [NonNegative] { return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) } } extension NonNegative : CoArbitrary { - public static func coarbitrary(x : NonNegative) -> (Gen -> Gen) { + public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { return x.getNonNegative.coarbitraryIntegral() } } @@ -508,14 +508,14 @@ private func undefined() -> A { private final class ArrowOfImpl, U : Arbitrary> : Arbitrary, CustomStringConvertible { private var table : Dictionary - private var arr : T -> U + private var arr : (T) -> U - init (_ table : Dictionary, _ arr : (T -> U)) { + init (_ table : Dictionary, _ arr : ((T) -> U)) { self.table = table self.arr = arr } - convenience init(_ arr : (T -> U)) { + convenience init(_ arr : ((T) -> U)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) self.arr = { [unowned self] x in @@ -538,7 +538,7 @@ private final class ArrowOfImpl, U : Arbitra } } - static func shrink(f : ArrowOfImpl) -> [ArrowOfImpl] { + static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { return f.table.flatMap { (x, y) in return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in return ArrowOfImpl({ (z : T) -> U in @@ -554,16 +554,16 @@ private final class ArrowOfImpl, U : Arbitra private final class IsoOfImpl, U : protocol> : Arbitrary, CustomStringConvertible { var table : Dictionary - var embed : T -> U - var project : U -> T + var embed : (T) -> U + var project : (U) -> T - init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { + init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { self.table = table self.embed = embed self.project = project } - convenience init(_ embed : (T -> U), _ project : (U -> T)) { + convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) self.embed = { [unowned self] t in @@ -591,16 +591,16 @@ private final class IsoOfImpl, U } static var arbitrary : Gen> { - return Gen<(T -> U, U -> T)>.zip(promote({ a in + return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in return T.coarbitrary(a)(U.arbitrary) }), promote({ a in return U.coarbitrary(a)(T.arbitrary) })).map(IsoOfImpl.init) } - static func shrink(f : IsoOfImpl) -> [IsoOfImpl] { + static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { return f.table.flatMap { (x, y) in - return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in return IsoOfImpl({ (z : T) -> U in if x == z { return y2 @@ -618,7 +618,7 @@ private final class IsoOfImpl, U } private final class PointerOfImpl : Arbitrary { - var ptr : UnsafeMutablePointer + var ptr : UnsafeMutablePointer? let size : Int var description : String { @@ -632,7 +632,7 @@ private final class PointerOfImpl : Arbitrary { deinit { if self.size > 0 && self.ptr != nil { - self.ptr.dealloc(self.size) + self.ptr?.deallocateCapacity(self.size) self.ptr = nil } } @@ -640,9 +640,10 @@ private final class PointerOfImpl : Arbitrary { static var arbitrary : Gen> { return Gen.sized { n in if n <= 0 { - return Gen.pure(PointerOfImpl(nil, 0)) + let size = 1 + return Gen.pure(PointerOfImpl(UnsafeMutablePointer(allocatingCapacity: size), size)) } - let pt = UnsafeMutablePointer.alloc(n) + let pt = UnsafeMutablePointer(allocatingCapacity: n) let gt = pt.initializeFrom <^> sequence(Array((0.. Property { +public func conjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in @@ -35,11 +35,11 @@ public func conjoin(ps : Testable...) -> Property { /// /// When disjoining properties all calls to `expectFailure` will fail. You can, /// however, `invert` the property. -public func disjoin(ps : Testable...) -> Property { +public func disjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in - return Gen.pure(Prop(unProp: roses.reduce(.MkRose({ TestResult.failed() }, { [] }), combine: disj))) + return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), combine: disj))) })) } @@ -49,7 +49,7 @@ public func disjoin(ps : Testable...) -> Property { /// The resulting property makes 100 random choices to test any of the given /// properties. Thus, running multiple test cases will result in distinct /// arbitrary sequences of each property being tested. -public func conjamb(ps : () -> Testable...) -> Property { +public func conjamb(_ ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) } @@ -59,7 +59,7 @@ extension Testable { public var noShrinking : Property { return self.mapRoseResult { rs in return rs.onRose { res, _ in - return .MkRose({ res }, { [] }) + return .mkRose({ res }, { [] }) } } } @@ -98,7 +98,7 @@ extension Testable { } /// Attaches a callback to a test case. - public func withCallback(cb : Callback) -> Property { + public func withCallback(_ cb : Callback) -> Property { return self.mapResult { (res) in return TestResult(ok: res.ok , expect: res.expect @@ -113,15 +113,15 @@ extension Testable { } /// Adds the given string to the counterexamples of a failing property. - public func counterexample(s : String) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample) { _ in + public func counterexample(_ s : String) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in return print(s) }) } /// Executes an action after the last failure of the property. - public func whenFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { _ in + public func whenFail(_ m : () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in return m() }) } @@ -130,9 +130,9 @@ extension Testable { /// /// Because the action is executed after every failing test it can be used /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in - if res.ok == .Some(false) { + public func whenEachFail(_ m : () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in + if res.ok == .some(false) { m() } }) @@ -144,13 +144,13 @@ extension Testable { /// This function maps AfterFinalFailure callbacks that have the /// `.Counterexample` kind to `.AfterTest` callbacks. public var verbose : Property { - func chattyCallbacks(cbs : [Callback]) -> [Callback] { - let c = Callback.AfterTest(kind: .Counterexample) { (st, res) in + func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { + let c = Callback.afterTest(kind: .counterexample) { (st, res) in switch res.ok { - case .Some(true): + case .some(true): print("\nPassed: ", terminator: "") printLabels(res) - case .Some(false): + case .some(false): print("\nFailed: ", terminator: "") printLabels(res) print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") @@ -162,8 +162,8 @@ extension Testable { return [c] + cbs.map { (c : Callback) -> Callback in switch c { - case let .AfterFinalFailure(.Counterexample, f): - return .AfterTest(kind: .Counterexample, f: f) + case let .afterFinalFailure(.counterexample, f): + return .afterTest(kind: .counterexample, f: f) default: return c } @@ -207,17 +207,17 @@ extension Testable { /// addition to shrunken test cases, upon failure SwiftCheck will print a /// distribution map for the property that shows a percentage success rate /// for the property. - public func label(s : String) -> Property { + public func label(_ s : String) -> Property { return self.classify(true, label: s) } /// Labels a property with a printable value. - public func collect(x : A) -> Property { + public func collect(_ x : A) -> Property { return self.label(String(x)) } /// Conditionally labels a property with a value. - public func classify(b : Bool, label : String) -> Property { + public func classify(_ b : Bool, label : String) -> Property { return self.cover(b, percentage: 0, label: label) } @@ -226,7 +226,7 @@ extension Testable { /// /// Discarded tests (i.e. ones with a false precondition) do not affect /// coverage. - public func cover(b : Bool, percentage : Int, label : String) -> Property { + public func cover(_ b : Bool, percentage : Int, label : String) -> Property { if b { return self.mapResult { res in return TestResult(ok: res.ok @@ -248,26 +248,26 @@ extension Testable { /// This function can be used to completely change the evaluation schema of /// generated test cases by replacing the test's rose tree with a custom /// one. - public func mapProp(f : Prop -> Prop) -> Property { + public func mapProp(_ f : (Prop) -> Prop) -> Property { return Property(f <^> self.property.unProperty) } /// Applies a function that modifies the test case generator's size. - public func mapSize(f : Int -> Int) -> Property { + public func mapSize(_ f : (Int) -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) }) } /// Applies a function that modifies the result of a test case. - public func mapTotalResult(f : TestResult -> TestResult) -> Property { + public func mapTotalResult(_ f : (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in return protectResults(f <^> rs) } } /// Applies a function that modifies the result of a test case. - public func mapResult(f : TestResult -> TestResult) -> Property { + public func mapResult(_ f : (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in return f <^> rs } @@ -275,7 +275,7 @@ extension Testable { /// Applies a function that modifies the underlying Rose Tree that a test /// case has generated. - public func mapRoseResult(f : Rose -> Rose) -> Property { + public func mapRoseResult(_ f : (Rose) -> Rose) -> Property { return self.mapProp { t in return Prop(unProp: f(t.unProp)) } @@ -287,7 +287,7 @@ extension Testable { /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. -public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { +public func shrinking(_ shrinker : (A) -> [A], initial : A, prop : (A) -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in return Prop(unProp: joinRose(rs.map { x in return x.unProp @@ -301,25 +301,25 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) /// to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. - case AfterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) /// The callback is posted after all cases in the test have failed. - case AfterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { /// Affected by the verbose combinator. - case Counterexample + case counterexample /// Not affected by the verbose combinator - case NotCounterexample + case notCounterexample } /// The types of quantification SwiftCheck can perform. public enum Quantification { /// Universal Quantification ("for all"). - case Universal + case universal /// Existential Quanfication ("there exists"). - case Existential + case existential /// Uniqueness Quantification ("there exists one and only one") // case Uniqueness /// Counting Quantification ("there exist exactly k") @@ -352,7 +352,7 @@ public struct TestResult { /// result. public enum TestResultMatcher { /// A case-able view of the current state of a test result. - case MatchResult( ok : Optional + case matchResult( ok : Optional , expect : Bool , reason : String , theException : Optional @@ -367,7 +367,7 @@ public struct TestResult { /// Destructures a test case into a matcher that can be used in switch /// statement. public var match : TestResultMatcher { - return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) + return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } /// Creates and returns a new test result initialized with the given @@ -395,58 +395,58 @@ public struct TestResult { /// Convenience constructor for a passing `TestResult`. public static var succeeded : TestResult { - return result(Optional.Some(true)) + return result(Optional.some(true)) } /// Convenience constructor for a failing `TestResult`. - public static func failed(reason : String = "") -> TestResult { - return result(Optional.Some(false), reason: reason) + public static func failed(_ reason : String = "") -> TestResult { + return result(Optional.some(false), reason: reason) } /// Convenience constructor for a discarded `TestResult`. public static var rejected : TestResult { - return result(Optional.None) + return result(Optional.none) } /// Lifts a `Bool`ean value to a TestResult by mapping true to /// `TestResult.suceeded` and false to `TestResult.failed`. - public static func liftBool(b : Bool) -> TestResult { + public static func liftBool(_ b : Bool) -> TestResult { if b { return TestResult.succeeded } - return result(Optional.Some(false), reason: "Falsifiable") + return result(Optional.some(false), reason: "Falsifiable") } } // MARK: - Implementation Details -private func exception(msg : String) -> ErrorType -> TestResult { +private func exception(_ msg : String) -> (ErrorProtocol) -> TestResult { return { e in TestResult.failed(String(e)) } } -private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { - return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in +private func props(_ shrinker : (A) -> [A], original : A, pf : (A) -> Testable) -> Rose> { + return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) } -private func result(ok : Bool?, reason : String = "") -> TestResult { +private func result(_ ok : Bool?, reason : String = "") -> TestResult { return TestResult( ok: ok , expect: true , reason: reason - , theException: .None + , theException: .none , labels: [:] , stamp: Set() , callbacks: [] , abort: false - , quantifier: .Universal + , quantifier: .universal ) } -private func protectResults(rs : Rose) -> Rose { +private func protectResults(_ rs : Rose) -> Rose { return rs.onRose { x, rs in - return .IORose({ - return .MkRose(protectResult({ x }), { rs.map(protectResults) }) + return .ioRose({ + return .mkRose(protectResult({ x }), { rs.map(protectResults) }) }) } } @@ -455,7 +455,7 @@ private func protectResults(rs : Rose) -> Rose { // return { protect(Rose.pure • exception("Exception"), x: f) } //} -internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { +internal func protect(_ f : (ErrorProtocol) -> A, x : () throws -> A) -> A { do { return try x() } catch let e { @@ -463,19 +463,19 @@ internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { } } -internal func id(x : A) -> A { +internal func id(_ x : A) -> A { return x } -internal func • (f : B -> C, g : A -> B) -> A -> C { +internal func • (f : (B) -> C, g : (A) -> B) -> (A) -> C { return { f(g($0)) } } -private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { +private func protectResult(_ r : () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"), x: r) } } -internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { +internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l r.forEach { (k, v) in if let val = map.updateValue(v, forKey: k) { @@ -485,7 +485,7 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, return map } -private func insertWith(f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { +private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { var res = m let oldV = res[k] if let existV = oldV { @@ -496,7 +496,7 @@ private func insertWith(f : (V, V) -> V, k : K, v : V, m : Dict return res } -private func sep(l : String, r : String) -> String { +private func sep(_ l : String, r : String) -> String { if l.isEmpty { return r } @@ -507,9 +507,9 @@ private func sep(l : String, r : String) -> String { return l + ", " + r } -private func mplus(l : Optional, r : Optional) -> Optional { +private func mplus(_ l : Optional, r : Optional) -> Optional { if let ls = l, rs = r { - return .Some(ls + rs) + return .some(ls + rs) } if l == nil { @@ -519,7 +519,7 @@ private func mplus(l : Optional, r : Optional) -> Optional TestResult -> TestResult { +private func addCallbacks(_ result : TestResult) -> (TestResult) -> TestResult { return { res in return TestResult(ok: res.ok , expect: res.expect @@ -533,7 +533,7 @@ private func addCallbacks(result : TestResult) -> TestResult -> TestResult { } } -private func addLabels(result : TestResult) -> TestResult -> TestResult { +private func addLabels(_ result : TestResult) -> (TestResult) -> TestResult { return { res in return TestResult(ok: res.ok , expect: res.expect @@ -547,7 +547,7 @@ private func addLabels(result : TestResult) -> TestResult -> TestResult { } } -private func printLabels(st : TestResult) { +private func printLabels(_ st : TestResult) { if st.labels.isEmpty { print("(.)") } else if st.labels.count == 1, let pt = st.labels.first { @@ -556,37 +556,37 @@ private func printLabels(st : TestResult) { let gAllLabels = st.labels.map({ (l, _) in return l + ", " }).reduce("", combine: +) - print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { +private func conj(_ k : (TestResult) -> TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { - return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) + return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) } else if let p = xs.first { - return .IORose(/*protectRose*/({ + return .ioRose(/*protectRose*/({ let rose = p.reduce switch rose { - case .MkRose(let result, _): + case .mkRose(let result, _): if !result().expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) } switch result().ok { - case .Some(true): + case .some(true): return conj(addLabels(result()) • addCallbacks(result()) • k, xs: [Rose](xs[1..](xs[1.. TestResult, xs : [Rose]) -> Rose fatalError("Non-exhaustive if-else statement reached") } -private func disj(p : Rose, q : Rose) -> Rose { +private func disj(_ p : Rose, q : Rose) -> Rose { return p.flatMap { result1 in if !result1.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result1.ok { - case .Some(true): + case .some(true): return Rose.pure(result1) - case .Some(false): + case .some(false): return q.flatMap { (result2 : TestResult) in if !result2.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { - case .Some(true): + case .some(true): return Rose.pure(result2) - case .Some(false): - let callbacks : [Callback] = [.AfterFinalFailure(kind: .Counterexample, + case .some(false): + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, f: { _ in return print("") })] - return Rose.pure(TestResult(ok: .Some(false), + return Rose.pure(TestResult(ok: .some(false), expect: true, reason: sep(result1.reason, r: result2.reason), theException: mplus(result1.theException, r: result2.theException), @@ -630,18 +630,18 @@ private func disj(p : Rose, q : Rose) -> Rose.pure(result2) } } - case .None: + case .none: return q.flatMap { (result2 : TestResult) in if !result2.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { - case .Some(true): + case .some(true): return Rose.pure(result2) default: return Rose.pure(result1) diff --git a/Sources/Random.swift b/Sources/Random.swift index 04bf379..6479f9e 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -41,7 +41,7 @@ public struct StdGen : RandomGeneneratorType { /// Convenience to create a `StdGen` from a given integer. public init(_ o : Int) { - func mkStdGen32(sMaybeNegative : Int) -> StdGen { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 @@ -113,17 +113,17 @@ public protocol RandomType { /// For continuous types there is no requirement that the values `lo` and /// `hi` are ever produced, but they may be, depending on the implementation /// and the interval. - static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) + static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) } /// Generates a random value from a LatticeType random type. -public func randomBound, G : RandomGeneneratorType>(gen : G) -> (A, G) { +public func randomBound, G : RandomGeneneratorType>(_ gen : G) -> (A, G) { return A.randomInRange((A.min, A.max), gen: gen) } extension Bool : RandomType { /// Returns a random `Bool`ean value using the given range and generator. - public static func randomInRange(range : (Bool, Bool), gen: G) -> (Bool, G) { + public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) return (x == 1, gg) } @@ -131,7 +131,7 @@ extension Bool : RandomType { extension Character : RandomType { /// Returns a random `Character` value using the given range and generator. - public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { + public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! let maxc = String(max).unicodeScalars.first! @@ -143,7 +143,7 @@ extension Character : RandomType { extension UnicodeScalar : RandomType { /// Returns a random `UnicodeScalar` value using the given range and generator. - public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) return (UnicodeScalar(val), gg) } @@ -151,7 +151,7 @@ extension UnicodeScalar : RandomType { extension Int : RandomType { /// Returns a random `Int` value using the given range and generator. - public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { + public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int(truncatingBitPattern: bb), gg) @@ -160,7 +160,7 @@ extension Int : RandomType { extension Int8 : RandomType { /// Returns a random `Int8` value using the given range and generator. - public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { + public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int8(truncatingBitPattern: bb), gg) @@ -169,7 +169,7 @@ extension Int8 : RandomType { extension Int16 : RandomType { /// Returns a random `Int16` value using the given range and generator. - public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { + public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int16(truncatingBitPattern: bb), gg) @@ -178,7 +178,7 @@ extension Int16 : RandomType { extension Int32 : RandomType { /// Returns a random `Int32` value using the given range and generator. - public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { + public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int32(truncatingBitPattern: bb), gg) @@ -187,7 +187,7 @@ extension Int32 : RandomType { extension Int64 : RandomType { /// Returns a random `Int64` value using the given range and generator. - public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { + public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { let (l, h) = range if l > h { return Int64.randomInRange((h, l), gen: gen) @@ -198,7 +198,7 @@ extension Int64 : RandomType { let k = Double(h) - Double(l) + 1 let magtgt = k * q - func entropize(mag : Double, _ v : Double, _ g : G) -> (Double, G) { + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { if mag >= magtgt { return (v, g) } else { @@ -209,14 +209,14 @@ extension Int64 : RandomType { } let (v, rng_) = entropize(1, 0, gen) - return (Int64(Double(l) + (v % k)), rng_) + return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) } } } extension UInt : RandomType { /// Returns a random `UInt` value using the given range and generator. - public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { + public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) return (UInt(truncatingBitPattern: bb), gg) @@ -225,7 +225,7 @@ extension UInt : RandomType { extension UInt8 : RandomType { /// Returns a random `UInt8` value using the given range and generator. - public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { + public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (UInt8(truncatingBitPattern: bb), gg) @@ -234,7 +234,7 @@ extension UInt8 : RandomType { extension UInt16 : RandomType { /// Returns a random `UInt16` value using the given range and generator. - public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { + public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (UInt16(truncatingBitPattern: bb), gg) @@ -243,7 +243,7 @@ extension UInt16 : RandomType { extension UInt32 : RandomType { /// Returns a random `UInt32` value using the given range and generator. - public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { + public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (UInt32(truncatingBitPattern: bb), gg) @@ -252,7 +252,7 @@ extension UInt32 : RandomType { extension UInt64 : RandomType { /// Returns a random `UInt64` value using the given range and generator. - public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { + public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (UInt64(bb), gg) @@ -261,7 +261,7 @@ extension UInt64 : RandomType { extension Float : RandomType { /// Produces a random `Float` value in the range `[Float.min, Float.max]`. - public static func random(rng : G) -> (Float, G) { + public static func random(_ rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) let twoto24 = Int32(2) ^ Int32(24) let mask24 = twoto24 - 1 @@ -270,7 +270,7 @@ extension Float : RandomType { } /// Returns a random `Float` value using the given range and generator. - public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { + public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { let (l, h) = range if l > h { return Float.randomInRange((h , l), gen: gen) @@ -283,7 +283,7 @@ extension Float : RandomType { extension Double : RandomType { /// Produces a random `Float` value in the range `[Double.min, Double.max]`. - public static func random(rng : G) -> (Double, G) { + public static func random(_ rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) let twoto53 = Int64(2) ^ Int64(53) let mask53 = twoto53 - 1 @@ -292,7 +292,7 @@ extension Double : RandomType { } /// Returns a random `Double` value using the given range and generator. - public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { + public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { let (l, h) = range if l > h { return Double.randomInRange((h , l), gen: gen) @@ -305,8 +305,8 @@ extension Double : RandomType { /// Implementation Details Follow -private func mkStdRNG(o : Int) -> StdGen { - func mkStdGen32(sMaybeNegative : Int) -> StdGen { +private func mkStdRNG(_ o : Int) -> StdGen { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 @@ -327,8 +327,8 @@ private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int if rv != 0 { return Int(rv) } - t.memory.tv_sec = now.tv_sec - t.memory.tv_nsec = Int(now.tv_usec) * 1000 + t.pointee.tv_sec = now.tv_sec + t.pointee.tv_nsec = Int(now.tv_usec) * 1000 return 0 } diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 6cc9544..b9eb1e8 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -16,18 +16,18 @@ /// `IORose` to printing values to the console and executing callbacks. public enum Rose { /// A normal branch in the Rose Tree. - case MkRose(() -> A, () -> [Rose]) + case mkRose(() -> A, () -> [Rose]) /// An IO branch in the Rose Tree. That is, a branch that must execute /// side effects before revealing further structure. - case IORose(() -> Rose) + case ioRose(() -> Rose) /// Case analysis for a Rose Tree. - public func onRose(f : (A, [Rose]) -> Rose) -> Rose { + public func onRose(_ f : (A, [Rose]) -> Rose) -> Rose { switch self { - case .MkRose(let x, let rs): + case .mkRose(let x, let rs): return f(x(), rs()) - case .IORose(let m): - return .IORose({ m().onRose(f) }) + case .ioRose(let m): + return .ioRose({ m().onRose(f) }) } } @@ -35,9 +35,9 @@ public enum Rose { /// `.MkRose` branch is encountered. That branch is then returned. public var reduce : Rose { switch self { - case .MkRose(_, _): + case .mkRose(_, _): return self - case .IORose(let m): + case .ioRose(let m): return m().reduce } } @@ -49,25 +49,25 @@ extension Rose /*: Functor*/ { /// For `.MkRose` branches the computation is applied to the node's value /// then application recurses into the sub-trees. For `.IORose` branches /// the map is suspended. - public func map(f : A -> B) -> Rose { + public func map(_ f : (A) -> B) -> Rose { return f <^> self } } /// Fmap | Maps a function over all the nodes of a Rose Tree. -public func <^> (f : A -> B, g : Rose) -> Rose { +public func <^> (f : (A) -> B, g : Rose) -> Rose { switch g { - case .MkRose(let root, let children): - return .MkRose({ f(root()) }, { children().map() { $0.map(f) } }) - case .IORose(let rs): - return .IORose({ rs().map(f) }) + case .mkRose(let root, let children): + return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) + case .ioRose(let rs): + return .ioRose({ rs().map(f) }) } } extension Rose /*: Applicative*/ { /// Lifts a value into a Rose Tree. - public static func pure(a : A) -> Rose { - return .MkRose({ a }, { [] }) + public static func pure(_ a : A) -> Rose { + return .mkRose({ a }, { [] }) } /// Applies a Rose Tree of functions to the receiver to yield a new Rose @@ -77,18 +77,18 @@ extension Rose /*: Applicative*/ { /// then application recurses into the sub-trees. For `.IORose` the branch /// is reduced to a `.MkRose` and applied, executing all side-effects along /// the way. - public func ap(fn : Rose B>) -> Rose { + public func ap(_ fn : Rose<(A) -> B>) -> Rose { return fn <*> self } } /// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose /// Tree of values. -public func <*> (fn : Rose B>, g : Rose) -> Rose { +public func <*> (fn : Rose<(A) -> B>, g : Rose) -> Rose { switch fn { - case .MkRose(let f, _): + case .mkRose(let f, _): return g.map(f()) - case .IORose(let rs): + case .ioRose(let rs): return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW } } @@ -96,19 +96,19 @@ public func <*> (fn : Rose B>, g : Rose) -> Rose { extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all /// together. - public func flatMap(fn : A -> Rose) -> Rose { + public func flatMap(_ fn : (A) -> Rose) -> Rose { return self >>- fn } } /// Flat Map | Maps the values in the receiver to Rose Trees and joins them all /// together. -public func >>- (m : Rose, fn : A -> Rose) -> Rose { +public func >>- (m : Rose, fn : (A) -> Rose) -> Rose { return joinRose(m.map(fn)) } /// Lifts functions to functions over Rose Trees. -public func liftM(f : A -> R, _ m1 : Rose) -> Rose { +public func liftM(_ f : (A) -> R, _ m1 : Rose) -> Rose { return m1.flatMap { x1 in return Rose.pure(f(x1)) } @@ -121,22 +121,22 @@ public func liftM(f : A -> R, _ m1 : Rose) -> Rose { /// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the /// value at the sub-tree node and a recursive call to join the branch's tree to /// its sub-trees. -public func joinRose(rs : Rose>) -> Rose { +public func joinRose(_ rs : Rose>) -> Rose { switch rs { - case .IORose(let rs): - return .IORose({ joinRose(rs()) }) - case .MkRose(let bx , let rs): + case .ioRose(let rs): + return .ioRose({ joinRose(rs()) }) + case .mkRose(let bx , let rs): switch bx() { - case .IORose(let rm): - return .IORose({ joinRose(.MkRose(rm, rs)) }) - case .MkRose(let x, let ts): - return .MkRose(x, { rs().map(joinRose) + ts() }) + case .ioRose(let rm): + return .ioRose({ joinRose(.mkRose(rm, rs)) }) + case .mkRose(let x, let ts): + return .mkRose(x, { rs().map(joinRose) + ts() }) } } } /// Sequences an array of Rose Trees into a Rose Tree of an array. -public func sequence(ms : [Rose]) -> Rose<[A]> { +public func sequence(_ ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in return m.flatMap { x in return n.flatMap { xs in @@ -148,6 +148,6 @@ public func sequence(ms : [Rose]) -> Rose<[A]> { /// Sequences the result of mapping values to Rose trees into a single rose tree /// of an array of values. -public func mapM(f : A -> Rose, xs : [A]) -> Rose<[B]> { +public func mapM(_ f : (A) -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) } diff --git a/Sources/Test.swift b/Sources/Test.swift index c51f0d7..5219ed2 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -97,113 +97,113 @@ /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A throws -> Testable)) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : ((A) throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B) throws -> Testable) -> Property { return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C) throws -> Testable) -> Property { return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -212,8 +212,8 @@ public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -222,8 +222,8 @@ public func forAllNoShrink(gen : Gen, pf : (A throws -> Testable)) -> Prop /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } @@ -232,8 +232,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) thr /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -242,8 +242,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -252,8 +252,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -262,8 +262,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -272,8 +272,8 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, _ g /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -282,15 +282,15 @@ public func forAllNoShrink(genA : Gen, _ genB : Gen, /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAllShrink(_ gen : Gen, shrinker : (A) -> [A], f : (A) throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in do { @@ -320,15 +320,15 @@ public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> T /// `SNF` involves turning every `exists` into a function returning the /// existential value, taking any other parameters being quantified over as /// needed. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func exists(pf : A throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func exists(_ pf : (A) throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func exists(gen : Gen, pf : A throws -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func exists(_ gen : Gen, pf : (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok , expect: res.expect @@ -338,27 +338,27 @@ public func exists(gen : Gen, pf : A throws -> Testable) -> Pr , stamp: res.stamp , callbacks: res.callbacks , abort: res.abort - , quantifier: .Existential) + , quantifier: .existential) } } /// Tests a property and prints the results to stdout. -public func quickCheck(prop : Testable, name : String = "") { +public func quickCheck(_ prop : Testable, name : String = "") { quickCheckWithResult(CheckerArguments(name: name), prop) } // MARK: - Implementation Details internal enum Result { - case Success(numTests : Int + case success(numTests : Int , labels : [(String, Int)] , output : String ) - case GaveUp(numTests : Int + case gaveUp(numTests : Int , labels : [(String,Int)] , output : String ) - case Failure(numTests : Int + case failure(numTests : Int , numShrinks : Int , usedSeed : StdGen , usedSize : Int @@ -366,7 +366,7 @@ internal enum Result { , labels : [(String,Int)] , output : String ) - case ExistentialFailure(numTests: Int + case existentialFailure(numTests: Int , usedSeed : StdGen , usedSize : Int , reason : String @@ -374,13 +374,13 @@ internal enum Result { , output : String , lastResult : TestResult ) - case NoExpectedFailure(numTests : Int + case noExpectedFailure(numTests : Int , usedSeed : StdGen , usedSize : Int , labels : [(String,Int)] , output : String ) - case InsufficientCoverage(numTests : Int + case insufficientCoverage(numTests : Int , usedSeed : StdGen , usedSize : Int , labels : [(String,Int)] @@ -389,11 +389,11 @@ internal enum Result { } private indirect enum Either { - case Left(L) - case Right(R) + case left(L) + case right(R) } -internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> Result { +internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { let istate = CheckerState(name: args.name , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests @@ -408,7 +408,7 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R , failedShrinkStepDistance: 0 , failedShrinkStepCount: 0 , shouldAbort: false - , quantifier: .Universal + , quantifier: .universal , arguments: args , silence: args.silence) let modP : Property = (p.exhaustive ? p.property.once : p.property) @@ -428,21 +428,21 @@ internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> R // - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. -private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { +private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { var state = st while true { switch runATest(state, caseGen: caseGen) { - case let .Left(fail): + case let .left(fail): switch (fail.0, doneTesting(fail.1)) { - case (.Success(_, _, _), _): + case (.success(_, _, _), _): return fail.0 - case let (_, .NoExpectedFailure(numTests, seed, sz, labels, output)): - return .NoExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) + case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): + return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) // Existential Failures need explicit propagation. Existentials increment the // discard count so we check if it has been surpassed. If it has with any kind // of success we're done. If no successes are found we've failed checking the // existential and report it as such. Otherwise turn the testing loop. - case (.ExistentialFailure(_, _, _, _, _, _, _), _): + case (.existentialFailure(_, _, _, _, _, _, _), _): if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { return reportExistentialFailure(fail.1, res: fail.0) } else { @@ -452,7 +452,7 @@ private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result default: return fail.0 } - case let .Right(lsta): + case let .right(lsta): if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { return doneTesting(lsta) } @@ -469,24 +469,24 @@ private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result // // On success the next state is returned. On failure the final result and state // are returned. -private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { +private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split // Execute the Rose Tree for the test and reduce to .MkRose. switch caseGen(rnd1, size).unProp.reduce { - case .MkRose(let resC, let ts): + case .mkRose(let resC, let ts): let res = resC() // Force the result only once. dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks switch res.match { // Success - case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): + case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): let nstate = CheckerState(name: st.name , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount.successor() + , successfulTestCount: (st.successfulTestCount + 1) , discardedTestCount: st.discardedTestCount , labels: unionWith(max, l: st.labels, r: labels) , collected: [stamp] + st.collected @@ -499,15 +499,15 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit , quantifier: quantifier , arguments: st.arguments , silence: st.silence) - return .Right(nstate) + return .right(nstate) // Discard - case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort, let quantifier): + case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): let nstate = CheckerState(name: st.name , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests , computeSize: st.computeSize , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() + , discardedTestCount: (st.discardedTestCount + 1) , labels: unionWith(max, l: st.labels, r: labels) , collected: st.collected , hasFulfilledExpectedFailure: expect @@ -519,10 +519,10 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit , quantifier: quantifier , arguments: st.arguments , silence: st.silence) - return .Right(nstate) + return .right(nstate) // Fail - case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): - if quantifier == .Existential { + case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): + if quantifier == .existential { // print("") } else if !expect { printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") @@ -532,13 +532,13 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit // Failure of an existential is not necessarily failure of the whole // test case, so treat this like a discard. - if quantifier == .Existential { + if quantifier == .existential { let nstate = CheckerState(name: st.name , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests , computeSize: st.computeSize , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() + , discardedTestCount: (st.discardedTestCount + 1) , labels: st.labels , collected: st.collected , hasFulfilledExpectedFailure: expect @@ -553,27 +553,27 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.ExistentialFailure(numTests: st.successfulTestCount.successor() + let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) , usedSeed: st.randomSeedGenerator , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) , reason: "Could not satisfy existential" , labels: summary(st) , output: "*** Failed! " , lastResult: res) - return .Left((resul, nstate)) + return .left((resul, nstate)) } - return .Right(nstate) + return .right(nstate) } // Attempt a shrink. let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) if !expect { - let s = Result.Success(numTests: st.successfulTestCount.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") - return .Left((s, st)) + let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") + return .left((s, st)) } - let stat = Result.Failure(numTests: st.successfulTestCount.successor() + let stat = Result.failure(numTests: (st.successfulTestCount + 1) , numShrinks: numShrinks , usedSeed: st.randomSeedGenerator , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) @@ -586,7 +586,7 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests , computeSize: st.computeSize , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() + , discardedTestCount: (st.discardedTestCount + 1) , labels: st.labels , collected: st.collected , hasFulfilledExpectedFailure: res.expect @@ -598,7 +598,7 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit , quantifier: quantifier , arguments: st.arguments , silence: st.silence) - return .Left((stat, nstate)) + return .left((stat, nstate)) } default: fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") @@ -606,17 +606,17 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit } } -private func doneTesting(st : CheckerState) -> Result { +private func doneTesting(_ st : CheckerState) -> Result { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { printCond(st.silence, "+++ OK, failed as expected. ") printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } printDistributionGraph(st) - return .NoExpectedFailure(numTests: st.successfulTestCount + return .noExpectedFailure(numTests: st.successfulTestCount , usedSeed: st.randomSeedGenerator , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) , labels: summary(st) @@ -624,7 +624,7 @@ private func doneTesting(st : CheckerState) -> Result { } else if insufficientCoverage(st) { printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .InsufficientCoverage( numTests: st.successfulTestCount + return .insufficientCoverage( numTests: st.successfulTestCount , usedSeed: st.randomSeedGenerator , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) , labels: summary(st) @@ -632,13 +632,13 @@ private func doneTesting(st : CheckerState) -> Result { } else { printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } } -private func giveUp(st: CheckerState) -> Result { +private func giveUp(_ st: CheckerState) -> Result { printDistributionGraph(st) - return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of @@ -652,7 +652,7 @@ private func giveUp(st: CheckerState) -> Result { // slow as hell. This way we stay in one stack frame no matter what and give ARC // a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 // megabytes for truly horrendous tests that used to eat 8 gigs. -private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { +private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") } @@ -660,7 +660,7 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts var lastResult = res var branches = ts var successfulShrinkCount = st.successfulShrinkCount - var failedShrinkStepDistance = st.failedShrinkStepDistance.successor() + var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) var failedShrinkStepCount = st.failedShrinkStepCount // cont is a sanity check so we don't fall into an infinite loop. It is set @@ -680,13 +680,13 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts // Try all possible courses of action in this Rose Tree branches.forEach { r in switch r.reduce { - case .MkRose(let resC, let ts1): + case .mkRose(let resC, let ts1): let res1 = resC() dispatchAfterTestCallbacks(st, res: res1) // Did we fail? Good! Failure is healthy. // Try the next set of branches. - if res1.ok == .Some(false) { + if res1.ok == .some(false) { lastResult = res1 branches = ts1() cont = true @@ -695,14 +695,14 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts // Otherwise increment the tried shrink counter and the failed // shrink counter. - failedShrinkStepDistance = failedShrinkStepDistance.successor() - failedShrinkStepCount = failedShrinkStepCount.successor() + failedShrinkStepDistance = (failedShrinkStepDistance + 1) + failedShrinkStepCount = (failedShrinkStepCount + 1) default: fatalError("Rose should not have reduced to IO") } } - successfulShrinkCount = successfulShrinkCount.successor() + successfulShrinkCount = (successfulShrinkCount + 1) } let state = CheckerState( name: st.name @@ -725,19 +725,19 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts return reportMinimumCaseFound(state, res: lastResult) } -private func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \(st.successfulTestCount.successor()) test" +private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (Int, Int, Int) { + let testMsg = " (after \((st.successfulTestCount + 1)) test" let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } -private func reportExistentialFailure(st : CheckerState, res : Result) -> Result { +private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result { switch res { - case let .ExistentialFailure(_, _, _, reason, _, _, lastTest): + case let .existentialFailure(_, _, _, reason, _, _, lastTest): let testMsg = " (after \(st.discardedTestCount) test" printCond(st.silence, "*** Failed! ", terminator: "") @@ -750,14 +750,14 @@ private func reportExistentialFailure(st : CheckerState, res : Result) -> Result } } -private func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterTestCallbacks(_ st : CheckerState, res : TestResult) { guard !st.silence else { return } res.callbacks.forEach { c in switch c { - case let .AfterTest(_, f): + case let .afterTest(_, f): f(st, res) default: break @@ -765,14 +765,14 @@ private func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { } } -private func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterFinalFailureCallbacks(_ st : CheckerState, res : TestResult) { guard !st.silence else { return } res.callbacks.forEach { c in switch c { - case let .AfterFinalFailure(_, f): + case let .afterFinalFailure(_, f): f(st, res) default: break @@ -780,28 +780,28 @@ private func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestRes } } -private func summary(s : CheckerState) -> [(String, Int)] { +private func summary(_ s : CheckerState) -> [(String, Int)] { let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) - let l : [[String]] = lff.sort().groupBy(==) + let l : [[String]] = lff.sorted().groupBy(==) return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } -private func labelPercentage(l : String, st : CheckerState) -> Int { +private func labelPercentage(_ l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap(Array.init).filter { $0 == l } return (100 * occur.count) / st.maxAllowableSuccessfulTests } -private func printDistributionGraph(st : CheckerState) { - func showP(n : Int) -> String { +private func printDistributionGraph(_ st : CheckerState) { + func showP(_ n : Int) -> String { return (n < 10 ? " " : "") + "\(n)" + "%" } let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) + return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) }) - let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) + let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) - let allLabels : [String] = Array(gPrint.sort().reverse()) + let allLabels : [String] = Array(gPrint.sorted().reversed()) var covers = [String]() st.labels.forEach { (l, reqP) in @@ -824,27 +824,27 @@ private func printDistributionGraph(st : CheckerState) { } } -private func pluralize(s : String, i : Int) -> String { +private func pluralize(_ s : String, i : Int) -> String { if i == 1 { return s } return s + "s" } -private func insufficientCoverage(st : CheckerState) -> Bool { +private func insufficientCoverage(_ st : CheckerState) -> Bool { return st.labels .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) .reduce(false, combine: { $0 || $1 }) } -private func printCond(cond : Bool, _ str : String, terminator : String = "\n") { +private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n") { if !cond { print(str, terminator: terminator) } } extension Array { - private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { + private func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { var result = [[Element]]() var accumulator = [Element]() self.forEach { current in @@ -868,9 +868,9 @@ extension Array { /// Testing loop stuff -private func computeSize(args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { - func computeSize_(successes : Int, _ discards : Int) -> Int { - func roundTo(n : Int, _ m : Int) -> Int { +private func computeSize(_ args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { + func computeSize_(_ successes : Int, _ discards : Int) -> Int { + func roundTo(_ n : Int, _ m : Int) -> Int { return (n / m) * m } @@ -885,7 +885,7 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca } } - func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { if successes == 0 && discards == 0 { return defaultSize } else { diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index 5275624..27dcee2 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -33,8 +33,8 @@ /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { +@warn_unused_result(message:"Did you forget to bind this property to a quantifier?") +public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -56,8 +56,8 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { +@warn_unused_result(message:"Did you forget to bind this property to a quantifier?") +public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -144,11 +144,11 @@ infix operator <- {} /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, _, seed, sz, reason, _, _): + case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .NoExpectedFailure(_, seed, sz, _, _): + case let .noExpectedFailure(_, seed, sz, _, _): XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .InsufficientCoverage(_, seed, sz, _, _): + case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return @@ -158,11 +158,11 @@ public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, _, seed, sz, reason, _, _): + case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .NoExpectedFailure(_, seed, sz, _, _): + case let .noExpectedFailure(_, seed, sz, _, _): XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .InsufficientCoverage(_, seed, sz, _, _): + case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 46acad1..566a4e7 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -65,7 +65,7 @@ public struct Prop : Testable { /// Returns a property that tests the receiver. public var property : Property { // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) - return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) + return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) } } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index bb54ac0..1eb87a4 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -61,61 +61,61 @@ public protocol WitnessedArbitrary { /// A property test that relies on a witness that the given type parameter /// is actually `Arbitrary`. - static func forAllWitnessed(wit : A -> Param, pf : (Self -> Testable)) -> Property + static func forAllWitnessed(_ wit : (A) -> Param, pf : ((Self) -> Testable)) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A -> Testable)) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : ((A) -> Testable)) -> Property { return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B) -> Testable) -> Property { return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C) -> Testable) -> Property { return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D) -> Testable) -> Property { return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { +@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") +public func forAll(_ pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 6f9d82a..d8302ac 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -21,9 +21,9 @@ extension Array where Element : Arbitrary { } /// The default shrinking function for `Array`s of arbitrary `Element`s. - public static func shrink(bl : Array) -> [[Element]] { + public static func shrink(_ bl : Array) -> [[Element]] { let rec : [[Element]] = shrinkOne(bl) - return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec + return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec } } @@ -32,7 +32,7 @@ extension Array : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Array`s. - public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : (([Element]) -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) }) @@ -46,7 +46,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } } @@ -56,7 +56,7 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(wit : A -> Element, pf : (AnyBidirectionalCollection -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) }) @@ -70,7 +70,7 @@ extension AnySequence where Element : Arbitrary { } /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. - public static func shrink(bl : AnySequence) -> [AnySequence] { + public static func shrink(_ bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } } @@ -80,7 +80,7 @@ extension AnySequence : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnySequence`s. - public static func forAllWitnessed(wit : A -> Element, pf : (AnySequence -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) }) @@ -94,7 +94,7 @@ extension ArraySlice where Element : Arbitrary { } /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. - public static func shrink(bl : ArraySlice) -> [ArraySlice] { + public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } } @@ -104,7 +104,7 @@ extension ArraySlice : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(wit : A -> Element, pf : (ArraySlice -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) }) @@ -123,10 +123,10 @@ extension CollectionOfOne : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(wit : A -> Element, pf : (CollectionOfOne -> Testable)) -> Property { - return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in - return pf(CollectionOfOne(wit(bl[.Zero]))) - }) + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { + return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in + return pf(CollectionOfOne(wit(bl[bl.startIndex]))) + }) } } @@ -135,16 +135,16 @@ extension Optional where Wrapped : Arbitrary { /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. public static var arbitrary : Gen> { return Gen>.frequency([ - (1, Gen>.pure(.None)), - (3, liftM(Optional.Some, Wrapped.arbitrary)), + (1, Gen>.pure(.none)), + (3, liftM(Optional.some, Wrapped.arbitrary)), ]) } /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. - public static func shrink(bl : Optional) -> [Optional] { + public static func shrink(_ bl : Optional) -> [Optional] { if let x = bl { - let rec : [Optional] = Wrapped.shrink(x).map(Optional.Some) - return [.None] + rec + let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) + return [.none] + rec } return [] } @@ -155,7 +155,7 @@ extension Optional : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Optional`s. - public static func forAllWitnessed(wit : A -> Wrapped, pf : (Optional -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -169,7 +169,7 @@ extension ContiguousArray where Element : Arbitrary { } /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. - public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { + public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } } @@ -179,7 +179,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(wit : A -> Element, pf : (ContiguousArray -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) }) @@ -192,15 +192,19 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { public static var arbitrary : Gen> { return [Key].arbitrary.flatMap { k in return [Value].arbitrary.flatMap { v in - return Gen.pure(Dictionary(Zip2Sequence(k, v))) + return Gen.pure(Dictionary(zip(k, v).map({ (k, v) -> (key: Key, value: Value) in + (key: k, value: v) + }))) } } } /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and /// `Value`s. - public static func shrink(d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } + public static func shrink(_ d : Dictionary) -> [Dictionary] { + return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in + (key: k, value: v) + })) } } } @@ -211,68 +215,56 @@ extension EmptyCollection : Arbitrary { } } -extension HalfOpenInterval where Bound : protocol { +extension Range where Bound : protocol { /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. - public static var arbitrary : Gen> { + public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in return Bound.arbitrary.flatMap { r in - return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) + return Gen.pure((min(l, r) ..< max(l, r))) } } } /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. - public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { - return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) + public static func shrink(_ bl : Range) -> [Range] { + return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) } } -extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { +extension LazyCollection where Base : protocol, Base.Index : Comparable { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } -extension LazySequence where Base : protocol { +extension LazySequence where Base : protocol { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary } } -extension Range where Element : protocol { - /// Returns a generator of `Range`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Element.arbitrary.flatMap { l in - return Element.arbitrary.flatMap { r in - return Gen.pure(min(l, r)..) -> [Range] { - return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(..<) - } -} - -extension Repeat where Element : Arbitrary { +extension Repeated where Element : Arbitrary { /// Returns a generator of `Repeat`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) + public static var arbitrary : Gen> { + let constructor: (Element, Int) -> Repeated = { (element, count) in + return repeatElement(element , count: count) + } + + return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) } } -extension Repeat : WitnessedArbitrary { +extension Repeated : WitnessedArbitrary { public typealias Param = Element /// Given a witness and a function to test, converts them into a universally /// quantified property over `Repeat`s. - public static func forAllWitnessed(wit : A -> Element, pf : (Repeat -> Testable)) -> Property { - return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { + return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) - return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) + return pf(repeatElement(xs.first!, count: xs.count)) }) } } @@ -292,7 +284,7 @@ extension Set where Element : protocol { } /// The default shrinking function for `Set`s of arbitrary `Element`s. - public static func shrink(s : Set) -> [Set] { + public static func shrink(_ s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } } @@ -302,7 +294,7 @@ extension Set : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Set`s. - public static func forAllWitnessed(wit : A -> Element, pf : (Set -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((Set) -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) } @@ -311,14 +303,14 @@ extension Set : WitnessedArbitrary { // MARK: - Implementation Details Follow -private func bits(n : N) -> Int { +private func bits(_ n : N) -> Int { if n / 2 == 0 { return 0 } return 1 + bits(n / 2) } -private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { +private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { let xs1 : [A] = take(k, xs: xs) let xs2 : [A] = drop(k, xs: xs) @@ -332,17 +324,17 @@ private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { } } -private func take(num : Int, xs : [T]) -> [T] { +private func take(_ num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[0..(num : Int, xs : [T]) -> [T] { +private func drop(_ num : Int, xs : [T]) -> [T] { let n = (num < xs.count) ? num : xs.count return [T](xs[n..(xs : [A]) -> [[A]] { +private func shrinkOne(_ xs : [A]) -> [[A]] { if xs.isEmpty { return [[A]]() } else if let x : A = xs.first { @@ -355,9 +347,9 @@ private func shrinkOne(xs : [A]) -> [[A]] { } extension Dictionary { - private init(_ pairs : S) { + private init(_ pairs : S) { self.init() - var g = pairs.generate() + var g = pairs.makeIterator() while let (k, v): (Key, Value) = g.next() { self[k] = v } diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index d729080..09667b4 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -477,7 +477,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -780,6 +780,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -814,6 +815,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -842,6 +844,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -887,6 +890,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -931,7 +935,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -964,7 +968,8 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_VERSION = 2.3; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -986,7 +991,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1005,7 +1010,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1071,6 +1076,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1116,6 +1122,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index e559f2e..81d7615 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -52,11 +52,11 @@ .oneOf([ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init) + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) @@ -45,11 +45,17 @@ class ComplexSpec : XCTestCase { } func testIPv6Properties() { + + let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } + let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } + let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } + let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } + let ipHexDigits = Gen.oneOf([ - hexDigits.proliferateSized(1).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(2).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(3).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(4).map{ String.init($0) + ":" }, + gen1, + gen2, + gen3, + gen4 ]) let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) @@ -62,12 +68,12 @@ class ComplexSpec : XCTestCase { // MARK: String Conveniences -func glue(parts : [Gen]) -> Gen { +func glue(_ parts : [Gen]) -> Gen { return sequence(parts).map { $0.reduce("", combine: +) } } extension String { private var initial : String { - return self[self.startIndex...choose((1, 1000))) { n in - return forAll(Gen.frequency(Array(count: n, repeatedValue: (1, Gen.pure(0))))) { $0 == 0 } + return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } } property("Gen.weighted behaves") <- { @@ -38,7 +38,7 @@ class GenSpec : XCTestCase { } property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.weighted(Array(count: n, repeatedValue: (1, 0)))) { $0 == 0 } + return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } } property("The only value Gen.pure generates is the given value") <- { @@ -68,14 +68,14 @@ class GenSpec : XCTestCase { property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in return !xs.isEmpty ==> { return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in - return xs.startsWith(ys) + return xs.starts(with: ys) } } } property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in - return (xs.count == ys.count) ^&&^ (xs.sort() == ys.sort()) + return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) } } @@ -123,23 +123,23 @@ class GenSpec : XCTestCase { } property("Gen.suchThat in series obeys both predicates") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in - return !(str.isEmpty || str.rangeOfString(",") != nil) + return !(str.isEmpty || str.range(of: ",") != nil) } } property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in return !str.isEmpty } } property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in - return str.rangeOfString(",") == nil + return str.range(of: ",") == nil } } @@ -165,7 +165,7 @@ class GenSpec : XCTestCase { property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in let fx = Gen.pure(x) let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<(Int -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } } property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in @@ -273,7 +273,7 @@ class GenSpec : XCTestCase { } property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in - let f : Int -> Gen = Gen.pure • fa.getArrow + let f : (Int) -> Gen = Gen.pure • fa.getArrow return (Gen.pure(a) >>- f) == f(a) } @@ -282,8 +282,8 @@ class GenSpec : XCTestCase { } property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in - let f : Int -> Gen = Gen.pure • fa.getArrow - let g : Int -> Gen = Gen.pure • ga.getArrow + let f : (Int) -> Gen = Gen.pure • fa.getArrow + let g : (Int) -> Gen = Gen.pure • ga.getArrow return forAllNoShrink(lawfulGen) { (m : Gen) in return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) } @@ -291,15 +291,15 @@ class GenSpec : XCTestCase { } } -internal func curry(f : (A, B) -> C) -> A -> B -> C { +internal func curry(_ f : (A, B) -> C) -> (A) -> (B) -> C { return { a in { b in f(a, b) } } } -internal func id(x : A) -> A { +internal func id(_ x : A) -> A { return x } -internal func • (f : B -> C, g : A -> B) -> A -> C { +internal func • (f : (B) -> C, g : (A) -> B) -> (A) -> C { return { f(g($0)) } } diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index ca3a210..767e8be 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -30,7 +30,7 @@ func == (l : Name, r : Name) -> Bool { return l.unName == r.unName } -private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { +private func liftM2(_ f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { return m1.flatMap { x1 in return m2.flatMap { x2 in return Gen.pure(f(x1, x2)) @@ -39,18 +39,18 @@ private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> G } indirect enum Exp : Equatable { - case Lam(Name, Exp) - case App(Exp, Exp) - case Var(Name) + case lam(Name, Exp) + case app(Exp, Exp) + case `var`(Name) } func == (l : Exp, r : Exp) -> Bool { switch (l, r) { - case let (.Lam(ln, le), .Lam(rn, re)): + case let (.lam(ln, le), .lam(rn, re)): return ln == rn && le == re - case let (.App(ln, le), .App(rn, re)): + case let (.app(ln, le), .app(rn, re)): return ln == rn && le == re - case let (.Var(n1), .Var(n2)): + case let (.var(n1), .var(n2)): return n1 == n2 default: return false @@ -58,12 +58,12 @@ func == (l : Exp, r : Exp) -> Bool { } extension Exp : Arbitrary { - private static func arbExpr(n : Int) -> Gen { + private static func arbExpr(_ n : Int) -> Gen { return Gen.frequency([ - (2, liftM(Exp.Var, Name.arbitrary)), + (2, liftM(Exp.var, Name.arbitrary)), ] + ((n <= 0) ? [] : [ - (5, liftM2(Exp.Lam, Name.arbitrary, arbExpr(n.predecessor()))), - (5, liftM2(Exp.App, arbExpr(n/2), arbExpr(n/2))), + (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), + (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), ])) } @@ -71,53 +71,53 @@ extension Exp : Arbitrary { return Gen.sized(self.arbExpr) } - static func shrink(e : Exp) -> [Exp] { + static func shrink(_ e : Exp) -> [Exp] { switch e { - case .Var(_): + case .var(_): return [] - case let .Lam(x, a): - return [a] + Exp.shrink(a).map { .Lam(x, $0) } - case let .App(a, b): + case let .lam(x, a): + return [a] + Exp.shrink(a).map { .lam(x, $0) } + case let .app(a, b): let part1 : [Exp] = [a, b] + [a].flatMap({ (expr : Exp) -> Exp? in - if case let .Lam(x, a) = expr { + if case let .lam(x, a) = expr { return a.subst(x, b) } return nil }) - let part2 : [Exp] = Exp.shrink(a).map { App($0, b) } - + Exp.shrink(b).map { App(a, $0) } + let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } + + Exp.shrink(b).map { app(a, $0) } return part1 + part2 } } var free : Set { switch self { - case let .Var(x): + case let .var(x): return Set([x]) - case let .Lam(x, a): - return a.free.subtract([x]) - case let .App(a, b): + case let .lam(x, a): + return a.free.subtracting([x]) + case let .app(a, b): return a.free.union(b.free) } } - func rename(x : Name, _ y : Name) -> Exp { + func rename(_ x : Name, _ y : Name) -> Exp { if x == y { return self } - return self.subst(x, .Var(y)) + return self.subst(x, .var(y)) } - func subst(x : Name, _ c : Exp) -> Exp { + func subst(_ x : Name, _ c : Exp) -> Exp { switch self { - case let .Var(y) where x == y : + case let .var(y) where x == y : return c - case let .Lam(y, a) where x != y: - return .Lam(y, a.subst(x, c)) - case let .App(a, b): - return .App(a.subst(x, c), b.subst(x, c)) + case let .lam(y, a) where x != y: + return .lam(y, a.subst(x, c)) + case let .app(a, b): + return .app(a.subst(x, c), b.subst(x, c)) default: return self } @@ -125,14 +125,14 @@ extension Exp : Arbitrary { var eval : Exp { switch self { - case .Var(_): + case .var(_): fatalError("Cannot evaluate free variable!") - case let .App(a, b): + case let .app(a, b): switch a.eval { - case let .Lam(x, aPrime): + case let .lam(x, aPrime): return aPrime.subst(x, b) default: - return .App(a.eval, b.eval) + return .app(a.eval, b.eval) } default: return self @@ -143,24 +143,24 @@ extension Exp : Arbitrary { extension Exp : CustomStringConvertible { var description : String { switch self { - case let .Var(x): + case let .var(x): return "$" + x.description - case let .Lam(x, t): + case let .lam(x, t): return "(λ $\(x.description).\(t.description))" - case let .App(a, b): + case let .app(a, b): return "(\(a.description) \(b.description))" } } } extension Name { - func fresh(ys : Set) -> Name { + func fresh(_ ys : Set) -> Name { let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } - return Set(zz).subtract(ys).first ?? self + return Set(zz).subtracting(ys).first ?? self } } -private func showResult(x : A, f : A -> Testable) -> Property { +private func showResult(_ x : A, f : (A) -> Testable) -> Property { return f(x).whenFail { print("Result: \(x)") } @@ -173,7 +173,7 @@ class LambdaSpec : XCTestCase { property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in return showResult(a.subst(x, b)) { subst_x_b_a in return a.free.contains(x) - ==> subst_x_b_a.free == a.free.subtract([x]).union(b.free) + ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) } }.expectFailure diff --git a/Tests/ModifierSpec.swift b/Tests/ModifierSpec.swift index a01cfd7..6e24549 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/ModifierSpec.swift @@ -20,7 +20,7 @@ class ModifierSpec : XCTestCase { } property("Pointers behave") <- forAll { (x : PointerOf) in - return x.getPointer == nil || x.size != 0 + return x.size != 0 } property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in @@ -41,9 +41,9 @@ class ModifierSpec : XCTestCase { property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in return - (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" + (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" ^&&^ - (xs.getArray == xs.getArray.reverse().reverse()) "Right identity" + (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" } property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index c98986f..581524e 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -12,7 +12,7 @@ import XCTest struct Path : Arbitrary { let unPath : [A] - private static func pathFrom(x : A) -> Gen<[A]> { + private static func pathFrom(_ x : A) -> Gen<[A]> { return Gen.sized { n in return Gen<[A]>.oneOf( [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } @@ -27,11 +27,11 @@ struct Path : Arbitrary { } } -func path(p : A -> Bool, _ pth : Path) -> Bool { +func path(_ p : (A) -> Bool, _ pth : Path) -> Bool { return pth.unPath.reduce(true, combine: { $0 && p($1) }) } -func somePath(p : A -> Bool, _ pth : Path) -> Property { +func somePath(_ p : (A) -> Bool, _ pth : Path) -> Property { return path({ !p($0) }, pth).expectFailure } @@ -46,19 +46,19 @@ struct Extremal> : Arbitrary { ]).map(Extremal.init) } - static func shrink(x : Extremal) -> [Extremal] { + static func shrink(_ x : Extremal) -> [Extremal] { return A.shrink(x.getExtremal).map(Extremal.init) } } class PathSpec : XCTestCase { - private static func smallProp>(pth : Path) -> Bool { + private static func smallProp>(_ pth : Path) -> Bool { return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 }, pth) } - private static func largeProp>(pth : Path) -> Property { + private static func largeProp>(_ pth : Path) -> Property { return somePath({ x in return (x < -1000000 || x > 1000000) }, pth) diff --git a/Tests/PropertySpec.swift b/Tests/PropertySpec.swift index c151a03..436687f 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/PropertySpec.swift @@ -14,17 +14,17 @@ func ==(l : Property, r : Property) -> Bool { let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) switch (res1, res2) { - case (.Success(_, _, _), .Success(_, _, _)): + case (.success(_, _, _), .success(_, _, _)): return true - case (.GaveUp(_, _, _), .GaveUp(_, _, _)): + case (.gaveUp(_, _, _), .gaveUp(_, _, _)): return true - case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): + case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): return true - case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): + case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): return true - case (.NoExpectedFailure(_, _, _, _, _), .NoExpectedFailure(_, _, _, _, _)): + case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): return true - case (.InsufficientCoverage(_, _, _, _, _), .InsufficientCoverage(_, _, _, _, _)): + case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): return true default: return false @@ -34,7 +34,7 @@ func ==(l : Property, r : Property) -> Bool { func ==(l : Property, r : Bool) -> Bool { let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) switch res1 { - case .Success(_, _, _): + case .success(_, _, _): return r == true default: return r == false @@ -44,7 +44,7 @@ func ==(l : Property, r : Bool) -> Bool { class PropertySpec : XCTestCase { func testProperties() { property("Once really only tests a property once") <- forAll { (n : Int) in - var bomb : Optional = .Some(n) + var bomb : Optional = .some(n) return forAll { (_ : Int) in let b = bomb! // Will explode if we test more than once bomb = nil @@ -71,7 +71,7 @@ class PropertySpec : XCTestCase { }.invert property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in - throw SwiftCheckError.Bogus + throw SwiftCheckError.bogus }.invert property("Invert does not affect discards") <- forAll { (n : Int) in @@ -92,7 +92,7 @@ class PropertySpec : XCTestCase { } property("==> Short Circuits") <- forAll { (n : Int) in - func isPositive(n : Int) -> Bool { + func isPositive(_ n : Int) -> Bool { if n > 0 { return true } else if (n & 1) == 0 { diff --git a/Tests/RawRepresentableSpec.swift b/Tests/RawRepresentableSpec.swift index 7f55c66..dc01299 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/RawRepresentableSpec.swift @@ -10,9 +10,9 @@ import XCTest import SwiftCheck enum ImplicitRawValues : Int { - case Foo - case Bar - case Baz + case foo + case bar + case baz } // Declaring the extension allows Swift to know this particular enum can be Arbitrary @@ -20,15 +20,15 @@ enum ImplicitRawValues : Int { extension ImplicitRawValues: Arbitrary {} enum ExplicitRawValues : Int { - case Zero = 0 - case One = 1 - case Two = 2 + case zero = 0 + case one = 1 + case two = 2 } class RawRepresentable_ArbitrarySpec: XCTestCase { func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in - return [.Foo, .Bar, .Baz].contains(e) + return [.foo, .bar, .baz].contains(e) } } @@ -36,7 +36,7 @@ class RawRepresentable_ArbitrarySpec: XCTestCase { // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically // infer protocol conformance property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in - return [.Zero, .One, .Two].contains(e) + return [.zero, .one, .two].contains(e) } } } diff --git a/Tests/ReplaySpec.swift b/Tests/ReplaySpec.swift index f9cd608..9723d6d 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/ReplaySpec.swift @@ -12,7 +12,7 @@ import XCTest class ReplaySpec : XCTestCase { func testProperties() { property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .Some(StdGen(seedl, seedr), size)) + let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) var foundArgs : [Int] = [] property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in foundArgs.append(x) diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index f411260..668ef21 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -10,15 +10,15 @@ import SwiftCheck import XCTest class RoseSpec : XCTestCase { - private static func intRoseTree(v : Int) -> Rose { - return .MkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + private static func intRoseTree(_ v : Int) -> Rose { + return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) } - private static func depthOneChildren(rose : Rose) -> [A] { + private static func depthOneChildren(_ rose : Rose) -> [A] { return rose.children.map { $0.root } } - private static func depthOneAndTwoChildren(rose : Rose) -> [A] { + private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { let topChildren = rose.children let vs = topChildren.map { $0.root } let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) @@ -93,23 +93,23 @@ struct RoseTreeOf : Arbitrary { } } -private func arbTree(n : Int) -> Gen> { +private func arbTree(_ n : Int) -> Gen> { if n == 0 { return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } } return Positive.arbitrary.flatMap { m in let n2 = n / (m.getPositive + 1) return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in - return Gen.pure(RoseTreeOf(.MkRose({ a }, { f.map { $0.getRose } }))) + return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) } } } private func == (l : Rose, r : Rose) -> Bool { switch (l, r) { - case let (.MkRose(l1, r1), .MkRose(l2, r2)): + case let (.mkRose(l1, r1), .mkRose(l2, r2)): return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } - case (.IORose(_), .IORose(_)): + case (.ioRose(_), .ioRose(_)): return true default: return false @@ -119,7 +119,7 @@ private func == (l : Rose, r : Rose) -> Bool { extension Rose { var root : A { switch self.reduce { - case let .MkRose(root, _): + case let .mkRose(root, _): return root() default: fatalError("Rose should not have reduced to .IORose") @@ -128,7 +128,7 @@ extension Rose { var children : [Rose] { switch self.reduce { - case let .MkRose(_, children): + case let .mkRose(_, children): return children() default: fatalError("Rose should not have reduced to .IORose") @@ -141,6 +141,6 @@ extension Rose { let vs = children.map { $0.collapse } let cs = children.flatMap({ $0.children }).map { $0.collapse } - return .MkRose({ self.root }, { vs + cs }) + return .mkRose({ self.root }, { vs + cs }) } } diff --git a/Tests/ShrinkSpec.swift b/Tests/ShrinkSpec.swift index 58e29ba..4a0e4f4 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/ShrinkSpec.swift @@ -10,7 +10,7 @@ import SwiftCheck import XCTest class ShrinkSpec : XCTestCase { - func shrinkArbitrary(x : A) -> [A] { + func shrinkArbitrary(_ x : A) -> [A] { let xs = A.shrink(x) if let x = xs.first { return xs + [x].flatMap(self.shrinkArbitrary) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 692e444..ed50611 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -112,11 +112,14 @@ class SimpleSpec : XCTestCase { || (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) } - + + let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) + let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) + let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ - ((>), (<=)), - ((<), (>=)), - ((==), (!=)), + greaterThan_lessThanEqualTo, + lessThan_greaterThanEqualTo, + equalTo_notEqualTo, ]) property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index bb9200a..87ed7ff 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -10,9 +10,9 @@ import SwiftCheck import XCTest extension Dictionary { - init(_ pairs : S) { + init(_ pairs : S) { self.init() - var g = pairs.generate() + var g = pairs.makeIterator() while let (k, v) : (Key, Value) = g.next() { self[k] = v } @@ -22,7 +22,7 @@ extension Dictionary { class TestSpec : XCTestCase { func testAll() { - let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map(Dictionary.init) + let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in return true @@ -38,16 +38,16 @@ class TestSpec : XCTestCase { property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in return - (xs.reverse().reverse() == xs) "Left identity" + (xs.reversed().reversed() == xs) "Left identity" ^&&^ - (xs == xs.reverse().reverse()) "Right identity" + (xs == xs.reversed().reversed()) "Right identity" } property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in return - (xs.sort().sort() == xs.sort()).verbose "Sort Left" + (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" ^&&^ - ((xs.sort() != xs.sort().sort()).verbose "Bad Sort Right") + ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") }.expectFailure property("map behaves") <- forAll { (xs : Array) in From 37c80a15d6e699b1e8217effe8f12ee49d055a0d Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 18 Jun 2016 08:26:07 -0400 Subject: [PATCH 315/460] Build without warnings and pass --- Sources/Random.swift | 18 ++++++++++++++---- Sources/Test.swift | 2 +- Sources/TestOperators.swift | 10 +++++----- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Sources/Random.swift b/Sources/Random.swift index 6479f9e..f0e4ad7 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -304,6 +304,10 @@ extension Double : RandomType { } /// Implementation Details Follow +private enum ClockTimeResult { + case success + case failure(Int) +} private func mkStdRNG(_ o : Int) -> StdGen { func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { @@ -315,22 +319,28 @@ private func mkStdRNG(_ o : Int) -> StdGen { let ct = Int(clock()) var tt = timespec() - clock_gettime(0, &tt) + switch clock_gettime(0, &tt) { + case .success: + break + case let .failure(error): + fatalError("call to `clock_gettime` failed. error: \(error)") + } + let (sec, psec) = (tt.tv_sec, tt.tv_nsec) let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } -private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { +private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> ClockTimeResult { var now : timeval = timeval() let rv = gettimeofday(&now, nil) if rv != 0 { - return Int(rv) + return .failure(Int(rv)) } t.pointee.tv_sec = now.tv_sec t.pointee.tv_nsec = Int(now.tv_usec) * 1000 - return 0 + return .success } #if os(Linux) diff --git a/Sources/Test.swift b/Sources/Test.swift index 5219ed2..6352c03 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -344,7 +344,7 @@ public func exists(_ gen : Gen, pf : (A) throws -> Testable) - /// Tests a property and prints the results to stdout. public func quickCheck(_ prop : Testable, name : String = "") { - quickCheckWithResult(CheckerArguments(name: name), prop) + _ = quickCheckWithResult(CheckerArguments(name: name), prop) } // MARK: - Implementation Details diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index 27dcee2..9f352c5 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -142,7 +142,7 @@ public struct CheckerArguments { infix operator <- {} /// Binds a Testable value to a property. -public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { +public func <- (checker : AssertiveQuickCheck, test : @autoclosure(escaping)() -> Testable) { switch quickCheckWithResult(checker.args, test()) { case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) @@ -171,12 +171,12 @@ public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { - quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. -public func <- (checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - quickCheckWithResult(checker.args, test()) +public func <- (checker : ReportiveQuickCheck, test : @autoclosure(escaping)() -> Testable) { + _ = quickCheckWithResult(checker.args, test()) } infix operator ==> { @@ -187,7 +187,7 @@ infix operator ==> { /// Models implication for properties. That is, the property holds if the first /// argument is false (in which case the test case is discarded), or if the /// given property holds. -public func ==> (b : Bool, @autoclosure p : () -> Testable) -> Property { +public func ==> (b : Bool, p : @autoclosure() -> Testable) -> Property { if b { return p().property } From 763bae2edd63b99d31f6d9897b36a66245ac9eac Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 18 Jun 2016 08:28:21 -0400 Subject: [PATCH 316/460] update project settings --- SwiftCheck.xcodeproj/project.pbxproj | 9 ++++++++- .../xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcshareddata/xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcshareddata/xcschemes/SwiftCheck.xcscheme | 10 +++++----- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index d729080..daad3a3 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -477,7 +477,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -780,6 +780,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -814,6 +815,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -842,6 +844,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -887,6 +890,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -964,6 +968,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 2.3; }; name = Release; @@ -1071,6 +1076,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1116,6 +1122,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index e559f2e..81d7615 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -52,11 +52,11 @@ Date: Sat, 18 Jun 2016 10:54:34 -0700 Subject: [PATCH 317/460] add Gen.compose to allow imperative generator composition Swift's lack of implicit conformance and polyvariadic functions makes composing generators using map/zip or functional operators cumbersome and/or infeasible for types with a large number of input parameters. Not only is manually gathering many generated values to create a new generator vulnerable to losing entropy, but it's also rife with duplicated calls to manually split the StdGen. GenComposer fixes this by encapsulating the logic of splitting the StdGen, as well as offering generic functions to remove even more boilerplate for the default use case (T.arbitrary). --- Sources/Modifiers.swift | 77 +++++++++++++++++++++++++++++++++++++++++ Tests/SimpleSpec.swift | 44 +++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 7da727a..e9850f1 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -649,3 +649,80 @@ private final class PointerOfImpl : Arbitrary { } } +/** + Class used to generate values from mulitple `Gen` instances. + + Given a StdGen and size, generate values from other generators, splitting the StdGen + after each call to `generate`, ensuring suffiicent entropy across generators. + + - seealso: Gen.compose +*/ +public final class GenComposer { + var stdgen: StdGen + var size: Int + + init(stdgen: StdGen, size: Int) { + self.stdgen = stdgen + self.size = size + } + + // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. + private func split() -> StdGen { + let old = stdgen + stdgen = old.split.0 + return old + } + + /// Generate a new `T` with a specific generator. + /// + /// - parameter gen: The generator used to create a random value. + /// + /// - returns: A random `T` using the receiver's stdgen and size. + /// + public func generate(gen: Gen) -> T { + return gen.unGen(split(), size) + } + + /// Generate a new `T` with it's default `arbitrary` generator. + /// + /// - returns: A random `T`. + /// + /// - seealso: generate\(gen:) + public func generate() -> T { + return generate(T.arbitrary) + } +} + +extension Gen { + /** + Create a generator by procedurally composing generated values from other generators. + + This is useful in cases where it's cumbersome to functionally compose multiple + generators using `zip` and `map`. For example: + + public static var arbitrary: Gen { + return Gen.compose { c in + return ArbitraryLargeFoo( + // use the nullary method to get an `arbitrary` value + a: c.generate(), + + // or pass a custom generator + b: c.generate(Bool.suchThat { $0 == false }), + + // .. and so on, for as many values & types as you need + c: c.generate(), ... + ) + } + } + + - parameter build: Function which is passed a GenComposer which can be used + + - returns: A generator which uses the `build` function to create arbitrary instances of `A`. + */ + public static func compose(build: GenComposer -> A) -> Gen { + return Gen(unGen: { (stdgen, size) -> A in + let composer = GenComposer(stdgen: stdgen, size: size) + return build(composer) + }) + } +} diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 692e444..358189e 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -41,6 +41,26 @@ public struct ArbitraryLargeFoo { let n : (Bool, Bool, Bool, Bool) } +extension ArbitraryLargeFoo: Equatable {} + +public func ==(i: ArbitraryLargeFoo, j: ArbitraryLargeFoo) -> Bool { + return + i.a == j.a + && i.b == j.b + && i.c == j.c + && i.d == j.d + && i.e == j.e + && i.f == j.f + && i.g == j.g + && i.h == j.h + && i.i == j.i + && i.j == j.j + && i.k == j.k + && i.l == j.l + && i.m == j.m + && i.n == j.n +} + extension ArbitraryLargeFoo : Arbitrary { public static var arbitrary : Gen { return Gen<(Int8, Int16, Int32, Int64 @@ -124,6 +144,30 @@ class SimpleSpec : XCTestCase { return op(x, y) ==== !iop(x, y) } } + + let composedArbitraryLargeFoo = Gen.compose { c in + return ArbitraryLargeFoo( + a: c.generate(), + b: c.generate(), + c: c.generate(), + d: c.generate(), + e: c.generate(), + f: c.generate(), + g: c.generate(), + h: c.generate(), + i: c.generate(), + j: c.generate(), + k: c.generate(), + l: (c.generate(), c.generate()), + m: (c.generate(), c.generate(), c.generate()), + n: (c.generate(), c.generate(), c.generate(), c.generate()) + ) + } + + property("composition generates high-entropy, arbitrary values") + <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in + return a != b + } } } From f68b8a4c67a6200165c5bc207b065156d2249180 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 18 Jun 2016 14:23:20 -0400 Subject: [PATCH 318/460] Narrow import This was meant to fix line 25 (dictionaryGen) implicitly being NSDictionary. It did not. It is still a desirable change. --- Tests/TestSpec.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index 87ed7ff..5e3d8f1 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -7,7 +7,7 @@ // import SwiftCheck -import XCTest +import class XCTest.XCTestCase extension Dictionary { init(_ pairs : S) { From 8471485f8a13c8d478ed0d2acd1458dbcd8fae74 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 18 Jun 2016 14:23:37 -0400 Subject: [PATCH 319/460] Avoid force unwrapping where reasonable --- Sources/Gen.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 537bd5e..0e3e31c 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -559,10 +559,8 @@ private func size(_ k : S, _ m : Int) -> Int { } private func selectOne(_ xs : [A]) -> [(A, [A])] { - if xs.isEmpty { - return [] - } - let y = xs.first! + guard let y = xs.first else { return [] } + let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) return [(y, ys)] + rec From 0510ee2af266aea0a3b304ff6da5abc8bfbb5885 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Sat, 18 Jun 2016 12:25:23 -0700 Subject: [PATCH 320/460] make GenComposer members private --- Sources/Modifiers.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index e9850f1..bd3a48e 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -658,8 +658,8 @@ private final class PointerOfImpl : Arbitrary { - seealso: Gen.compose */ public final class GenComposer { - var stdgen: StdGen - var size: Int + private var stdgen: StdGen + private var size: Int init(stdgen: StdGen, size: Int) { self.stdgen = stdgen From df99726940876c123726e24c75acdc57c366ec5b Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Sat, 18 Jun 2016 12:41:03 -0700 Subject: [PATCH 321/460] fixing comments in response to comments on comments --- Sources/Modifiers.swift | 62 +++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index bd3a48e..8463484 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -649,14 +649,12 @@ private final class PointerOfImpl : Arbitrary { } } -/** - Class used to generate values from mulitple `Gen` instances. - - Given a StdGen and size, generate values from other generators, splitting the StdGen - after each call to `generate`, ensuring suffiicent entropy across generators. - - - seealso: Gen.compose -*/ +/// Class used to generate values from mulitple `Gen` instances. +/// +/// Given a StdGen and size, generate values from other generators, splitting the StdGen +/// after each call to `generate`, ensuring suffiicent entropy across generators. +/// +/// - seealso: Gen.compose public final class GenComposer { private var stdgen: StdGen private var size: Int @@ -694,31 +692,29 @@ public final class GenComposer { } extension Gen { - /** - Create a generator by procedurally composing generated values from other generators. - - This is useful in cases where it's cumbersome to functionally compose multiple - generators using `zip` and `map`. For example: - - public static var arbitrary: Gen { - return Gen.compose { c in - return ArbitraryLargeFoo( - // use the nullary method to get an `arbitrary` value - a: c.generate(), - - // or pass a custom generator - b: c.generate(Bool.suchThat { $0 == false }), - - // .. and so on, for as many values & types as you need - c: c.generate(), ... - ) - } - } - - - parameter build: Function which is passed a GenComposer which can be used - - - returns: A generator which uses the `build` function to create arbitrary instances of `A`. - */ + /// Create a generator by procedurally composing generated values from other generators. + /// + /// This is useful in cases where it's cumbersome to functionally compose multiple + /// generators using `zip` and `map`. For example: + /// + /// public static var arbitrary: Gen { + /// return Gen.compose { c in + /// return ArbitraryLargeFoo( + /// // use the nullary method to get an `arbitrary` value + /// a: c.generate(), + /// + /// // or pass a custom generator + /// b: c.generate(Bool.suchThat { $0 == false }), + /// + /// // .. and so on, for as many values & types as you need + /// c: c.generate(), ... + /// ) + /// } + /// } + /// + /// - parameter build: Function which is passed a GenComposer which can be used + /// + /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. public static func compose(build: GenComposer -> A) -> Gen { return Gen(unGen: { (stdgen, size) -> A in let composer = GenComposer(stdgen: stdgen, size: size) From 9c7d0b86443f36e651d8930be6670d44f5a4b664 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Sat, 18 Jun 2016 12:41:52 -0700 Subject: [PATCH 322/460] spelling & gammer fixes, minus superfluous comment line --- Sources/Modifiers.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 8463484..7436fc6 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -652,7 +652,7 @@ private final class PointerOfImpl : Arbitrary { /// Class used to generate values from mulitple `Gen` instances. /// /// Given a StdGen and size, generate values from other generators, splitting the StdGen -/// after each call to `generate`, ensuring suffiicent entropy across generators. +/// after each call to `generate`, ensuring sufficient entropy across generators. /// /// - seealso: Gen.compose public final class GenComposer { @@ -676,12 +676,11 @@ public final class GenComposer { /// - parameter gen: The generator used to create a random value. /// /// - returns: A random `T` using the receiver's stdgen and size. - /// public func generate(gen: Gen) -> T { return gen.unGen(split(), size) } - /// Generate a new `T` with it's default `arbitrary` generator. + /// Generate a new `T` with its default `arbitrary` generator. /// /// - returns: A random `T`. /// From d704d8ca07ea4fe818a616fb9135eb1fa02e5ca6 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Mon, 20 Jun 2016 08:19:45 -0400 Subject: [PATCH 323/460] add Gen.compose test for mutable type plus a hacky workaround for property w/ 0 size?... --- Tests/SimpleSpec.swift | 72 +++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 358189e..cf10684 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -24,6 +24,31 @@ extension ArbitraryFoo : Arbitrary { } } +public struct ArbitraryMutableFoo : Arbitrary { + var a: Int8 + var b: Int16 + + public init() { + a = 0 + b = 0 + } + + public static var arbitrary: Gen { + return Gen.compose { c in + var foo = ArbitraryMutableFoo() + foo.a = c.generate() + foo.b = c.generate() + return foo + } + } +} + +extension ArbitraryMutableFoo: Equatable {} + +public func == (lhs: ArbitraryMutableFoo, rhs: ArbitraryMutableFoo) -> Bool { + return lhs.a == rhs.a && lhs.b == rhs.b +} + public struct ArbitraryLargeFoo { let a : Int8 let b : Int16 @@ -83,6 +108,26 @@ extension ArbitraryLargeFoo : Arbitrary { } } +let composedArbitraryLargeFoo = Gen.compose { c in + let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } + return ArbitraryLargeFoo( + a: c.generate(), + b: c.generate(evenInt16), + c: c.generate(), + d: c.generate(), + e: c.generate(), + f: c.generate(), + g: c.generate(), + h: c.generate(), + i: c.generate(), + j: c.generate(), + k: c.generate(), + l: (c.generate(), c.generate()), + m: (c.generate(), c.generate(), c.generate()), + n: (c.generate(), c.generate(), c.generate(), c.generate()) + ) +} + class SimpleSpec : XCTestCase { func testAll() { property("Integer Equality is Reflexive") <- forAll { (i : Int8) in @@ -145,29 +190,18 @@ class SimpleSpec : XCTestCase { } } - let composedArbitraryLargeFoo = Gen.compose { c in - return ArbitraryLargeFoo( - a: c.generate(), - b: c.generate(), - c: c.generate(), - d: c.generate(), - e: c.generate(), - f: c.generate(), - g: c.generate(), - h: c.generate(), - i: c.generate(), - j: c.generate(), - k: c.generate(), - l: (c.generate(), c.generate()), - m: (c.generate(), c.generate(), c.generate()), - n: (c.generate(), c.generate(), c.generate(), c.generate()) - ) - } - property("composition generates high-entropy, arbitrary values") <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in return a != b } } + + func testComposeWithMutableType() { + property("composition allows setting values on mutable types") + <- (forAll { (a: ArbitraryMutableFoo, b: ArbitraryMutableFoo) in + return a != b + // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size + }.mapSize { $0 + 100 }) + } } From afb0acbb5720806b40fcc77af9912f87c0f8c8c1 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Mon, 20 Jun 2016 08:20:39 -0400 Subject: [PATCH 324/460] add Gen.compose README docs --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/README.md b/README.md index 5d3e3ab..a66c0ea 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,73 @@ class SimpleSpec : XCTestCase { } ``` +There's also a `Gen.compose` method which allows you to procedurally compose values from multiple generators to construct instances of a type: + +``` swift +public struct ArbitraryLargeFoo { + let a : Int8 + let b : Int16 + let c : Int32 + let d : Int64 + let e : UInt8 + let f : UInt16 + let g : UInt32 + let h : UInt64 + let i : Int + let j : UInt + let k : Bool + let l : (Bool, Bool) + let m : (Bool, Bool, Bool) + let n : (Bool, Bool, Bool, Bool) + + public static var arbitrary: Gen = Gen.compose { c in + // c is a `GenComposer` which will generate the values you need, either from the default `arbitrary` member of the + // type or a given generator + let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } + return ArbitraryLargeFoo( + a: c.generate(), // `generate()` infers the type to return a value from `Int8.arbitrary` + b: c.generate(evenInt16), // returns a value from `evenInt16` + c: c.generate(), + d: c.generate(), + e: c.generate(), + f: c.generate(), + g: c.generate(), + h: c.generate(), + i: c.generate(), + j: c.generate(), + k: c.generate(), + l: (c.generate(), c.generate()), + m: (c.generate(), c.generate(), c.generate()), + n: (c.generate(), c.generate(), c.generate(), c.generate()) + ) + } +} + +``` + +`Gen.compose` can also be used with types that can only be customized with setters: + +``` swift +public struct ArbitraryMutableFoo : Arbitrary { + var a: Int8 + var b: Int16 + + public init() { + a = 0 + b = 0 + } + + public static var arbitrary: Gen { + return Gen.compose { c in + var foo = ArbitraryMutableFoo() + foo.a = c.generate() + foo.b = c.generate() + return foo + } + } +} +``` + For everything else, SwiftCheck defines a number of combinators to make working with custom generators as simple as possible: From d5589b92ce6bed7785452ba209cabc60869439ee Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Mon, 20 Jun 2016 10:58:07 -0400 Subject: [PATCH 325/460] add simulator timeout hacks for iOS tests ensure simulator is launched w/ the desired device (as specified in xcodebuild -destination argument) --- .travis.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a93f50..c64b714 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,17 @@ matrix: script: - set -o pipefail - xcodebuild test -scheme SwiftCheck | xcpretty -c - - xcodebuild test -scheme SwiftCheck-iOS -destination 'platform=iOS Simulator,name=iPad Pro' | xcpretty -c + # -- Start iOS -- + - iOS_DEVICE_NAME="iPad Pro" + - iOS_RUNTIME_VERSION="9.3" + # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image + - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") + - echo $SIMULATOR_ID + - echo $iOS_DEVICE_NAME + - echo $iOS_RUNTIME_VERSION + - open -b com.apple.iphonesimulator --args -CurrentDeviceUDID $SIMULATOR_ID + - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c + # -- End iOS -- - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - os: linux language: generic From c9629cce6635f8b7b96ae874768392f71ba97aea Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Mon, 20 Jun 2016 14:40:42 -0400 Subject: [PATCH 326/460] add comments explaining sim timeout workaround --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c64b714..6c40df6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,13 +20,15 @@ matrix: - set -o pipefail - xcodebuild test -scheme SwiftCheck | xcpretty -c # -- Start iOS -- + # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - iOS_DEVICE_NAME="iPad Pro" - iOS_RUNTIME_VERSION="9.3" - # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image + # Get simulator identifier for desired device/runtime pair - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") - echo $SIMULATOR_ID - echo $iOS_DEVICE_NAME - echo $iOS_RUNTIME_VERSION + # !!!: Start simulator w/ desired device—helps avoid issues w/ Xcode timing out when waiting for simulator to become ready - open -b com.apple.iphonesimulator --args -CurrentDeviceUDID $SIMULATOR_ID - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c # -- End iOS -- From b40b4957e452e7e6abf5aa5858c50015a171b8f3 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Thu, 7 Jul 2016 19:37:14 -0400 Subject: [PATCH 327/460] warn unused result is the default --- Sources/Test.swift | 27 --------------------------- Sources/TestOperators.swift | 2 -- Sources/Witness.swift | 8 -------- 3 files changed, 37 deletions(-) diff --git a/Sources/Test.swift b/Sources/Test.swift index 6352c03..675df47 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -97,112 +97,96 @@ /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : ((A) throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B) throws -> Testable) -> Property { return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C) throws -> Testable) -> Property { return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -212,7 +196,6 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -222,7 +205,6 @@ public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } @@ -232,7 +214,6 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : (A, B) t /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -242,7 +223,6 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : G /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -252,7 +232,6 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -262,7 +241,6 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ ge /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -272,7 +250,6 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -282,14 +259,12 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAllShrink(_ gen : Gen, shrinker : (A) -> [A], f : (A) throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in @@ -320,14 +295,12 @@ public func forAllShrink(_ gen : Gen, shrinker : (A) -> [A], f : (A) throw /// `SNF` involves turning every `exists` into a function returning the /// existential value, taking any other parameters being quantified over as /// needed. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func exists(_ pf : (A) throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func exists(_ gen : Gen, pf : (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index 9f352c5..f6f4d5e 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -33,7 +33,6 @@ /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -@warn_unused_result(message:"Did you forget to bind this property to a quantifier?") public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } @@ -56,7 +55,6 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. -@warn_unused_result(message:"Did you forget to bind this property to a quantifier?") public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index 1eb87a4..5e9b7f4 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -66,56 +66,48 @@ public protocol WitnessedArbitrary { /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : ((A) -> Testable)) -> Property { return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B) -> Testable) -> Property { return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C) -> Testable) -> Property { return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D) -> Testable) -> Property { return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F, G) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message:"Did you forget to bind this quantifier to a property?") public func forAll(_ pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } From 8ca6a6921cda96bbb6287a747d1087a59d413b59 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Fri, 8 Jul 2016 11:44:08 -0400 Subject: [PATCH 328/460] Xcode 8b2 --- Cartfile.resolved | 2 +- Carthage/Checkouts/Operadics | 2 +- Sources/Modifiers.swift | 6 +++--- Tests/SimpleSpec.swift | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 1dd0fd1..42bd8b3 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Operadics" "0.1.4" +github "typelift/Operadics" "0.2.0" diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics index c65e635..8117a84 160000 --- a/Carthage/Checkouts/Operadics +++ b/Carthage/Checkouts/Operadics @@ -1 +1 @@ -Subproject commit c65e6355e22282a89d68a8a2d594a32c36c1e7b0 +Subproject commit 8117a84bb4111814c35af80285f3f9baff290d7e diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index a641475..c875ad0 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -677,7 +677,7 @@ public final class GenComposer { /// - parameter gen: The generator used to create a random value. /// /// - returns: A random `T` using the receiver's stdgen and size. - public func generate(gen: Gen) -> T { + public func generate(using gen: Gen) -> T { return gen.unGen(split(), size) } @@ -687,7 +687,7 @@ public final class GenComposer { /// /// - seealso: generate\(gen:) public func generate() -> T { - return generate(T.arbitrary) + return generate(using: T.arbitrary) } } @@ -715,7 +715,7 @@ extension Gen { /// - parameter build: Function which is passed a GenComposer which can be used /// /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. - public static func compose(build: GenComposer -> A) -> Gen { + public static func compose(build: (GenComposer) -> A) -> Gen { return Gen(unGen: { (stdgen, size) -> A in let composer = GenComposer(stdgen: stdgen, size: size) return build(composer) diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index b7c8b6b..f355a5e 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -112,7 +112,7 @@ let composedArbitraryLargeFoo = Gen.compose { c in let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } return ArbitraryLargeFoo( a: c.generate(), - b: c.generate(evenInt16), + b: c.generate(using: evenInt16), c: c.generate(), d: c.generate(), e: c.generate(), From 6ff84191234e5c397bd6d9c6b1bac97de33bff47 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Thu, 21 Jul 2016 14:58:04 -0400 Subject: [PATCH 329/460] update for Xcode 8b3 --- Sources/Modifiers.swift | 2 +- Sources/Property.swift | 2 +- Tutorial.playground/Contents.swift | 79 +++++++----------------------- 3 files changed, 20 insertions(+), 63 deletions(-) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index c875ad0..0db0dea 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -577,7 +577,7 @@ private final class IsoOfImpl, U self.project = { [unowned self] u in let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self.table[k] { + if let k = ts.first, let _ = self.table[k] { return k } let y = project(u) diff --git a/Sources/Property.swift b/Sources/Property.swift index 899e24f..da66a7e 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -508,7 +508,7 @@ private func sep(_ l : String, r : String) -> String { } private func mplus(_ l : Optional, r : Optional) -> Optional { - if let ls = l, rs = r { + if let ls = l, let rs = r { return .some(ls + rs) } diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 37c057a..6dc8893 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -1,6 +1,7 @@ //: Playground - noun: a place where people can play import SwiftCheck +import Foundation.NSDate //: # Prerequisites @@ -129,7 +130,7 @@ pairsOfNumbers.generate // This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. let weightedGen = Gen.weighted([ (1, nil), - (3, .Some(5)), + (3, .some(5)), ]) weightedGen.generate @@ -245,8 +246,8 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ let localEmail = allowedLocalCharacters .proliferateNonEmpty // Make a non-empty array of characters - .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. - .map(String.init) // Then make a string. + .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) // Such that the last character isn't a dot. + .map { String($0) } // Then make a string. //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine them all into one big generator. @@ -255,20 +256,20 @@ let hostname = Gen.oneOf([ lowerCaseLetters, numeric, Gen.pure("-"), -]).proliferateNonEmpty.map(String.init) +]).proliferateNonEmpty.map { String($0) } //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. let tld = lowerCaseLetters .proliferateNonEmpty .suchThat({ $0.count > 1 }) - .map(String.init) + .map { String($0) } //: So now that we've got all the pieces, so how do we put them together to make the final generator? Well, how //: about some glue? // Concatenates an array of `String` `Gen`erators together in order. -func glue(parts : [Gen]) -> Gen { +func glue(_ parts : [Gen]) -> Gen { return sequence(parts).map { $0.reduce("", combine: +) } } @@ -281,7 +282,6 @@ emailGen.generate emailGen.generate emailGen.generate - //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: @@ -309,56 +309,12 @@ emailGen.generate //: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance //: for `Int` calls `arc4random_uniform`. //: -//: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen -//: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. - -import class Foundation.NSDate -import typealias Foundation.NSTimeInterval - -//: Here's the obvious way to do it -// -// extension NSDate : Arbitrary { -// public static var arbitrary : Gen { -// return Gen.oneOf([ -// Gen.pure(NSDate()), -// Gen.pure(NSDate.distantFuture()), -// Gen.pure(NSDate.distantPast()), -// NSDate.init <^> NSTimeInterval.arbitrary, -// ]) -// } -// } -// -//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` -//: in the wrong position. What to do? -//: -//: Let's write a wrapper! - -struct ArbitraryDate : Arbitrary { - let getDate : NSDate - - init(date : NSDate) { self.getDate = date } - - static var arbitrary : Gen { - return Gen.oneOf([ - Gen.pure(NSDate()), - Gen.pure(NSDate.distantFuture()), - Gen.pure(NSDate.distantPast()), - NSDate.init <^> NSTimeInterval.arbitrary, - ]).map(ArbitraryDate.init) - } -} - -ArbitraryDate.arbitrary.generate.getDate -ArbitraryDate.arbitrary.generate.getDate - -//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't -//: generate with another that we can. -//: -//: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but +//: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't +//: generate with another that we can–for a few of the more "difficult" types in the Swift STL, but //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: -public struct ArbitraryPositive> : Arbitrary { +public struct ArbitraryPositive> : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -395,7 +351,7 @@ ArbitraryPositive.arbitrary.generate.getPositive // | | // v v property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in - return xs.reverse().reverse() == xs + return xs.reversed().reversed() == xs } // From now on, all of our examples will take the form above. @@ -499,7 +455,7 @@ struct ArbitraryEmail : Arbitrary { // Let's be wrong for the sake of example property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in - return !email.getEmail.containsString(".") + return !email.getEmail.contains(".") }.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail // and live up to your expectations, SwiftCheck treats that as a failure of the test case. @@ -531,7 +487,7 @@ func sieve(n : Int) -> [Int] { marked[1] = true for p in 2.. [Int] { // // Short and sweet check if a number is prime by enumerating from 2...⌈√(x)⌉ and checking // for a nonzero modulus. -func isPrime(n : Int) -> Bool { +func isPrime(_ n : Int) -> Bool { if n == 0 || n == 1 { return false } else if n == 2 { @@ -569,7 +525,7 @@ func isPrime(n : Int) -> Bool { //: following property: reportProperty("All Prime") <- forAll { (n : Positive) in - let primes = sieve(n.getPositive) + let primes = sieve(n: n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) return forAll(primeNumberGen) { (p : Int) in @@ -624,7 +580,7 @@ reportProperty("All Prime") <- forAll { (n : Positive) in // //: Looks like we used `to:` when we meant `through:`. Let's try again: -func sieveProperly(n : Int) -> [Int] { +func sieveProperly(_ n : Int) -> [Int] { if n <= 1 { return [] } @@ -634,7 +590,8 @@ func sieveProperly(n : Int) -> [Int] { marked[1] = true for p in 2.. Date: Fri, 29 Jul 2016 13:06:24 -0400 Subject: [PATCH 330/460] update legacy swift settings in remaining targets --- SwiftCheck.xcodeproj/project.pbxproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 09667b4..f333996 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -497,9 +497,11 @@ }; 84DF75F71B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; 84DF76011B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; }; }; @@ -749,6 +751,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -781,6 +784,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -800,6 +804,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -816,6 +821,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -1044,6 +1050,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1077,6 +1084,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1104,6 +1112,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1123,6 +1132,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; VALIDATE_PRODUCT = YES; }; name = Release; From 01e12ef6e2f73dd2e408868ccd4bfb5cbc62d824 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Mon, 1 Aug 2016 16:08:16 -0400 Subject: [PATCH 331/460] Xcode 8b4 --- Sources/Gen.swift | 10 +++++----- Sources/Modifiers.swift | 30 +++++++++++++++--------------- Sources/Property.swift | 8 ++++---- Sources/Random.swift | 2 +- Sources/Rose.swift | 2 +- Sources/Test.swift | 4 ++-- Sources/WitnessedArbitrary.swift | 8 ++++---- Tests/ComplexSpec.swift | 2 +- Tests/FailureSpec.swift | 2 +- Tests/ModifierSpec.swift | 2 +- Tests/PathSpec.swift | 8 ++++---- Tests/TestSpec.swift | 2 +- 12 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 0e3e31c..89e8a75 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,7 +44,7 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf>(_ xs : S) -> Gen { + public static func fromElementsOf(_ xs : S) -> Gen { return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } @@ -77,7 +77,7 @@ public struct Gen { /// Constructs a Generator that produces permutations of a given array. public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(isOrderedBefore: { l, r in l.0 < r.0 }).map { $0.1 }) + return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) } } @@ -105,7 +105,7 @@ public struct Gen { /// /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf, S.Index : protocol, S.Index : RandomType>(_ gs : S) -> Gen { + public static func oneOf, S.Index : RandomType & Comparable, S.Index : RandomType>(_ gs : S) -> Gen { assert(gs.count != 0, "oneOf used with empty list") return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in @@ -123,7 +123,7 @@ public struct Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") - return choose((1, xs.map({ $0.0 }).reduce(0, combine: +))).flatMap { l in + return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in return pick(l, xs) } } @@ -487,7 +487,7 @@ public func >>- (m : Gen, fn : (A) -> Gen) -> Gen { /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(_ ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), combine: { n, m in + return ms.reduce(Gen<[A]>.pure([]), { n, m in return m.flatMap { x in return n.flatMap { xs in return Gen<[A]>.pure(xs + [x]) diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 0db0dea..a89eecc 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -152,7 +152,7 @@ extension ArrayOf : CoArbitrary { } /// Generates a sorted array of arbitrary values of type A. -public struct OrderedArrayOf> : Arbitrary, CustomStringConvertible { +public struct OrderedArrayOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying sorted array of values. public let getOrderedArray : [A] @@ -184,7 +184,7 @@ public struct OrderedArrayOf> : Arbitrary, C /// Generates an dictionary of arbitrary keys and values. -public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { +public struct DictionaryOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying dictionary of values. public let getDictionary : Dictionary @@ -249,7 +249,7 @@ extension OptionalOf : CoArbitrary { } /// Generates a set of arbitrary values of type A. -public struct SetOf> : Arbitrary, CustomStringConvertible { +public struct SetOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying set of values. public let getSet : Set @@ -315,7 +315,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { } /// Generates a Swift function from T to U. -public struct ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { +public struct ArrowOf : Arbitrary, CustomStringConvertible { private let _impl : ArrowOfImpl /// Retrieves the underlying function value, `T -> U`. @@ -344,7 +344,7 @@ extension ArrowOf : CustomReflectable { } /// Generates two isomorphic Swift functions from `T` to `U` and back again. -public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { +public struct IsoOf : Arbitrary, CustomStringConvertible { private let _impl : IsoOfImpl /// Retrieves the underlying embedding function, `T -> U`. @@ -380,7 +380,7 @@ extension IsoOf : CustomReflectable { /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. -public struct Large> : Arbitrary { +public struct Large : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A @@ -405,7 +405,7 @@ public struct Large> : Arbitrary } /// Guarantees that every generated integer is greater than 0. -public struct Positive> : Arbitrary, CustomStringConvertible { +public struct Positive : Arbitrary, CustomStringConvertible { /// Retrieves the underlying positive value. public let getPositive : A @@ -437,7 +437,7 @@ extension Positive : CoArbitrary { } /// Guarantees that every generated integer is never 0. -public struct NonZero> : Arbitrary, CustomStringConvertible { +public struct NonZero : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-zero value. public let getNonZero : A @@ -468,7 +468,7 @@ extension NonZero : CoArbitrary { } /// Guarantees that every generated integer is greater than or equal to 0. -public struct NonNegative> : Arbitrary, CustomStringConvertible { +public struct NonNegative : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-negative value. public let getNonNegative : A @@ -506,7 +506,7 @@ private func undefined() -> A { fatalError("") } -private final class ArrowOfImpl, U : Arbitrary> : Arbitrary, CustomStringConvertible { +private final class ArrowOfImpl : Arbitrary, CustomStringConvertible { private var table : Dictionary private var arr : (T) -> U @@ -552,7 +552,7 @@ private final class ArrowOfImpl, U : Arbitra } } -private final class IsoOfImpl, U : protocol> : Arbitrary, CustomStringConvertible { +private final class IsoOfImpl : Arbitrary, CustomStringConvertible { var table : Dictionary var embed : (T) -> U var project : (U) -> T @@ -632,7 +632,7 @@ private final class PointerOfImpl : Arbitrary { deinit { if self.size > 0 && self.ptr != nil { - self.ptr?.deallocateCapacity(self.size) + self.ptr?.deallocate(capacity: self.size) self.ptr = nil } } @@ -641,10 +641,10 @@ private final class PointerOfImpl : Arbitrary { return Gen.sized { n in if n <= 0 { let size = 1 - return Gen.pure(PointerOfImpl(UnsafeMutablePointer(allocatingCapacity: size), size)) + return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) } - let pt = UnsafeMutablePointer(allocatingCapacity: n) - let gt = pt.initializeFrom <^> sequence(Array((0...allocate(capacity: n) + let gt = pt.initialize <^> sequence(Array((0.. Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in - return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), combine: disj))) + return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) })) } @@ -420,7 +420,7 @@ public struct TestResult { // MARK: - Implementation Details -private func exception(_ msg : String) -> (ErrorProtocol) -> TestResult { +private func exception(_ msg : String) -> (Error) -> TestResult { return { e in TestResult.failed(String(e)) } } @@ -455,7 +455,7 @@ private func protectResults(_ rs : Rose) -> Rose { // return { protect(Rose.pure • exception("Exception"), x: f) } //} -internal func protect(_ f : (ErrorProtocol) -> A, x : () throws -> A) -> A { +internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { do { return try x() } catch let e { @@ -555,7 +555,7 @@ private func printLabels(_ st : TestResult) { } else { let gAllLabels = st.labels.map({ (l, _) in return l + ", " - }).reduce("", combine: +) + }).reduce("", +) print("(" + gAllLabels[gAllLabels.startIndex.., G : RandomGeneneratorType>(_ gen : G) -> (A, G) { +public func randomBound(_ gen : G) -> (A, G) { return A.randomInRange((A.min, A.max), gen: gen) } diff --git a/Sources/Rose.swift b/Sources/Rose.swift index b9eb1e8..9b0f9ef 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -137,7 +137,7 @@ public func joinRose(_ rs : Rose>) -> Rose { /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(_ ms : [Rose]) -> Rose<[A]> { - return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in + return ms.reduce(Rose<[A]>.pure([]), { n, m in return m.flatMap { x in return n.flatMap { xs in return Rose<[A]>.pure(xs + [x]) diff --git a/Sources/Test.swift b/Sources/Test.swift index 675df47..8dcb949 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -770,7 +770,7 @@ private func printDistributionGraph(_ st : CheckerState) { } let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) + return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) }) let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) @@ -807,7 +807,7 @@ private func pluralize(_ s : String, i : Int) -> String { private func insufficientCoverage(_ st : CheckerState) -> Bool { return st.labels .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) - .reduce(false, combine: { $0 || $1 }) + .reduce(false, { $0 || $1 }) } private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n") { diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index d8302ac..4af8a94 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -215,7 +215,7 @@ extension EmptyCollection : Arbitrary { } } -extension Range where Bound : protocol { +extension Range where Bound : Comparable & Arbitrary { /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in @@ -231,14 +231,14 @@ extension Range where Bound : protocol { } } -extension LazyCollection where Base : protocol, Base.Index : Comparable { +extension LazyCollection where Base : Collection & Arbitrary, Base.Index : Comparable { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } -extension LazySequence where Base : protocol { +extension LazySequence where Base : Sequence & Arbitrary { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary @@ -269,7 +269,7 @@ extension Repeated : WitnessedArbitrary { } } -extension Set where Element : protocol { +extension Set where Element : Arbitrary & Hashable { /// Returns a generator of `Set`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index 037aef3..30c9ffd 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -69,7 +69,7 @@ class ComplexSpec : XCTestCase { // MARK: String Conveniences func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", combine: +) } + return sequence(parts).map { $0.reduce("", +) } } extension String { diff --git a/Tests/FailureSpec.swift b/Tests/FailureSpec.swift index d13d102..cc54dbc 100644 --- a/Tests/FailureSpec.swift +++ b/Tests/FailureSpec.swift @@ -9,7 +9,7 @@ import SwiftCheck import XCTest -enum SwiftCheckError : ErrorProtocol { +enum SwiftCheckError : Error { case bogus } diff --git a/Tests/ModifierSpec.swift b/Tests/ModifierSpec.swift index 6e24549..8c9b084 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/ModifierSpec.swift @@ -59,7 +59,7 @@ class ModifierSpec : XCTestCase { property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) + return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) } } } diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index 581524e..c027c16 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -28,14 +28,14 @@ struct Path : Arbitrary { } func path(_ p : (A) -> Bool, _ pth : Path) -> Bool { - return pth.unPath.reduce(true, combine: { $0 && p($1) }) + return pth.unPath.reduce(true, { $0 && p($1) }) } func somePath(_ p : (A) -> Bool, _ pth : Path) -> Property { return path({ !p($0) }, pth).expectFailure } -struct Extremal> : Arbitrary { +struct Extremal : Arbitrary { let getExtremal : A static var arbitrary : Gen> { @@ -52,13 +52,13 @@ struct Extremal> : Arbitrary { } class PathSpec : XCTestCase { - private static func smallProp>(_ pth : Path) -> Bool { + private static func smallProp(_ pth : Path) -> Bool { return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 }, pth) } - private static func largeProp>(_ pth : Path) -> Property { + private static func largeProp(_ pth : Path) -> Property { return somePath({ x in return (x < -1000000 || x > 1000000) }, pth) diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index 5e3d8f1..eab6bb7 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -59,7 +59,7 @@ class TestSpec : XCTestCase { property("filter behaves") <- forAll { (xs : Array) in return forAll { (pred : ArrowOf) in let f = pred.getArrow - return (xs.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) + return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) } } } From d10548f998f2623e1fc69974e577cb3b10034468 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Mon, 1 Aug 2016 16:09:58 -0400 Subject: [PATCH 332/460] Xcode 8b4 (Tutorial) --- Tutorial.playground/Contents.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 6dc8893..7c82048 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -270,7 +270,7 @@ let tld = lowerCaseLetters // Concatenates an array of `String` `Gen`erators together in order. func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", combine: +) } + return sequence(parts).map { $0.reduce("", +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) @@ -314,7 +314,7 @@ emailGen.generate //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: -public struct ArbitraryPositive> : Arbitrary { +public struct ArbitraryPositive : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -364,7 +364,7 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) + return xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) // ^ This property says that if we filter an array then apply the predicate // to all its elements, then they should all respond with `true`. } From bd0a7c1081f91be0e25091eaf6eb1e0dcee16418 Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Fri, 19 Aug 2016 21:32:20 -0400 Subject: [PATCH 333/460] Update to 8 beta 6 --- Sources/Arbitrary.swift | 6 +- Sources/CoArbitrary.swift | 2 +- Sources/Gen.swift | 84 ++++++------ Sources/Modifiers.swift | 28 ++-- Sources/Operators.swift | 220 ++++++++++++++----------------- Sources/Property.swift | 32 ++--- Sources/Random.swift | 2 +- Sources/Rose.swift | 20 +-- Sources/State.swift | 2 +- Sources/Test.swift | 82 ++++++------ Sources/TestOperators.swift | 79 +++++------ Sources/Witness.swift | 36 +++-- Sources/WitnessedArbitrary.swift | 30 ++--- Tests/ComplexSpec.swift | 4 +- Tests/GenSpec.swift | 4 +- Tests/LambdaSpec.swift | 2 +- Tests/ShrinkSpec.swift | 9 -- Tests/TestSpec.swift | 11 -- 18 files changed, 320 insertions(+), 333 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index b63b295..eefe7a6 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -295,12 +295,12 @@ extension Double : Arbitrary { extension UnicodeScalar : Arbitrary { /// Returns a generator of `UnicodeScalar` values. public static var arbitrary : Gen { - return UInt32.arbitrary.flatMap(Gen.pure • UnicodeScalar.init) + return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } } /// The default shrinking function for `UnicodeScalar` values. public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { - let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value)))) + let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } } } @@ -371,7 +371,7 @@ private func asAny(_ x : T) -> Any { } extension Array where Element : Hashable { - private var nub : [Element] { + fileprivate var nub : [Element] { return [Element](Set(self)) } } diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index 37c4e07..ce98d9a 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -33,7 +33,7 @@ extension Integer { /// function if you can, it can be quite an expensive operation given a detailed /// enough description. public func coarbitraryPrintable(_ x : A) -> (Gen) -> Gen { - return String.coarbitrary(String(x)) + return String.coarbitrary(String(describing: x)) } extension Bool : CoArbitrary { diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 89e8a75..4c38d03 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,7 +44,9 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf(_ xs : S) -> Gen { + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : Comparable & RandomType + { return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } @@ -82,7 +84,7 @@ public struct Gen { } /// Constructs a generator that depends on a size parameter. - public static func sized(_ f : (Int) -> Gen) -> Gen { + public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { return Gen(unGen: { r, n in return f(n).unGen(r, n) }) @@ -103,9 +105,11 @@ public struct Gen { /// Constructs a Generator that randomly selects and uses a particular /// generator from the given sequence of Generators. /// - /// If control over the distribution of generators is needed, see + /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf, S.Index : RandomType & Comparable, S.Index : RandomType>(_ gs : S) -> Gen { + public static func oneOf(_ gs : S) -> Gen + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType + { assert(gs.count != 0, "oneOf used with empty list") return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in @@ -116,10 +120,12 @@ public struct Gen { /// Given a sequence of Generators and weights associated with them, this /// function randomly selects and uses a Generator. /// - /// Only use this function when you need to assign uneven "weights" to each - /// generator. If all generators need to have an equal chance of being + /// Only use this function when you need to assign uneven "weights" to each + /// generator. If all generators need to have an equal chance of being /// selected, use `Gen.oneOf`. - public static func frequency)>(_ xs : S) -> Gen { + public static func frequency(_ xs : S) -> Gen + where S.Iterator.Element == (Int, Gen) + { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") @@ -133,10 +139,12 @@ public struct Gen { /// /// This function operates in exactly the same manner as `Gen.frequency`, /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather - /// than only Generators. It can help in cases where your `Gen.from*` call - /// contains only `Gen.pure` calls by allowing you to remove every + /// than only Generators. It can help in cases where your `Gen.from*` call + /// contains only `Gen.pure` calls by allowing you to remove every /// `Gen.pure` in favor of a direct list of values. - public static func weighted(_ xs : S) -> Gen { + public static func weighted(_ xs : S) -> Gen + where S.Iterator.Element == (Int, A) + { return frequency(xs.map { ($0, Gen.pure($1)) }) } } @@ -260,55 +268,55 @@ extension Gen /*: Cartesian*/ { /// Returns a new generator that applies a given function to any outputs the /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { return zip(ga1, ga2).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// three receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: (A1, A2, A3) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { return zip(ga1, ga2, ga3).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// four receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: (A1, A2, A3, A4) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// five receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: (A1, A2, A3, A4, A5) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// six receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// seven receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// eight receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// nine receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) } /// Returns a new generator that applies a given function to any outputs the /// ten receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) } } @@ -332,7 +340,7 @@ extension Gen { /// Modifiers a Generator's size parameter by transforming it with the given /// function. - public func scale(_ f : (Int) -> Int) -> Gen { + public func scale(_ f : @escaping (Int) -> Int) -> Gen { return Gen.sized { n in return self.resize(f(n)) } @@ -343,10 +351,10 @@ extension Gen { /// it never occured. /// /// Because the Generator will spin until it reaches a non-failing case, - /// executing a condition that fails more often than it succeeds may result - /// in a space leak. At that point, it is better to use `suchThatOptional` + /// executing a condition that fails more often than it succeeds may result + /// in a space leak. At that point, it is better to use `suchThatOptional` /// or `.invert` the test case. - public func suchThat(_ p : (A) -> Bool) -> Gen { + public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { return self.suchThatOptional(p).flatMap { mx in switch mx { case .some(let x): @@ -360,10 +368,10 @@ extension Gen { } /// Modifies a Generator such that it attempts to generate values that - /// satisfy a predicate. All attempts are encoded in the form of an - /// `Optional` where values satisfying the predicate are wrapped in `.Some` + /// satisfy a predicate. All attempts are encoded in the form of an + /// `Optional` where values satisfying the predicate are wrapped in `.Some` /// and failing values are `.None`. - public func suchThatOptional(_ p : (A) -> Bool) -> Gen> { + public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { return Gen>.sized { n in return attemptBoundedTry(self, 0, max(n, 1), p) } @@ -396,7 +404,7 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the /// receiver creates. - public func map(_ f : (A) -> B) -> Gen { + public func map(_ f : @escaping (A) -> B) -> Gen { return f <^> self } } @@ -407,9 +415,9 @@ extension Gen /*: Functor*/ { /// This function is most useful for converting between generators of inter- /// related types. For example, you might have a Generator of `Character` /// values that you then `.proliferate` into an `Array` of `Character`s. You -/// can then use `fmap` to convert that generator of `Array`s to a generator of +/// can then use `fmap` to convert that generator of `Array`s to a generator of /// `String`s. -public func <^> (f : (A) -> B, g : Gen) -> Gen { +public func <^> (f : @escaping (A) -> B, g : Gen) -> Gen { return Gen(unGen: { r, n in return f(g.unGen(r, n)) }) @@ -457,10 +465,10 @@ extension Gen /*: Monad*/ { /// This generator is then given a new random seed and returned. /// /// `flatMap` allows for the creation of Generators that depend on other - /// generators. One might, for example, use a Generator of integers to - /// control the length of a Generator of strings, or use it to choose a + /// generators. One might, for example, use a Generator of integers to + /// control the length of a Generator of strings, or use it to choose a /// random index into a Generator of arrays. - public func flatMap(_ fn : (A) -> Gen) -> Gen { + public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { return self >>- fn } } @@ -469,10 +477,10 @@ extension Gen /*: Monad*/ { /// generator. This generator is then given a new random seed and returned. /// /// `flatMap` allows for the creation of Generators that depend on other -/// generators. One might, for example, use a Generator of integers to control -/// the length of a Generator of strings, or use it to choose a random index +/// generators. One might, for example, use a Generator of integers to control +/// the length of a Generator of strings, or use it to choose a random index /// into a Generator of arrays. -public func >>- (m : Gen, fn : (A) -> Gen) -> Gen { +public func >>- (m : Gen, fn : @escaping (A) -> Gen) -> Gen { return Gen(unGen: { r, n in let (r1, r2) = r.split let m2 = fn(m.unGen(r1, n)) @@ -505,7 +513,7 @@ public func join(_ rs : Gen>) -> Gen { /// Lifts a function from some A to some R to a function from generators of A to /// generators of R. -public func liftM(_ f : (A) -> R, _ m1 : Gen) -> Gen { +public func liftM(_ f : @escaping (A) -> R, _ m1 : Gen) -> Gen { return m1.flatMap{ x1 in return Gen.pure(f(x1)) } @@ -519,7 +527,7 @@ public func promote(_ x : Rose>) -> Gen> { } /// Promotes a function returning generators to a generator of functions. -public func promote(_ m : (A) -> Gen) -> Gen<(A) -> B> { +public func promote(_ m : @escaping (A) -> Gen) -> Gen<(A) -> B> { return delay().flatMap { eval in return Gen<(A) -> B>.pure(eval • m) } @@ -541,7 +549,7 @@ private func vary(_ k : S, _ rng : StdGen) -> StdGen { return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : (A) -> Bool) -> Gen> { +private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { if bound == 0 { return Gen.pure(.none) } diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index a89eecc..0bc47f7 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -292,7 +292,7 @@ extension SetOf : CoArbitrary { /// Generates pointers of varying size of random values of type T. public struct PointerOf : Arbitrary, CustomStringConvertible { - private let _impl : PointerOfImpl + fileprivate let _impl : PointerOfImpl /// Retrieves the underlying pointer value. public var getPointer : UnsafePointer { @@ -316,7 +316,7 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { /// Generates a Swift function from T to U. public struct ArrowOf : Arbitrary, CustomStringConvertible { - private let _impl : ArrowOfImpl + fileprivate let _impl : ArrowOfImpl /// Retrieves the underlying function value, `T -> U`. public var getArrow : (T) -> U { @@ -345,7 +345,7 @@ extension ArrowOf : CustomReflectable { /// Generates two isomorphic Swift functions from `T` to `U` and back again. public struct IsoOf : Arbitrary, CustomStringConvertible { - private let _impl : IsoOfImpl + fileprivate let _impl : IsoOfImpl /// Retrieves the underlying embedding function, `T -> U`. public var getTo : (T) -> U { @@ -506,9 +506,9 @@ private func undefined() -> A { fatalError("") } -private final class ArrowOfImpl : Arbitrary, CustomStringConvertible { - private var table : Dictionary - private var arr : (T) -> U +fileprivate final class ArrowOfImpl : Arbitrary, CustomStringConvertible { + fileprivate var table : Dictionary + fileprivate var arr : (T) -> U init (_ table : Dictionary, _ arr : ((T) -> U)) { self.table = table @@ -552,10 +552,10 @@ private final class ArrowOfImpl : Arb } } -private final class IsoOfImpl : Arbitrary, CustomStringConvertible { - var table : Dictionary - var embed : (T) -> U - var project : (U) -> T +fileprivate final class IsoOfImpl : Arbitrary, CustomStringConvertible { + fileprivate var table : Dictionary + fileprivate var embed : (T) -> U + fileprivate var project : (U) -> T init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { self.table = table @@ -686,7 +686,9 @@ public final class GenComposer { /// - returns: A random `T`. /// /// - seealso: generate\(gen:) - public func generate() -> T { + public func generate() -> T + where T: Arbitrary + { return generate(using: T.arbitrary) } } @@ -713,9 +715,9 @@ extension Gen { /// } /// /// - parameter build: Function which is passed a GenComposer which can be used - /// + /// /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. - public static func compose(build: (GenComposer) -> A) -> Gen { + public static func compose(build: @escaping (GenComposer) -> A) -> Gen { return Gen(unGen: { (stdgen, size) -> A in let composer = GenComposer(stdgen: stdgen, size: size) return build(composer) diff --git a/Sources/Operators.swift b/Sources/Operators.swift index e4218fe..c6755ce 100644 --- a/Sources/Operators.swift +++ b/Sources/Operators.swift @@ -12,219 +12,200 @@ // MARK: Combinators +precedencegroup CompositionPrecedence { + associativity: right + higherThan: BitwiseShiftPrecedence +} + /// Compose | Applies one function to the result of another function to produce a third function. -infix operator • { - associativity right - precedence 190 +infix operator • : CompositionPrecedence + +precedencegroup RightAssociativeCombinatorPrecedence { + associativity: right + lowerThan: DefaultPrecedence } -/// Apply | Applies an argument to a function. -infix operator § { - associativity right - precedence 95 +precedencegroup LeftAssociativeCombinatorPrecedence { + associativity: left + lowerThan: DefaultPrecedence } +/// Apply | Applies an argument to a function. +infix operator § : RightAssociativeCombinatorPrecedence + /// Pipe Backward | Applies the function to its left to an argument on its right. -infix operator <| { - associativity right - precedence 95 -} +infix operator <| : RightAssociativeCombinatorPrecedence /// Pipe forward | Applies an argument on the left to a function on the right. -infix operator |> { - associativity left - precedence 95 -} +infix operator |> : LeftAssociativeCombinatorPrecedence /// On | Given a "combining" function and a function that converts arguments to the target of the /// combiner, returns a function that applies the right hand side to two arguments, then runs both /// results through the combiner. -infix operator |*| { - associativity left - precedence 100 +infix operator |*| : LeftAssociativeCombinatorPrecedence + +// MARK: Control.* + +precedencegroup FunctorPrecedence { + associativity: left + higherThan: DefaultPrecedence } +precedencegroup FunctorSequencePrecedence { + associativity: left + higherThan: FunctorPrecedence +} -// MARK: Control.* +precedencegroup MonadPrecedenceLeft { + associativity: left + higherThan: FunctorSequencePrecedence +} -/// Fmap | Maps a function over the value encapsulated by a functor. -infix operator <^> { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 130 +precedencegroup MonadPrecedenceRight { + associativity: right + higherThan: FunctorSequencePrecedence } +/// Fmap | Maps a function over the value encapsulated by a functor. +infix operator <^> : FunctorPrecedence + /// Replace | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator <^ { - associativity left - precedence 140 -} +infix operator <^ : FunctorSequencePrecedence /// Replace Backwards | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator ^> { - associativity left - precedence 140 -} +infix operator ^> : FunctorSequencePrecedence /// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. -infix operator <*> { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 130 -} +infix operator <*> : FunctorPrecedence /// Sequence Right | Disregards the Functor on the Left. /// /// Default definition: /// `const(id) <^> a <*> b` -infix operator *> { - associativity left - precedence 140 -} +infix operator *> : FunctorSequencePrecedence /// Sequence Left | Disregards the Functor on the Right. /// /// Default definition: /// `const <^> a <*> b` -infix operator <* { - associativity left - precedence 140 -} +infix operator <* : FunctorSequencePrecedence /// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the /// left to a function on the right yielding a new monad. -infix operator >>- { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 100 -} +infix operator >>- : MonadPrecedenceLeft -/// Bind Backwards | Composes two monadic actions by passing the value inside the monad on the +/// Bind Backwards | Composes two monadic actions by passing the value inside the monad on the /// right to the funciton on the left. -infix operator -<< { - associativity right - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 100 -} +infix operator -<< : MonadPrecedenceRight /// Left-to-Right Kleisli | Composition for monads. -infix operator >>->> { - associativity right - precedence 110 -} +infix operator >>->> : MonadPrecedenceRight /// Right-to-Left Kleisli | Composition for monads. -infix operator <<-<< { - associativity right - precedence 110 -} +infix operator <<-<< : MonadPrecedenceRight /// Extend | Duplicates the surrounding context and computes a value from it while remaining in the /// original context. -infix operator ->> { - associativity left - precedence 110 +infix operator ->> : MonadPrecedenceLeft + +precedencegroup FunctorExtrasPrecedence { + associativity: left + higherThan: FunctorSequencePrecedence } /// Imap | Maps covariantly over the index of a right-leaning bifunctor. -infix operator <^^> { - associativity left - precedence 140 -} +infix operator <^^> : FunctorExtrasPrecedence /// Contramap | Contravariantly maps a function over the value encapsulated by a functor. -infix operator { - associativity left - precedence 140 -} +infix operator : FunctorExtrasPrecedence // MARK: Data.Result -/// From | Creates a Result given a function that can possibly fail with an error. -infix operator !! { - associativity none - precedence 120 +precedencegroup ResultPrecedence { + associativity: none + higherThan: FunctorPrecedence } +/// From | Creates a Result given a function that can possibly fail with an error. +infix operator !! : ResultPrecedence + // MARK: Data.Monoid /// Append | Alias for a Semigroup's operation. -infix operator <> { - associativity right - precedence 160 -} +infix operator <> : AdditionPrecedence // MARK: Control.Category +precedencegroup CategoryPrecedence { + associativity: right + higherThan: MonadPrecedenceRight +} + /// Right-to-Left Composition | Composes two categories to form a new category with the source of /// the second category and the target of the first category. /// /// This function is literally `•`, but for Categories. -infix operator <<< { - associativity right - precedence 110 -} +infix operator <<< : CategoryPrecedence /// Left-to-Right Composition | Composes two categories to form a new category with the source of /// the first category and the target of the second category. /// /// Function composition with the arguments flipped. -infix operator >>> { - associativity right - precedence 110 -} +infix operator >>> : CategoryPrecedence // MARK: Control.Arrow +precedencegroup ArrowPrecedence { + associativity: right + higherThan: CategoryPrecedence +} + /// Split | Splits two computations and combines the result into one Arrow yielding a tuple of /// the result of each side. -infix operator *** { - associativity right - precedence 130 -} +infix operator *** : ArrowPrecedence /// Fanout | Given two functions with the same source but different targets, this function /// splits the computation and combines the result of each Arrow into a tuple of the result of /// each side. -infix operator &&& { - associativity right - precedence 130 -} +infix operator &&& : ArrowPrecedence // MARK: Control.Arrow.Choice -/// Splat | Splits two computations and combines the results into Eithers on the left and right. -infix operator +++ { - associativity right - precedence 120 +precedencegroup ArrowChoicePrecedence { + associativity: right + higherThan: ArrowPrecedence } +/// Splat | Splits two computations and combines the results into Eithers on the left and right. +infix operator +++ : ArrowChoicePrecedence + /// Fanin | Given two functions with the same target but different sources, this function splits /// the input between the two and merges the output. -infix operator ||| { - associativity right - precedence 120 -} +infix operator ||| : ArrowChoicePrecedence // MARK: Control.Arrow.Plus -/// Op | Combines two ArrowZero monoids. -infix operator <+> { - associativity right - precedence 150 +precedencegroup ArrowPlusPrecedence { + associativity: right + higherThan: ArrowChoicePrecedence } +/// Op | Combines two ArrowZero monoids. +infix operator <+> : ArrowPlusPrecedence + // MARK: Data.JSON +precedencegroup JSONPrecedence { + associativity: right + higherThan: ArrowPlusPrecedence +} + /// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. /// /// If the given keypath is not present or the retrieved value is not of the appropriate type, this /// function returns `.None`. -infix operator ()) -> Property { + public func whenFail(_ m : @escaping () -> ()) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in return m() }) @@ -128,9 +128,9 @@ extension Testable { /// Executes an action after the every failure of the property. /// - /// Because the action is executed after every failing test it can be used + /// Because the action is executed after every failing test it can be used /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(_ m : () -> ()) -> Property { + public func whenEachFail(_ m : @escaping () -> ()) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in if res.ok == .some(false) { m() @@ -213,7 +213,7 @@ extension Testable { /// Labels a property with a printable value. public func collect(_ x : A) -> Property { - return self.label(String(x)) + return self.label(String(describing: x)) } /// Conditionally labels a property with a value. @@ -248,34 +248,34 @@ extension Testable { /// This function can be used to completely change the evaluation schema of /// generated test cases by replacing the test's rose tree with a custom /// one. - public func mapProp(_ f : (Prop) -> Prop) -> Property { + public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { return Property(f <^> self.property.unProperty) } /// Applies a function that modifies the test case generator's size. - public func mapSize(_ f : (Int) -> Int) -> Property { + public func mapSize(_ f : @escaping (Int) -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(f(n)) }) } /// Applies a function that modifies the result of a test case. - public func mapTotalResult(_ f : (TestResult) -> TestResult) -> Property { + public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in return protectResults(f <^> rs) } } /// Applies a function that modifies the result of a test case. - public func mapResult(_ f : (TestResult) -> TestResult) -> Property { + public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in return f <^> rs } } - /// Applies a function that modifies the underlying Rose Tree that a test + /// Applies a function that modifies the underlying Rose Tree that a test /// case has generated. - public func mapRoseResult(_ f : (Rose) -> Rose) -> Property { + public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { return self.mapProp { t in return Prop(unProp: f(t.unProp)) } @@ -287,7 +287,7 @@ extension Testable { /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. -public func shrinking(_ shrinker : (A) -> [A], initial : A, prop : (A) -> Testable) -> Property { +public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : @escaping (A) -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in return Prop(unProp: joinRose(rs.map { x in return x.unProp @@ -421,10 +421,10 @@ public struct TestResult { // MARK: - Implementation Details private func exception(_ msg : String) -> (Error) -> TestResult { - return { e in TestResult.failed(String(e)) } + return { e in TestResult.failed(String(describing: e)) } } -private func props(_ shrinker : (A) -> [A], original : A, pf : (A) -> Testable) -> Rose> { +private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @escaping (A) -> Testable) -> Rose> { return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) @@ -467,11 +467,11 @@ internal func id(_ x : A) -> A { return x } -internal func • (f : (B) -> C, g : (A) -> B) -> (A) -> C { +internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } -private func protectResult(_ r : () throws -> TestResult) -> (() -> TestResult) { +private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"), x: r) } } @@ -560,7 +560,7 @@ private func printLabels(_ st : TestResult) { } } -private func conj(_ k : (TestResult) -> TestResult, xs : [Rose]) -> Rose { +private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) } else if let p = xs.first { diff --git a/Sources/Random.swift b/Sources/Random.swift index ae86e9c..0e018bf 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -145,7 +145,7 @@ extension UnicodeScalar : RandomType { /// Returns a random `UnicodeScalar` value using the given range and generator. public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) - return (UnicodeScalar(val), gg) + return (UnicodeScalar(val)!, gg) } } diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 9b0f9ef..93113c5 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -22,7 +22,7 @@ public enum Rose { case ioRose(() -> Rose) /// Case analysis for a Rose Tree. - public func onRose(_ f : (A, [Rose]) -> Rose) -> Rose { + public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { switch self { case .mkRose(let x, let rs): return f(x(), rs()) @@ -46,16 +46,16 @@ public enum Rose { extension Rose /*: Functor*/ { /// Maps a function over all the nodes of a Rose Tree. /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` branches + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` branches /// the map is suspended. - public func map(_ f : (A) -> B) -> Rose { + public func map(_ f : @escaping (A) -> B) -> Rose { return f <^> self } } /// Fmap | Maps a function over all the nodes of a Rose Tree. -public func <^> (f : (A) -> B, g : Rose) -> Rose { +public func <^> (f : @escaping (A) -> B, g : Rose) -> Rose { switch g { case .mkRose(let root, let children): return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) @@ -94,21 +94,21 @@ public func <*> (fn : Rose<(A) -> B>, g : Rose) -> Rose { } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all + /// Maps the values in the receiver to Rose Trees and joins them all /// together. - public func flatMap(_ fn : (A) -> Rose) -> Rose { + public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { return self >>- fn } } -/// Flat Map | Maps the values in the receiver to Rose Trees and joins them all +/// Flat Map | Maps the values in the receiver to Rose Trees and joins them all /// together. -public func >>- (m : Rose, fn : (A) -> Rose) -> Rose { +public func >>- (m : Rose, fn : @escaping (A) -> Rose) -> Rose { return joinRose(m.map(fn)) } /// Lifts functions to functions over Rose Trees. -public func liftM(_ f : (A) -> R, _ m1 : Rose) -> Rose { +public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { return m1.flatMap { x1 in return Rose.pure(f(x1)) } diff --git a/Sources/State.swift b/Sources/State.swift index 847ca3c..007fd84 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -57,7 +57,7 @@ public struct CheckerState { public init( name : String , maxAllowableSuccessfulTests : Int , maxAllowableDiscardedTests : Int - , computeSize : (Int, Int) -> Int + , computeSize : @escaping (Int, Int) -> Int , successfulTestCount : Int , discardedTestCount : Int , labels : Dictionary diff --git a/Sources/Test.swift b/Sources/Test.swift index 8dcb949..ed02e42 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -42,10 +42,10 @@ /// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in /// /// /// This part of the property uses `==>`, or the "implication" -/// /// combinator. Implication only executes the following block if -/// /// the preceding expression returns true. It can be used to +/// /// combinator. Implication only executes the following block if +/// /// the preceding expression returns true. It can be used to /// /// discard test cases that contain data you don't want to test with. -/// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { +/// return (!s.getSet.isEmpty && s.getSet != [0]) ==> { /// /// /// N.B. `shrinkArbitrary` is a internal method call that invokes the shrinker. /// let ls = self.shrinkArbitrary(s).map { $0.getSet } @@ -103,43 +103,43 @@ public func forAll(_ pf : ((A) throws -> Testable)) -> Property { /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -public func forAll(_ pf : (A, B) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property { return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -public func forAll(_ pf : (A, B, C) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -public func forAll(_ pf : (A, B, C, D) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -public func forAll(_ pf : (A, B, C, D, E) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -public func forAll(_ pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -public func forAll(_ pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -public func forAll(_ pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } @@ -151,43 +151,43 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. -public func forAll(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -203,75 +203,75 @@ public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> /// Given 2 explicit generators, converts a function to a universally quantified /// property for those 2 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property for those 3 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property for those 4 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property for those 5 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property for those 6 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property for those 7 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property for those 8 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } -/// Given an explicit generator and shrinker, converts a function to a +/// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. -public func forAllShrink(_ gen : Gen, shrinker : (A) -> [A], f : (A) throws -> Testable) -> Property { +public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : @escaping (A) throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in do { - return (try f(xs)).counterexample(String(xs)) + return (try f(xs)).counterexample(String(describing: xs)) } catch let e { - return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(xs)) + return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) } }).unProperty }) @@ -292,16 +292,16 @@ public func forAllShrink(_ gen : Gen, shrinker : (A) -> [A], f : (A) throw /// used for *negative* statements "there does not exist `foo` such that `bar`". /// It is recommended that you avoid `exists` and instead reduce your property /// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). -/// `SNF` involves turning every `exists` into a function returning the -/// existential value, taking any other parameters being quantified over as +/// `SNF` involves turning every `exists` into a function returning the +/// existential value, taking any other parameters being quantified over as /// needed. -public func exists(_ pf : (A) throws -> Testable) -> Property { +public func exists(_ pf : @escaping (A) throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } -/// Given an explicit generator, converts a function to an existentially +/// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. -public func exists(_ gen : Gen, pf : (A) throws -> Testable) -> Property { +public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult(ok: res.ok , expect: res.expect @@ -817,7 +817,7 @@ private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n" } extension Array { - private func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { + fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { var result = [[Element]]() var accumulator = [Element]() self.forEach { current in diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index f6f4d5e..f8360b5 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -40,12 +40,12 @@ public func property(_ msg : String, arguments : CheckerArguments? = nil, file : /// Describes a checker that uses XCTest to assert all testing failures and /// display them in both the testing log and Xcode. public struct AssertiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line @@ -62,12 +62,12 @@ public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, /// Describes a checker that only reports failures to the testing log but does /// not assert when a property fails. public struct ReportiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line @@ -137,10 +137,10 @@ public struct CheckerArguments { internal var name : String } -infix operator <- {} +infix operator <- /// Binds a Testable value to a property. -public func <- (checker : AssertiveQuickCheck, test : @autoclosure(escaping)() -> Testable) { +public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () -> Testable) { switch quickCheckWithResult(checker.args, test()) { case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) @@ -173,17 +173,19 @@ public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { } /// Binds a Testable value to a property. -public func <- (checker : ReportiveQuickCheck, test : @autoclosure(escaping)() -> Testable) { +public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () -> Testable) { _ = quickCheckWithResult(checker.args, test()) } -infix operator ==> { - associativity right - precedence 100 +precedencegroup SwiftCheckImplicationPrecedence { + associativity: right + lowerThan: ComparisonPrecedence } +infix operator ==> : SwiftCheckImplicationPrecedence + /// Models implication for properties. That is, the property holds if the first -/// argument is false (in which case the test case is discarded), or if the +/// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : @autoclosure() -> Testable) -> Property { if b { @@ -202,24 +204,25 @@ public func ==> (b : Bool, p : () -> Testable) -> Property { return Discard().property } -infix operator ==== { - precedence 140 -} +infix operator ==== : ComparisonPrecedence /// Like equality but prints a verbose description when it fails. -public func ==== (x : A, y : A) -> Property { - return (x == y).counterexample(String(x) + " /= " + String(y)) +public func ==== (x : A, y : A) -> Property + where A : Equatable +{ + return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) } - -infix operator { - associativity left - precedence 200 +precedencegroup SwiftCheckLabelPrecedence { + associativity: right + higherThan: BitwiseShiftPrecedence } +infix operator : SwiftCheckLabelPrecedence + /// Attaches a label to a property. /// -/// Labelled properties aid in testing conjunctions and disjunctions, or any +/// Labelled properties aid in testing conjunctions and disjunctions, or any /// other cases where test cases need to be distinct from one another. In /// addition to shrunken test cases, upon failure SwiftCheck will print a /// distribution map for the property that shows a percentage success rate for @@ -228,12 +231,15 @@ public func (p : Testable, s : String) -> Property { return p.label(s) } -infix operator ^&&^ { - associativity right - precedence 110 +precedencegroup SwiftCheckLogicalPrecedence { + associativity: left + higherThan: LogicalConjunctionPrecedence + lowerThan: ComparisonPrecedence } -/// Takes the conjunction of two properties and treats them as a single large +infix operator ^&&^ : SwiftCheckLogicalPrecedence + +/// Takes the conjunction of two properties and treats them as a single large /// property. /// /// Conjoined properties succeed only when both sub-properties succeed and fail @@ -243,12 +249,9 @@ public func ^&&^ (p1 : Testable, p2 : Testable) -> Property { } -infix operator ^||^ { - associativity right - precedence 110 -} +infix operator ^||^ : SwiftCheckLogicalPrecedence -/// Takes the disjunction of two properties and treats them as a single large +/// Takes the disjunction of two properties and treats them as a single large /// property. /// /// Disjoined properties succeed only when one or more sub-properties succeed diff --git a/Sources/Witness.swift b/Sources/Witness.swift index 5e9b7f4..f9139c3 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -59,55 +59,71 @@ public protocol WitnessedArbitrary { /// The witnessing type parameter. associatedtype Param - /// A property test that relies on a witness that the given type parameter + /// A property test that relies on a witness that the given type parameter /// is actually `Arbitrary`. - static func forAllWitnessed(_ wit : (A) -> Param, pf : ((Self) -> Testable)) -> Property + static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -public func forAll(_ pf : ((A) -> Testable)) -> Property { +public func forAll(_ pf : ((A) -> Testable)) -> Property + where A.Param : Arbitrary +{ return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -public func forAll(_ pf : (A, B) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary +{ return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -public func forAll(_ pf : (A, B, C) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary +{ return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -public func forAll(_ pf : (A, B, C, D) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary +{ return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -public func forAll(_ pf : (A, B, C, D, E) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -public func forAll(_ pf : (A, B, C, D, E, F) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -public func forAll(_ pf : (A, B, C, D, E, F, G) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -public func forAll(_ pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 4af8a94..30c3e00 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -32,7 +32,7 @@ extension Array : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Array`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : (([Element]) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) }) @@ -56,7 +56,7 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) }) @@ -80,7 +80,7 @@ extension AnySequence : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnySequence`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) }) @@ -104,7 +104,7 @@ extension ArraySlice : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) }) @@ -123,7 +123,7 @@ extension CollectionOfOne : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[bl.startIndex]))) }) @@ -155,7 +155,7 @@ extension Optional : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Optional`s. - public static func forAllWitnessed(_ wit : (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -179,7 +179,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) }) @@ -190,11 +190,9 @@ extension ContiguousArray : WitnessedArbitrary { extension Dictionary where Key : Arbitrary, Value : Arbitrary { /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. public static var arbitrary : Gen> { - return [Key].arbitrary.flatMap { k in - return [Value].arbitrary.flatMap { v in - return Gen.pure(Dictionary(zip(k, v).map({ (k, v) -> (key: Key, value: Value) in - (key: k, value: v) - }))) + return [Key].arbitrary.flatMap { (k : [Key]) in + return [Value].arbitrary.flatMap { (v : [Value]) in + return Gen.pure(Dictionary(zip(k, v))) } } } @@ -261,7 +259,7 @@ extension Repeated : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Repeat`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) return pf(repeatElement(xs.first!, count: xs.count)) @@ -294,7 +292,7 @@ extension Set : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Set`s. - public static func forAllWitnessed(_ wit : (A) -> Element, pf : ((Set) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) } @@ -347,7 +345,9 @@ private func shrinkOne(_ xs : [A]) -> [[A]] { } extension Dictionary { - private init(_ pairs : S) { + fileprivate init(_ pairs : S) + where S.Iterator.Element == (Key, Value) + { self.init() var g = pairs.makeIterator() while let (k, v): (Key, Value) = g.next() { diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index 30c9ffd..561f59e 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -58,7 +58,7 @@ class ComplexSpec : XCTestCase { gen4 ]) - let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) + let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 @@ -73,7 +73,7 @@ func glue(_ parts : [Gen]) -> Gen { } extension String { - private var initial : String { + fileprivate var initial : String { return self[self.startIndex..(_ f : (A, B) -> C) -> (A) -> (B) -> C { +internal func curry(_ f : @escaping (A, B) -> C) -> (A) -> (B) -> C { return { a in { b in f(a, b) } } } @@ -299,7 +299,7 @@ internal func id(_ x : A) -> A { return x } -internal func • (f : (B) -> C, g : (A) -> B) -> (A) -> C { +internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index 767e8be..cad964f 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -30,7 +30,7 @@ func == (l : Name, r : Name) -> Bool { return l.unName == r.unName } -private func liftM2(_ f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { +private func liftM2(_ f : @escaping (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { return m1.flatMap { x1 in return m2.flatMap { x2 in return Gen.pure(f(x1, x2)) diff --git a/Tests/ShrinkSpec.swift b/Tests/ShrinkSpec.swift index 4a0e4f4..ae8ac83 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/ShrinkSpec.swift @@ -37,14 +37,5 @@ class ShrinkSpec : XCTestCase { return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) } } - - // This should not hold because eventually you'll get to [0, 0] which gets shrunk from - // [0] to [[]] which doesn't shrink so you're out of luck. We'll ExpectFailure here. - property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in - return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { - let ls = self.shrinkArbitrary(s).map { $0.getSet } - return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) - } - }.expectFailure } } diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index eab6bb7..1629ee9 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -9,17 +9,6 @@ import SwiftCheck import class XCTest.XCTestCase -extension Dictionary { - init(_ pairs : S) { - self.init() - var g = pairs.makeIterator() - while let (k, v) : (Key, Value) = g.next() { - self[k] = v - } - } -} - - class TestSpec : XCTestCase { func testAll() { let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } From 8365d2830be4a2a6a8ec4b702e3fa53b309515fa Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 20 Aug 2016 09:37:41 -0400 Subject: [PATCH 334/460] spaces instead of tabs naturally --- Sources/Arbitrary.swift | 576 +++++++-------- Sources/CoArbitrary.swift | 232 +++---- Sources/Gen.swift | 948 ++++++++++++------------- Sources/Lattice.swift | 136 ++-- Sources/Modifiers.swift | 1046 ++++++++++++++-------------- Sources/Operators.swift | 62 +- Sources/Property.swift | 1066 ++++++++++++++-------------- Sources/Random.swift | 484 ++++++------- Sources/Rose.swift | 190 ++--- Sources/State.swift | 160 ++--- Sources/Test.swift | 1120 +++++++++++++++--------------- Sources/TestOperators.swift | 274 ++++---- Sources/Testable.swift | 128 ++-- Sources/Witness.swift | 56 +- Sources/WitnessedArbitrary.swift | 496 ++++++------- Tests/BooleanIdentitySpec.swift | 94 +-- Tests/ComplexSpec.swift | 78 +-- Tests/DiscardSpec.swift | 24 +- Tests/FailureSpec.swift | 88 +-- Tests/GenSpec.swift | 590 ++++++++-------- Tests/LambdaSpec.swift | 298 ++++---- Tests/ModifierSpec.swift | 102 ++- Tests/PathSpec.swift | 150 ++-- Tests/PropertySpec.swift | 268 +++---- Tests/RawRepresentableSpec.swift | 38 +- Tests/ReplaySpec.swift | 32 +- Tests/RoseSpec.swift | 241 ++++--- Tests/ShrinkSpec.swift | 48 +- Tests/SimpleSpec.swift | 202 +++--- Tests/TestSpec.swift | 78 +-- 30 files changed, 4650 insertions(+), 4655 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index eefe7a6..8bec3e1 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -8,386 +8,386 @@ /// A type that implements random generation and shrinking of values. /// -/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times -/// (usually 100 if the default settings are used). During that time, the -/// receiver has an opportunity to call through to any data or sources of +/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times +/// (usually 100 if the default settings are used). During that time, the +/// receiver has an opportunity to call through to any data or sources of /// randomness it needs to return what it deems an "Arbitrary" value. /// -/// Shrinking is reduction in the complexity of a tested value to remove noise -/// and present a minimal counterexample when a property fails. A shrink -/// necessitates returning a list of all possible "smaller" values for +/// Shrinking is reduction in the complexity of a tested value to remove noise +/// and present a minimal counterexample when a property fails. A shrink +/// necessitates returning a list of all possible "smaller" values for /// SwiftCheck to run through. As long as each individual value in the returned -/// list is less than or equal to the size of the input value, and is not a -/// duplicate of the input value, a minimal case should be reached fairly -/// efficiently. Shrinking is an optional extension of normal testing. If no -/// implementation of `shrink` is provided, SwiftCheck will default to an empty +/// list is less than or equal to the size of the input value, and is not a +/// duplicate of the input value, a minimal case should be reached fairly +/// efficiently. Shrinking is an optional extension of normal testing. If no +/// implementation of `shrink` is provided, SwiftCheck will default to an empty /// one - that is, no shrinking will occur. /// /// As an example, take the `ArrayOf` implementation of shrink: /// /// Arbitrary.shrink(ArrayOf([1, 2, 3])) -/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] +/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// /// SwiftCheck will search each case forward, one-by-one, and continue shrinking /// until it has reached a case it deems minimal enough to present. /// -/// SwiftCheck implements a number of generators for common Swift Standard +/// SwiftCheck implements a number of generators for common Swift Standard /// Library types for convenience. If more fine-grained testing is required see -/// `Modifiers.swift` for an example of how to define a "Modifier" type to +/// `Modifiers.swift` for an example of how to define a "Modifier" type to /// implement it. public protocol Arbitrary { - /// The generator for this particular type. - /// - /// This function should call out to any sources of randomness or state - /// necessary to generate values. It should not, however, be written as a - /// deterministic function. If such a generator is needed, combinators are - /// provided in `Gen.swift`. - static var arbitrary : Gen { get } - - /// An optional shrinking function. If this function goes unimplemented, it - /// is the same as returning the empty list. - /// - /// Shrunken values must be less than or equal to the "size" of the original - /// type but never the same as the value provided to this function (or a loop - /// will form in the shrinker). It is recommended that they be presented - /// smallest to largest to speed up the overall shrinking process. - static func shrink(_ : Self) -> [Self] + /// The generator for this particular type. + /// + /// This function should call out to any sources of randomness or state + /// necessary to generate values. It should not, however, be written as a + /// deterministic function. If such a generator is needed, combinators are + /// provided in `Gen.swift`. + static var arbitrary : Gen { get } + + /// An optional shrinking function. If this function goes unimplemented, it + /// is the same as returning the empty list. + /// + /// Shrunken values must be less than or equal to the "size" of the original + /// type but never the same as the value provided to this function (or a loop + /// will form in the shrinker). It is recommended that they be presented + /// smallest to largest to speed up the overall shrinking process. + static func shrink(_ : Self) -> [Self] } extension Arbitrary { - /// The implementation of a shrink that returns no alternatives. - public static func shrink(_ : Self) -> [Self] { - return [] - } + /// The implementation of a shrink that returns no alternatives. + public static func shrink(_ : Self) -> [Self] { + return [] + } } extension Integer { - /// Shrinks any `IntegerType`. - public var shrinkIntegral : [Self] { - return unfoldr({ i in - if i <= 0 { - return .none - } - let n = i / 2 - return .some((n, n)) - }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) - } + /// Shrinks any `IntegerType`. + public var shrinkIntegral : [Self] { + return unfoldr({ i in + if i <= 0 { + return .none + } + let n = i / 2 + return .some((n, n)) + }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) + } } extension RawRepresentable where RawValue: Arbitrary { - /// Default implementation, maps arbitrary values of its `RawValue` type - /// until a valid representation is obtained. Naturally, you should strive - /// to override this with a more efficient version. - public static var arbitrary: Gen { - return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } - } + /// Default implementation, maps arbitrary values of its `RawValue` type + /// until a valid representation is obtained. Naturally, you should strive + /// to override this with a more efficient version. + public static var arbitrary: Gen { + return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } + } } extension Bool : Arbitrary { - /// Returns a generator of `Bool`ean values. - public static var arbitrary : Gen { - return Gen.choose((false, true)) - } - - /// The default shrinking function for `Bool`ean values. - public static func shrink(_ x : Bool) -> [Bool] { - if x { - return [false] - } - return [] - } + /// Returns a generator of `Bool`ean values. + public static var arbitrary : Gen { + return Gen.choose((false, true)) + } + + /// The default shrinking function for `Bool`ean values. + public static func shrink(_ x : Bool) -> [Bool] { + if x { + return [false] + } + return [] + } } extension Int : Arbitrary { - /// Returns a generator of `Int` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((-n, n)) - } - } - - /// The default shrinking function for `Int` values. - public static func shrink(_ x : Int) -> [Int] { - return x.shrinkIntegral - } + /// Returns a generator of `Int` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((-n, n)) + } + } + + /// The default shrinking function for `Int` values. + public static func shrink(_ x : Int) -> [Int] { + return x.shrinkIntegral + } } extension Int8 : Arbitrary { - /// Returns a generator of `Int8` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int8` values. - public static func shrink(_ x : Int8) -> [Int8] { - return x.shrinkIntegral - } + /// Returns a generator of `Int8` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int8` values. + public static func shrink(_ x : Int8) -> [Int8] { + return x.shrinkIntegral + } } extension Int16 : Arbitrary { - /// Returns a generator of `Int16` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int16` values. - public static func shrink(_ x : Int16) -> [Int16] { - return x.shrinkIntegral - } + /// Returns a generator of `Int16` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int16` values. + public static func shrink(_ x : Int16) -> [Int16] { + return x.shrinkIntegral + } } extension Int32 : Arbitrary { - /// Returns a generator of `Int32` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int32` values. - public static func shrink(_ x : Int32) -> [Int32] { - return x.shrinkIntegral - } + /// Returns a generator of `Int32` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int32` values. + public static func shrink(_ x : Int32) -> [Int32] { + return x.shrinkIntegral + } } extension Int64 : Arbitrary { - /// Returns a generator of `Int64` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int64(-n), Int64(n))) - } - } - - /// The default shrinking function for `Int64` values. - public static func shrink(_ x : Int64) -> [Int64] { - return x.shrinkIntegral - } + /// Returns a generator of `Int64` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int64(-n), Int64(n))) + } + } + + /// The default shrinking function for `Int64` values. + public static func shrink(_ x : Int64) -> [Int64] { + return x.shrinkIntegral + } } extension UInt : Arbitrary { - /// Returns a generator of `UInt` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt(n))) } - } - - /// The default shrinking function for `UInt` values. - public static func shrink(_ x : UInt) -> [UInt] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt(n))) } + } + + /// The default shrinking function for `UInt` values. + public static func shrink(_ x : UInt) -> [UInt] { + return x.shrinkIntegral + } } extension UInt8 : Arbitrary { - /// Returns a generator of `UInt8` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } - } - } - - /// The default shrinking function for `UInt8` values. - public static func shrink(_ x : UInt8) -> [UInt8] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt8` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } + } + } + + /// The default shrinking function for `UInt8` values. + public static func shrink(_ x : UInt8) -> [UInt8] { + return x.shrinkIntegral + } } extension UInt16 : Arbitrary { - /// Returns a generator of `UInt16` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } - } - - /// The default shrinking function for `UInt16` values. - public static func shrink(_ x : UInt16) -> [UInt16] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt16` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } + } + + /// The default shrinking function for `UInt16` values. + public static func shrink(_ x : UInt16) -> [UInt16] { + return x.shrinkIntegral + } } extension UInt32 : Arbitrary { - /// Returns a generator of `UInt32` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } - } - - /// The default shrinking function for `UInt32` values. - public static func shrink(_ x : UInt32) -> [UInt32] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt32` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } + } + + /// The default shrinking function for `UInt32` values. + public static func shrink(_ x : UInt32) -> [UInt32] { + return x.shrinkIntegral + } } extension UInt64 : Arbitrary { - /// Returns a generator of `UInt64` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt64(n))) } - } - - /// The default shrinking function for `UInt64` values. - public static func shrink(_ x : UInt64) -> [UInt64] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt64` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt64(n))) } + } + + /// The default shrinking function for `UInt64` values. + public static func shrink(_ x : UInt64) -> [UInt64] { + return x.shrinkIntegral + } } extension Float : Arbitrary { - /// Returns a generator of `Float` values. - public static var arbitrary : Gen { - let precision : Int64 = 9999999999999 - - return Gen.sized { n in - if n == 0 { - return Gen.pure(0.0) - } - - let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - let denominator = Gen.choose((1, precision)) - - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Float(a) / Float(b)) } } - } - } - - /// The default shrinking function for `Float` values. - public static func shrink(_ x : Float) -> [Float] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) - } + /// Returns a generator of `Float` values. + public static var arbitrary : Gen { + let precision : Int64 = 9999999999999 + + return Gen.sized { n in + if n == 0 { + return Gen.pure(0.0) + } + + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator + >>- { b in Gen.pure(Float(a) / Float(b)) } } + } + } + + /// The default shrinking function for `Float` values. + public static func shrink(_ x : Float) -> [Float] { + return unfoldr({ i in + if i == 0.0 { + return .none + } + let n = i / 2.0 + return .some((n, n)) + }, initial: x) + } } extension Double : Arbitrary { - /// Returns a generator of `Double` values. - public static var arbitrary : Gen { - let precision : Int64 = 9999999999999 - - return Gen.sized { n in - if n == 0 { - return Gen.pure(0.0) - } - - let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - let denominator = Gen.choose((1, precision)) - - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Double(a) / Double(b)) } } - } - } - - /// The default shrinking function for `Double` values. - public static func shrink(_ x : Double) -> [Double] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) - } + /// Returns a generator of `Double` values. + public static var arbitrary : Gen { + let precision : Int64 = 9999999999999 + + return Gen.sized { n in + if n == 0 { + return Gen.pure(0.0) + } + + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator + >>- { b in Gen.pure(Double(a) / Double(b)) } } + } + } + + /// The default shrinking function for `Double` values. + public static func shrink(_ x : Double) -> [Double] { + return unfoldr({ i in + if i == 0.0 { + return .none + } + let n = i / 2.0 + return .some((n, n)) + }, initial: x) + } } extension UnicodeScalar : Arbitrary { - /// Returns a generator of `UnicodeScalar` values. - public static var arbitrary : Gen { - return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } - } - - /// The default shrinking function for `UnicodeScalar` values. - public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { - let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! - return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } - } + /// Returns a generator of `UnicodeScalar` values. + public static var arbitrary : Gen { + return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } + } + + /// The default shrinking function for `UnicodeScalar` values. + public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { + let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! + return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } + } } extension String : Arbitrary { - /// Returns a generator of `String` values. - public static var arbitrary : Gen { - let chars = Gen.sized(Character.arbitrary.proliferateSized) - return chars >>- { Gen.pure(String($0)) } - } - - /// The default shrinking function for `String` values. - public static func shrink(_ s : String) -> [String] { - return [Character].shrink([Character](s.characters)).map { String($0) } - } + /// Returns a generator of `String` values. + public static var arbitrary : Gen { + let chars = Gen.sized(Character.arbitrary.proliferateSized) + return chars >>- { Gen.pure(String($0)) } + } + + /// The default shrinking function for `String` values. + public static func shrink(_ s : String) -> [String] { + return [Character].shrink([Character](s.characters)).map { String($0) } + } } extension Character : Arbitrary { - /// Returns a generator of `Character` values. - public static var arbitrary : Gen { - return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - } - - /// The default shrinking function for `Character` values. - public static func shrink(_ x : Character) -> [Character] { - let ss = String(x).unicodeScalars - return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) - } + /// Returns a generator of `Character` values. + public static var arbitrary : Gen { + return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + } + + /// The default shrinking function for `Character` values. + public static func shrink(_ x : Character) -> [Character] { + let ss = String(x).unicodeScalars + return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) + } } extension AnyIndex : Arbitrary { - /// Returns a generator of `AnyForwardIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) - } + /// Returns a generator of `AnyForwardIndex` values. + public static var arbitrary : Gen { + return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) + } } extension Mirror : Arbitrary { - /// Returns a generator of `Mirror` values. - public static var arbitrary : Gen { - let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.map(asAny), - Int.arbitrary.map(asAny), - UInt.arbitrary.map(asAny), - Float.arbitrary.map(asAny), - Double.arbitrary.map(asAny), - Character.arbitrary.map(asAny), - ]) - - let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.map(asAny), - Array.arbitrary.map(asAny), - Set.arbitrary.map(asAny), - ]) - - return Gen.oneOf([ - genAny, - genAnyWitnessed, - ]).map(Mirror.init) - } + /// Returns a generator of `Mirror` values. + public static var arbitrary : Gen { + let genAny : Gen = Gen.oneOf([ + Bool.arbitrary.map(asAny), + Int.arbitrary.map(asAny), + UInt.arbitrary.map(asAny), + Float.arbitrary.map(asAny), + Double.arbitrary.map(asAny), + Character.arbitrary.map(asAny), + ]) + + let genAnyWitnessed : Gen = Gen.oneOf([ + Optional.arbitrary.map(asAny), + Array.arbitrary.map(asAny), + Set.arbitrary.map(asAny), + ]) + + return Gen.oneOf([ + genAny, + genAnyWitnessed, + ]).map(Mirror.init) + } } // MARK: - Implementation Details Follow private func asAny(_ x : T) -> Any { - return x + return x } extension Array where Element : Hashable { - fileprivate var nub : [Element] { - return [Element](Set(self)) - } + fileprivate var nub : [Element] { + return [Element](Set(self)) + } } private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { - var acc = [A]() - var ini = initial - while let next = f(ini) { - acc.insert(next.0, at: 0) - ini = next.1 - } - return acc + var acc = [A]() + var ini = initial + while let next = f(ini) { + acc.insert(next.0, at: 0) + ini = next.1 + } + return acc } #if os(Linux) - import Glibc + import Glibc #else - import Darwin + import Darwin #endif diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index ce98d9a..e226fee 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -6,194 +6,194 @@ // Copyright © 2016 Typelift. All rights reserved. // -/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` -/// allows generating random values, `CoArbitrary` allows observance of random -/// values passing through as input to random functions. A `CoArbitrary` type +/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` +/// allows generating random values, `CoArbitrary` allows observance of random +/// values passing through as input to random functions. A `CoArbitrary` type /// is thus able to influence the flow of values in the function. /// -/// `CoArbitrary` types must take an arbitrary value of their type and yield a +/// `CoArbitrary` types must take an arbitrary value of their type and yield a /// function that transforms a given generator by returning a new generator that -/// depends on the input value. Put simply, the function should perturb the -/// given generator (more than likely using `Gen.variant()`) based on the value +/// depends on the input value. Put simply, the function should perturb the +/// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a - /// generator. - static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) + /// Uses an instance of the receiver to return a function that perturbs a + /// generator. + static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } extension Integer { - /// A coarbitrary implementation for any IntegerType - public func coarbitraryIntegral() -> (Gen) -> Gen { - return { $0.variant(self) } - } + /// A coarbitrary implementation for any IntegerType + public func coarbitraryIntegral() -> (Gen) -> Gen { + return { $0.variant(self) } + } } -/// A coarbitrary implementation for any Printable type. Avoid using this +/// A coarbitrary implementation for any Printable type. Avoid using this /// function if you can, it can be quite an expensive operation given a detailed /// enough description. public func coarbitraryPrintable(_ x : A) -> (Gen) -> Gen { - return String.coarbitrary(String(describing: x)) + return String.coarbitrary(String(describing: x)) } extension Bool : CoArbitrary { - /// The default coarbitrary implementation for `Bool` values. - public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { - return { g in - if x { - return g.variant(1) - } - return g.variant(0) - } - } + /// The default coarbitrary implementation for `Bool` values. + public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { + return { g in + if x { + return g.variant(1) + } + return g.variant(0) + } + } } extension UnicodeScalar : CoArbitrary { - /// The default coarbitrary implementation for `UnicodeScalar` values. - public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { - return UInt32.coarbitrary(x.value) - } + /// The default coarbitrary implementation for `UnicodeScalar` values. + public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { + return UInt32.coarbitrary(x.value) + } } extension Character : CoArbitrary { - /// The default coarbitrary implementation for `Character` values. - public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { - let ss = String(x).unicodeScalars - return UnicodeScalar.coarbitrary(ss[ss.startIndex]) - } + /// The default coarbitrary implementation for `Character` values. + public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { + let ss = String(x).unicodeScalars + return UnicodeScalar.coarbitrary(ss[ss.startIndex]) + } } extension String : CoArbitrary { - /// The default coarbitrary implementation for `String` values. - public static func coarbitrary(_ x : String) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.characters.index(after: x.startIndex)..(_ x : String) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.characters.index(after: x.startIndex)..(_ x : Int) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int` values. + public static func coarbitrary(_ x : Int) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int8 : CoArbitrary { - /// The default coarbitrary implementation for `Int8` values. - public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int8` values. + public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int16 : CoArbitrary { - /// The default coarbitrary implementation for `Int16` values. - public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int16` values. + public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int32 : CoArbitrary { - /// The default coarbitrary implementation for `Int32` values. - public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int32` values. + public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int64 : CoArbitrary { - /// The default coarbitrary implementation for `Int64` values. - public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int64` values. + public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt : CoArbitrary { - /// The default coarbitrary implementation for `UInt` values. - public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt` values. + public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt8 : CoArbitrary { - /// The default coarbitrary implementation for `UInt8` values. - public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt8` values. + public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt16 : CoArbitrary { - /// The default coarbitrary implementation for `UInt16` values. - public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt16` values. + public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt32 : CoArbitrary { - /// The default coarbitrary implementation for `UInt32` values. - public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt32` values. + public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt64 : CoArbitrary { - /// The default coarbitrary implementation for `UInt64` values. - public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt64` values. + public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { - /// The default coarbitrary implementation for `Float` values. - public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { - return Int64(x).coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Float` values. + public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { + return Int64(x).coarbitraryIntegral() + } } extension Double : CoArbitrary { - /// The default coarbitrary implementation for `Double` values. - public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { - return Int64(x).coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Double` values. + public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { + return Int64(x).coarbitraryIntegral() + } } extension Array : CoArbitrary { - /// The default coarbitrary implementation for an `Array` of values. - public static func coarbitrary(_ a : [Element]) -> ((Gen) -> Gen) { - if a.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(_ a : [Element]) -> ((Gen) -> Gen) { + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(_ x : Dictionary) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for a `Dictionary` of values. + public static func coarbitrary(_ x : Dictionary) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } extension Optional : CoArbitrary { - /// The default coarbitrary implementation for `Optional` values. - public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { - if let _ = x { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for `Optional` values. + public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { + if let _ = x { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } extension Set : CoArbitrary { - /// The default coarbitrary implementation for `Set`s of values. - public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for `Set`s of values. + public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 4c38d03..0fc4667 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -8,584 +8,584 @@ /// `Gen` represents a generator for random arbitrary values of type `A`. /// -/// `Gen` wraps a function that, when given a random number generator and a -/// size, can be used to control the distribution of resultant values. A -/// generator relies on its size to help control aspects like the length of +/// `Gen` wraps a function that, when given a random number generator and a +/// size, can be used to control the distribution of resultant values. A +/// generator relies on its size to help control aspects like the length of /// generated arrays and the magnitude of integral values. public struct Gen { - /// The function underlying the receiver. - /// - /// +--- An RNG - /// | +--- The size of generated values. - /// | | - /// v v - let unGen : (StdGen, Int) -> A - - /// Generates a value. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var generate : A { - let r = newStdGen() - return unGen(r, 30) - } - - /// Generates some example values. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var sample : [A] { - return sequence((2...20).map(self.resize)).generate - } - - /// Constructs a Generator that selects a random value from the given - /// collection and produces only that value. - /// - /// The input collection is required to be non-empty. - public static func fromElementsOf(_ xs : S) -> Gen - where S.Index : Comparable & RandomType - { - return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in - return xs[i] - } - } - - /// Constructs a Generator that selects a random value from the given - /// interval and produces only that value. - /// - /// The input interval is required to be non-empty. + /// The function underlying the receiver. + /// + /// +--- An RNG + /// | +--- The size of generated values. + /// | | + /// v v + let unGen : (StdGen, Int) -> A + + /// Generates a value. + /// + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. + public var generate : A { + let r = newStdGen() + return unGen(r, 30) + } + + /// Generates some example values. + /// + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. + public var sample : [A] { + return sequence((2...20).map(self.resize)).generate + } + + /// Constructs a Generator that selects a random value from the given + /// collection and produces only that value. + /// + /// The input collection is required to be non-empty. + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : Comparable & RandomType + { + return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in + return xs[i] + } + } + + /// Constructs a Generator that selects a random value from the given + /// interval and produces only that value. + /// + /// The input interval is required to be non-empty. public static func fromElementsIn(_ xs : ClosedRange) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") - - return choose((xs.lowerBound, xs.upperBound)) - } - - /// Constructs a Generator that uses a given array to produce smaller arrays - /// composed of its initial segments. The size of each initial segment - /// increases with the receiver's size parameter. - /// - /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { - assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") - - return Gen<[S]>.sized { n in - let ss = xs[xs.startIndex...pure([S](ss)) - } - } - - /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { - return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) - } - } - - /// Constructs a generator that depends on a size parameter. - public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { - return Gen(unGen: { r, n in - return f(n).unGen(r, n) - }) - } - - /// Constructs a random element in the range of two `RandomType`s. - /// - /// When using this function, it is necessary to explicitly specialize the - /// generic parameter `A`. For example: - /// - /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - public static func choose(_ rng : (A, A)) -> Gen { - return Gen(unGen: { s, _ in - return A.randomInRange(rng, gen: s).0 - }) - } - - /// Constructs a Generator that randomly selects and uses a particular - /// generator from the given sequence of Generators. - /// - /// If control over the distribution of generators is needed, see - /// `Gen.frequency` or `Gen.weighted`. + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") + + return choose((xs.lowerBound, xs.upperBound)) + } + + /// Constructs a Generator that uses a given array to produce smaller arrays + /// composed of its initial segments. The size of each initial segment + /// increases with the receiver's size parameter. + /// + /// The input array is required to be non-empty. + public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { + assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") + + return Gen<[S]>.sized { n in + let ss = xs[xs.startIndex...pure([S](ss)) + } + } + + /// Constructs a Generator that produces permutations of a given array. + public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { + return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in + return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) + } + } + + /// Constructs a generator that depends on a size parameter. + public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { + return Gen(unGen: { r, n in + return f(n).unGen(r, n) + }) + } + + /// Constructs a random element in the range of two `RandomType`s. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + public static func choose(_ rng : (A, A)) -> Gen { + return Gen(unGen: { s, _ in + return A.randomInRange(rng, gen: s).0 + }) + } + + /// Constructs a Generator that randomly selects and uses a particular + /// generator from the given sequence of Generators. + /// + /// If control over the distribution of generators is needed, see + /// `Gen.frequency` or `Gen.weighted`. public static func oneOf(_ gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType { - assert(gs.count != 0, "oneOf used with empty list") + assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in + return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in return gs[x] - } - } - - /// Given a sequence of Generators and weights associated with them, this - /// function randomly selects and uses a Generator. - /// - /// Only use this function when you need to assign uneven "weights" to each - /// generator. If all generators need to have an equal chance of being - /// selected, use `Gen.oneOf`. - public static func frequency(_ xs : S) -> Gen - where S.Iterator.Element == (Int, Gen) - { - let xs: [(Int, Gen)] = Array(xs) - assert(xs.count != 0, "frequency used with empty list") - - return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in - return pick(l, xs) - } - } - - /// Given a list of values and weights associated with them, this function - /// randomly selects and uses a Generator wrapping one of the values. - /// - /// This function operates in exactly the same manner as `Gen.frequency`, - /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather - /// than only Generators. It can help in cases where your `Gen.from*` call - /// contains only `Gen.pure` calls by allowing you to remove every - /// `Gen.pure` in favor of a direct list of values. - public static func weighted(_ xs : S) -> Gen - where S.Iterator.Element == (Int, A) - { - return frequency(xs.map { ($0, Gen.pure($1)) }) - } + } + } + + /// Given a sequence of Generators and weights associated with them, this + /// function randomly selects and uses a Generator. + /// + /// Only use this function when you need to assign uneven "weights" to each + /// generator. If all generators need to have an equal chance of being + /// selected, use `Gen.oneOf`. + public static func frequency(_ xs : S) -> Gen + where S.Iterator.Element == (Int, Gen) + { + let xs: [(Int, Gen)] = Array(xs) + assert(xs.count != 0, "frequency used with empty list") + + return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in + return pick(l, xs) + } + } + + /// Given a list of values and weights associated with them, this function + /// randomly selects and uses a Generator wrapping one of the values. + /// + /// This function operates in exactly the same manner as `Gen.frequency`, + /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather + /// than only Generators. It can help in cases where your `Gen.from*` call + /// contains only `Gen.pure` calls by allowing you to remove every + /// `Gen.pure` in favor of a direct list of values. + public static func weighted(_ xs : S) -> Gen + where S.Iterator.Element == (Int, A) + { + return frequency(xs.map { ($0, Gen.pure($1)) }) + } } extension Gen /*: Cartesian*/ { - /// Zips together 2 generators of type `A` and `B` into a generator of pairs. - public static func zip(_ gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return Gen<(A, B)>(unGen: { r, n in - let (r1, r2) = r.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n)) - }) - } - - /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of - /// triples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { - return Gen<(A, B, C)>(unGen: { r, n in - let (r1, r2_) = r.split - let (r2, r3) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) - }) - } - - /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a - /// generator of quadruples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { - return Gen<(A, B, C, D)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1, r2) = r1_.split - let (r3, r4) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) - }) - } - - /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a - /// generator of quintuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { - return Gen<(A, B, C, D, E)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r1) = r1_.split - let (r2, r3) = r2_.split - let (r4, r5) = r1__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) - }) - } - - /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into - /// a generator of sextuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { - return Gen<(A, B, C, D, E, F)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1, r2) = r2_.split - let (r3, r4) = r1__.split - let (r5, r6) = r2__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) - }) - } - - /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` - /// into a generator of septuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { - return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r1) = r2_.split - let (r2, r3) = r1__.split - let (r4, r5) = r2__.split - let (r6, r7) = r1___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) - }) - } - - /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and - /// `H` into a generator of octuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { - return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1, r2) = r1__.split - let (r3, r4) = r2__.split - let (r5, r6) = r1___.split - let (r7, r8) = r2___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) - }) - } - - /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, and `I` into a generator of nonuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { - return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r1) = r1__.split - let (r2, r3) = r2__.split - let (r4, r5) = r1___.split - let (r6, r7) = r2___.split - let (r8, r9) = r1____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) - }) - } - - /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, `I`, and `J` into a generator of decuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { - return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r2____) = r1__.split - let (r1, r2) = r2__.split - let (r3, r4) = r1___.split - let (r5, r6) = r2___.split - let (r7, r8) = r1____.split - let (r9, r10) = r2____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) - }) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// three receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// four receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// five receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// six receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// seven receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// eight receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// nine receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// ten receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) - } + /// Zips together 2 generators of type `A` and `B` into a generator of pairs. + public static func zip(_ gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { + return Gen<(A, B)>(unGen: { r, n in + let (r1, r2) = r.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n)) + }) + } + + /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of + /// triples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { + return Gen<(A, B, C)>(unGen: { r, n in + let (r1, r2_) = r.split + let (r2, r3) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) + }) + } + + /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a + /// generator of quadruples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { + return Gen<(A, B, C, D)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1, r2) = r1_.split + let (r3, r4) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) + }) + } + + /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a + /// generator of quintuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { + return Gen<(A, B, C, D, E)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r1) = r1_.split + let (r2, r3) = r2_.split + let (r4, r5) = r1__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) + }) + } + + /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into + /// a generator of sextuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { + return Gen<(A, B, C, D, E, F)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1, r2) = r2_.split + let (r3, r4) = r1__.split + let (r5, r6) = r2__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) + }) + } + + /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` + /// into a generator of septuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { + return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r1) = r2_.split + let (r2, r3) = r1__.split + let (r4, r5) = r2__.split + let (r6, r7) = r1___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) + }) + } + + /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and + /// `H` into a generator of octuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { + return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1, r2) = r1__.split + let (r3, r4) = r2__.split + let (r5, r6) = r1___.split + let (r7, r8) = r2___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) + }) + } + + /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, and `I` into a generator of nonuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { + return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r1) = r1__.split + let (r2, r3) = r2__.split + let (r4, r5) = r1___.split + let (r6, r7) = r2___.split + let (r8, r9) = r1____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) + }) + } + + /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, `I`, and `J` into a generator of decuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { + return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r2____) = r1__.split + let (r1, r2) = r2__.split + let (r3, r4) = r1___.split + let (r5, r6) = r2___.split + let (r7, r8) = r1____.split + let (r9, r10) = r2____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) + }) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// three receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { + return zip(ga1, ga2, ga3).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// four receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// five receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// six receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// seven receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// eight receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// nine receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// ten receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + } } // MARK: Generator Modifiers extension Gen { - /// Shakes up the receiver's internal Random Number Generator with a seed. - public func variant(_ seed : S) -> Gen { - return Gen(unGen: { rng, n in - return self.unGen(vary(seed, rng), n) - }) - } - - /// Modifies a Generator to always use a given size. - public func resize(_ n : Int) -> Gen { - return Gen(unGen: { r, _ in - return self.unGen(r, n) - }) - } - - /// Modifiers a Generator's size parameter by transforming it with the given - /// function. - public func scale(_ f : @escaping (Int) -> Int) -> Gen { - return Gen.sized { n in - return self.resize(f(n)) - } - } - - /// Modifies a Generator such that it only returns values that satisfy a - /// predicate. When the predicate fails the test case is treated as though - /// it never occured. - /// - /// Because the Generator will spin until it reaches a non-failing case, - /// executing a condition that fails more often than it succeeds may result - /// in a space leak. At that point, it is better to use `suchThatOptional` - /// or `.invert` the test case. - public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { - return self.suchThatOptional(p).flatMap { mx in - switch mx { - case .some(let x): - return Gen.pure(x) - case .none: - return Gen.sized { n in - return self.suchThat(p).resize((n + 1)) - } - } - } - } - - /// Modifies a Generator such that it attempts to generate values that - /// satisfy a predicate. All attempts are encoded in the form of an - /// `Optional` where values satisfying the predicate are wrapped in `.Some` - /// and failing values are `.None`. - public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { - return Gen>.sized { n in - return attemptBoundedTry(self, 0, max(n, 1), p) - } - } - - /// Modifies a Generator such that it produces arrays with a length - /// determined by the receiver's size parameter. - public var proliferate : Gen<[A]> { - return Gen<[A]>.sized { n in - return Gen.choose((0, n)) >>- self.proliferateSized - } - } - - /// Modifies a Generator such that it produces non-empty arrays with a - /// length determined by the receiver's size parameter. - public var proliferateNonEmpty : Gen<[A]> { - return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))) >>- self.proliferateSized - } - } - - /// Modifies a Generator such that it only produces arrays of a given length. - public func proliferateSized(_ k : Int) -> Gen<[A]> { - return sequence(Array>(repeating: self, count: k)) - } + /// Shakes up the receiver's internal Random Number Generator with a seed. + public func variant(_ seed : S) -> Gen { + return Gen(unGen: { rng, n in + return self.unGen(vary(seed, rng), n) + }) + } + + /// Modifies a Generator to always use a given size. + public func resize(_ n : Int) -> Gen { + return Gen(unGen: { r, _ in + return self.unGen(r, n) + }) + } + + /// Modifiers a Generator's size parameter by transforming it with the given + /// function. + public func scale(_ f : @escaping (Int) -> Int) -> Gen { + return Gen.sized { n in + return self.resize(f(n)) + } + } + + /// Modifies a Generator such that it only returns values that satisfy a + /// predicate. When the predicate fails the test case is treated as though + /// it never occured. + /// + /// Because the Generator will spin until it reaches a non-failing case, + /// executing a condition that fails more often than it succeeds may result + /// in a space leak. At that point, it is better to use `suchThatOptional` + /// or `.invert` the test case. + public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { + return self.suchThatOptional(p).flatMap { mx in + switch mx { + case .some(let x): + return Gen.pure(x) + case .none: + return Gen.sized { n in + return self.suchThat(p).resize((n + 1)) + } + } + } + } + + /// Modifies a Generator such that it attempts to generate values that + /// satisfy a predicate. All attempts are encoded in the form of an + /// `Optional` where values satisfying the predicate are wrapped in `.Some` + /// and failing values are `.None`. + public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { + return Gen>.sized { n in + return attemptBoundedTry(self, 0, max(n, 1), p) + } + } + + /// Modifies a Generator such that it produces arrays with a length + /// determined by the receiver's size parameter. + public var proliferate : Gen<[A]> { + return Gen<[A]>.sized { n in + return Gen.choose((0, n)) >>- self.proliferateSized + } + } + + /// Modifies a Generator such that it produces non-empty arrays with a + /// length determined by the receiver's size parameter. + public var proliferateNonEmpty : Gen<[A]> { + return Gen<[A]>.sized { n in + return Gen.choose((1, max(1, n))) >>- self.proliferateSized + } + } + + /// Modifies a Generator such that it only produces arrays of a given length. + public func proliferateSized(_ k : Int) -> Gen<[A]> { + return sequence(Array>(repeating: self, count: k)) + } } // MARK: Instances extension Gen /*: Functor*/ { - /// Returns a new generator that applies a given function to any outputs the - /// receiver creates. - public func map(_ f : @escaping (A) -> B) -> Gen { - return f <^> self - } + /// Returns a new generator that applies a given function to any outputs the + /// receiver creates. + public func map(_ f : @escaping (A) -> B) -> Gen { + return f <^> self + } } -/// Fmap | Returns a new generator that applies a given function to any outputs +/// Fmap | Returns a new generator that applies a given function to any outputs /// the given generator creates. /// /// This function is most useful for converting between generators of inter- -/// related types. For example, you might have a Generator of `Character` +/// related types. For example, you might have a Generator of `Character` /// values that you then `.proliferate` into an `Array` of `Character`s. You /// can then use `fmap` to convert that generator of `Array`s to a generator of /// `String`s. public func <^> (f : @escaping (A) -> B, g : Gen) -> Gen { - return Gen(unGen: { r, n in - return f(g.unGen(r, n)) - }) + return Gen(unGen: { r, n in + return f(g.unGen(r, n)) + }) } extension Gen /*: Applicative*/ { - /// Lifts a value into a generator that will only generate that value. - public static func pure(_ a : A) -> Gen { - return Gen(unGen: { _ in - return a - }) - } - - /// Given a generator of functions, applies any generated function to any - /// outputs the receiver creates. - public func ap(_ fn : Gen<(A) -> B>) -> Gen { - return fn <*> self - } + /// Lifts a value into a generator that will only generate that value. + public static func pure(_ a : A) -> Gen { + return Gen(unGen: { _ in + return a + }) + } + + /// Given a generator of functions, applies any generated function to any + /// outputs the receiver creates. + public func ap(_ fn : Gen<(A) -> B>) -> Gen { + return fn <*> self + } } /// Ap | Returns a Generator that uses the first given Generator to produce -/// functions and the second given Generator to produce values that it applies -/// to those functions. It can be used in conjunction with <^> to simplify the -/// application of "combining" functions to a large amount of sub-generators. +/// functions and the second given Generator to produce values that it applies +/// to those functions. It can be used in conjunction with <^> to simplify the +/// application of "combining" functions to a large amount of sub-generators. /// For example: /// /// struct Foo { let b : Int; let c : Int; let d : Int } /// /// let genFoo = curry(Foo.init) <^> Int.arbitrary <*> Int.arbitrary <*> Int.arbitrary /// -/// This combinator acts like `zip`, but instead of creating pairs it creates +/// This combinator acts like `zip`, but instead of creating pairs it creates /// values after applying the zipped function to the zipped value. /// -/// Promotes function application to a Generator of functions applied to a +/// Promotes function application to a Generator of functions applied to a /// Generator of values. public func <*> (fn : Gen<(A) -> B>, g : Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - return fn.unGen(r1, n)(g.unGen(r2, n)) - }) + return Gen(unGen: { r, n in + let (r1, r2) = r.split + return fn.unGen(r1, n)(g.unGen(r2, n)) + }) } extension Gen /*: Monad*/ { - /// Applies the function to any generated values to yield a new generator. - /// This generator is then given a new random seed and returned. - /// - /// `flatMap` allows for the creation of Generators that depend on other - /// generators. One might, for example, use a Generator of integers to - /// control the length of a Generator of strings, or use it to choose a - /// random index into a Generator of arrays. - public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { - return self >>- fn - } + /// Applies the function to any generated values to yield a new generator. + /// This generator is then given a new random seed and returned. + /// + /// `flatMap` allows for the creation of Generators that depend on other + /// generators. One might, for example, use a Generator of integers to + /// control the length of a Generator of strings, or use it to choose a + /// random index into a Generator of arrays. + public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { + return self >>- fn + } } -/// Flat Map | Applies the function to any generated values to yield a new +/// Flat Map | Applies the function to any generated values to yield a new /// generator. This generator is then given a new random seed and returned. /// -/// `flatMap` allows for the creation of Generators that depend on other +/// `flatMap` allows for the creation of Generators that depend on other /// generators. One might, for example, use a Generator of integers to control /// the length of a Generator of strings, or use it to choose a random index /// into a Generator of arrays. public func >>- (m : Gen, fn : @escaping (A) -> Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - let m2 = fn(m.unGen(r1, n)) - return m2.unGen(r2, n) - }) + return Gen(unGen: { r, n in + let (r1, r2) = r.split + let m2 = fn(m.unGen(r1, n)) + return m2.unGen(r2, n) + }) } -/// Creates and returns a Generator of arrays of values drawn from each +/// Creates and returns a Generator of arrays of values drawn from each /// generator in the given array. /// -/// The array that is created is guaranteed to use each of the given Generators -/// in the order they were given to the function exactly once. Thus all arrays +/// The array that is created is guaranteed to use each of the given Generators +/// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(_ ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), { n, m in - return m.flatMap { x in - return n.flatMap { xs in - return Gen<[A]>.pure(xs + [x]) - } - } - }) + return ms.reduce(Gen<[A]>.pure([]), { n, m in + return m.flatMap { x in + return n.flatMap { xs in + return Gen<[A]>.pure(xs + [x]) + } + } + }) } /// Flattens a generator of generators by one level. public func join(_ rs : Gen>) -> Gen { - return rs.flatMap { x in - return x - } + return rs.flatMap { x in + return x + } } /// Lifts a function from some A to some R to a function from generators of A to /// generators of R. public func liftM(_ f : @escaping (A) -> R, _ m1 : Gen) -> Gen { - return m1.flatMap{ x1 in - return Gen.pure(f(x1)) - } + return m1.flatMap{ x1 in + return Gen.pure(f(x1)) + } } /// Promotes a rose of generators to a generator of rose values. public func promote(_ x : Rose>) -> Gen> { - return delay().flatMap { eval in - return Gen>.pure(liftM(eval, x)) - } + return delay().flatMap { eval in + return Gen>.pure(liftM(eval, x)) + } } /// Promotes a function returning generators to a generator of functions. public func promote(_ m : @escaping (A) -> Gen) -> Gen<(A) -> B> { - return delay().flatMap { eval in - return Gen<(A) -> B>.pure(eval • m) - } + return delay().flatMap { eval in + return Gen<(A) -> B>.pure(eval • m) + } } // MARK: - Implementation Details private func delay() -> Gen<(Gen) -> A> { - return Gen(unGen: { r, n in - return { g in - return g.unGen(r, n) - } - }) + return Gen(unGen: { r, n in + return { g in + return g.unGen(r, n) + } + }) } private func vary(_ k : S, _ rng : StdGen) -> StdGen { - let s = rng.split - let gen = ((k % 2) == 0) ? s.0 : s.1 - return (k == (k / 2)) ? gen : vary(k / 2, rng) + let s = rng.split + let gen = ((k % 2) == 0) ? s.0 : s.1 + return (k == (k / 2)) ? gen : vary(k / 2, rng) } private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { - if bound == 0 { - return Gen.pure(.none) - } - return gen.resize(2 * k + bound).flatMap { x in - if pred(x) { - return Gen.pure(.some(x)) - } - return attemptBoundedTry(gen, (k + 1), bound - 1, pred) - } + if bound == 0 { + return Gen.pure(.none) + } + return gen.resize(2 * k + bound).flatMap { x in + if pred(x) { + return Gen.pure(.some(x)) + } + return attemptBoundedTry(gen, (k + 1), bound - 1, pred) + } } private func size(_ k : S, _ m : Int) -> Int { - let n = Double(m) - return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) + let n = Double(m) + return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } private func selectOne(_ xs : [A]) -> [(A, [A])] { guard let y = xs.first else { return [] } - let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) - return [(y, ys)] + rec + let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) + return [(y, ys)] + rec } private func pick(_ n : Int, _ lst : [(Int, Gen)]) -> Gen { - let (k, x) = lst[0] - let tl = Array<(Int, Gen)>(lst[1..)>(lst[1..) in /// return x.description == "(*)" /// } /// -/// For an example of the latter see the `ArrowOf` modifier. Because Swift's +/// For an example of the latter see the `ArrowOf` modifier. Because Swift's /// type system treats arrows (`->`) as an opaque entity that you can't interact -/// with or extend, SwiftCheck provides `ArrowOf` to enable the generation of -/// functions between 2 types. That's right, we can generate arbitrary +/// with or extend, SwiftCheck provides `ArrowOf` to enable the generation of +/// functions between 2 types. That's right, we can generate arbitrary /// functions! /// /// property("map accepts SwiftCheck arrows") <- forAll { (xs : [Int]) in /// return forAll { (f : ArrowOf) in -/// /// Just to prove it really is a function (that is, every input -/// /// always maps to the same output), and not just a trick, we +/// /// Just to prove it really is a function (that is, every input +/// /// always maps to the same output), and not just a trick, we /// /// map twice and should get equal arrays. -/// return xs.map(f.getArrow) == xs.map(f.getArrow) +/// return xs.map(f.getArrow) == xs.map(f.getArrow) /// } /// } /// /// Finally, modifiers nest to allow the generation of intricate structures that -/// would not otherwise be possible due to the limitations above. For example, -/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a -/// type that normally looks like `Array>>`), +/// would not otherwise be possible due to the limitations above. For example, +/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a +/// type that normally looks like `Array>>`), /// would look like this: /// /// property("Generating monstrous data types is possible") <- forAll { (xs : ArrayOf>>) in /// /// We're gonna need a bigger boat. /// } -/// For types that either do not have a `CustomStringConvertible` instance or -/// that wish to have no description to print, Blind will create a default +/// For types that either do not have a `CustomStringConvertible` instance or +/// that wish to have no description to print, Blind will create a default /// description for them. public struct Blind : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying value. - public let getBlind : A - - public init(_ blind : A) { - self.getBlind = blind - } - - /// A default short description for the blind value. - /// - /// By default, the value of this property is `(*)`. - public var description : String { - return "(*)" - } - - /// Returns a generator of `Blind` values. - public static var arbitrary : Gen> { - return Blind.init <^> A.arbitrary - } - - /// The default shrinking function for `Blind` values. - public static func shrink(_ bl : Blind) -> [Blind] { - return A.shrink(bl.getBlind).map(Blind.init) - } + /// Retrieves the underlying value. + public let getBlind : A + + public init(_ blind : A) { + self.getBlind = blind + } + + /// A default short description for the blind value. + /// + /// By default, the value of this property is `(*)`. + public var description : String { + return "(*)" + } + + /// Returns a generator of `Blind` values. + public static var arbitrary : Gen> { + return Blind.init <^> A.arbitrary + } + + /// The default shrinking function for `Blind` values. + public static func shrink(_ bl : Blind) -> [Blind] { + return A.shrink(bl.getBlind).map(Blind.init) + } } extension Blind : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Guarantees test cases for its underlying type will not be shrunk. public struct Static : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying value. - public let getStatic : A - - public init(_ fixed : A) { - self.getStatic = fixed - } - - /// A textual representation of `self`. - public var description : String { - return "Static( \(self.getStatic) )" - } - - /// Returns a generator of `Static` values. - public static var arbitrary : Gen> { - return Static.init <^> A.arbitrary - } + /// Retrieves the underlying value. + public let getStatic : A + + public init(_ fixed : A) { + self.getStatic = fixed + } + + /// A textual representation of `self`. + public var description : String { + return "Static( \(self.getStatic) )" + } + + /// Returns a generator of `Static` values. + public static var arbitrary : Gen> { + return Static.init <^> A.arbitrary + } } extension Static : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Generates an array of arbitrary values of type A. public struct ArrayOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying array of values. - public let getArray : [A] - - /// Retrieves the underlying array of values as a contiguous array. - public var getContiguousArray : ContiguousArray { - return ContiguousArray(self.getArray) - } - - public init(_ array : [A]) { - self.getArray = array - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getArray)" - } - - /// Returns a generator of `ArrayOf` values. - public static var arbitrary : Gen> { - return ArrayOf.init <^> Array.arbitrary - } - - /// The default shrinking function for an `ArrayOf` values. - public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { - return Array.shrink(bl.getArray).map(ArrayOf.init) - } + /// Retrieves the underlying array of values. + public let getArray : [A] + + /// Retrieves the underlying array of values as a contiguous array. + public var getContiguousArray : ContiguousArray { + return ContiguousArray(self.getArray) + } + + public init(_ array : [A]) { + self.getArray = array + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getArray)" + } + + /// Returns a generator of `ArrayOf` values. + public static var arbitrary : Gen> { + return ArrayOf.init <^> Array.arbitrary + } + + /// The default shrinking function for an `ArrayOf` values. + public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { + return Array.shrink(bl.getArray).map(ArrayOf.init) + } } extension ArrayOf : CoArbitrary { - public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { - let a = x.getArray - if a.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1..(_ x : ArrayOf) -> ((Gen) -> Gen) { + let a = x.getArray + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1.. : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying sorted array of values. - public let getOrderedArray : [A] - - /// Retrieves the underlying sorted array of values as a contiguous - /// array. - public var getContiguousArray : ContiguousArray { - return ContiguousArray(self.getOrderedArray) - } - - public init(_ array : [A]) { - self.getOrderedArray = array.sorted() - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getOrderedArray)" - } - - /// Returns a generator for an `OrderedArrayOf` values. - public static var arbitrary : Gen> { - return OrderedArrayOf.init <^> Array.arbitrary - } - - /// The default shrinking function for an `OrderedArrayOf` values. - public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { - return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) - } + /// Retrieves the underlying sorted array of values. + public let getOrderedArray : [A] + + /// Retrieves the underlying sorted array of values as a contiguous + /// array. + public var getContiguousArray : ContiguousArray { + return ContiguousArray(self.getOrderedArray) + } + + public init(_ array : [A]) { + self.getOrderedArray = array.sorted() + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getOrderedArray)" + } + + /// Returns a generator for an `OrderedArrayOf` values. + public static var arbitrary : Gen> { + return OrderedArrayOf.init <^> Array.arbitrary + } + + /// The default shrinking function for an `OrderedArrayOf` values. + public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { + return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) + } } /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying dictionary of values. - public let getDictionary : Dictionary - - public init(_ dict : Dictionary) { - self.getDictionary = dict - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getDictionary)" - } - - /// Returns a generator for a `DictionaryOf` values. - public static var arbitrary : Gen> { - return DictionaryOf.init <^> Dictionary.arbitrary - } - - /// The default shrinking function for a `DictionaryOf` values. - public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { - return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) - } + /// Retrieves the underlying dictionary of values. + public let getDictionary : Dictionary + + public init(_ dict : Dictionary) { + self.getDictionary = dict + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getDictionary)" + } + + /// Returns a generator for a `DictionaryOf` values. + public static var arbitrary : Gen> { + return DictionaryOf.init <^> Dictionary.arbitrary + } + + /// The default shrinking function for a `DictionaryOf` values. + public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { + return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) + } } extension DictionaryOf : CoArbitrary { - public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { - return Dictionary.coarbitrary(x.getDictionary) - } + public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { + return Dictionary.coarbitrary(x.getDictionary) + } } /// Generates an Optional of arbitrary values of type A. public struct OptionalOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying optional value. - public let getOptional : A? - - public init(_ opt : A?) { - self.getOptional = opt - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getOptional)" - } - - /// Returns a generator for `OptionalOf` values. - public static var arbitrary : Gen> { - return OptionalOf.init <^> Optional.arbitrary - } - - /// The default shrinking function for `OptionalOf` values. - public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { - return Optional.shrink(bl.getOptional).map(OptionalOf.init) - } + /// Retrieves the underlying optional value. + public let getOptional : A? + + public init(_ opt : A?) { + self.getOptional = opt + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getOptional)" + } + + /// Returns a generator for `OptionalOf` values. + public static var arbitrary : Gen> { + return OptionalOf.init <^> Optional.arbitrary + } + + /// The default shrinking function for `OptionalOf` values. + public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { + return Optional.shrink(bl.getOptional).map(OptionalOf.init) + } } extension OptionalOf : CoArbitrary { - public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { - if let _ = x.getOptional { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { + if let _ = x.getOptional { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } /// Generates a set of arbitrary values of type A. public struct SetOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying set of values. - public let getSet : Set - - public init(_ set : Set) { - self.getSet = set - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getSet)" - } - - /// Returns a generator for a `SetOf` values. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure(SetOf(Set([]))) - } - - return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) - } - } - } - - /// The default shrinking function for a `SetOf` values. - public static func shrink(_ s : SetOf) -> [SetOf] { - return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) - } + /// Retrieves the underlying set of values. + public let getSet : Set + + public init(_ set : Set) { + self.getSet = set + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getSet)" + } + + /// Returns a generator for a `SetOf` values. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure(SetOf(Set([]))) + } + + return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) + } + } + } + + /// The default shrinking function for a `SetOf` values. + public static func shrink(_ s : SetOf) -> [SetOf] { + return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) + } } extension SetOf : CoArbitrary { - public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { - if x.getSet.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { + if x.getSet.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } /// Generates pointers of varying size of random values of type T. public struct PointerOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : PointerOfImpl - - /// Retrieves the underlying pointer value. - public var getPointer : UnsafePointer { - return UnsafePointer(self._impl.ptr!) - } - - public var size : Int { - return self._impl.size - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for a `PointerOf` values. - public static var arbitrary : Gen> { - return PointerOfImpl.arbitrary.map(PointerOf.init) - } + fileprivate let _impl : PointerOfImpl + + /// Retrieves the underlying pointer value. + public var getPointer : UnsafePointer { + return UnsafePointer(self._impl.ptr!) + } + + public var size : Int { + return self._impl.size + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for a `PointerOf` values. + public static var arbitrary : Gen> { + return PointerOfImpl.arbitrary.map(PointerOf.init) + } } /// Generates a Swift function from T to U. public struct ArrowOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : ArrowOfImpl - - /// Retrieves the underlying function value, `T -> U`. - public var getArrow : (T) -> U { - return self._impl.arr - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for an `ArrowOf` function values. - public static var arbitrary : Gen> { - return ArrowOfImpl.arbitrary.map(ArrowOf.init) - } + fileprivate let _impl : ArrowOfImpl + + /// Retrieves the underlying function value, `T -> U`. + public var getArrow : (T) -> U { + return self._impl.arr + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for an `ArrowOf` function values. + public static var arbitrary : Gen> { + return ArrowOfImpl.arbitrary.map(ArrowOf.init) + } } extension ArrowOf : CustomReflectable { - public var customMirror : Mirror { - return Mirror(self, children: [ - "types": "\(T.self) -> \(U.self)", - "currentMap": self._impl.table, - ]) - } + public var customMirror : Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self._impl.table, + ]) + } } /// Generates two isomorphic Swift functions from `T` to `U` and back again. public struct IsoOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : IsoOfImpl - - /// Retrieves the underlying embedding function, `T -> U`. - public var getTo : (T) -> U { - return self._impl.embed - } - - /// Retrieves the underlying projecting function, `U -> T`. - public var getFrom : (U) -> T { - return self._impl.project - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for an `IsoOf` function values. - public static var arbitrary : Gen> { - return IsoOfImpl.arbitrary.map(IsoOf.init) - } + fileprivate let _impl : IsoOfImpl + + /// Retrieves the underlying embedding function, `T -> U`. + public var getTo : (T) -> U { + return self._impl.embed + } + + /// Retrieves the underlying projecting function, `U -> T`. + public var getFrom : (U) -> T { + return self._impl.project + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for an `IsoOf` function values. + public static var arbitrary : Gen> { + return IsoOfImpl.arbitrary.map(IsoOf.init) + } } extension IsoOf : CustomReflectable { - public var customMirror : Mirror { - return Mirror(self, children: [ - "embed": "\(T.self) -> \(U.self)", - "project": "\(U.self) -> \(T.self)", - "currentMap": self._impl.table, - ]) - } + public var customMirror : Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self._impl.table, + ]) + } } -/// By default, SwiftCheck generates values drawn from a small range. `Large` +/// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. public struct Large : Arbitrary { - /// Retrieves the underlying large value. - public let getLarge : A - - public init(_ lrg : A) { - self.getLarge = lrg - } - - /// A textual representation of `self`. - public var description : String { - return "Large( \(self.getLarge) )" - } - - /// Returns a generator of `Large` values. - public static var arbitrary : Gen> { - return Gen.choose((A.min, A.max)).map(Large.init) - } - - /// The default shrinking function for `Large` values. - public static func shrink(_ bl : Large) -> [Large] { - return bl.getLarge.shrinkIntegral.map(Large.init) - } + /// Retrieves the underlying large value. + public let getLarge : A + + public init(_ lrg : A) { + self.getLarge = lrg + } + + /// A textual representation of `self`. + public var description : String { + return "Large( \(self.getLarge) )" + } + + /// Returns a generator of `Large` values. + public static var arbitrary : Gen> { + return Gen.choose((A.min, A.max)).map(Large.init) + } + + /// The default shrinking function for `Large` values. + public static func shrink(_ bl : Large) -> [Large] { + return bl.getLarge.shrinkIntegral.map(Large.init) + } } /// Guarantees that every generated integer is greater than 0. public struct Positive : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying positive value. - public let getPositive : A - - public init(_ pos : A) { - self.getPositive = pos - } - - /// A textual representation of `self`. - public var description : String { - return "Positive( \(self.getPositive) )" - } - - /// Returns a generator of `Positive` values. - public static var arbitrary : Gen> { - return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } - } - - /// The default shrinking function for `Positive` values. - public static func shrink(_ bl : Positive) -> [Positive] { - return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) - } + /// Retrieves the underlying positive value. + public let getPositive : A + + public init(_ pos : A) { + self.getPositive = pos + } + + /// A textual representation of `self`. + public var description : String { + return "Positive( \(self.getPositive) )" + } + + /// Returns a generator of `Positive` values. + public static var arbitrary : Gen> { + return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } + } + + /// The default shrinking function for `Positive` values. + public static func shrink(_ bl : Positive) -> [Positive] { + return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) + } } extension Positive : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Guarantees that every generated integer is never 0. public struct NonZero : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying non-zero value. - public let getNonZero : A - - public init(_ non : A) { - self.getNonZero = non - } - - /// A textual representation of `self`. - public var description : String { - return "NonZero( \(self.getNonZero) )" - } - - /// Returns a generator of `NonZero` values. - public static var arbitrary : Gen> { - return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } - } - - /// The default shrinking function for `NonZero` values. - public static func shrink(_ bl : NonZero) -> [NonZero] { - return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) - } + /// Retrieves the underlying non-zero value. + public let getNonZero : A + + public init(_ non : A) { + self.getNonZero = non + } + + /// A textual representation of `self`. + public var description : String { + return "NonZero( \(self.getNonZero) )" + } + + /// Returns a generator of `NonZero` values. + public static var arbitrary : Gen> { + return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } + } + + /// The default shrinking function for `NonZero` values. + public static func shrink(_ bl : NonZero) -> [NonZero] { + return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) + } } extension NonZero : CoArbitrary { - public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { - return x.getNonZero.coarbitraryIntegral() - } + public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { + return x.getNonZero.coarbitraryIntegral() + } } /// Guarantees that every generated integer is greater than or equal to 0. public struct NonNegative : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying non-negative value. - public let getNonNegative : A - - public init(_ non : A) { - self.getNonNegative = non - } - - /// A textual representation of `self`. - public var description : String { - return "NonNegative( \(self.getNonNegative) )" - } - - /// Returns a generator of `NonNegative` values. - public static var arbitrary : Gen> { - return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } - } - - /// The default shrinking function for `NonNegative` values. - public static func shrink(_ bl : NonNegative) -> [NonNegative] { - return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) - } + /// Retrieves the underlying non-negative value. + public let getNonNegative : A + + public init(_ non : A) { + self.getNonNegative = non + } + + /// A textual representation of `self`. + public var description : String { + return "NonNegative( \(self.getNonNegative) )" + } + + /// Returns a generator of `NonNegative` values. + public static var arbitrary : Gen> { + return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } + } + + /// The default shrinking function for `NonNegative` values. + public static func shrink(_ bl : NonNegative) -> [NonNegative] { + return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) + } } extension NonNegative : CoArbitrary { - public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { - return x.getNonNegative.coarbitraryIntegral() - } + public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { + return x.getNonNegative.coarbitraryIntegral() + } } @@ -503,191 +503,191 @@ extension NonNegative : CoArbitrary { private func undefined() -> A { - fatalError("") + fatalError("") } fileprivate final class ArrowOfImpl : Arbitrary, CustomStringConvertible { - fileprivate var table : Dictionary - fileprivate var arr : (T) -> U - - init (_ table : Dictionary, _ arr : ((T) -> U)) { - self.table = table - self.arr = arr - } - - convenience init(_ arr : ((T) -> U)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - - self.arr = { [unowned self] x in - if let v = self.table[x] { - return v - } - let y = arr(x) - self.table[x] = y - return y - } - } - - var description : String { - return "\(T.self) -> \(U.self)" - } - - static var arbitrary : Gen> { - return ArrowOfImpl.init <^> promote { a in - return T.coarbitrary(a)(U.arbitrary) - } - } - - static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { - return f.table.flatMap { (x, y) in - return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in - return ArrowOfImpl({ (z : T) -> U in - if x == z { - return y2 - } - return f.arr(z) - }) - }) - } - } + fileprivate var table : Dictionary + fileprivate var arr : (T) -> U + + init (_ table : Dictionary, _ arr : ((T) -> U)) { + self.table = table + self.arr = arr + } + + convenience init(_ arr : ((T) -> U)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }) + + self.arr = { [unowned self] x in + if let v = self.table[x] { + return v + } + let y = arr(x) + self.table[x] = y + return y + } + } + + var description : String { + return "\(T.self) -> \(U.self)" + } + + static var arbitrary : Gen> { + return ArrowOfImpl.init <^> promote { a in + return T.coarbitrary(a)(U.arbitrary) + } + } + + static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { + return f.table.flatMap { (x, y) in + return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in + return ArrowOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.arr(z) + }) + }) + } + } } fileprivate final class IsoOfImpl : Arbitrary, CustomStringConvertible { - fileprivate var table : Dictionary - fileprivate var embed : (T) -> U - fileprivate var project : (U) -> T - - init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { - self.table = table - self.embed = embed - self.project = project - } - - convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - - self.embed = { [unowned self] t in - if let v = self.table[t] { - return v - } - let y = embed(t) - self.table[t] = y - return y - } - - self.project = { [unowned self] u in - let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, let _ = self.table[k] { - return k - } - let y = project(u) - self.table[y] = u - return y - } - } - - var description : String { - return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" - } - - static var arbitrary : Gen> { - return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in - return T.coarbitrary(a)(U.arbitrary) - }), promote({ a in - return U.coarbitrary(a)(T.arbitrary) - })).map(IsoOfImpl.init) - } - - static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { - return f.table.flatMap { (x, y) in - return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in - return IsoOfImpl({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) - }, { (z : U) -> T in - if y == z { - return y1 - } - return f.project(z) - }) - }) - } - } + fileprivate var table : Dictionary + fileprivate var embed : (T) -> U + fileprivate var project : (U) -> T + + init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { + self.table = table + self.embed = embed + self.project = project + } + + convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + + self.embed = { [unowned self] t in + if let v = self.table[t] { + return v + } + let y = embed(t) + self.table[t] = y + return y + } + + self.project = { [unowned self] u in + let ts = self.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, let _ = self.table[k] { + return k + } + let y = project(u) + self.table[y] = u + return y + } + } + + var description : String { + return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" + } + + static var arbitrary : Gen> { + return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in + return T.coarbitrary(a)(U.arbitrary) + }), promote({ a in + return U.coarbitrary(a)(T.arbitrary) + })).map(IsoOfImpl.init) + } + + static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { + return f.table.flatMap { (x, y) in + return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return IsoOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) + }) + }) + } + } } private final class PointerOfImpl : Arbitrary { - var ptr : UnsafeMutablePointer? - let size : Int - - var description : String { - return "\(self.ptr)" - } - - init(_ ptr : UnsafeMutablePointer, _ size : Int) { - self.ptr = ptr - self.size = size - } - - deinit { - if self.size > 0 && self.ptr != nil { - self.ptr?.deallocate(capacity: self.size) - self.ptr = nil - } - } - - static var arbitrary : Gen> { - return Gen.sized { n in - if n <= 0 { + var ptr : UnsafeMutablePointer? + let size : Int + + var description : String { + return "\(self.ptr)" + } + + init(_ ptr : UnsafeMutablePointer, _ size : Int) { + self.ptr = ptr + self.size = size + } + + deinit { + if self.size > 0 && self.ptr != nil { + self.ptr?.deallocate(capacity: self.size) + self.ptr = nil + } + } + + static var arbitrary : Gen> { + return Gen.sized { n in + if n <= 0 { let size = 1 - return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) - } - let pt = UnsafeMutablePointer.allocate(capacity: n) - let gt = pt.initialize <^> sequence(Array((0...allocate(capacity: size), size)) + } + let pt = UnsafeMutablePointer.allocate(capacity: n) + let gt = pt.initialize <^> sequence(Array((0.. StdGen { let old = stdgen stdgen = old.split.0 return old } - + /// Generate a new `T` with a specific generator. /// /// - parameter gen: The generator used to create a random value. - /// + /// /// - returns: A random `T` using the receiver's stdgen and size. public func generate(using gen: Gen) -> T { return gen.unGen(split(), size) } - + /// Generate a new `T` with its default `arbitrary` generator. /// /// - returns: A random `T`. /// /// - seealso: generate\(gen:) public func generate() -> T - where T: Arbitrary + where T: Arbitrary { return generate(using: T.arbitrary) } @@ -695,25 +695,25 @@ public final class GenComposer { extension Gen { /// Create a generator by procedurally composing generated values from other generators. - /// + /// /// This is useful in cases where it's cumbersome to functionally compose multiple /// generators using `zip` and `map`. For example: - /// + /// /// public static var arbitrary: Gen { /// return Gen.compose { c in /// return ArbitraryLargeFoo( /// // use the nullary method to get an `arbitrary` value /// a: c.generate(), - /// + /// /// // or pass a custom generator /// b: c.generate(Bool.suchThat { $0 == false }), - /// + /// /// // .. and so on, for as many values & types as you need /// c: c.generate(), ... /// ) /// } /// } - /// + /// /// - parameter build: Function which is passed a GenComposer which can be used /// /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. diff --git a/Sources/Operators.swift b/Sources/Operators.swift index c6755ce..19681d7 100644 --- a/Sources/Operators.swift +++ b/Sources/Operators.swift @@ -6,28 +6,28 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // Released under the MIT License. // -// Precedence marks for certain symbols aligned with Runes +// Precedence marks for certain symbols aligned with Runes // ~( https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift ) until Swift gets a proper // resolver. // MARK: Combinators precedencegroup CompositionPrecedence { - associativity: right - higherThan: BitwiseShiftPrecedence + associativity: right + higherThan: BitwiseShiftPrecedence } /// Compose | Applies one function to the result of another function to produce a third function. infix operator • : CompositionPrecedence precedencegroup RightAssociativeCombinatorPrecedence { - associativity: right - lowerThan: DefaultPrecedence + associativity: right + lowerThan: DefaultPrecedence } precedencegroup LeftAssociativeCombinatorPrecedence { - associativity: left - lowerThan: DefaultPrecedence + associativity: left + lowerThan: DefaultPrecedence } /// Apply | Applies an argument to a function. @@ -47,23 +47,23 @@ infix operator |*| : LeftAssociativeCombinatorPrecedence // MARK: Control.* precedencegroup FunctorPrecedence { - associativity: left - higherThan: DefaultPrecedence + associativity: left + higherThan: DefaultPrecedence } precedencegroup FunctorSequencePrecedence { - associativity: left - higherThan: FunctorPrecedence + associativity: left + higherThan: FunctorPrecedence } precedencegroup MonadPrecedenceLeft { - associativity: left - higherThan: FunctorSequencePrecedence + associativity: left + higherThan: FunctorSequencePrecedence } precedencegroup MonadPrecedenceRight { - associativity: right - higherThan: FunctorSequencePrecedence + associativity: right + higherThan: FunctorSequencePrecedence } /// Fmap | Maps a function over the value encapsulated by a functor. @@ -82,13 +82,13 @@ infix operator <*> : FunctorPrecedence /// Sequence Right | Disregards the Functor on the Left. /// /// Default definition: -/// `const(id) <^> a <*> b` +/// `const(id) <^> a <*> b` infix operator *> : FunctorSequencePrecedence /// Sequence Left | Disregards the Functor on the Right. /// /// Default definition: -/// `const <^> a <*> b` +/// `const <^> a <*> b` infix operator <* : FunctorSequencePrecedence /// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the @@ -110,8 +110,8 @@ infix operator <<-<< : MonadPrecedenceRight infix operator ->> : MonadPrecedenceLeft precedencegroup FunctorExtrasPrecedence { - associativity: left - higherThan: FunctorSequencePrecedence + associativity: left + higherThan: FunctorSequencePrecedence } /// Imap | Maps covariantly over the index of a right-leaning bifunctor. @@ -123,8 +123,8 @@ infix operator : FunctorExtrasPrecedence // MARK: Data.Result precedencegroup ResultPrecedence { - associativity: none - higherThan: FunctorPrecedence + associativity: none + higherThan: FunctorPrecedence } /// From | Creates a Result given a function that can possibly fail with an error. @@ -138,8 +138,8 @@ infix operator <> : AdditionPrecedence // MARK: Control.Category precedencegroup CategoryPrecedence { - associativity: right - higherThan: MonadPrecedenceRight + associativity: right + higherThan: MonadPrecedenceRight } /// Right-to-Left Composition | Composes two categories to form a new category with the source of @@ -157,8 +157,8 @@ infix operator >>> : CategoryPrecedence // MARK: Control.Arrow precedencegroup ArrowPrecedence { - associativity: right - higherThan: CategoryPrecedence + associativity: right + higherThan: CategoryPrecedence } /// Split | Splits two computations and combines the result into one Arrow yielding a tuple of @@ -173,8 +173,8 @@ infix operator &&& : ArrowPrecedence // MARK: Control.Arrow.Choice precedencegroup ArrowChoicePrecedence { - associativity: right - higherThan: ArrowPrecedence + associativity: right + higherThan: ArrowPrecedence } /// Splat | Splits two computations and combines the results into Eithers on the left and right. @@ -187,8 +187,8 @@ infix operator ||| : ArrowChoicePrecedence // MARK: Control.Arrow.Plus precedencegroup ArrowPlusPrecedence { - associativity: right - higherThan: ArrowChoicePrecedence + associativity: right + higherThan: ArrowChoicePrecedence } /// Op | Combines two ArrowZero monoids. @@ -197,8 +197,8 @@ infix operator <+> : ArrowPlusPrecedence // MARK: Data.JSON precedencegroup JSONPrecedence { - associativity: right - higherThan: ArrowPlusPrecedence + associativity: right + higherThan: ArrowPlusPrecedence } /// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. diff --git a/Sources/Property.swift b/Sources/Property.swift index 143d4b8..4f68c34 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -6,647 +6,647 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// Takes the conjunction of multiple properties and reports all successes and -/// failures as one combined property. That is, this property holds when all +/// Takes the conjunction of multiple properties and reports all successes and +/// failures as one combined property. That is, this property holds when all /// sub-properties hold and fails when one or more sub-properties fail. /// /// Conjoined properties are each tested normally but are collected and labelled -/// together. This can mean multiple failures in distinct sub-properties are -/// masked. If fine-grained error reporting is needed, use a combination of +/// together. This can mean multiple failures in distinct sub-properties are +/// masked. If fine-grained error reporting is needed, use a combination of /// `disjoin(_:)` and `verbose(_:)`. /// /// When conjoining properties all calls to `expectFailure` will fail. public func conjoin(_ ps : Testable...) -> Property { - return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.map { $0.unProp } - })).flatMap({ roses in - return Gen.pure(Prop(unProp: conj(id, xs: roses))) - })) + return Property(sequence(ps.map({ (p : Testable) in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in + return Gen.pure(Prop(unProp: conj(id, xs: roses))) + })) } -/// Takes the disjunction of multiple properties and reports all successes and +/// Takes the disjunction of multiple properties and reports all successes and /// failures of each sub-property distinctly. That is, this property holds when /// any one of its sub-properties holds and fails when all of its sub-properties /// fail simultaneously. /// -/// Disjoined properties, when used in conjunction with labelling, cause +/// Disjoined properties, when used in conjunction with labelling, cause /// SwiftCheck to print a distribution map of the success rate of each sub- /// property. /// /// When disjoining properties all calls to `expectFailure` will fail. You can, /// however, `invert` the property. public func disjoin(_ ps : Testable...) -> Property { - return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.map { $0.unProp } - })).flatMap({ roses in - return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) - })) + return Property(sequence(ps.map({ (p : Testable) in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in + return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) + })) } -/// Takes the nondeterministic conjunction of multiple properties and treats +/// Takes the nondeterministic conjunction of multiple properties and treats /// them as a single large property. /// -/// The resulting property makes 100 random choices to test any of the given -/// properties. Thus, running multiple test cases will result in distinct +/// The resulting property makes 100 random choices to test any of the given +/// properties. Thus, running multiple test cases will result in distinct /// arbitrary sequences of each property being tested. public func conjamb(_ ps : () -> Testable...) -> Property { - let ls = ps.lazy.map { $0().property.unProperty } - return Property(Gen.oneOf(ls)) + let ls = ps.lazy.map { $0().property.unProperty } + return Property(Gen.oneOf(ls)) } extension Testable { - /// Modifies a property so it will not shrink when it fails. - public var noShrinking : Property { - return self.mapRoseResult { rs in - return rs.onRose { res, _ in - return .mkRose({ res }, { [] }) - } - } - } - - /// Inverts the result of a test. That is, test cases that would pass now - /// fail and vice versa. - /// - /// Discarded tests remain discarded under inversion. - public var invert : Property { - return self.mapResult { res in - return TestResult(ok: res.ok.map(!) - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Modifies a property so that it only will be tested once. - public var once : Property { - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: true - , quantifier: res.quantifier) - } - } - - /// Attaches a callback to a test case. - public func withCallback(_ cb : Callback) -> Property { - return self.mapResult { (res) in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: [cb] + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Adds the given string to the counterexamples of a failing property. - public func counterexample(_ s : String) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in - return print(s) - }) - } - - /// Executes an action after the last failure of the property. - public func whenFail(_ m : @escaping () -> ()) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in - return m() - }) - } - - /// Executes an action after the every failure of the property. - /// - /// Because the action is executed after every failing test it can be used - /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(_ m : @escaping () -> ()) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in - if res.ok == .some(false) { - m() - } - }) - } - - /// Modifies a property so it prints out every generated test case and the - /// result of the property every time it is tested. - /// - /// This function maps AfterFinalFailure callbacks that have the - /// `.Counterexample` kind to `.AfterTest` callbacks. - public var verbose : Property { - func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { - let c = Callback.afterTest(kind: .counterexample) { (st, res) in - switch res.ok { - case .some(true): - print("\nPassed: ", terminator: "") - printLabels(res) - case .some(false): - print("\nFailed: ", terminator: "") - printLabels(res) - print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") - default: - print("\nDiscarded: ", terminator: "") - printLabels(res) - } - } - - return [c] + cbs.map { (c : Callback) -> Callback in - switch c { - case let .afterFinalFailure(.counterexample, f): - return .afterTest(kind: .counterexample, f: f) - default: - return c - } - } - } - - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks + chattyCallbacks(res.callbacks) - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Modifies a property to indicate that it is expected to fail. - /// - /// If the property does not fail, SwiftCheck will report an error. - public var expectFailure : Property { - return self.mapTotalResult { res in - return TestResult(ok: res.ok - , expect: false - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Attaches a label to a property. - /// - /// Labelled properties aid in testing conjunctions and disjunctions, or any - /// other cases where test cases need to be distinct from one another. In - /// addition to shrunken test cases, upon failure SwiftCheck will print a - /// distribution map for the property that shows a percentage success rate - /// for the property. - public func label(_ s : String) -> Property { - return self.classify(true, label: s) - } - - /// Labels a property with a printable value. - public func collect(_ x : A) -> Property { - return self.label(String(describing: x)) - } - - /// Conditionally labels a property with a value. - public func classify(_ b : Bool, label : String) -> Property { - return self.cover(b, percentage: 0, label: label) - } - - /// Checks that at least the given proportion of successful test cases - /// belong to the given class. - /// - /// Discarded tests (i.e. ones with a false precondition) do not affect - /// coverage. - public func cover(_ b : Bool, percentage : Int, label : String) -> Property { - if b { - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: insertWith(max, k: label, v: percentage, m: res.labels) - , stamp: res.stamp.union([label]) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - return self.property - } - - /// Applies a function that modifies the property generator's inner `Prop`. - /// - /// This function can be used to completely change the evaluation schema of - /// generated test cases by replacing the test's rose tree with a custom - /// one. - public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { - return Property(f <^> self.property.unProperty) - } - - /// Applies a function that modifies the test case generator's size. - public func mapSize(_ f : @escaping (Int) -> Int) -> Property { - return Property(Gen.sized { n in - return self.property.unProperty.resize(f(n)) - }) - } - - /// Applies a function that modifies the result of a test case. - public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { - return self.mapRoseResult { rs in - return protectResults(f <^> rs) - } - } - - /// Applies a function that modifies the result of a test case. - public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { - return self.mapRoseResult { rs in - return f <^> rs - } - } - - /// Applies a function that modifies the underlying Rose Tree that a test - /// case has generated. - public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { - return self.mapProp { t in - return Prop(unProp: f(t.unProp)) - } - } + /// Modifies a property so it will not shrink when it fails. + public var noShrinking : Property { + return self.mapRoseResult { rs in + return rs.onRose { res, _ in + return .mkRose({ res }, { [] }) + } + } + } + + /// Inverts the result of a test. That is, test cases that would pass now + /// fail and vice versa. + /// + /// Discarded tests remain discarded under inversion. + public var invert : Property { + return self.mapResult { res in + return TestResult(ok: res.ok.map(!) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Modifies a property so that it only will be tested once. + public var once : Property { + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: true + , quantifier: res.quantifier) + } + } + + /// Attaches a callback to a test case. + public func withCallback(_ cb : Callback) -> Property { + return self.mapResult { (res) in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: [cb] + res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Adds the given string to the counterexamples of a failing property. + public func counterexample(_ s : String) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in + return print(s) + }) + } + + /// Executes an action after the last failure of the property. + public func whenFail(_ m : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in + return m() + }) + } + + /// Executes an action after the every failure of the property. + /// + /// Because the action is executed after every failing test it can be used + /// to track the list of failures generated by the shrinking mechanism. + public func whenEachFail(_ m : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in + if res.ok == .some(false) { + m() + } + }) + } + + /// Modifies a property so it prints out every generated test case and the + /// result of the property every time it is tested. + /// + /// This function maps AfterFinalFailure callbacks that have the + /// `.Counterexample` kind to `.AfterTest` callbacks. + public var verbose : Property { + func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { + let c = Callback.afterTest(kind: .counterexample) { (st, res) in + switch res.ok { + case .some(true): + print("\nPassed: ", terminator: "") + printLabels(res) + case .some(false): + print("\nFailed: ", terminator: "") + printLabels(res) + print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") + default: + print("\nDiscarded: ", terminator: "") + printLabels(res) + } + } + + return [c] + cbs.map { (c : Callback) -> Callback in + switch c { + case let .afterFinalFailure(.counterexample, f): + return .afterTest(kind: .counterexample, f: f) + default: + return c + } + } + } + + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + chattyCallbacks(res.callbacks) + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Modifies a property to indicate that it is expected to fail. + /// + /// If the property does not fail, SwiftCheck will report an error. + public var expectFailure : Property { + return self.mapTotalResult { res in + return TestResult(ok: res.ok + , expect: false + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Attaches a label to a property. + /// + /// Labelled properties aid in testing conjunctions and disjunctions, or any + /// other cases where test cases need to be distinct from one another. In + /// addition to shrunken test cases, upon failure SwiftCheck will print a + /// distribution map for the property that shows a percentage success rate + /// for the property. + public func label(_ s : String) -> Property { + return self.classify(true, label: s) + } + + /// Labels a property with a printable value. + public func collect(_ x : A) -> Property { + return self.label(String(describing: x)) + } + + /// Conditionally labels a property with a value. + public func classify(_ b : Bool, label : String) -> Property { + return self.cover(b, percentage: 0, label: label) + } + + /// Checks that at least the given proportion of successful test cases + /// belong to the given class. + /// + /// Discarded tests (i.e. ones with a false precondition) do not affect + /// coverage. + public func cover(_ b : Bool, percentage : Int, label : String) -> Property { + if b { + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: insertWith(max, k: label, v: percentage, m: res.labels) + , stamp: res.stamp.union([label]) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + return self.property + } + + /// Applies a function that modifies the property generator's inner `Prop`. + /// + /// This function can be used to completely change the evaluation schema of + /// generated test cases by replacing the test's rose tree with a custom + /// one. + public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { + return Property(f <^> self.property.unProperty) + } + + /// Applies a function that modifies the test case generator's size. + public func mapSize(_ f : @escaping (Int) -> Int) -> Property { + return Property(Gen.sized { n in + return self.property.unProperty.resize(f(n)) + }) + } + + /// Applies a function that modifies the result of a test case. + public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + return self.mapRoseResult { rs in + return protectResults(f <^> rs) + } + } + + /// Applies a function that modifies the result of a test case. + public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + return self.mapRoseResult { rs in + return f <^> rs + } + } + + /// Applies a function that modifies the underlying Rose Tree that a test + /// case has generated. + public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { + return self.mapProp { t in + return Prop(unProp: f(t.unProp)) + } + } } -/// Using a shrinking function, shrinks a given argument to a property if it +/// Using a shrinking function, shrinks a given argument to a property if it /// fails. /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : @escaping (A) -> Testable) -> Property { - return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in - return Prop(unProp: joinRose(rs.map { x in - return x.unProp - })) - }) + return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in + return Prop(unProp: joinRose(rs.map { x in + return x.unProp + })) + }) } -/// A `Callback` is a block of code that can be run after a test case has -/// finished. They consist of a kind and the callback block itself, which is +/// A `Callback` is a block of code that can be run after a test case has +/// finished. They consist of a kind and the callback block itself, which is /// given the state SwiftCheck ran the test case with and the result of the test /// to do with as it sees fit. public enum Callback { - /// A callback that is posted after a test case has completed. - case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) - /// The callback is posted after all cases in the test have failed. - case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + /// A callback that is posted after a test case has completed. + case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + /// The callback is posted after all cases in the test have failed. + case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { - /// Affected by the verbose combinator. - case counterexample - /// Not affected by the verbose combinator - case notCounterexample + /// Affected by the verbose combinator. + case counterexample + /// Not affected by the verbose combinator + case notCounterexample } /// The types of quantification SwiftCheck can perform. public enum Quantification { - /// Universal Quantification ("for all"). - case universal - /// Existential Quanfication ("there exists"). - case existential - /// Uniqueness Quantification ("there exists one and only one") -// case Uniqueness - /// Counting Quantification ("there exist exactly k") -// case Counting + /// Universal Quantification ("for all"). + case universal + /// Existential Quanfication ("there exists"). + case existential + /// Uniqueness Quantification ("there exists one and only one") + // case Uniqueness + /// Counting Quantification ("there exist exactly k") + // case Counting } /// A `TestResult` represents the result of performing a single test. public struct TestResult { - /// The result of executing the test case. For Discarded test cases the - /// value of this property is `.None`. - let ok : Optional - /// Indicates what the expected result of the property is. - let expect : Bool - /// A message indicating the reason a test case failed. - let reason : String - /// The exception that was thrown if one occured during testing. - let theException : Optional - /// All the labels used during the test case. - let labels : Dictionary - /// The collected values for the test case. - let stamp : Set - /// Callbacks attached to the test case. - let callbacks : [Callback] - /// Indicates that any further testing of the property should cease. - let abort : Bool - /// The quantifier being applied to this test case. - let quantifier : Quantification - - /// Provides a pattern-match-friendly view of the current state of a test - /// result. - public enum TestResultMatcher { - /// A case-able view of the current state of a test result. - case matchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification - ) - } - - /// Destructures a test case into a matcher that can be used in switch - /// statement. - public var match : TestResultMatcher { - return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) - } - - /// Creates and returns a new test result initialized with the given - /// parameters. - public init( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - , quantifier : Quantification) - { - self.ok = ok - self.expect = expect - self.reason = reason - self.theException = theException - self.labels = labels - self.stamp = stamp - self.callbacks = callbacks - self.abort = abort - self.quantifier = quantifier - } - - /// Convenience constructor for a passing `TestResult`. - public static var succeeded : TestResult { - return result(Optional.some(true)) - } - - /// Convenience constructor for a failing `TestResult`. - public static func failed(_ reason : String = "") -> TestResult { - return result(Optional.some(false), reason: reason) - } - - /// Convenience constructor for a discarded `TestResult`. - public static var rejected : TestResult { - return result(Optional.none) - } - - /// Lifts a `Bool`ean value to a TestResult by mapping true to - /// `TestResult.suceeded` and false to `TestResult.failed`. - public static func liftBool(_ b : Bool) -> TestResult { - if b { - return TestResult.succeeded - } - return result(Optional.some(false), reason: "Falsifiable") - } + /// The result of executing the test case. For Discarded test cases the + /// value of this property is `.None`. + let ok : Optional + /// Indicates what the expected result of the property is. + let expect : Bool + /// A message indicating the reason a test case failed. + let reason : String + /// The exception that was thrown if one occured during testing. + let theException : Optional + /// All the labels used during the test case. + let labels : Dictionary + /// The collected values for the test case. + let stamp : Set + /// Callbacks attached to the test case. + let callbacks : [Callback] + /// Indicates that any further testing of the property should cease. + let abort : Bool + /// The quantifier being applied to this test case. + let quantifier : Quantification + + /// Provides a pattern-match-friendly view of the current state of a test + /// result. + public enum TestResultMatcher { + /// A case-able view of the current state of a test result. + case matchResult( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : Array + , abort : Bool + , quantifier : Quantification + ) + } + + /// Destructures a test case into a matcher that can be used in switch + /// statement. + public var match : TestResultMatcher { + return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) + } + + /// Creates and returns a new test result initialized with the given + /// parameters. + public init( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : [Callback] + , abort : Bool + , quantifier : Quantification) + { + self.ok = ok + self.expect = expect + self.reason = reason + self.theException = theException + self.labels = labels + self.stamp = stamp + self.callbacks = callbacks + self.abort = abort + self.quantifier = quantifier + } + + /// Convenience constructor for a passing `TestResult`. + public static var succeeded : TestResult { + return result(Optional.some(true)) + } + + /// Convenience constructor for a failing `TestResult`. + public static func failed(_ reason : String = "") -> TestResult { + return result(Optional.some(false), reason: reason) + } + + /// Convenience constructor for a discarded `TestResult`. + public static var rejected : TestResult { + return result(Optional.none) + } + + /// Lifts a `Bool`ean value to a TestResult by mapping true to + /// `TestResult.suceeded` and false to `TestResult.failed`. + public static func liftBool(_ b : Bool) -> TestResult { + if b { + return TestResult.succeeded + } + return result(Optional.some(false), reason: "Falsifiable") + } } // MARK: - Implementation Details private func exception(_ msg : String) -> (Error) -> TestResult { - return { e in TestResult.failed(String(describing: e)) } + return { e in TestResult.failed(String(describing: e)) } } private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @escaping (A) -> Testable) -> Rose> { - return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in - return props(shrinker, original: x1, pf: pf) - }}) + return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in + return props(shrinker, original: x1, pf: pf) + }}) } private func result(_ ok : Bool?, reason : String = "") -> TestResult { - return TestResult( ok: ok - , expect: true - , reason: reason - , theException: .none - , labels: [:] - , stamp: Set() - , callbacks: [] - , abort: false - , quantifier: .universal - ) + return TestResult( ok: ok + , expect: true + , reason: reason + , theException: .none + , labels: [:] + , stamp: Set() + , callbacks: [] + , abort: false + , quantifier: .universal + ) } private func protectResults(_ rs : Rose) -> Rose { - return rs.onRose { x, rs in - return .ioRose({ - return .mkRose(protectResult({ x }), { rs.map(protectResults) }) - }) - } + return rs.onRose { x, rs in + return .ioRose({ + return .mkRose(protectResult({ x }), { rs.map(protectResults) }) + }) + } } //internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { -// return { protect(Rose.pure • exception("Exception"), x: f) } +// return { protect(Rose.pure • exception("Exception"), x: f) } //} internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { - do { - return try x() - } catch let e { - return f(e) - } + do { + return try x() + } catch let e { + return f(e) + } } internal func id(_ x : A) -> A { - return x + return x } internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { - return { f(g($0)) } + return { f(g($0)) } } private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> TestResult) { - return { protect(exception("Exception"), x: r) } + return { protect(exception("Exception"), x: r) } } internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { - var map = l - r.forEach { (k, v) in - if let val = map.updateValue(v, forKey: k) { - map.updateValue(f(val, v), forKey: k) - } - } - return map + var map = l + r.forEach { (k, v) in + if let val = map.updateValue(v, forKey: k) { + map.updateValue(f(val, v), forKey: k) + } + } + return map } private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { - var res = m - let oldV = res[k] - if let existV = oldV { - res[k] = f(existV, v) - } else { - res[k] = v - } - return res + var res = m + let oldV = res[k] + if let existV = oldV { + res[k] = f(existV, v) + } else { + res[k] = v + } + return res } private func sep(_ l : String, r : String) -> String { - if l.isEmpty { - return r - } - - if r.isEmpty { - return l - } - return l + ", " + r + if l.isEmpty { + return r + } + + if r.isEmpty { + return l + } + return l + ", " + r } private func mplus(_ l : Optional, r : Optional) -> Optional { - if let ls = l, let rs = r { - return .some(ls + rs) - } + if let ls = l, let rs = r { + return .some(ls + rs) + } - if l == nil { - return r - } + if l == nil { + return r + } - return l + return l } private func addCallbacks(_ result : TestResult) -> (TestResult) -> TestResult { - return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: result.callbacks + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } + return { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: result.callbacks + res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } } private func addLabels(_ result : TestResult) -> (TestResult) -> TestResult { - return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: unionWith(max, l: res.labels, r: result.labels) - , stamp: res.stamp.union(result.stamp) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } + return { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: unionWith(max, l: res.labels, r: result.labels) + , stamp: res.stamp.union(result.stamp) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } } private func printLabels(_ st : TestResult) { - if st.labels.isEmpty { - print("(.)") - } else if st.labels.count == 1, let pt = st.labels.first { - print("(\(pt.0))") - } else { - let gAllLabels = st.labels.map({ (l, _) in - return l + ", " - }).reduce("", +) - print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { - if xs.isEmpty { - return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) - } else if let p = xs.first { - return .ioRose(/*protectRose*/({ - let rose = p.reduce - switch rose { - case .mkRose(let result, _): - if !result().expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) - } - - switch result().ok { - case .some(true): - return conj(addLabels(result()) • addCallbacks(result()) • k, xs: [Rose](xs[1..](xs[1..](xs[1..](xs[1.., q : Rose) -> Rose { - return p.flatMap { result1 in - if !result1.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result1.ok { - case .some(true): - return Rose.pure(result1) - case .some(false): - return q.flatMap { (result2 : TestResult) in - if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result2.ok { - case .some(true): - return Rose.pure(result2) - case .some(false): - let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, - f: { _ in - return print("") - })] - return Rose.pure(TestResult(ok: .some(false), - expect: true, - reason: sep(result1.reason, r: result2.reason), - theException: mplus(result1.theException, r: result2.theException), - labels: [:], - stamp: Set(), - callbacks: result1.callbacks + callbacks + result2.callbacks, - abort: false, - quantifier: .universal)) - case .none: - return Rose.pure(result2) - } - } - case .none: - return q.flatMap { (result2 : TestResult) in - if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result2.ok { - case .some(true): - return Rose.pure(result2) - default: - return Rose.pure(result1) - } - } - } - } + return p.flatMap { result1 in + if !result1.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result1.ok { + case .some(true): + return Rose.pure(result1) + case .some(false): + return q.flatMap { (result2 : TestResult) in + if !result2.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result2.ok { + case .some(true): + return Rose.pure(result2) + case .some(false): + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, + f: { _ in + return print("") + })] + return Rose.pure(TestResult(ok: .some(false), + expect: true, + reason: sep(result1.reason, r: result2.reason), + theException: mplus(result1.theException, r: result2.theException), + labels: [:], + stamp: Set(), + callbacks: result1.callbacks + callbacks + result2.callbacks, + abort: false, + quantifier: .universal)) + case .none: + return Rose.pure(result2) + } + } + case .none: + return q.flatMap { (result2 : TestResult) in + if !result2.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result2.ok { + case .some(true): + return Rose.pure(result2) + default: + return Rose.pure(result1) + } + } + } + } } diff --git a/Sources/Random.swift b/Sources/Random.swift index 0e018bf..7379a0a 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -7,300 +7,300 @@ // /// Provides a standard interface to an underlying Random Value Generator of any -/// type. It is analogous to `GeneratorType`, but rather than consume a +/// type. It is analogous to `GeneratorType`, but rather than consume a /// sequence it uses sources of randomness to generate values indefinitely. public protocol RandomGeneneratorType { - /// The next operation returns an Int that is uniformly distributed in the - /// range returned by `genRange` (including both end points), and a new - /// generator. - var next : (Int, Self) { get } - /// The genRange operation yields the range of values returned by the - /// generator. - /// - /// This property must return integers in ascending order. - var genRange : (Int, Int) { get } - /// Splits the receiver into two distinct random value generators. - var split : (Self, Self) { get } + /// The next operation returns an Int that is uniformly distributed in the + /// range returned by `genRange` (including both end points), and a new + /// generator. + var next : (Int, Self) { get } + /// The genRange operation yields the range of values returned by the + /// generator. + /// + /// This property must return integers in ascending order. + var genRange : (Int, Int) { get } + /// Splits the receiver into two distinct random value generators. + var split : (Self, Self) { get } } -/// `StdGen` represents a pseudo-random number generator. The library makes it -/// possible to generate repeatable results, by starting with a specified +/// `StdGen` represents a pseudo-random number generator. The library makes it +/// possible to generate repeatable results, by starting with a specified /// initial random number generator, or to get different results on each run by -/// using the system-initialised generator or by supplying a seed from some +/// using the system-initialised generator or by supplying a seed from some /// other source. public struct StdGen : RandomGeneneratorType { - let seed1 : Int - let seed2 : Int - - /// Creates a `StdGen` initialized at the given seeds that is suitable for - /// replaying of tests. - public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { - self.seed1 = replaySeed1 - self.seed2 = replaySeed2 - } - - /// Convenience to create a `StdGen` from a given integer. - public init(_ o : Int) { - func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { - let s = sMaybeNegative & Int.max - let (q, s1) = (s / 2147483562, s % 2147483562) - let s2 = q % 2147483398 - return StdGen((s1 + 1), (s2 + 1)) - } - self = mkStdGen32(o) - } - - /// Returns an `Int` generated uniformly within the bounds of the generator - /// and a new distinct random number generator. - public var next : (Int, StdGen) { - let s1 = self.seed1 - let s2 = self.seed2 - - let k = s1 / 53668 - let s1_ = 40014 * (s1 - k * 53668) - k * 12211 - let s1__ = s1_ < 0 ? s1_ + 2147483563 : s1_ - - let k_ = s2 / 52774 - let s2_ = 40692 * (s2 - k_ * 52774) - k_ * 3791 - let s2__ = s2_ < 0 ? s2_ + 2147483399 : s2_ - - let z = s1__ - s2__ - let z_ = z < 1 ? z + 2147483562 : z - return (z_, StdGen(s1__, s2__)) - } - - /// Splits the receiver and returns two distinct random number generators. - public var split : (StdGen, StdGen) { - let s1 = self.seed1 - let s2 = self.seed2 - let std = self.next.1 - return (StdGen(s1 == 2147483562 ? 1 : s1 + 1, std.seed2), StdGen(std.seed1, s2 == 1 ? 2147483398 : s2 - 1)) - } - - public var genRange : (Int, Int) { - return (Int.min, Int.max) - } + let seed1 : Int + let seed2 : Int + + /// Creates a `StdGen` initialized at the given seeds that is suitable for + /// replaying of tests. + public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { + self.seed1 = replaySeed1 + self.seed2 = replaySeed2 + } + + /// Convenience to create a `StdGen` from a given integer. + public init(_ o : Int) { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen((s1 + 1), (s2 + 1)) + } + self = mkStdGen32(o) + } + + /// Returns an `Int` generated uniformly within the bounds of the generator + /// and a new distinct random number generator. + public var next : (Int, StdGen) { + let s1 = self.seed1 + let s2 = self.seed2 + + let k = s1 / 53668 + let s1_ = 40014 * (s1 - k * 53668) - k * 12211 + let s1__ = s1_ < 0 ? s1_ + 2147483563 : s1_ + + let k_ = s2 / 52774 + let s2_ = 40692 * (s2 - k_ * 52774) - k_ * 3791 + let s2__ = s2_ < 0 ? s2_ + 2147483399 : s2_ + + let z = s1__ - s2__ + let z_ = z < 1 ? z + 2147483562 : z + return (z_, StdGen(s1__, s2__)) + } + + /// Splits the receiver and returns two distinct random number generators. + public var split : (StdGen, StdGen) { + let s1 = self.seed1 + let s2 = self.seed2 + let std = self.next.1 + return (StdGen(s1 == 2147483562 ? 1 : s1 + 1, std.seed2), StdGen(std.seed1, s2 == 1 ? 2147483398 : s2 - 1)) + } + + public var genRange : (Int, Int) { + return (Int.min, Int.max) + } } extension StdGen : Equatable, CustomStringConvertible { - public var description : String { - return "\(self.seed1) \(self.seed2)" - } + public var description : String { + return "\(self.seed1) \(self.seed2)" + } } /// Equality over random number generators. /// /// Two `StdGen`s are equal iff their seeds match. public func == (l : StdGen, r : StdGen) -> Bool { - return l.seed1 == r.seed1 && l.seed2 == r.seed2 + return l.seed1 == r.seed1 && l.seed2 == r.seed2 } private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. public func newStdGen() -> StdGen { - let (left, right) = theStdGen.split - theStdGen = left - return right + let (left, right) = theStdGen.split + theStdGen = left + return right } /// Types that can generate random versions of themselves. public protocol RandomType { - /// Takes a range `(lo, hi)` and a random number generator `G`, and returns - /// a random value uniformly distributed in the closed interval `[lo,hi]`, - /// together with a new generator. It is unspecified what happens if lo>hi. - /// - /// For continuous types there is no requirement that the values `lo` and - /// `hi` are ever produced, but they may be, depending on the implementation - /// and the interval. - static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) + /// Takes a range `(lo, hi)` and a random number generator `G`, and returns + /// a random value uniformly distributed in the closed interval `[lo,hi]`, + /// together with a new generator. It is unspecified what happens if lo>hi. + /// + /// For continuous types there is no requirement that the values `lo` and + /// `hi` are ever produced, but they may be, depending on the implementation + /// and the interval. + static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) } /// Generates a random value from a LatticeType random type. public func randomBound(_ gen : G) -> (A, G) { - return A.randomInRange((A.min, A.max), gen: gen) + return A.randomInRange((A.min, A.max), gen: gen) } extension Bool : RandomType { - /// Returns a random `Bool`ean value using the given range and generator. - public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { - let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) - return (x == 1, gg) - } + /// Returns a random `Bool`ean value using the given range and generator. + public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { + let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) + return (x == 1, gg) + } } extension Character : RandomType { - /// Returns a random `Character` value using the given range and generator. - public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { - let (min, max) = range - let minc = String(min).unicodeScalars.first! - let maxc = String(max).unicodeScalars.first! - - let (val, gg) = UnicodeScalar.randomInRange((minc, maxc), gen: gen) - return (Character(val), gg) - } + /// Returns a random `Character` value using the given range and generator. + public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { + let (min, max) = range + let minc = String(min).unicodeScalars.first! + let maxc = String(max).unicodeScalars.first! + + let (val, gg) = UnicodeScalar.randomInRange((minc, maxc), gen: gen) + return (Character(val), gg) + } } extension UnicodeScalar : RandomType { - /// Returns a random `UnicodeScalar` value using the given range and generator. - public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { - let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) - return (UnicodeScalar(val)!, gg) - } + /// Returns a random `UnicodeScalar` value using the given range and generator. + public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) + return (UnicodeScalar(val)!, gg) + } } extension Int : RandomType { - /// Returns a random `Int` value using the given range and generator. - public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int` value using the given range and generator. + public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int(truncatingBitPattern: bb), gg) + } } extension Int8 : RandomType { - /// Returns a random `Int8` value using the given range and generator. - public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int8(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int8` value using the given range and generator. + public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int8(truncatingBitPattern: bb), gg) + } } extension Int16 : RandomType { - /// Returns a random `Int16` value using the given range and generator. - public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int16(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int16` value using the given range and generator. + public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int16(truncatingBitPattern: bb), gg) + } } extension Int32 : RandomType { - /// Returns a random `Int32` value using the given range and generator. - public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int32(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int32` value using the given range and generator. + public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int32(truncatingBitPattern: bb), gg) + } } extension Int64 : RandomType { - /// Returns a random `Int64` value using the given range and generator. - public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { - let (l, h) = range - if l > h { - return Int64.randomInRange((h, l), gen: gen) - } else { - let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) - let b = Double(genhi - genlo + 1) - let q : Double = 1000 - let k = Double(h) - Double(l) + 1 - let magtgt = k * q - - func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { - if mag >= magtgt { - return (v, g) - } else { - let (x, g_) = g.next - let v_ = (v * b + (Double(x) - Double(genlo))) - return entropize(mag * b, v_, g_) - } - } - - let (v, rng_) = entropize(1, 0, gen) - return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) - } - } + /// Returns a random `Int64` value using the given range and generator. + public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { + let (l, h) = range + if l > h { + return Int64.randomInRange((h, l), gen: gen) + } else { + let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 + let magtgt = k * q + + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { + if mag >= magtgt { + return (v, g) + } else { + let (x, g_) = g.next + let v_ = (v * b + (Double(x) - Double(genlo))) + return entropize(mag * b, v_, g_) + } + } + + let (v, rng_) = entropize(1, 0, gen) + return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) + } + } } extension UInt : RandomType { - /// Returns a random `UInt` value using the given range and generator. - public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) - return (UInt(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt` value using the given range and generator. + public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) + return (UInt(truncatingBitPattern: bb), gg) + } } extension UInt8 : RandomType { - /// Returns a random `UInt8` value using the given range and generator. - public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt8(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt8` value using the given range and generator. + public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt8(truncatingBitPattern: bb), gg) + } } extension UInt16 : RandomType { - /// Returns a random `UInt16` value using the given range and generator. - public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt16(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt16` value using the given range and generator. + public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt16(truncatingBitPattern: bb), gg) + } } extension UInt32 : RandomType { - /// Returns a random `UInt32` value using the given range and generator. - public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt32(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt32` value using the given range and generator. + public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt32(truncatingBitPattern: bb), gg) + } } extension UInt64 : RandomType { - /// Returns a random `UInt64` value using the given range and generator. - public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt64(bb), gg) - } + /// Returns a random `UInt64` value using the given range and generator. + public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt64(bb), gg) + } } extension Float : RandomType { - /// Produces a random `Float` value in the range `[Float.min, Float.max]`. - public static func random(_ rng : G) -> (Float, G) { - let (x, rng_) : (Int32, G) = randomBound(rng) - let twoto24 = Int32(2) ^ Int32(24) - let mask24 = twoto24 - 1 - - return (Float(mask24 & (x)) / Float(twoto24), rng_) - } - - /// Returns a random `Float` value using the given range and generator. - public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { - let (l, h) = range - if l > h { - return Float.randomInRange((h , l), gen: gen) - } else { - let (coef, g_) = Float.random(gen) - return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) - } - } + /// Produces a random `Float` value in the range `[Float.min, Float.max]`. + public static func random(_ rng : G) -> (Float, G) { + let (x, rng_) : (Int32, G) = randomBound(rng) + let twoto24 = Int32(2) ^ Int32(24) + let mask24 = twoto24 - 1 + + return (Float(mask24 & (x)) / Float(twoto24), rng_) + } + + /// Returns a random `Float` value using the given range and generator. + public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { + let (l, h) = range + if l > h { + return Float.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Float.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } + } } extension Double : RandomType { - /// Produces a random `Float` value in the range `[Double.min, Double.max]`. - public static func random(_ rng : G) -> (Double, G) { - let (x, rng_) : (Int64, G) = randomBound(rng) - let twoto53 = Int64(2) ^ Int64(53) - let mask53 = twoto53 - 1 - - return (Double(mask53 & (x)) / Double(twoto53), rng_) - } - - /// Returns a random `Double` value using the given range and generator. - public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { - let (l, h) = range - if l > h { - return Double.randomInRange((h , l), gen: gen) - } else { - let (coef, g_) = Double.random(gen) - return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) - } - } + /// Produces a random `Float` value in the range `[Double.min, Double.max]`. + public static func random(_ rng : G) -> (Double, G) { + let (x, rng_) : (Int64, G) = randomBound(rng) + let twoto53 = Int64(2) ^ Int64(53) + let mask53 = twoto53 - 1 + + return (Double(mask53 & (x)) / Double(twoto53), rng_) + } + + /// Returns a random `Double` value using the given range and generator. + public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { + let (l, h) = range + if l > h { + return Double.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Double.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } + } } /// Implementation Details Follow @@ -310,15 +310,15 @@ private enum ClockTimeResult { } private func mkStdRNG(_ o : Int) -> StdGen { - func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { - let s = sMaybeNegative & Int.max - let (q, s1) = (s / 2147483562, s % 2147483562) - let s2 = q % 2147483398 - return StdGen(s1 + 1, s2 + 1) - } - - let ct = Int(clock()) - var tt = timespec() + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen(s1 + 1, s2 + 1) + } + + let ct = Int(clock()) + var tt = timespec() switch clock_gettime(0, &tt) { case .success: break @@ -326,25 +326,25 @@ private func mkStdRNG(_ o : Int) -> StdGen { fatalError("call to `clock_gettime` failed. error: \(error)") } - let (sec, psec) = (tt.tv_sec, tt.tv_nsec) - let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) - return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) + let (sec, psec) = (tt.tv_sec, tt.tv_nsec) + let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) + return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> ClockTimeResult { - var now : timeval = timeval() - let rv = gettimeofday(&now, nil) - if rv != 0 { - return .failure(Int(rv)) - } - t.pointee.tv_sec = now.tv_sec - t.pointee.tv_nsec = Int(now.tv_usec) * 1000 - - return .success + var now : timeval = timeval() + let rv = gettimeofday(&now, nil) + if rv != 0 { + return .failure(Int(rv)) + } + t.pointee.tv_sec = now.tv_sec + t.pointee.tv_nsec = Int(now.tv_usec) * 1000 + + return .success } #if os(Linux) - import Glibc + import Glibc #else - import Darwin + import Darwin #endif diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 93113c5..04365a3 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -6,148 +6,148 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the -/// steps necessary for testing a property. The first case, .MkRose, consists -/// of a value and a list of trees. The second, case, .IORose, is a suspended -/// IO action SwiftCheck must execute in order to produce another Rose tree. +/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the +/// steps necessary for testing a property. The first case, .MkRose, consists +/// of a value and a list of trees. The second, case, .IORose, is a suspended +/// IO action SwiftCheck must execute in order to produce another Rose tree. /// All values in a `Rose` are lazy. /// -/// In practice SwiftCheck will minimize the side-effects performed in a given +/// In practice SwiftCheck will minimize the side-effects performed in a given /// `IORose` to printing values to the console and executing callbacks. public enum Rose { - /// A normal branch in the Rose Tree. - case mkRose(() -> A, () -> [Rose]) - /// An IO branch in the Rose Tree. That is, a branch that must execute - /// side effects before revealing further structure. - case ioRose(() -> Rose) + /// A normal branch in the Rose Tree. + case mkRose(() -> A, () -> [Rose]) + /// An IO branch in the Rose Tree. That is, a branch that must execute + /// side effects before revealing further structure. + case ioRose(() -> Rose) - /// Case analysis for a Rose Tree. - public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { - switch self { - case .mkRose(let x, let rs): - return f(x(), rs()) - case .ioRose(let m): - return .ioRose({ m().onRose(f) }) - } - } + /// Case analysis for a Rose Tree. + public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { + switch self { + case .mkRose(let x, let rs): + return f(x(), rs()) + case .ioRose(let m): + return .ioRose({ m().onRose(f) }) + } + } - /// Reduces a rose tree by evaluating all `.IORose` branches until the first - /// `.MkRose` branch is encountered. That branch is then returned. - public var reduce : Rose { - switch self { - case .mkRose(_, _): - return self - case .ioRose(let m): - return m().reduce - } - } + /// Reduces a rose tree by evaluating all `.IORose` branches until the first + /// `.MkRose` branch is encountered. That branch is then returned. + public var reduce : Rose { + switch self { + case .mkRose(_, _): + return self + case .ioRose(let m): + return m().reduce + } + } } extension Rose /*: Functor*/ { - /// Maps a function over all the nodes of a Rose Tree. - /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` branches - /// the map is suspended. - public func map(_ f : @escaping (A) -> B) -> Rose { - return f <^> self - } + /// Maps a function over all the nodes of a Rose Tree. + /// + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` branches + /// the map is suspended. + public func map(_ f : @escaping (A) -> B) -> Rose { + return f <^> self + } } /// Fmap | Maps a function over all the nodes of a Rose Tree. public func <^> (f : @escaping (A) -> B, g : Rose) -> Rose { - switch g { - case .mkRose(let root, let children): - return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) - case .ioRose(let rs): - return .ioRose({ rs().map(f) }) - } + switch g { + case .mkRose(let root, let children): + return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) + case .ioRose(let rs): + return .ioRose({ rs().map(f) }) + } } extension Rose /*: Applicative*/ { - /// Lifts a value into a Rose Tree. - public static func pure(_ a : A) -> Rose { - return .mkRose({ a }, { [] }) - } + /// Lifts a value into a Rose Tree. + public static func pure(_ a : A) -> Rose { + return .mkRose({ a }, { [] }) + } - /// Applies a Rose Tree of functions to the receiver to yield a new Rose - /// Tree of values. - /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` the branch - /// is reduced to a `.MkRose` and applied, executing all side-effects along - /// the way. - public func ap(_ fn : Rose<(A) -> B>) -> Rose { - return fn <*> self - } + /// Applies a Rose Tree of functions to the receiver to yield a new Rose + /// Tree of values. + /// + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` the branch + /// is reduced to a `.MkRose` and applied, executing all side-effects along + /// the way. + public func ap(_ fn : Rose<(A) -> B>) -> Rose { + return fn <*> self + } } -/// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose +/// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose /// Tree of values. public func <*> (fn : Rose<(A) -> B>, g : Rose) -> Rose { - switch fn { - case .mkRose(let f, _): - return g.map(f()) - case .ioRose(let rs): - return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW - } + switch fn { + case .mkRose(let f, _): + return g.map(f()) + case .ioRose(let rs): + return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + } } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all - /// together. - public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { - return self >>- fn - } + /// Maps the values in the receiver to Rose Trees and joins them all + /// together. + public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { + return self >>- fn + } } /// Flat Map | Maps the values in the receiver to Rose Trees and joins them all /// together. public func >>- (m : Rose, fn : @escaping (A) -> Rose) -> Rose { - return joinRose(m.map(fn)) + return joinRose(m.map(fn)) } /// Lifts functions to functions over Rose Trees. public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { - return m1.flatMap { x1 in - return Rose.pure(f(x1)) - } + return m1.flatMap { x1 in + return Rose.pure(f(x1)) + } } /// Flattens a Rose Tree of Rose Trees by a single level. /// -/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the -/// kind of subtree at the node dictates the behavior of the join. For -/// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the +/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the +/// kind of subtree at the node dictates the behavior of the join. For +/// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the /// value at the sub-tree node and a recursive call to join the branch's tree to /// its sub-trees. public func joinRose(_ rs : Rose>) -> Rose { - switch rs { - case .ioRose(let rs): - return .ioRose({ joinRose(rs()) }) - case .mkRose(let bx , let rs): - switch bx() { - case .ioRose(let rm): - return .ioRose({ joinRose(.mkRose(rm, rs)) }) - case .mkRose(let x, let ts): - return .mkRose(x, { rs().map(joinRose) + ts() }) - } - } + switch rs { + case .ioRose(let rs): + return .ioRose({ joinRose(rs()) }) + case .mkRose(let bx , let rs): + switch bx() { + case .ioRose(let rm): + return .ioRose({ joinRose(.mkRose(rm, rs)) }) + case .mkRose(let x, let ts): + return .mkRose(x, { rs().map(joinRose) + ts() }) + } + } } /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(_ ms : [Rose]) -> Rose<[A]> { - return ms.reduce(Rose<[A]>.pure([]), { n, m in - return m.flatMap { x in - return n.flatMap { xs in - return Rose<[A]>.pure(xs + [x]) - } - } - }) + return ms.reduce(Rose<[A]>.pure([]), { n, m in + return m.flatMap { x in + return n.flatMap { xs in + return Rose<[A]>.pure(xs + [x]) + } + } + }) } /// Sequences the result of mapping values to Rose trees into a single rose tree /// of an array of values. public func mapM(_ f : (A) -> Rose, xs : [A]) -> Rose<[B]> { - return sequence(xs.map(f)) + return sequence(xs.map(f)) } diff --git a/Sources/State.swift b/Sources/State.swift index 007fd84..c7e2d00 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -8,86 +8,86 @@ /// The internal state of the testing system. public struct CheckerState { - /// The name bound to the current property (not labels). - let name : String - /// The maximum number of successful tests before SwiftCheck gives up. - /// Defaults to 100. - let maxAllowableSuccessfulTests : Int - /// The maximum number of discarded tests before SwiftCheck gives up. - let maxAllowableDiscardedTests : Int - /// The function that generates the sizes fed to the generators for each - /// test case. - let computeSize : (Int, Int) -> Int - /// The count of the number of successful test cases seen so far. - let successfulTestCount : Int - /// The count of the number of discarded test cases seen so far. - let discardedTestCount : Int - /// A dictionary of labels collected inside the test case. Each maps to an - /// integer describing the number of passed tests. It is used in - /// conjunction with the number of successful tests to print a coverage - /// percentage. - let labels : Dictionary - /// A uniqued collection of all the labels collected during the test case. - let collected : [Set] - /// Returns whether the test case has fulfilled its expected failure - /// outcome. If the test case fails and it was expected this property - /// returns true. If the test case doesn't fail and it was not expected to - /// fail this property returns true. Only when the test case's outcome and - /// its failure fulfillment expectation do not match does this property - /// return false. - let hasFulfilledExpectedFailure : Bool - /// The Random Number Generator backing the testing session. - let randomSeedGenerator : StdGen - /// Returns the number of successful shrinking steps performed so far. - let successfulShrinkCount : Int - /// Returns the number of failed shrinking steps since the last successful - /// shrink. - let failedShrinkStepDistance : Int - /// Returns the number of failed shrink steps. - let failedShrinkStepCount : Int - /// Returns whether the testing system should cease testing altogether. - let shouldAbort : Bool - /// The quantifier being applied to this test case. - let quantifier : Quantification - /// The arguments currently being applied to the testing driver. - let arguments : CheckerArguments + /// The name bound to the current property (not labels). + let name : String + /// The maximum number of successful tests before SwiftCheck gives up. + /// Defaults to 100. + let maxAllowableSuccessfulTests : Int + /// The maximum number of discarded tests before SwiftCheck gives up. + let maxAllowableDiscardedTests : Int + /// The function that generates the sizes fed to the generators for each + /// test case. + let computeSize : (Int, Int) -> Int + /// The count of the number of successful test cases seen so far. + let successfulTestCount : Int + /// The count of the number of discarded test cases seen so far. + let discardedTestCount : Int + /// A dictionary of labels collected inside the test case. Each maps to an + /// integer describing the number of passed tests. It is used in + /// conjunction with the number of successful tests to print a coverage + /// percentage. + let labels : Dictionary + /// A uniqued collection of all the labels collected during the test case. + let collected : [Set] + /// Returns whether the test case has fulfilled its expected failure + /// outcome. If the test case fails and it was expected this property + /// returns true. If the test case doesn't fail and it was not expected to + /// fail this property returns true. Only when the test case's outcome and + /// its failure fulfillment expectation do not match does this property + /// return false. + let hasFulfilledExpectedFailure : Bool + /// The Random Number Generator backing the testing session. + let randomSeedGenerator : StdGen + /// Returns the number of successful shrinking steps performed so far. + let successfulShrinkCount : Int + /// Returns the number of failed shrinking steps since the last successful + /// shrink. + let failedShrinkStepDistance : Int + /// Returns the number of failed shrink steps. + let failedShrinkStepCount : Int + /// Returns whether the testing system should cease testing altogether. + let shouldAbort : Bool + /// The quantifier being applied to this test case. + let quantifier : Quantification + /// The arguments currently being applied to the testing driver. + let arguments : CheckerArguments - let silence : Bool + let silence : Bool - public init( name : String - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , computeSize : @escaping (Int, Int) -> Int - , successfulTestCount : Int - , discardedTestCount : Int - , labels : Dictionary - , collected : [Set] - , hasFulfilledExpectedFailure : Bool - , randomSeedGenerator : StdGen - , successfulShrinkCount : Int - , failedShrinkStepDistance : Int - , failedShrinkStepCount : Int - , shouldAbort : Bool - , quantifier : Quantification - , arguments : CheckerArguments - , silence : Bool) - { - self.name = name - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.computeSize = computeSize - self.successfulTestCount = successfulTestCount - self.discardedTestCount = discardedTestCount - self.labels = labels - self.collected = collected - self.hasFulfilledExpectedFailure = hasFulfilledExpectedFailure - self.randomSeedGenerator = randomSeedGenerator - self.successfulShrinkCount = successfulShrinkCount - self.failedShrinkStepDistance = failedShrinkStepDistance - self.failedShrinkStepCount = failedShrinkStepCount - self.shouldAbort = shouldAbort - self.quantifier = quantifier - self.arguments = arguments - self.silence = silence - } + public init( name : String + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , computeSize : @escaping (Int, Int) -> Int + , successfulTestCount : Int + , discardedTestCount : Int + , labels : Dictionary + , collected : [Set] + , hasFulfilledExpectedFailure : Bool + , randomSeedGenerator : StdGen + , successfulShrinkCount : Int + , failedShrinkStepDistance : Int + , failedShrinkStepCount : Int + , shouldAbort : Bool + , quantifier : Quantification + , arguments : CheckerArguments + , silence : Bool) + { + self.name = name + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.computeSize = computeSize + self.successfulTestCount = successfulTestCount + self.discardedTestCount = discardedTestCount + self.labels = labels + self.collected = collected + self.hasFulfilledExpectedFailure = hasFulfilledExpectedFailure + self.randomSeedGenerator = randomSeedGenerator + self.successfulShrinkCount = successfulShrinkCount + self.failedShrinkStepDistance = failedShrinkStepDistance + self.failedShrinkStepCount = failedShrinkStepCount + self.shouldAbort = shouldAbort + self.quantifier = quantifier + self.arguments = arguments + self.silence = silence + } } diff --git a/Sources/Test.swift b/Sources/Test.swift index ed02e42..f684e13 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -8,24 +8,24 @@ // MARK: - Property Testing with SwiftCheck -/// Property Testing is a more static and expressive form of Test-Driven -/// Development that emphasizes the testability of program properties - A -/// statement or invariant that can be proven to hold when fed any number of +/// Property Testing is a more static and expressive form of Test-Driven +/// Development that emphasizes the testability of program properties - A +/// statement or invariant that can be proven to hold when fed any number of /// arguments of a particular kind. It is akin to Fuzz Testing but is made /// significantly more powerful by the primitives in this framework. /// -/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a -/// value that is capable of producing a framework type called `Prop`, which -/// models individual test cases that themselves are capable of passing or +/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a +/// value that is capable of producing a framework type called `Prop`, which +/// models individual test cases that themselves are capable of passing or /// failing "in the small" with a `TestResult`. For those familiar with /// Protocol-Oriented Programming, lying at the heart of all of these types is a -/// protocol called `Testable` that provides any type a means of converting -/// itself to a `Property`. SwiftCheck uses `Testable` early and often in -/// functions and operators to enable a high level of nesting of framework -/// primitives and an even higher level of genericity in the interface. By -/// default SwiftCheck provides `Testable` instances for `Bool`, `Property`, +/// protocol called `Testable` that provides any type a means of converting +/// itself to a `Property`. SwiftCheck uses `Testable` early and often in +/// functions and operators to enable a high level of nesting of framework +/// primitives and an even higher level of genericity in the interface. By +/// default SwiftCheck provides `Testable` instances for `Bool`, `Property`, /// `Prop`, and several other internal framework types. Practically, this means -/// any assertions you could make in `XCTest` will work immediately with the +/// any assertions you could make in `XCTest` will work immediately with the /// framework. // MARK: - Going Further @@ -41,7 +41,7 @@ /// v /// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in /// -/// /// This part of the property uses `==>`, or the "implication" +/// /// This part of the property uses `==>`, or the "implication" /// /// combinator. Implication only executes the following block if /// /// the preceding expression returns true. It can be used to /// /// discard test cases that contain data you don't want to test with. @@ -59,22 +59,22 @@ /// | +--- The property will print EVERY generated test case to the console. /// + --- We expect this property not to hold. /// -/// Testing is not limited to just these listed functions. New users should -/// check out our test suite and the files `Gen.swift`, `Property.swift`, -/// `Modifiers.swift`, and the top half of this very file to learn more about +/// Testing is not limited to just these listed functions. New users should +/// check out our test suite and the files `Gen.swift`, `Property.swift`, +/// `Modifiers.swift`, and the top half of this very file to learn more about /// the various parts of the SwiftCheck testing mechanism. // MARK: - Quantifiers -/// Below is the method all SwiftCheck properties are based on, `forAll`. It -/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a +/// Below is the method all SwiftCheck properties are based on, `forAll`. It +/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a /// property holds when the given testing block returns `true` or truthy values, -/// and fails when the testing block returns `false` or falsy values. The +/// and fails when the testing block returns `false` or falsy values. The /// testing block is usually used with Swift's abbreviated block syntax and -/// requires type annotations for all value positions being requested. For +/// requires type annotations for all value positions being requested. For /// example: /// -/// + This is "Property Notation". It allows you to give your properties a +/// + This is "Property Notation". It allows you to give your properties a /// | name and instructs SwiftCheck to test it. /// | /// | This backwards arrow binds a property name and a property + @@ -82,113 +82,113 @@ /// | | /// v v /// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in -/// return -/// (xs.reverse().reverse() == xs) "Reverse on the left" -/// ^&&^ -/// (xs == xs.reverse().reverse()) "Reverse on the right" +/// return +/// (xs.reverse().reverse() == xs) "Reverse on the left" +/// ^&&^ +/// (xs == xs.reverse().reverse()) "Reverse on the right" /// } /// -/// Why require types? For one, Swift cannot infer the types of local variables -/// because SwiftCheck uses highly polymorphic testing primitives. But, more -/// importantly, types are required because SwiftCheck uses them to select the -/// appropriate `Gen`erators and shrinkers for each data type automagically by -/// default. Those `Gen`erators and shrinkers are then used to create 100 +/// Why require types? For one, Swift cannot infer the types of local variables +/// because SwiftCheck uses highly polymorphic testing primitives. But, more +/// importantly, types are required because SwiftCheck uses them to select the +/// appropriate `Gen`erators and shrinkers for each data type automagically by +/// default. Those `Gen`erators and shrinkers are then used to create 100 /// random test cases that are evaluated lazily to produce a final result. /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. public func forAll(_ pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) + return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property { - return forAll { t in forAll { b in try pf(t, b) } } + return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAll { t in forAll { b, c in try pf(t, b, c) } } + return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } + return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } + return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } + return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } + return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } + return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(gen, shrinker: A.shrink, f: pf) + return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) + return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified @@ -197,7 +197,7 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) + return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified @@ -206,7 +206,7 @@ public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified @@ -215,7 +215,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escapin /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified @@ -224,7 +224,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : G /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified @@ -233,7 +233,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified @@ -242,7 +242,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ ge /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified @@ -251,7 +251,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified @@ -260,620 +260,620 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : @escaping (A) throws -> Testable) -> Property { - return Property(gen.flatMap { x in - return shrinking(shrinker, initial: x, prop: { xs in - do { - return (try f(xs)).counterexample(String(describing: xs)) - } catch let e { - return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) - } - }).unProperty - }) -} - -/// Converts a function into an existentially quantified property using the -/// default shrinker and generator for that type to search for a passing case. + return Property(gen.flatMap { x in + return shrinking(shrinker, initial: x, prop: { xs in + do { + return (try f(xs)).counterexample(String(describing: xs)) + } catch let e { + return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) + } + }).unProperty + }) +} + +/// Converts a function into an existentially quantified property using the +/// default shrinker and generator for that type to search for a passing case. /// SwiftCheck only runs a limited number of trials before giving up and failing. /// -/// The nature of Existential Quantification means SwiftCheck would have to +/// The nature of Existential Quantification means SwiftCheck would have to /// enumerate over the entire domain of the type `A` in order to return a proper -/// value. Because such a traversal is both impractical and leads to -/// computationally questionable behavior (infinite loops and the like), -/// SwiftCheck instead interprets `exists` as a finite search over arbitrarily +/// value. Because such a traversal is both impractical and leads to +/// computationally questionable behavior (infinite loops and the like), +/// SwiftCheck instead interprets `exists` as a finite search over arbitrarily /// many values (around 500). No shrinking is performed during the search. /// /// Existential Quantification should rarely be used, and in practice is usually /// used for *negative* statements "there does not exist `foo` such that `bar`". -/// It is recommended that you avoid `exists` and instead reduce your property -/// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). +/// It is recommended that you avoid `exists` and instead reduce your property +/// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). /// `SNF` involves turning every `exists` into a function returning the /// existential value, taking any other parameters being quantified over as /// needed. public func exists(_ pf : @escaping (A) throws -> Testable) -> Property { - return exists(A.arbitrary, pf: pf) + return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { - return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: .existential) - } + return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: .existential) + } } /// Tests a property and prints the results to stdout. public func quickCheck(_ prop : Testable, name : String = "") { - _ = quickCheckWithResult(CheckerArguments(name: name), prop) + _ = quickCheckWithResult(CheckerArguments(name: name), prop) } // MARK: - Implementation Details internal enum Result { - case success(numTests : Int - , labels : [(String, Int)] - , output : String - ) - case gaveUp(numTests : Int - , labels : [(String,Int)] - , output : String - ) - case failure(numTests : Int - , numShrinks : Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - ) - case existentialFailure(numTests: Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - , lastResult : TestResult - ) - case noExpectedFailure(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String - ) - case insufficientCoverage(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String - ) + case success(numTests : Int + , labels : [(String, Int)] + , output : String + ) + case gaveUp(numTests : Int + , labels : [(String,Int)] + , output : String + ) + case failure(numTests : Int + , numShrinks : Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String + ) + case existentialFailure(numTests: Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String + , lastResult : TestResult + ) + case noExpectedFailure(numTests : Int + , usedSeed : StdGen + , usedSize : Int + , labels : [(String,Int)] + , output : String + ) + case insufficientCoverage(numTests : Int + , usedSeed : StdGen + , usedSize : Int + , labels : [(String,Int)] + , output : String + ) } private indirect enum Either { - case left(L) - case right(R) + case left(L) + case right(R) } internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { - let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: { computeSize(args, vals: $0) } - , successfulTestCount: 0 - , discardedTestCount: 0 - , labels: [:] - , collected: [] - , hasFulfilledExpectedFailure: false - , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() - , successfulShrinkCount: 0 - , failedShrinkStepDistance: 0 - , failedShrinkStepCount: 0 - , shouldAbort: false - , quantifier: .universal - , arguments: args - , silence: args.silence) - let modP : Property = (p.exhaustive ? p.property.once : p.property) - return test(istate, caseGen: modP.unProperty.unGen) + let istate = CheckerState(name: args.name + , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests + , computeSize: { computeSize(args, vals: $0) } + , successfulTestCount: 0 + , discardedTestCount: 0 + , labels: [:] + , collected: [] + , hasFulfilledExpectedFailure: false + , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() + , successfulShrinkCount: 0 + , failedShrinkStepDistance: 0 + , failedShrinkStepCount: 0 + , shouldAbort: false + , quantifier: .universal + , arguments: args + , silence: args.silence) + let modP : Property = (p.exhaustive ? p.property.once : p.property) + return test(istate, caseGen: modP.unProperty.unGen) } // Main Testing Loop: // -// Given an initial state and the inner function that runs the property begins -// turning a runloop that starts firing off individual test cases. Only 3 +// Given an initial state and the inner function that runs the property begins +// turning a runloop that starts firing off individual test cases. Only 3 // functions get dispatched from this loop: // -// - runATest: Does what it says; .Left indicates failure, .Right indicates +// - runATest: Does what it says; .Left indicates failure, .Right indicates // continuation. -// - doneTesting: Invoked when testing the property fails or succeeds once and +// - doneTesting: Invoked when testing the property fails or succeeds once and // for all. -// - giveUp: When the number of discarded tests exceeds the number given in the +// - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { - var state = st - while true { - switch runATest(state, caseGen: caseGen) { - case let .left(fail): - switch (fail.0, doneTesting(fail.1)) { - case (.success(_, _, _), _): - return fail.0 - case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): - return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) - // Existential Failures need explicit propagation. Existentials increment the - // discard count so we check if it has been surpassed. If it has with any kind - // of success we're done. If no successes are found we've failed checking the - // existential and report it as such. Otherwise turn the testing loop. - case (.existentialFailure(_, _, _, _, _, _, _), _): - if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { - return reportExistentialFailure(fail.1, res: fail.0) - } else { - state = fail.1 - break - } - default: - return fail.0 - } - case let .right(lsta): - if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { - return doneTesting(lsta) - } - if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { - return giveUp(lsta) - } - state = lsta - } - } -} - -// Executes a single test of the property given an initial state and the + var state = st + while true { + switch runATest(state, caseGen: caseGen) { + case let .left(fail): + switch (fail.0, doneTesting(fail.1)) { + case (.success(_, _, _), _): + return fail.0 + case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): + return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) + // Existential Failures need explicit propagation. Existentials increment the + // discard count so we check if it has been surpassed. If it has with any kind + // of success we're done. If no successes are found we've failed checking the + // existential and report it as such. Otherwise turn the testing loop. + case (.existentialFailure(_, _, _, _, _, _, _), _): + if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { + return reportExistentialFailure(fail.1, res: fail.0) + } else { + state = fail.1 + break + } + default: + return fail.0 + } + case let .right(lsta): + if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { + return doneTesting(lsta) + } + if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { + return giveUp(lsta) + } + state = lsta + } + } +} + +// Executes a single test of the property given an initial state and the // generator function. // // On success the next state is returned. On failure the final result and state // are returned. private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { - let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) - let (rnd1, rnd2) = st.randomSeedGenerator.split - - // Execute the Rose Tree for the test and reduce to .MkRose. - switch caseGen(rnd1, size).unProp.reduce { - case .mkRose(let resC, let ts): - let res = resC() // Force the result only once. - dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks - - switch res.match { - // Success - case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: (st.successfulTestCount + 1) - , discardedTestCount: st.discardedTestCount - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .right(nstate) - // Discard - case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .right(nstate) - // Fail - case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): - if quantifier == .existential { -// print("") - } else if !expect { - printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") - } else { - printCond(st.silence, "*** Failed! ", terminator: "") - } - - // Failure of an existential is not necessarily failure of the whole - // test case, so treat this like a discard. - if quantifier == .existential { - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - - /// However, some existentials outlive their usefulness - if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: "Could not satisfy existential" - , labels: summary(st) - , output: "*** Failed! " - , lastResult: res) - return .left((resul, nstate)) - } - return .right(nstate) - } - - // Attempt a shrink. - let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) - - if !expect { - let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") - return .left((s, st)) - } - - let stat = Result.failure(numTests: (st.successfulTestCount + 1) - , numShrinks: numShrinks - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: res.expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .left((stat, nstate)) - } - default: - fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") - break - } + let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) + let (rnd1, rnd2) = st.randomSeedGenerator.split + + // Execute the Rose Tree for the test and reduce to .MkRose. + switch caseGen(rnd1, size).unProp.reduce { + case .mkRose(let resC, let ts): + let res = resC() // Force the result only once. + dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks + + switch res.match { + // Success + case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: (st.successfulTestCount + 1) + , discardedTestCount: st.discardedTestCount + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .right(nstate) + // Discard + case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .right(nstate) + // Fail + case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): + if quantifier == .existential { + // print("") + } else if !expect { + printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") + } else { + printCond(st.silence, "*** Failed! ", terminator: "") + } + + // Failure of an existential is not necessarily failure of the whole + // test case, so treat this like a discard. + if quantifier == .existential { + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + + /// However, some existentials outlive their usefulness + if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { + let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , reason: "Could not satisfy existential" + , labels: summary(st) + , output: "*** Failed! " + , lastResult: res) + return .left((resul, nstate)) + } + return .right(nstate) + } + + // Attempt a shrink. + let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) + + if !expect { + let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") + return .left((s, st)) + } + + let stat = Result.failure(numTests: (st.successfulTestCount + 1) + , numShrinks: numShrinks + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , reason: res.reason + , labels: summary(st) + , output: "*** Failed! ") + + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: res.expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .left((stat, nstate)) + } + default: + fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") + break + } } private func doneTesting(_ st : CheckerState) -> Result { - if !st.hasFulfilledExpectedFailure { - if insufficientCoverage(st) { - printCond(st.silence, "+++ OK, failed as expected. ") - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") - } - - printDistributionGraph(st) - return .noExpectedFailure(numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") - } else if insufficientCoverage(st) { - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .insufficientCoverage( numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") - } else { - printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") - } + if !st.hasFulfilledExpectedFailure { + if insufficientCoverage(st) { + printCond(st.silence, "+++ OK, failed as expected. ") + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") + } + + printDistributionGraph(st) + return .noExpectedFailure(numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") + } else if insufficientCoverage(st) { + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .insufficientCoverage( numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") + } else { + printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") + } } private func giveUp(_ st: CheckerState) -> Result { - printDistributionGraph(st) - return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") + printDistributionGraph(st) + return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of // failed shrinks, total number of shrinks performed). // -// This ridiculously stateful looping nonsense is due to limitations of the -// Swift unroller and, more importantly, ARC. This has been written with -// recursion in the past, and it was fabulous and beautiful, but it generated -// useless objects that ARC couldn't release on the order of Gigabytes for -// complex shrinks (much like `split` in the Swift Standard Library), and was +// This ridiculously stateful looping nonsense is due to limitations of the +// Swift unroller and, more importantly, ARC. This has been written with +// recursion in the past, and it was fabulous and beautiful, but it generated +// useless objects that ARC couldn't release on the order of Gigabytes for +// complex shrinks (much like `split` in the Swift Standard Library), and was // slow as hell. This way we stay in one stack frame no matter what and give ARC // a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 // megabytes for truly horrendous tests that used to eat 8 gigs. private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { - if let e = res.theException { - fatalError("Test failed due to exception: \(e)") - } - - var lastResult = res - var branches = ts - var successfulShrinkCount = st.successfulShrinkCount - var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) - var failedShrinkStepCount = st.failedShrinkStepCount - - // cont is a sanity check so we don't fall into an infinite loop. It is set - // to false at each new iteration and true when we select a new set of - // branches to test. If the branch selection doesn't change then we have - // exhausted our possibilities and so must have reached a minimal case. - var cont = true - while cont { - /// If we're out of branches we're out of options. - if branches.isEmpty { - break - } - - cont = false - failedShrinkStepDistance = 0 - - // Try all possible courses of action in this Rose Tree - branches.forEach { r in - switch r.reduce { - case .mkRose(let resC, let ts1): - let res1 = resC() - dispatchAfterTestCallbacks(st, res: res1) - - // Did we fail? Good! Failure is healthy. - // Try the next set of branches. - if res1.ok == .some(false) { - lastResult = res1 - branches = ts1() - cont = true - break - } - - // Otherwise increment the tried shrink counter and the failed - // shrink counter. - failedShrinkStepDistance = (failedShrinkStepDistance + 1) - failedShrinkStepCount = (failedShrinkStepCount + 1) - default: - fatalError("Rose should not have reduced to IO") - } - } - - successfulShrinkCount = (successfulShrinkCount + 1) - } - - let state = CheckerState( name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure - , randomSeedGenerator: st.randomSeedGenerator - , successfulShrinkCount: successfulShrinkCount - , failedShrinkStepDistance: failedShrinkStepDistance - , failedShrinkStepCount: failedShrinkStepCount - , shouldAbort: st.shouldAbort - , quantifier: st.quantifier - , arguments: st.arguments - , silence: st.silence) - return reportMinimumCaseFound(state, res: lastResult) + if let e = res.theException { + fatalError("Test failed due to exception: \(e)") + } + + var lastResult = res + var branches = ts + var successfulShrinkCount = st.successfulShrinkCount + var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) + var failedShrinkStepCount = st.failedShrinkStepCount + + // cont is a sanity check so we don't fall into an infinite loop. It is set + // to false at each new iteration and true when we select a new set of + // branches to test. If the branch selection doesn't change then we have + // exhausted our possibilities and so must have reached a minimal case. + var cont = true + while cont { + /// If we're out of branches we're out of options. + if branches.isEmpty { + break + } + + cont = false + failedShrinkStepDistance = 0 + + // Try all possible courses of action in this Rose Tree + branches.forEach { r in + switch r.reduce { + case .mkRose(let resC, let ts1): + let res1 = resC() + dispatchAfterTestCallbacks(st, res: res1) + + // Did we fail? Good! Failure is healthy. + // Try the next set of branches. + if res1.ok == .some(false) { + lastResult = res1 + branches = ts1() + cont = true + break + } + + // Otherwise increment the tried shrink counter and the failed + // shrink counter. + failedShrinkStepDistance = (failedShrinkStepDistance + 1) + failedShrinkStepCount = (failedShrinkStepCount + 1) + default: + fatalError("Rose should not have reduced to IO") + } + } + + successfulShrinkCount = (successfulShrinkCount + 1) + } + + let state = CheckerState( name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: st.discardedTestCount + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure + , randomSeedGenerator: st.randomSeedGenerator + , successfulShrinkCount: successfulShrinkCount + , failedShrinkStepDistance: failedShrinkStepDistance + , failedShrinkStepCount: failedShrinkStepCount + , shouldAbort: st.shouldAbort + , quantifier: st.quantifier + , arguments: st.arguments + , silence: st.silence) + return reportMinimumCaseFound(state, res: lastResult) } private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \((st.successfulTestCount + 1)) test" - let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" + let testMsg = " (after \((st.successfulTestCount + 1)) test" + let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" - printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") - dispatchAfterFinalFailureCallbacks(st, res: res) - return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + dispatchAfterFinalFailureCallbacks(st, res: res) + return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result { - switch res { - case let .existentialFailure(_, _, _, reason, _, _, lastTest): - let testMsg = " (after \(st.discardedTestCount) test" + switch res { + case let .existentialFailure(_, _, _, reason, _, _, lastTest): + let testMsg = " (after \(st.discardedTestCount) test" - printCond(st.silence, "*** Failed! ", terminator: "") - printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") - dispatchAfterFinalFailureCallbacks(st, res: lastTest) - return res - default: - fatalError("Cannot report existential failure on non-failure type \(res)") - } + printCond(st.silence, "*** Failed! ", terminator: "") + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") + dispatchAfterFinalFailureCallbacks(st, res: lastTest) + return res + default: + fatalError("Cannot report existential failure on non-failure type \(res)") + } } private func dispatchAfterTestCallbacks(_ st : CheckerState, res : TestResult) { - guard !st.silence else { - return - } - - res.callbacks.forEach { c in - switch c { - case let .afterTest(_, f): - f(st, res) - default: - break - } - } + guard !st.silence else { + return + } + + res.callbacks.forEach { c in + switch c { + case let .afterTest(_, f): + f(st, res) + default: + break + } + } } private func dispatchAfterFinalFailureCallbacks(_ st : CheckerState, res : TestResult) { - guard !st.silence else { - return - } + guard !st.silence else { + return + } - res.callbacks.forEach { c in - switch c { - case let .afterFinalFailure(_, f): - f(st, res) - default: - break - } - } + res.callbacks.forEach { c in + switch c { + case let .afterFinalFailure(_, f): + f(st, res) + default: + break + } + } } private func summary(_ s : CheckerState) -> [(String, Int)] { - let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) - let l : [[String]] = lff.sorted().groupBy(==) - return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } + let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) + let l : [[String]] = lff.sorted().groupBy(==) + return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } private func labelPercentage(_ l : String, st : CheckerState) -> Int { - let occur = st.collected.flatMap(Array.init).filter { $0 == l } - return (100 * occur.count) / st.maxAllowableSuccessfulTests + let occur = st.collected.flatMap(Array.init).filter { $0 == l } + return (100 * occur.count) / st.maxAllowableSuccessfulTests } private func printDistributionGraph(_ st : CheckerState) { - func showP(_ n : Int) -> String { - return (n < 10 ? " " : "") + "\(n)" + "%" - } - - let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) - }) - let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) - let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) - let allLabels : [String] = Array(gPrint.sorted().reversed()) - - var covers = [String]() - st.labels.forEach { (l, reqP) in - let p = labelPercentage(l, st: st) - if p < reqP { - covers += ["only \(p)% " + l + ", not \(reqP)%"] - } - } - - let all = covers + allLabels - if all.isEmpty { - printCond(st.silence, ".") - } else if all.count == 1, let pt = all.first { - printCond(st.silence, "(\(pt))") - } else { - printCond(st.silence, ":") - all.forEach { pt in - printCond(st.silence, pt) - } - } + func showP(_ n : Int) -> String { + return (n < 10 ? " " : "") + "\(n)" + "%" + } + + let gAllLabels : [String] = st.collected.map({ (s : Set) in + return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) + }) + let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) + let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) + let allLabels : [String] = Array(gPrint.sorted().reversed()) + + var covers = [String]() + st.labels.forEach { (l, reqP) in + let p = labelPercentage(l, st: st) + if p < reqP { + covers += ["only \(p)% " + l + ", not \(reqP)%"] + } + } + + let all = covers + allLabels + if all.isEmpty { + printCond(st.silence, ".") + } else if all.count == 1, let pt = all.first { + printCond(st.silence, "(\(pt))") + } else { + printCond(st.silence, ":") + all.forEach { pt in + printCond(st.silence, pt) + } + } } private func pluralize(_ s : String, i : Int) -> String { - if i == 1 { - return s - } - return s + "s" + if i == 1 { + return s + } + return s + "s" } private func insufficientCoverage(_ st : CheckerState) -> Bool { - return st.labels - .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) - .reduce(false, { $0 || $1 }) + return st.labels + .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) + .reduce(false, { $0 || $1 }) } private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n") { - if !cond { - print(str, terminator: terminator) - } + if !cond { + print(str, terminator: terminator) + } } extension Array { - fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { - var result = [[Element]]() - var accumulator = [Element]() - self.forEach { current in - if let prev = accumulator.last { - if p(prev, current) { - accumulator.append(current) - } else { - result.append(accumulator) - accumulator = [ current ] - } - } else { - return accumulator.append(current) - } - } - if !accumulator.isEmpty { - result.append(accumulator); - } - return result - } + fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { + var result = [[Element]]() + var accumulator = [Element]() + self.forEach { current in + if let prev = accumulator.last { + if p(prev, current) { + accumulator.append(current) + } else { + result.append(accumulator) + accumulator = [ current ] + } + } else { + return accumulator.append(current) + } + } + if !accumulator.isEmpty { + result.append(accumulator); + } + return result + } } /// Testing loop stuff private func computeSize(_ args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { - func computeSize_(_ successes : Int, _ discards : Int) -> Int { - func roundTo(_ n : Int, _ m : Int) -> Int { - return (n / m) * m - } - - if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else if successes >= args.maxAllowableSuccessfulTests { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else if args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else { - return min((successes % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + discards / 10, args.maxTestCaseSize) - } - } - - func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { - if successes == 0 && discards == 0 { - return defaultSize - } else { - return computeSize(successes, discards) - } - } - - - if let (_, argSize) = args.replay { - return initialSizeForTest( argSize - , successes: vals.successes - , discards: vals.discards - , computeSize: computeSize_ - ) - } - return computeSize_(vals.successes, vals.discards) + func computeSize_(_ successes : Int, _ discards : Int) -> Int { + func roundTo(_ n : Int, _ m : Int) -> Int { + return (n / m) * m + } + + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if successes >= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else { + return min((successes % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + discards / 10, args.maxTestCaseSize) + } + } + + func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + if successes == 0 && discards == 0 { + return defaultSize + } else { + return computeSize(successes, discards) + } + } + + + if let (_, argSize) = args.replay { + return initialSizeForTest( argSize + , successes: vals.successes + , discards: vals.discards + , computeSize: computeSize_ + ) + } + return computeSize_(vals.successes, vals.discards) } diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index f8360b5..c8e8f31 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -6,19 +6,19 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// The main interface for the SwiftCheck testing mechanism. `property` -/// notation is used to define a property that SwiftCheck can generate test -/// cases for and a human-readable label for debugging output. A simple +/// The main interface for the SwiftCheck testing mechanism. `property` +/// notation is used to define a property that SwiftCheck can generate test +/// cases for and a human-readable label for debugging output. A simple /// property test might look like the following: /// /// property("reflexitivity") <- forAll { (i : Int8) in -/// return i == i +/// return i == i /// } /// -/// SwiftCheck will report all failures through the XCTest mechanism like a +/// SwiftCheck will report all failures through the XCTest mechanism like a /// normal testing assert, but with the minimal failing case reported as well. /// -/// If necessary, arguments can be provided to this function to change the +/// If necessary, arguments can be provided to this function to change the /// behavior of the testing mechanism: /// /// let args = CheckerArguments @@ -29,157 +29,157 @@ /// ) /// /// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in -/// return i == i +/// return i == i /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that uses XCTest to assert all testing failures and /// display them in both the testing log and Xcode. public struct AssertiveQuickCheck { - fileprivate let msg : String - fileprivate let file : StaticString - fileprivate let line : UInt - fileprivate let args : CheckerArguments - - fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that only reports failures to the testing log but does /// not assert when a property fails. public struct ReportiveQuickCheck { - fileprivate let msg : String - fileprivate let file : StaticString - fileprivate let line : UInt - fileprivate let args : CheckerArguments - - fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } -/// Represents the arguments the test driver will use while performing testing, +/// Represents the arguments the test driver will use while performing testing, /// shrinking, and printing results. public struct CheckerArguments { - /// Provides a way of re-doing a test at the given size with a new generator. - let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself - /// passes. - /// - /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` - /// on the property instead. - let maxAllowableSuccessfulTests : Int - /// The maximum number of tests cases that can be discarded before testing gives up on the - /// property. - /// - /// The default value of this property is 500. In general, most tests will require less than - /// this amount. `Discard`ed test cases do not affect the passing or failing status of the - /// property as a whole. - let maxAllowableDiscardedTests : Int - /// The limit to the size of all generators in the test. - /// - /// The default value of this property is 100. If "large" values, in magnitude or - /// size, are necessary then increase this value, else keep it relatively near the default. If - /// it becomes too small the samples present in the test case will lose diversity. - let maxTestCaseSize : Int - - internal let silence : Bool - - public init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - ) - { - self = CheckerArguments( replay: replay - , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: maxAllowableDiscardedTests - , maxTestCaseSize: maxTestCaseSize - , name: "" - ) - } - - internal init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - , name : String - , silence : Bool = false - ) - { - - self.replay = replay - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.maxTestCaseSize = maxTestCaseSize - self.name = name - self.silence = silence - } - - internal var name : String + /// Provides a way of re-doing a test at the given size with a new generator. + let replay : Optional<(StdGen, Int)> + /// The maximum number of test cases that must pass before the property itself + /// passes. + /// + /// The default value of this property is 100. In general, some tests may require more than + /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// on the property instead. + let maxAllowableSuccessfulTests : Int + /// The maximum number of tests cases that can be discarded before testing gives up on the + /// property. + /// + /// The default value of this property is 500. In general, most tests will require less than + /// this amount. `Discard`ed test cases do not affect the passing or failing status of the + /// property as a whole. + let maxAllowableDiscardedTests : Int + /// The limit to the size of all generators in the test. + /// + /// The default value of this property is 100. If "large" values, in magnitude or + /// size, are necessary then increase this value, else keep it relatively near the default. If + /// it becomes too small the samples present in the test case will lose diversity. + let maxTestCaseSize : Int + + internal let silence : Bool + + public init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + ) + { + self = CheckerArguments( replay: replay + , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: maxAllowableDiscardedTests + , maxTestCaseSize: maxTestCaseSize + , name: "" + ) + } + + internal init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + , name : String + , silence : Bool = false + ) + { + + self.replay = replay + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.maxTestCaseSize = maxTestCaseSize + self.name = name + self.silence = silence + } + + internal var name : String } infix operator <- /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () -> Testable) { - switch quickCheckWithResult(checker.args, test()) { - case let .failure(_, _, seed, sz, reason, _, _): - XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .noExpectedFailure(_, seed, sz, _, _): - XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return - } + switch quickCheckWithResult(checker.args, test()) { + case let .failure(_, _, seed, sz, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .noExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .insufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + default: + return + } } /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { - switch quickCheckWithResult(checker.args, test()) { - case let .failure(_, _, seed, sz, reason, _, _): - XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .noExpectedFailure(_, seed, sz, _, _): - XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return - } + switch quickCheckWithResult(checker.args, test()) { + case let .failure(_, _, seed, sz, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .noExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .insufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + default: + return + } } /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { - _ = quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () -> Testable) { - _ = quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } precedencegroup SwiftCheckImplicationPrecedence { - associativity: right - lowerThan: ComparisonPrecedence + associativity: right + lowerThan: ComparisonPrecedence } infix operator ==> : SwiftCheckImplicationPrecedence @@ -188,34 +188,34 @@ infix operator ==> : SwiftCheckImplicationPrecedence /// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : @autoclosure() -> Testable) -> Property { - if b { - return p().property - } - return Discard().property + if b { + return p().property + } + return Discard().property } /// Models implication for properties. That is, the property holds if the first -/// argument is false (in which case the test case is discarded), or if the +/// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : () -> Testable) -> Property { - if b { - return p().property - } - return Discard().property + if b { + return p().property + } + return Discard().property } infix operator ==== : ComparisonPrecedence /// Like equality but prints a verbose description when it fails. public func ==== (x : A, y : A) -> Property - where A : Equatable + where A : Equatable { - return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) + return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) } precedencegroup SwiftCheckLabelPrecedence { - associativity: right - higherThan: BitwiseShiftPrecedence + associativity: right + higherThan: BitwiseShiftPrecedence } infix operator : SwiftCheckLabelPrecedence @@ -223,18 +223,18 @@ infix operator : SwiftCheckLabelPrecedence /// Attaches a label to a property. /// /// Labelled properties aid in testing conjunctions and disjunctions, or any -/// other cases where test cases need to be distinct from one another. In -/// addition to shrunken test cases, upon failure SwiftCheck will print a -/// distribution map for the property that shows a percentage success rate for +/// other cases where test cases need to be distinct from one another. In +/// addition to shrunken test cases, upon failure SwiftCheck will print a +/// distribution map for the property that shows a percentage success rate for /// the property. public func (p : Testable, s : String) -> Property { - return p.label(s) + return p.label(s) } precedencegroup SwiftCheckLogicalPrecedence { - associativity: left - higherThan: LogicalConjunctionPrecedence - lowerThan: ComparisonPrecedence + associativity: left + higherThan: LogicalConjunctionPrecedence + lowerThan: ComparisonPrecedence } infix operator ^&&^ : SwiftCheckLogicalPrecedence @@ -242,10 +242,10 @@ infix operator ^&&^ : SwiftCheckLogicalPrecedence /// Takes the conjunction of two properties and treats them as a single large /// property. /// -/// Conjoined properties succeed only when both sub-properties succeed and fail +/// Conjoined properties succeed only when both sub-properties succeed and fail /// when one or more sub-properties fail. public func ^&&^ (p1 : Testable, p2 : Testable) -> Property { - return conjoin(p1.property, p2.property) + return conjoin(p1.property, p2.property) } @@ -254,10 +254,10 @@ infix operator ^||^ : SwiftCheckLogicalPrecedence /// Takes the disjunction of two properties and treats them as a single large /// property. /// -/// Disjoined properties succeed only when one or more sub-properties succeed +/// Disjoined properties succeed only when one or more sub-properties succeed /// and fail when both sub-properties fail. public func ^||^ (p1 : Testable, p2 : Testable) -> Property { - return disjoin(p1.property, p2.property) + return disjoin(p1.property, p2.property) } import XCTest diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 566a4e7..88975f4 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -7,105 +7,105 @@ // -/// The type of things that can be tested. Consequently, the type of things +/// The type of things that can be tested. Consequently, the type of things /// that can be returned from a `forAll` block. /// -/// `Testable` values must be able to produce a `Rose`, that is a -/// rose tree of test cases that terminates in a passing or failing -/// `TestResult`. SwiftCheck provides instances for `Bool`, `Discard`, `Prop`, -/// and `Property`. The last of these enables `forAll`s to return further +/// `Testable` values must be able to produce a `Rose`, that is a +/// rose tree of test cases that terminates in a passing or failing +/// `TestResult`. SwiftCheck provides instances for `Bool`, `Discard`, `Prop`, +/// and `Property`. The last of these enables `forAll`s to return further /// `forAll`s that can depend on previously generated values. public protocol Testable { - /// Returns true iff a single test case is exhaustive i.e. adequately covers - /// the search space. - /// - /// If true, the property will only be tested once. Defaults to false. - var exhaustive : Bool { get } - - /// Returns a `Property`, which SwiftCheck uses to perform test case - /// generation. - var property : Property { get } + /// Returns true iff a single test case is exhaustive i.e. adequately covers + /// the search space. + /// + /// If true, the property will only be tested once. Defaults to false. + var exhaustive : Bool { get } + + /// Returns a `Property`, which SwiftCheck uses to perform test case + /// generation. + var property : Property { get } } extension Testable { - /// By default, all `Testable` types are non-exhaustive. - public var exhaustive : Bool { - return false - } + /// By default, all `Testable` types are non-exhaustive. + public var exhaustive : Bool { + return false + } } /// A property is anything that generates `Prop`s. public struct Property : Testable { - let unProperty : Gen + let unProperty : Gen - public init(_ val : Gen) { - self.unProperty = val - } + public init(_ val : Gen) { + self.unProperty = val + } - /// Yields self. - public var property : Property { - return self - } + /// Yields self. + public var property : Property { + return self + } } -/// A `Prop` describes a strategy for evaluating a test case to a final -/// `TestResult`. It holds a Rose Tree of branches that evaluate the test and -/// any modifiers and mappings that may have been applied to a particular +/// A `Prop` describes a strategy for evaluating a test case to a final +/// `TestResult`. It holds a Rose Tree of branches that evaluate the test and +/// any modifiers and mappings that may have been applied to a particular /// testing tree. /// -/// As a testable value, it creates a Property that generates only its testing +/// As a testable value, it creates a Property that generates only its testing /// tree. public struct Prop : Testable { - var unProp : Rose + var unProp : Rose - /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive - /// property tests. - public var exhaustive : Bool { return true } + /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive + /// property tests. + public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. - public var property : Property { -// return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) - return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) - } + /// Returns a property that tests the receiver. + public var property : Property { + // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) + return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) + } } /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { - /// `Discard`s are trivially exhaustive. - public var exhaustive : Bool { return true } + /// `Discard`s are trivially exhaustive. + public var exhaustive : Bool { return true } - /// Create a `Discard` suitable for - public init() { } + /// Create a `Discard` suitable for + public init() { } - /// Returns a property that always rejects whatever result occurs. - public var property : Property { - return TestResult.rejected.property - } + /// Returns a property that always rejects whatever result occurs. + public var property : Property { + return TestResult.rejected.property + } } extension TestResult : Testable { - /// `TestResult`s are trivially exhaustive. - public var exhaustive : Bool { return true } + /// `TestResult`s are trivially exhaustive. + public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. - public var property : Property { - return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) - } + /// Returns a property that tests the receiver. + public var property : Property { + return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) + } } extension Bool : Testable { - /// `Bool`ean values are trivially exhaustive. - public var exhaustive : Bool { return true } - - /// Returns a property that evaluates to a test success if the receiver is - /// `true`, else returns a property that evaluates to a test failure. - public var property : Property { - return TestResult.liftBool(self).property - } + /// `Bool`ean values are trivially exhaustive. + public var exhaustive : Bool { return true } + + /// Returns a property that evaluates to a test success if the receiver is + /// `true`, else returns a property that evaluates to a test failure. + public var property : Property { + return TestResult.liftBool(self).property + } } extension Gen /*: Testable*/ where A : Testable { - public var property : Property { - return Property(self >>- { $0.property.unProperty }) - } + public var property : Property { + return Property(self >>- { $0.property.unProperty }) + } } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index f9139c3..2e804a8 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -13,14 +13,14 @@ /// say, the `Element`s underlying an `Array` are all `Arbitrary`, we /// instead ask the conformee to hand over information about the type parameter /// it wishes to guarantee is `Arbitrary` then SwiftCheck will synthesize a -/// function to act as a Witness that the parameter is in fact `Arbitrary`. -/// SwiftCheck presents a stronger but less general version of `forAll` that +/// function to act as a Witness that the parameter is in fact `Arbitrary`. +/// SwiftCheck presents a stronger but less general version of `forAll` that /// must be implemented by the conformee to guarantee a type-safe interface with /// the rest of the framework. /// -/// Implementating the `WitnessedArbitrary` protocol functions much like +/// Implementating the `WitnessedArbitrary` protocol functions much like /// implementing the `Arbitrary` protocol, but with a little extra baggage. For -/// example, to implement the protocol for `Array`, we declare the usual +/// example, to implement the protocol for `Array`, we declare the usual /// `arbitrary` and `shrink`: /// /// extension Array where Element : Arbitrary { @@ -30,12 +30,12 @@ /// if k == 0 { /// return Gen.pure([]) /// } -/// +/// /// return sequence((0...k).map { _ in Element.arbitrary }) /// } /// } /// } -/// +/// /// public static func shrink(bl : Array) -> [[Element]] { /// let rec : [[Element]] = shrinkOne(bl) /// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec @@ -48,7 +48,7 @@ /// /// extension Array : WitnessedArbitrary { /// public typealias Param = Element -/// +/// /// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { /// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in /// return pf(bl.map(wit)) @@ -56,74 +56,74 @@ /// } /// } public protocol WitnessedArbitrary { - /// The witnessing type parameter. - associatedtype Param + /// The witnessing type parameter. + associatedtype Param - /// A property test that relies on a witness that the given type parameter - /// is actually `Arbitrary`. - static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property + /// A property test that relies on a witness that the given type parameter + /// is actually `Arbitrary`. + static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. public func forAll(_ pf : ((A) -> Testable)) -> Property - where A.Param : Arbitrary + where A.Param : Arbitrary { - return A.forAllWitnessed(id, pf: pf) + return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary { - return forAll { t in forAll { b in pf(t, b) } } + return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary { - return forAll { t in forAll { b, c in pf(t, b, c) } } + return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary { - return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } + return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } + return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } + return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } + return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } + return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 30c3e00..791bd4d 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -7,351 +7,351 @@ // extension Array where Element : Arbitrary { - /// Returns a generator of `Array`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure([]) - } - - return sequence((0...k).map { _ in Element.arbitrary }) - } - } - } - - /// The default shrinking function for `Array`s of arbitrary `Element`s. - public static func shrink(_ bl : Array) -> [[Element]] { - let rec : [[Element]] = shrinkOne(bl) - return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec - } + /// Returns a generator of `Array`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure([]) + } + + return sequence((0...k).map { _ in Element.arbitrary }) + } + } + } + + /// The default shrinking function for `Array`s of arbitrary `Element`s. + public static func shrink(_ bl : Array) -> [[Element]] { + let rec : [[Element]] = shrinkOne(bl) + return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec + } } extension Array : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Array`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { - return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in - return pf(bl.map(wit)) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Array`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { + return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in + return pf(bl.map(wit)) + }) + } } extension AnyBidirectionalCollection where Element : Arbitrary { - /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return AnyBidirectionalCollection.init <^> [Element].arbitrary - } - - /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { - return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) - } + /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return AnyBidirectionalCollection.init <^> [Element].arbitrary + } + + /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. + public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) + } } extension AnyBidirectionalCollection : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { - return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in - return pf(AnyBidirectionalCollection(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnyBidirectionalCollection`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { + return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in + return pf(AnyBidirectionalCollection(bl.map(wit))) + }) + } } extension AnySequence where Element : Arbitrary { - /// Returns a generator of `AnySequence`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return AnySequence.init <^> [Element].arbitrary - } - - /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. - public static func shrink(_ bl : AnySequence) -> [AnySequence] { - return [Element].shrink([Element](bl)).map(AnySequence.init) - } + /// Returns a generator of `AnySequence`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return AnySequence.init <^> [Element].arbitrary + } + + /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. + public static func shrink(_ bl : AnySequence) -> [AnySequence] { + return [Element].shrink([Element](bl)).map(AnySequence.init) + } } extension AnySequence : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnySequence`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { - return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in - return pf(AnySequence(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnySequence`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { + return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in + return pf(AnySequence(bl.map(wit))) + }) + } } extension ArraySlice where Element : Arbitrary { - /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return ArraySlice.init <^> [Element].arbitrary - } - - /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. - public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { - return [Element].shrink([Element](bl)).map(ArraySlice.init) - } + /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return ArraySlice.init <^> [Element].arbitrary + } + + /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. + public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { + return [Element].shrink([Element](bl)).map(ArraySlice.init) + } } extension ArraySlice : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { - return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in - return pf(ArraySlice(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ArraySlice`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { + return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in + return pf(ArraySlice(bl.map(wit))) + }) + } } extension CollectionOfOne where Element : Arbitrary { - /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return CollectionOfOne.init <^> Element.arbitrary - } + /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return CollectionOfOne.init <^> Element.arbitrary + } } extension CollectionOfOne : WitnessedArbitrary { - public typealias Param = Element + public typealias Param = Element - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `CollectionOfOne`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[bl.startIndex]))) }) - } + } } /// Generates an Optional of arbitrary values of type A. extension Optional where Wrapped : Arbitrary { - /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. - public static var arbitrary : Gen> { - return Gen>.frequency([ - (1, Gen>.pure(.none)), - (3, liftM(Optional.some, Wrapped.arbitrary)), - ]) - } - - /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. - public static func shrink(_ bl : Optional) -> [Optional] { - if let x = bl { - let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) - return [.none] + rec - } - return [] - } + /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. + public static var arbitrary : Gen> { + return Gen>.frequency([ + (1, Gen>.pure(.none)), + (3, liftM(Optional.some, Wrapped.arbitrary)), + ]) + } + + /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. + public static func shrink(_ bl : Optional) -> [Optional] { + if let x = bl { + let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) + return [.none] + rec + } + return [] + } } extension Optional : WitnessedArbitrary { - public typealias Param = Wrapped - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Optional`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { - return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } + public typealias Param = Wrapped + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Optional`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { + return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } } extension ContiguousArray where Element : Arbitrary { - /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return ContiguousArray.init <^> [Element].arbitrary - } - - /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. - public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { - return [Element].shrink([Element](bl)).map(ContiguousArray.init) - } + /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return ContiguousArray.init <^> [Element].arbitrary + } + + /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. + public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { + return [Element].shrink([Element](bl)).map(ContiguousArray.init) + } } extension ContiguousArray : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { - return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in - return pf(ContiguousArray(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ContiguousArray`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { + return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in + return pf(ContiguousArray(bl.map(wit))) + }) + } } /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { - /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. - public static var arbitrary : Gen> { - return [Key].arbitrary.flatMap { (k : [Key]) in - return [Value].arbitrary.flatMap { (v : [Value]) in - return Gen.pure(Dictionary(zip(k, v))) - } - } - } - - /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and - /// `Value`s. - public static func shrink(_ d : Dictionary) -> [Dictionary] { + /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. + public static var arbitrary : Gen> { + return [Key].arbitrary.flatMap { (k : [Key]) in + return [Value].arbitrary.flatMap { (v : [Value]) in + return Gen.pure(Dictionary(zip(k, v))) + } + } + } + + /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and + /// `Value`s. + public static func shrink(_ d : Dictionary) -> [Dictionary] { return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in (key: k, value: v) })) } - } + } } extension EmptyCollection : Arbitrary { - /// Returns a generator of `EmptyCollection`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.pure(EmptyCollection()) - } + /// Returns a generator of `EmptyCollection`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.pure(EmptyCollection()) + } } extension Range where Bound : Comparable & Arbitrary { - /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. - public static var arbitrary : Gen> { - return Bound.arbitrary.flatMap { l in - return Bound.arbitrary.flatMap { r in - return Gen.pure((min(l, r) ..< max(l, r))) - } - } - } - - /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. - public static func shrink(_ bl : Range) -> [Range] { - return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) - } + /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. + public static var arbitrary : Gen> { + return Bound.arbitrary.flatMap { l in + return Bound.arbitrary.flatMap { r in + return Gen.pure((min(l, r) ..< max(l, r))) + } + } + } + + /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. + public static func shrink(_ bl : Range) -> [Range] { + return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) + } } extension LazyCollection where Base : Collection & Arbitrary, Base.Index : Comparable { - /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. - public static var arbitrary : Gen> { - return LazyCollection.arbitrary - } + /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. + public static var arbitrary : Gen> { + return LazyCollection.arbitrary + } } extension LazySequence where Base : Sequence & Arbitrary { - /// Returns a generator of `LazySequence`s of arbitrary `Base`s. - public static var arbitrary : Gen> { - return LazySequence.arbitrary - } + /// Returns a generator of `LazySequence`s of arbitrary `Base`s. + public static var arbitrary : Gen> { + return LazySequence.arbitrary + } } extension Repeated where Element : Arbitrary { - /// Returns a generator of `Repeat`s of arbitrary `Element`s. - public static var arbitrary : Gen> { + /// Returns a generator of `Repeat`s of arbitrary `Element`s. + public static var arbitrary : Gen> { let constructor: (Element, Int) -> Repeated = { (element, count) in return repeatElement(element , count: count) } - return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) - } + return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) + } } extension Repeated : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Repeat`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { - return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in - let xs = bl.map(wit) - return pf(repeatElement(xs.first!, count: xs.count)) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Repeat`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { + return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in + let xs = bl.map(wit) + return pf(repeatElement(xs.first!, count: xs.count)) + }) + } } extension Set where Element : Arbitrary & Hashable { - /// Returns a generator of `Set`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure(Set([])) - } - - return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) - } - } - } - - /// The default shrinking function for `Set`s of arbitrary `Element`s. - public static func shrink(_ s : Set) -> [Set] { - return [Element].shrink([Element](s)).map(Set.init) - } + /// Returns a generator of `Set`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure(Set([])) + } + + return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) + } + } + } + + /// The default shrinking function for `Set`s of arbitrary `Element`s. + public static func shrink(_ s : Set) -> [Set] { + return [Element].shrink([Element](s)).map(Set.init) + } } extension Set : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Set`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { - return forAll { (xs : [A]) in - return pf(Set(xs.map(wit))) - } - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Set`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { + return forAll { (xs : [A]) in + return pf(Set(xs.map(wit))) + } + } } // MARK: - Implementation Details Follow private func bits(_ n : N) -> Int { - if n / 2 == 0 { - return 0 - } - return 1 + bits(n / 2) + if n / 2 == 0 { + return 0 + } + return 1 + bits(n / 2) } private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 : [A] = take(k, xs: xs) - let xs2 : [A] = drop(k, xs: xs) - - if k > n { - return [] - } else if xs2.isEmpty { - return [[]] - } else { - let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) - return [xs2] + rec - } + let xs1 : [A] = take(k, xs: xs) + let xs2 : [A] = drop(k, xs: xs) + + if k > n { + return [] + } else if xs2.isEmpty { + return [[]] + } else { + let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + return [xs2] + rec + } } private func take(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n..(_ xs : [A]) -> [[A]] { - if xs.isEmpty { - return [[A]]() - } else if let x : A = xs.first { - let xss = [A](xs[1..(_ pairs : S) - where S.Iterator.Element == (Key, Value) - { - self.init() - var g = pairs.makeIterator() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } + fileprivate init(_ pairs : S) + where S.Iterator.Element == (Key, Value) + { + self.init() + var g = pairs.makeIterator() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } } diff --git a/Tests/BooleanIdentitySpec.swift b/Tests/BooleanIdentitySpec.swift index d8954b8..f2c3036 100644 --- a/Tests/BooleanIdentitySpec.swift +++ b/Tests/BooleanIdentitySpec.swift @@ -10,51 +10,51 @@ import SwiftCheck import XCTest class BooleanIdentitySpec : XCTestCase { - func testAll() { - property("Law of complements") <- forAll { (x : Bool) in - return ((x || !x) == true) && ((x && !x) == false) - } - - property("Law of double negation") <- forAll { (x : Bool) in - return !(!x) == x - } - - property("Law of idempotency") <- forAll { (x : Bool) in - return ((x || x) == x) && ((x && x) == x) - } - - property("Law of dominance") <- forAll { (x : Bool) in - return ((x || false) == x) && ((x && true) == x) - } - - property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x || y) == (y || x)) && ((x && y) == (y && x)) - } - - property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) - } - - property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = !(x && y) == (!x || !y) - let r = !(x || y) == (!x && !y) - return l && r - } - - property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x && (x || y)) == x - let r = (x || (x && y)) == x - return l && r - } - - property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x && (!x || y)) == (x && y) - let r = (x || (!x && y)) == (x || y) - return l && r - } - - property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) - } - } + func testAll() { + property("Law of complements") <- forAll { (x : Bool) in + return ((x || !x) == true) && ((x && !x) == false) + } + + property("Law of double negation") <- forAll { (x : Bool) in + return !(!x) == x + } + + property("Law of idempotency") <- forAll { (x : Bool) in + return ((x || x) == x) && ((x && x) == x) + } + + property("Law of dominance") <- forAll { (x : Bool) in + return ((x || false) == x) && ((x && true) == x) + } + + property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x || y) == (y || x)) && ((x && y) == (y && x)) + } + + property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) + } + + property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r + } + + property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x && (x || y)) == x + let r = (x || (x && y)) == x + return l && r + } + + property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x && (!x || y)) == (x && y) + let r = (x || (!x && y)) == (x || y) + return l && r + } + + property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) + } + } } diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index 561f59e..a9e9432 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -14,66 +14,66 @@ let lower : Gen = Gen.fromElementsIn("a"..."z") let numeric : Gen = Gen.fromElementsIn("0"..."9") let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) let hexDigits = Gen.oneOf([ - Gen.fromElementsIn("A"..."F"), - numeric, -]) + Gen.fromElementsIn("A"..."F"), + numeric, + ]) class ComplexSpec : XCTestCase { - func testEmailAddressProperties() { - let localEmail = Gen.oneOf([ - upper, - lower, - numeric, - special, - ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) + func testEmailAddressProperties() { + let localEmail = Gen.oneOf([ + upper, + lower, + numeric, + special, + ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) - let hostname = Gen.oneOf([ - lower, - numeric, - Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) + let hostname = Gen.oneOf([ + lower, + numeric, + Gen.pure("-"), + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) - let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) + let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) - let args = CheckerArguments(maxTestCaseSize: 10) - - property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in - return e.characters.filter({ $0 == "@" }).count == 1 - }.once - } + let args = CheckerArguments(maxTestCaseSize: 10) - func testIPv6Properties() { + property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in + return e.characters.filter({ $0 == "@" }).count == 1 + }.once + } + + func testIPv6Properties() { let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } - let ipHexDigits = Gen.oneOf([ - gen1, - gen2, - gen3, - gen4 - ]) + let ipHexDigits = Gen.oneOf([ + gen1, + gen2, + gen3, + gen4 + ]) - let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) + let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) - property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in - return e.characters.filter({ $0 == ":" }).count == 3 - } - } + property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in + return e.characters.filter({ $0 == ":" }).count == 3 + } + } } // MARK: String Conveniences func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", +) } + return sequence(parts).map { $0.reduce("", +) } } extension String { - fileprivate var initial : String { - return self[self.startIndex.. (x + 1) }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x + c < y + c }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x - c < y - c }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, - forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, - forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, - forAll { (a : Float, b : Float, c : Float) in - return exists { (x : Float) in - return exists { (y : Float) in - return (x != y) ==> { a * pow(x, 2) + b * x + c == a * pow(y, 2) + b * y + c } - } - } - }, - forAll { (_ : Int) in throw SwiftCheckError.bogus }, - forAll { (_ : Int, _ : Float, _ : Int) in throw SwiftCheckError.bogus }.expectFailure.expectFailure, - exists { (_ : Int) in throw SwiftCheckError.bogus }, - ] + private var failCount : Int = 0 + private let tests : [Property] = [ + forAll { (_ : Int) in false }.expectFailure.expectFailure, + forAll { (_ : Int) in false }, + exists { (x : Int) in x != x }, + exists { (x : Int) in x != 0 }, + forAll { (x : Int) in x != x }, + forAll { (b : Bool) in !(b || !b) }, + forAll { (x : Int) in x > (x + 1) }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x + c < y + c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x - c < y - c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, + forAll { (a : Float, b : Float, c : Float) in + return exists { (x : Float) in + return exists { (y : Float) in + return (x != y) ==> { a * pow(x, 2) + b * x + c == a * pow(y, 2) + b * y + c } + } + } + }, + forAll { (_ : Int) in throw SwiftCheckError.bogus }, + forAll { (_ : Int, _ : Float, _ : Int) in throw SwiftCheckError.bogus }.expectFailure.expectFailure, + exists { (_ : Int) in throw SwiftCheckError.bogus }, + ] - func testProperties() { - self.tests.forEach { t in - property("Fail") <- t - } - } + func testProperties() { + self.tests.forEach { t in + property("Fail") <- t + } + } - /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) - /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) - override func recordFailure(withDescription message : String, inFile file : String, atLine line : UInt, expected : Bool) { - if !expected { - assert(false, "Assertion should never throw.") - } else { -// super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) - failCount = (failCount + 1) - } - } + /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) + /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) + override func recordFailure(withDescription message : String, inFile file : String, atLine line : UInt, expected : Bool) { + if !expected { + assert(false, "Assertion should never throw.") + } else { + // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) + failCount = (failCount + 1) + } + } - override func tearDown() { - XCTAssert(failCount == tests.count) - } + override func tearDown() { + XCTAssert(failCount == tests.count) + } } diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 805b008..9e21732 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -10,301 +10,301 @@ import SwiftCheck import XCTest class GenSpec : XCTestCase { - func testAll() { - property("Gen.frequency behaves") <- { - let g = Gen.frequency([ - (10, Gen.pure(0)), - (5, Gen.pure(1)), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } - } - - property("Gen.weighted behaves") <- { - let g = Gen.weighted([ - (10, 0), - (5, 1), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } - } - - property("The only value Gen.pure generates is the given value") <- { - let g = Gen.pure(0) - return forAll(g) { $0 == 0 } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in - if xss.isEmpty { - return Discard() - } - let l = Set(xss) - return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } - } - - property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in - return (n1 < n2) ==> { - let interval = n1...n2 - return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } - } - } - - property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in - return !xs.isEmpty ==> { - return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in - return xs.starts(with: ys) - } - } - } - - property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in - return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in - return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) - } - } - - property("oneOf n") <- forAll { (xss : ArrayOf) in - if xss.getArray.isEmpty { - return Discard() - } - let l = Set(xss.getArray) - return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } - } - - property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in - let g1 = Gen.pure(n1) - let g2 = Gen.pure(n2) - return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } - } - - property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) - return forAll(g) { $0.getArray.count == n } - } - - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { - return $0.getArray.isEmpty - } - - property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in - var n : Int = 0 - return forAll(Gen.sized { xx in - n = xx - return Int.arbitrary - }.resize(n)) { (x : Int) in - return x <= n - } - } - - property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in - var n : Int = 0 - return forAllNoShrink(Gen<[Int]>.sized({ xx in - n = xx - return [Int].arbitrary - }).resize(n)) { (xs : [Int]) in - return xs.count <= n - } - } - - property("Gen.suchThat in series obeys both predicates") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !(str.isEmpty || str.range(of: ",") != nil) - } - } - - property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !str.isEmpty - } - } - - property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return str.range(of: ",") == nil - } - } - - property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in - return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in - return ss == xs - } - } - - property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in - let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) - return forAllNoShrink(g) { (x1, y1) in - return (x1, y1) == (x, y) - } - } - - property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in - let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) - let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) - return rightBiasedZip ~= leftBiasedZip - } - - property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in - let fx = Gen.pure(x) - let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } - } - - property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in - Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) - } - - property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in - Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) - } - - property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in - let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) - return forAllNoShrink(g) { (x1, y1, z1) in - return (x1, y1, z1) == (x, y, z) - } - } - - property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in - let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) - return forAllNoShrink(g) { (x1, y1, z1, w1) in - return (x1, y1, z1, w1) == (x, y, z, w) - } - } - - property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in - let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in - return (x1, y1, z1, w1, a1) == (x, y, z, w, a) - } - } - - property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - } - } - - property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && c1 == c - } - } - - property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1) == (c, d) - } - } - - property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1) == (c, d, e) - } - } - } - - property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int, f : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1, f1) == (c, d, e, f) - } - } - } - } - - func testLaws() { - /// Turns out Gen is a really sketchy monad because of the underlying randomness. - let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) - let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) - - property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.map(id)) == id(x) - } - - property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in - return forAllNoShrink(lawfulGen) { (x : Gen) in - return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) - } - } - - property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (Gen.pure(id) <*> x) == x - } - - property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) - } - - property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) - } - - property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - return (Gen.pure(a) >>- f) == f(a) - } - - property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in - return (m >>- Gen.pure) == m - } - - property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - let g : (Int) -> Gen = Gen.pure • ga.getArrow - return forAllNoShrink(lawfulGen) { (m : Gen) in - return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) - } - } - } + func testAll() { + property("Gen.frequency behaves") <- { + let g = Gen.frequency([ + (10, Gen.pure(0)), + (5, Gen.pure(1)), + ]) + + return forAll(g) { (i : Int) in + return true + } + } + + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } + } + + property("Gen.weighted behaves") <- { + let g = Gen.weighted([ + (10, 0), + (5, 1), + ]) + + return forAll(g) { (i : Int) in + return true + } + } + + property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } + } + + property("The only value Gen.pure generates is the given value") <- { + let g = Gen.pure(0) + return forAll(g) { $0 == 0 } + } + + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in + if xss.isEmpty { + return Discard() + } + let l = Set(xss) + return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } + } + + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in + return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } + } + + property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + return (n1 < n2) ==> { + let interval = n1...n2 + return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } + } + } + + property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in + return !xs.isEmpty ==> { + return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in + return xs.starts(with: ys) + } + } + } + + property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in + return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in + return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) + } + } + + property("oneOf n") <- forAll { (xss : ArrayOf) in + if xss.getArray.isEmpty { + return Discard() + } + let l = Set(xss.getArray) + return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } + } + + property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in + let g1 = Gen.pure(n1) + let g2 = Gen.pure(n2) + return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } + } + + property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in + let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) + return forAll(g) { $0.getArray.count == n } + } + + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { + return $0.getArray.isEmpty + } + + property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in + var n : Int = 0 + return forAll(Gen.sized { xx in + n = xx + return Int.arbitrary + }.resize(n)) { (x : Int) in + return x <= n + } + } + + property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in + var n : Int = 0 + return forAllNoShrink(Gen<[Int]>.sized({ xx in + n = xx + return [Int].arbitrary + }).resize(n)) { (xs : [Int]) in + return xs.count <= n + } + } + + property("Gen.suchThat in series obeys both predicates") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !(str.isEmpty || str.range(of: ",") != nil) + } + } + + property("Gen.suchThat in series obeys its first property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !str.isEmpty + } + } + + property("Gen.suchThat in series obeys its last property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return str.range(of: ",") == nil + } + } + + property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in + return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in + return ss == xs + } + } + + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in + let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) + return forAllNoShrink(g) { (x1, y1) in + return (x1, y1) == (x, y) + } + } + + property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in + let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) + let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) + return rightBiasedZip ~= leftBiasedZip + } + + property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in + let fx = Gen.pure(x) + let ff = Gen>.pure(f).map { $0.getArrow } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + } + + property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in + Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) + } + + property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in + Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) + } + + property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in + let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) + return forAllNoShrink(g) { (x1, y1, z1) in + return (x1, y1, z1) == (x, y, z) + } + } + + property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in + let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) + return forAllNoShrink(g) { (x1, y1, z1, w1) in + return (x1, y1, z1, w1) == (x, y, z, w) + } + } + + property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in + let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in + return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + } + } + + property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + } + } + + property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && c1 == c + } + } + + property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1) == (c, d) + } + } + + property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1) == (c, d, e) + } + } + } + + property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int, f : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1, f1) == (c, d, e, f) + } + } + } + } + + func testLaws() { + /// Turns out Gen is a really sketchy monad because of the underlying randomness. + let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) + let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) + + property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.map(id)) == id(x) + } + + property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAllNoShrink(lawfulGen) { (x : Gen) in + return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) + } + } + + property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (Gen.pure(id) <*> x) == x + } + + property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + return (Gen.pure(a) >>- f) == f(a) + } + + property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in + return (m >>- Gen.pure) == m + } + + property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + let g : (Int) -> Gen = Gen.pure • ga.getArrow + return forAllNoShrink(lawfulGen) { (m : Gen) in + return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) + } + } + } } internal func curry(_ f : @escaping (A, B) -> C) -> (A) -> (B) -> C { - return { a in { b in f(a, b) } } + return { a in { b in f(a, b) } } } internal func id(_ x : A) -> A { - return x + return x } internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { - return { f(g($0)) } + return { f(g($0)) } } private func ==(l : Gen, r : Gen) -> Bool { - return l.proliferateSized(10).generate == r.proliferateSized(10).generate + return l.proliferateSized(10).generate == r.proliferateSized(10).generate } /// `Gen` product is associative and has a natural isomorphism. @@ -312,16 +312,16 @@ private func ==(l : Gen, r : Gen) -> Bool { /// - Returns: True *iff* `(a1, a2, a3) == (b1, b2, b3)` /// where `lhs = Gen((a1, (a2, a3)))` and `rhs = Gen(((b1, b2), b3))`. private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> Bool { - let normalizedL = lhs.map { ($0, $1.0, $1.1) } - let normalizedR = rhs.map { ($0.0, $0.1, $1) } - - let sampleSize = 10 - let sampleL = normalizedL.proliferateSized(sampleSize).generate - let sampleR = normalizedR.proliferateSized(sampleSize).generate - - for (tupleL, tupleR) in zip(sampleL, sampleR) { - guard tupleL == tupleR else { return false } - } - - return true + let normalizedL = lhs.map { ($0, $1.0, $1.1) } + let normalizedR = rhs.map { ($0.0, $0.1, $1) } + + let sampleSize = 10 + let sampleL = normalizedL.proliferateSized(sampleSize).generate + let sampleR = normalizedR.proliferateSized(sampleSize).generate + + for (tupleL, tupleR) in zip(sampleL, sampleR) { + guard tupleL == tupleR else { return false } + } + + return true } diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index cad964f..ba60a2c 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -10,183 +10,183 @@ import SwiftCheck import XCTest struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { - let unName : String + let unName : String - static var arbitrary : Gen { - let gc : Gen = Gen.fromElementsIn("a"..."z") - return gc.map { Name(unName: String($0)) } - } + static var arbitrary : Gen { + let gc : Gen = Gen.fromElementsIn("a"..."z") + return gc.map { Name(unName: String($0)) } + } - var description : String { - return self.unName - } + var description : String { + return self.unName + } - var hashValue : Int { - return self.unName.hashValue - } + var hashValue : Int { + return self.unName.hashValue + } } func == (l : Name, r : Name) -> Bool { - return l.unName == r.unName + return l.unName == r.unName } private func liftM2(_ f : @escaping (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { - return m1.flatMap { x1 in - return m2.flatMap { x2 in - return Gen.pure(f(x1, x2)) - } - } + return m1.flatMap { x1 in + return m2.flatMap { x2 in + return Gen.pure(f(x1, x2)) + } + } } indirect enum Exp : Equatable { - case lam(Name, Exp) - case app(Exp, Exp) - case `var`(Name) + case lam(Name, Exp) + case app(Exp, Exp) + case `var`(Name) } func == (l : Exp, r : Exp) -> Bool { - switch (l, r) { - case let (.lam(ln, le), .lam(rn, re)): - return ln == rn && le == re - case let (.app(ln, le), .app(rn, re)): - return ln == rn && le == re - case let (.var(n1), .var(n2)): - return n1 == n2 - default: - return false - } + switch (l, r) { + case let (.lam(ln, le), .lam(rn, re)): + return ln == rn && le == re + case let (.app(ln, le), .app(rn, re)): + return ln == rn && le == re + case let (.var(n1), .var(n2)): + return n1 == n2 + default: + return false + } } extension Exp : Arbitrary { - private static func arbExpr(_ n : Int) -> Gen { - return Gen.frequency([ - (2, liftM(Exp.var, Name.arbitrary)), - ] + ((n <= 0) ? [] : [ - (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), - (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), - ])) - } - - static var arbitrary : Gen { - return Gen.sized(self.arbExpr) - } - - static func shrink(_ e : Exp) -> [Exp] { - switch e { - case .var(_): - return [] - case let .lam(x, a): - return [a] + Exp.shrink(a).map { .lam(x, $0) } - case let .app(a, b): - let part1 : [Exp] = [a, b] - + [a].flatMap({ (expr : Exp) -> Exp? in - if case let .lam(x, a) = expr { - return a.subst(x, b) - } - return nil - }) - - let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } - + Exp.shrink(b).map { app(a, $0) } - return part1 + part2 - } - } - - var free : Set { - switch self { - case let .var(x): - return Set([x]) - case let .lam(x, a): - return a.free.subtracting([x]) - case let .app(a, b): - return a.free.union(b.free) - } - } - - func rename(_ x : Name, _ y : Name) -> Exp { - if x == y { - return self - } - return self.subst(x, .var(y)) - } - - func subst(_ x : Name, _ c : Exp) -> Exp { - switch self { - case let .var(y) where x == y : - return c - case let .lam(y, a) where x != y: - return .lam(y, a.subst(x, c)) - case let .app(a, b): - return .app(a.subst(x, c), b.subst(x, c)) - default: - return self - } - } - - var eval : Exp { - switch self { - case .var(_): - fatalError("Cannot evaluate free variable!") - case let .app(a, b): - switch a.eval { - case let .lam(x, aPrime): - return aPrime.subst(x, b) - default: - return .app(a.eval, b.eval) - } - default: - return self - } - } + private static func arbExpr(_ n : Int) -> Gen { + return Gen.frequency([ + (2, liftM(Exp.var, Name.arbitrary)), + ] + ((n <= 0) ? [] : [ + (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), + (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), + ])) + } + + static var arbitrary : Gen { + return Gen.sized(self.arbExpr) + } + + static func shrink(_ e : Exp) -> [Exp] { + switch e { + case .var(_): + return [] + case let .lam(x, a): + return [a] + Exp.shrink(a).map { .lam(x, $0) } + case let .app(a, b): + let part1 : [Exp] = [a, b] + + [a].flatMap({ (expr : Exp) -> Exp? in + if case let .lam(x, a) = expr { + return a.subst(x, b) + } + return nil + }) + + let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } + + Exp.shrink(b).map { app(a, $0) } + return part1 + part2 + } + } + + var free : Set { + switch self { + case let .var(x): + return Set([x]) + case let .lam(x, a): + return a.free.subtracting([x]) + case let .app(a, b): + return a.free.union(b.free) + } + } + + func rename(_ x : Name, _ y : Name) -> Exp { + if x == y { + return self + } + return self.subst(x, .var(y)) + } + + func subst(_ x : Name, _ c : Exp) -> Exp { + switch self { + case let .var(y) where x == y : + return c + case let .lam(y, a) where x != y: + return .lam(y, a.subst(x, c)) + case let .app(a, b): + return .app(a.subst(x, c), b.subst(x, c)) + default: + return self + } + } + + var eval : Exp { + switch self { + case .var(_): + fatalError("Cannot evaluate free variable!") + case let .app(a, b): + switch a.eval { + case let .lam(x, aPrime): + return aPrime.subst(x, b) + default: + return .app(a.eval, b.eval) + } + default: + return self + } + } } extension Exp : CustomStringConvertible { - var description : String { - switch self { - case let .var(x): - return "$" + x.description - case let .lam(x, t): - return "(λ $\(x.description).\(t.description))" - case let .app(a, b): - return "(\(a.description) \(b.description))" - } - } + var description : String { + switch self { + case let .var(x): + return "$" + x.description + case let .lam(x, t): + return "(λ $\(x.description).\(t.description))" + case let .app(a, b): + return "(\(a.description) \(b.description))" + } + } } extension Name { - func fresh(_ ys : Set) -> Name { - let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } - return Set(zz).subtracting(ys).first ?? self - } + func fresh(_ ys : Set) -> Name { + let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } + return Set(zz).subtracting(ys).first ?? self + } } private func showResult(_ x : A, f : (A) -> Testable) -> Property { - return f(x).whenFail { - print("Result: \(x)") - } + return f(x).whenFail { + print("Result: \(x)") + } } class LambdaSpec : XCTestCase { - func testAll() { - let tiny = CheckerArguments(maxTestCaseSize: 10) - - property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return a.free.contains(x) - ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) - } - }.expectFailure - - property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return !a.free.contains(x) ==> subst_x_b_a == a - } - } - - property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return !a.free.contains(x) ==> subst_x_b_a.free == a.free - } - } - } + func testAll() { + let tiny = CheckerArguments(maxTestCaseSize: 10) + + property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return a.free.contains(x) + ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) + } + }.expectFailure + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a == a + } + } + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a.free == a.free + } + } + } } diff --git a/Tests/ModifierSpec.swift b/Tests/ModifierSpec.swift index 8c9b084..7deb624 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/ModifierSpec.swift @@ -10,56 +10,54 @@ import SwiftCheck import XCTest class ModifierSpec : XCTestCase { - func testModifiers() { - property("All blind variables print '(*)'") <- forAll { (x : Blind) in - return x.description == "(*)" - } - - property("Static propositions never shrink") <- forAll { (x : Static) in - return Static.shrink(x).isEmpty - } - - property("Pointers behave") <- forAll { (x : PointerOf) in - return x.size != 0 - } - - property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in - return x.getPositive > 0 - } - - property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in - return x.getNonZero != 0 - } - - property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in - return x.getNonNegative >= 0 - } - - property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in - return true - } - - property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in - return - (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" - ^&&^ - (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" - } - - property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in - return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) - } - - property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in - return - iso.getFrom(iso.getTo(x)) == x - ^&&^ - iso.getTo(iso.getFrom(y)) == y - } - - property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in - let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) - } - } + func testModifiers() { + property("All blind variables print '(*)'") <- forAll { (x : Blind) in + return x.description == "(*)" + } + + property("Static propositions never shrink") <- forAll { (x : Static) in + return Static.shrink(x).isEmpty + } + + property("Pointers behave") <- forAll { (x : PointerOf) in + return x.size != 0 + } + + property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in + return x.getPositive > 0 + } + + property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in + return x.getNonZero != 0 + } + + property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in + return x.getNonNegative >= 0 + } + + property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in + return true + } + + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in + return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" + ^&&^ + (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" + } + + property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in + return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) + } + + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in + return iso.getFrom(iso.getTo(x)) == x + ^&&^ + iso.getTo(iso.getFrom(y)) == y + } + + property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in + let f = pred.getArrow + return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + } } diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index c027c16..75bfb5b 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -10,92 +10,92 @@ import SwiftCheck import XCTest struct Path : Arbitrary { - let unPath : [A] - - private static func pathFrom(_ x : A) -> Gen<[A]> { - return Gen.sized { n in - return Gen<[A]>.oneOf( - [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } - ).map { [x] + $0 } - } - } - - static var arbitrary : Gen> { - return A.arbitrary >>- { x in - return pathFrom(x).map(Path.init) - } - } + let unPath : [A] + + private static func pathFrom(_ x : A) -> Gen<[A]> { + return Gen.sized { n in + return Gen<[A]>.oneOf( + [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } + ).map { [x] + $0 } + } + } + + static var arbitrary : Gen> { + return A.arbitrary >>- { x in + return pathFrom(x).map(Path.init) + } + } } func path(_ p : (A) -> Bool, _ pth : Path) -> Bool { - return pth.unPath.reduce(true, { $0 && p($1) }) + return pth.unPath.reduce(true, { $0 && p($1) }) } func somePath(_ p : (A) -> Bool, _ pth : Path) -> Property { - return path({ !p($0) }, pth).expectFailure + return path({ !p($0) }, pth).expectFailure } struct Extremal : Arbitrary { - let getExtremal : A - - static var arbitrary : Gen> { - return Gen.frequency([ - (1, Gen.pure(A.min)), - (1, Gen.pure(A.max)), - (8, A.arbitrary) - ]).map(Extremal.init) - } - - static func shrink(_ x : Extremal) -> [Extremal] { - return A.shrink(x.getExtremal).map(Extremal.init) - } + let getExtremal : A + + static var arbitrary : Gen> { + return Gen.frequency([ + (1, Gen.pure(A.min)), + (1, Gen.pure(A.max)), + (8, A.arbitrary) + ]).map(Extremal.init) + } + + static func shrink(_ x : Extremal) -> [Extremal] { + return A.shrink(x.getExtremal).map(Extremal.init) + } } class PathSpec : XCTestCase { - private static func smallProp(_ pth : Path) -> Bool { - return path({ x in - return (x >= -100 || -100 >= 0) && x <= 100 - }, pth) - } - - private static func largeProp(_ pth : Path) -> Property { - return somePath({ x in - return (x < -1000000 || x > 1000000) - }, pth) - } - - func testAll() { - property("Int") <- forAll { (x : Path) in - return somePath({ x in - return (x < 1000000 || x > -1000000) - }, x) - } - - property("Int32") <- forAll { (x : Path) in - return path({ x in - return (x >= -100 || -100 >= 0) && x <= 100 - }, x) - } - - property("UInt") <- forAll { (x : Path) in - return somePath({ x in - return (x < 1000000 || x > 0) - }, x) - } - - property("UInt32") <- forAll { (x : Path) in - return path({ x in - return (x >= 0 || -100 >= 0) && x <= 100 - }, x) - } - - property("Large Int") <- forAll { (x : Path>) in - return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) - } - - property("Large UInt") <- forAll { (x : Path>) in - return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) - } - } + private static func smallProp(_ pth : Path) -> Bool { + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, pth) + } + + private static func largeProp(_ pth : Path) -> Property { + return somePath({ x in + return (x < -1000000 || x > 1000000) + }, pth) + } + + func testAll() { + property("Int") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > -1000000) + }, x) + } + + property("Int32") <- forAll { (x : Path) in + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, x) + } + + property("UInt") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > 0) + }, x) + } + + property("UInt32") <- forAll { (x : Path) in + return path({ x in + return (x >= 0 || -100 >= 0) && x <= 100 + }, x) + } + + property("Large Int") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + + property("Large UInt") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + } } diff --git a/Tests/PropertySpec.swift b/Tests/PropertySpec.swift index 436687f..f6e113f 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/PropertySpec.swift @@ -10,144 +10,144 @@ import XCTest func ==(l : Property, r : Property) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) - let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) - - switch (res1, res2) { - case (.success(_, _, _), .success(_, _, _)): - return true - case (.gaveUp(_, _, _), .gaveUp(_, _, _)): - return true - case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): - return true - case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): - return true - case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): - return true - case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): - return true - default: - return false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) + + switch (res1, res2) { + case (.success(_, _, _), .success(_, _, _)): + return true + case (.gaveUp(_, _, _), .gaveUp(_, _, _)): + return true + case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): + return true + case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): + return true + case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): + return true + case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): + return true + default: + return false + } } func ==(l : Property, r : Bool) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) - switch res1 { - case .success(_, _, _): - return r == true - default: - return r == false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + switch res1 { + case .success(_, _, _): + return r == true + default: + return r == false + } } class PropertySpec : XCTestCase { - func testProperties() { - property("Once really only tests a property once") <- forAll { (n : Int) in - var bomb : Optional = .some(n) - return forAll { (_ : Int) in - let b = bomb! // Will explode if we test more than once - bomb = nil - return b == n - }.once - } - - property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in - return conjamb({ - return true "picked 1" - }, { - return true "picked 2" - }, { - return true "picked 3" - }) - } - - property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in - return n == n - }.invert.expectFailure - - property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in - return n != n - }.invert - - property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in - throw SwiftCheckError.bogus - }.invert - - property("Invert does not affect discards") <- forAll { (n : Int) in - return Discard() - }.invert - - property("Existential Quantification works") <- exists { (x : Int) in - return true - } - - property("Cover reports failures properly") <- forAll { (s : Set) in - return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") - }.expectFailure - - property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in - let p = p2 ==> p1 - return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) - } - - property("==> Short Circuits") <- forAll { (n : Int) in - func isPositive(_ n : Int) -> Bool { - if n > 0 { - return true - } else if (n & 1) == 0 { - fatalError("Should never get here") - } else { - return isPositive(n) // or here - } - } - return (n > 0) ==> isPositive(n) - } - - property("Prop Law of complements") <- forAll { (x : Bool) in - return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) - } - - property("Prop Law of double negation") <- forAll { (x : Bool) in - return x.invert.invert == x - } - - property("Prop Law of idempotency") <- forAll { (x : Bool) in - return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) - } - - property("Prop Law of dominance") <- forAll { (x : Bool) in - return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) - } - - property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) - } - - property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) - } - - property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) - let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) - return l ^&&^ r - } - - property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x ^||^ y)) == x - let r = (x ^||^ (x ^&&^ y)) == x - return l ^&&^ r - } - - property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) - let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) - return l ^&&^ r - } - - property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) - } - } + func testProperties() { + property("Once really only tests a property once") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.once + } + + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in + return conjamb({ + return true "picked 1" + }, { + return true "picked 2" + }, { + return true "picked 3" + }) + } + + property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in + return n == n + }.invert.expectFailure + + property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in + return n != n + }.invert + + property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in + throw SwiftCheckError.bogus + }.invert + + property("Invert does not affect discards") <- forAll { (n : Int) in + return Discard() + }.invert + + property("Existential Quantification works") <- exists { (x : Int) in + return true + } + + property("Cover reports failures properly") <- forAll { (s : Set) in + return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") + }.expectFailure + + property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in + let p = p2 ==> p1 + return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) + } + + property("==> Short Circuits") <- forAll { (n : Int) in + func isPositive(_ n : Int) -> Bool { + if n > 0 { + return true + } else if (n & 1) == 0 { + fatalError("Should never get here") + } else { + return isPositive(n) // or here + } + } + return (n > 0) ==> isPositive(n) + } + + property("Prop Law of complements") <- forAll { (x : Bool) in + return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) + } + + property("Prop Law of double negation") <- forAll { (x : Bool) in + return x.invert.invert == x + } + + property("Prop Law of idempotency") <- forAll { (x : Bool) in + return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) + } + + property("Prop Law of dominance") <- forAll { (x : Bool) in + return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) + } + + property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) + } + + property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) + } + + property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) + let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) + return l ^&&^ r + } + + property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x ^||^ y)) == x + let r = (x ^||^ (x ^&&^ y)) == x + return l ^&&^ r + } + + property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) + let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) + return l ^&&^ r + } + + property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) + } + } } diff --git a/Tests/RawRepresentableSpec.swift b/Tests/RawRepresentableSpec.swift index dc01299..64b15f0 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/RawRepresentableSpec.swift @@ -10,9 +10,9 @@ import XCTest import SwiftCheck enum ImplicitRawValues : Int { - case foo - case bar - case baz + case foo + case bar + case baz } // Declaring the extension allows Swift to know this particular enum can be Arbitrary @@ -20,23 +20,23 @@ enum ImplicitRawValues : Int { extension ImplicitRawValues: Arbitrary {} enum ExplicitRawValues : Int { - case zero = 0 - case one = 1 - case two = 2 + case zero = 0 + case one = 1 + case two = 2 } class RawRepresentable_ArbitrarySpec: XCTestCase { - func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { - property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in - return [.foo, .bar, .baz].contains(e) - } - } - - func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { - // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically - // infer protocol conformance - property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in - return [.zero, .one, .two].contains(e) - } - } + func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { + property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in + return [.foo, .bar, .baz].contains(e) + } + } + + func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { + // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically + // infer protocol conformance + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in + return [.zero, .one, .two].contains(e) + } + } } diff --git a/Tests/ReplaySpec.swift b/Tests/ReplaySpec.swift index 9723d6d..20c496a 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/ReplaySpec.swift @@ -10,22 +10,22 @@ import SwiftCheck import XCTest class ReplaySpec : XCTestCase { - func testProperties() { - property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) - var foundArgs : [Int] = [] - property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in - foundArgs.append(x) - return true - } + func testProperties() { + property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in + let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) + var foundArgs : [Int] = [] + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs.append(x) + return true + } - var foundArgs2 : [Int] = [] - property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in - foundArgs2.append(x) - return foundArgs.contains(x) - } + var foundArgs2 : [Int] = [] + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs2.append(x) + return foundArgs.contains(x) + } - return foundArgs == foundArgs2 - } - } + return foundArgs == foundArgs2 + } + } } diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index 668ef21..eca2917 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -10,137 +10,136 @@ import SwiftCheck import XCTest class RoseSpec : XCTestCase { - private static func intRoseTree(_ v : Int) -> Rose { - return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) - } - - private static func depthOneChildren(_ rose : Rose) -> [A] { - return rose.children.map { $0.root } - } - - private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { - let topChildren = rose.children - let vs = topChildren.map { $0.root } - let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) - return vs + cs - } - - func testAll() { - property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in - let tree = RoseSpec.intRoseTree(i) - return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) - } - } - - func testLaws() { - let smallArgs = CheckerArguments(maxTestCaseSize: 5) - property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (x.getRose.map(id)) == id(x.getRose) - } - - property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in - return forAll { (x : RoseTreeOf) in - return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) - } - } - - property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (Rose.pure(id) <*> x.getRose) == x.getRose - } - - property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in - let f = fl.getRose.map({ $0.getArrow }) - let g = gl.getRose.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) - } - - property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in - let f = fl.getRose.map({ $0.getArrow }) - let g = gl.getRose.map({ $0.getArrow }) - return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) - } - - property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in - return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose - } - - property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in - return (m.getRose >>- Rose.pure) == m.getRose - } - - property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in - return forAll { (m : RoseTreeOf) in - return - ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) - == - (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) - } - } - } + private static func intRoseTree(_ v : Int) -> Rose { + return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + } + + private static func depthOneChildren(_ rose : Rose) -> [A] { + return rose.children.map { $0.root } + } + + private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { + let topChildren = rose.children + let vs = topChildren.map { $0.root } + let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) + return vs + cs + } + + func testAll() { + property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in + let tree = RoseSpec.intRoseTree(i) + return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) + } + } + + func testLaws() { + let smallArgs = CheckerArguments(maxTestCaseSize: 5) + property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (x.getRose.map(id)) == id(x.getRose) + } + + property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAll { (x : RoseTreeOf) in + return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) + } + } + + property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (Rose.pure(id) <*> x.getRose) == x.getRose + } + + property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in + return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose + } + + property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in + return (m.getRose >>- Rose.pure) == m.getRose + } + + property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in + return forAll { (m : RoseTreeOf) in + return ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) + == + (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) + } + } + } } struct RoseTreeOf : Arbitrary { - let getRose : Rose - - init(_ rose : Rose) { - self.getRose = rose - } - - static var arbitrary : Gen> { - return Gen.sized { n in - return arbTree(n) - } - } + let getRose : Rose + + init(_ rose : Rose) { + self.getRose = rose + } + + static var arbitrary : Gen> { + return Gen.sized { n in + return arbTree(n) + } + } } private func arbTree(_ n : Int) -> Gen> { - if n == 0 { - return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } - } - return Positive.arbitrary.flatMap { m in - let n2 = n / (m.getPositive + 1) - return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in - return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) - } - } + if n == 0 { + return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } + } + return Positive.arbitrary.flatMap { m in + let n2 = n / (m.getPositive + 1) + return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in + return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) + } + } } private func == (l : Rose, r : Rose) -> Bool { - switch (l, r) { - case let (.mkRose(l1, r1), .mkRose(l2, r2)): - return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } - case (.ioRose(_), .ioRose(_)): - return true - default: - return false - } + switch (l, r) { + case let (.mkRose(l1, r1), .mkRose(l2, r2)): + return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } + case (.ioRose(_), .ioRose(_)): + return true + default: + return false + } } extension Rose { - var root : A { - switch self.reduce { - case let .mkRose(root, _): - return root() - default: - fatalError("Rose should not have reduced to .IORose") - } - } - - var children : [Rose] { - switch self.reduce { - case let .mkRose(_, children): - return children() - default: - fatalError("Rose should not have reduced to .IORose") - } - } - - var collapse : Rose { - let children = self.children - - let vs = children.map { $0.collapse } - let cs = children.flatMap({ $0.children }).map { $0.collapse } - - return .mkRose({ self.root }, { vs + cs }) - } + var root : A { + switch self.reduce { + case let .mkRose(root, _): + return root() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var children : [Rose] { + switch self.reduce { + case let .mkRose(_, children): + return children() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var collapse : Rose { + let children = self.children + + let vs = children.map { $0.collapse } + let cs = children.flatMap({ $0.children }).map { $0.collapse } + + return .mkRose({ self.root }, { vs + cs }) + } } diff --git a/Tests/ShrinkSpec.swift b/Tests/ShrinkSpec.swift index ae8ac83..11c7a7f 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/ShrinkSpec.swift @@ -10,32 +10,32 @@ import SwiftCheck import XCTest class ShrinkSpec : XCTestCase { - func shrinkArbitrary(_ x : A) -> [A] { - let xs = A.shrink(x) - if let x = xs.first { - return xs + [x].flatMap(self.shrinkArbitrary) - } - return xs - } + func shrinkArbitrary(_ x : A) -> [A] { + let xs = A.shrink(x) + if let x = xs.first { + return xs + [x].flatMap(self.shrinkArbitrary) + } + return xs + } - func testAll() { - property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in - return !Set(Int.shrink(n)).contains(n) - } + func testAll() { + property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in + return !Set(Int.shrink(n)).contains(n) + } - property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in - return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) - } + property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in + return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) + } - property("Shrinking an array never gives back the original") <- forAll { (l : Array) in - return Array.shrink(l).filter({ $0 == l }).isEmpty - } + property("Shrinking an array never gives back the original") <- forAll { (l : Array) in + return Array.shrink(l).filter({ $0 == l }).isEmpty + } - property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in - return (!l.getArray.isEmpty && l.getArray != [0]) ==> { - let ls = self.shrinkArbitrary(l).map { $0.getArray } - return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) - } - } - } + property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in + return (!l.getArray.isEmpty && l.getArray != [0]) ==> { + let ls = self.shrinkArbitrary(l).map { $0.getArray } + return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) + } + } + } } diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index f355a5e..035f054 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -10,18 +10,18 @@ import SwiftCheck import XCTest public struct ArbitraryFoo { - let x : Int - let y : Int + let x : Int + let y : Int - public var description : String { - return "Arbitrary Foo!" - } + public var description : String { + return "Arbitrary Foo!" + } } extension ArbitraryFoo : Arbitrary { - public static var arbitrary : Gen { - return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) - } + public static var arbitrary : Gen { + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) + } } public struct ArbitraryMutableFoo : Arbitrary { @@ -50,20 +50,20 @@ public func == (lhs: ArbitraryMutableFoo, rhs: ArbitraryMutableFoo) -> Bool { } public struct ArbitraryLargeFoo { - let a : Int8 - let b : Int16 - let c : Int32 - let d : Int64 - let e : UInt8 - let f : UInt16 - let g : UInt32 - let h : UInt64 - let i : Int - let j : UInt - let k : Bool - let l : (Bool, Bool) - let m : (Bool, Bool, Bool) - let n : (Bool, Bool, Bool, Bool) + let a : Int8 + let b : Int16 + let c : Int32 + let d : Int64 + let e : UInt8 + let f : UInt16 + let g : UInt32 + let h : UInt64 + let i : Int + let j : UInt + let k : Bool + let l : (Bool, Bool) + let m : (Bool, Bool, Bool) + let n : (Bool, Bool, Bool, Bool) } extension ArbitraryLargeFoo: Equatable {} @@ -87,25 +87,25 @@ public func ==(i: ArbitraryLargeFoo, j: ArbitraryLargeFoo) -> Bool { } extension ArbitraryLargeFoo : Arbitrary { - public static var arbitrary : Gen { - return Gen<(Int8, Int16, Int32, Int64 - , UInt8, UInt16, UInt32, UInt64 - , Int , UInt)> - .zip( Int8.arbitrary, Int16.arbitrary, Int32.arbitrary, Int64.arbitrary - , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary - , Int.arbitrary, UInt.arbitrary) - .flatMap { t in - return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> - .map( - Bool.arbitrary, - Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), - Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), - Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) - ) { t2 in - (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) - }.map(ArbitraryLargeFoo.init) - } - } + public static var arbitrary : Gen { + return Gen<(Int8, Int16, Int32, Int64 + , UInt8, UInt16, UInt32, UInt64 + , Int , UInt)> + .zip( Int8.arbitrary, Int16.arbitrary, Int32.arbitrary, Int64.arbitrary + , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary + , Int.arbitrary, UInt.arbitrary) + .flatMap { t in + return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> + .map( + Bool.arbitrary, + Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) + ) { t2 in + (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) + }.map(ArbitraryLargeFoo.init) + } + } } let composedArbitraryLargeFoo = Gen.compose { c in @@ -129,75 +129,75 @@ let composedArbitraryLargeFoo = Gen.compose { c in } class SimpleSpec : XCTestCase { - func testAll() { - property("Integer Equality is Reflexive") <- forAll { (i : Int8) in - return i == i - } - - property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in - return i == i - } - - property("Float Equality is Reflexive") <- forAll { (i : Float) in - return i == i - } - - property("Double Equality is Reflexive") <- forAll { (i : Double) in - return i == i - } - - property("String Equality is Reflexive") <- forAll { (s : String) in - return s == s - } - - property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in - return i.x == i.x && i.y == i.y - } - - property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in - return i.a == i.a - && i.b == i.b - && i.c == i.c - && i.d == i.d - && i.e == i.e - && i.f == i.f - && i.g == i.g - && i.h == i.h - && i.i == i.i - && i.j == i.j - && i.k == i.k - && i.l == i.l - && i.m == i.m - && i.n == i.n - } - - property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in - return - (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) - || - (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) - } + func testAll() { + property("Integer Equality is Reflexive") <- forAll { (i : Int8) in + return i == i + } + + property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in + return i == i + } + + property("Float Equality is Reflexive") <- forAll { (i : Float) in + return i == i + } + + property("Double Equality is Reflexive") <- forAll { (i : Double) in + return i == i + } + + property("String Equality is Reflexive") <- forAll { (s : String) in + return s == s + } + + property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in + return i.x == i.x && i.y == i.y + } + + property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in + return i.a == i.a + && i.b == i.b + && i.c == i.c + && i.d == i.d + && i.e == i.e + && i.f == i.f + && i.g == i.g + && i.h == i.h + && i.i == i.i + && i.j == i.j + && i.k == i.k + && i.l == i.l + && i.m == i.m + && i.n == i.n + } + + property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in + return + (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) + || + (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) + } let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) - let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ - greaterThan_lessThanEqualTo, - lessThan_greaterThanEqualTo, - equalTo_notEqualTo, - ]) - - property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in - return forAll { (x : UInt8, y : UInt8) in - return op(x, y) ==== !iop(x, y) - } - } + let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ + greaterThan_lessThanEqualTo, + lessThan_greaterThanEqualTo, + equalTo_notEqualTo, + ]) + + property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in + return forAll { (x : UInt8, y : UInt8) in + return op(x, y) ==== !iop(x, y) + } + } property("composition generates high-entropy, arbitrary values") <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in return a != b } - } + } func testComposeWithMutableType() { property("composition allows setting values on mutable types") diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index 1629ee9..ebbd567 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -10,47 +10,45 @@ import SwiftCheck import class XCTest.XCTestCase class TestSpec : XCTestCase { - func testAll() { + func testAll() { let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } - property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in - return true - } - - property("Optionals behave") <- forAll { (xs : Int?) in - return true - } - - property("Sets behave") <- forAll { (xs : Set) in - return true - } - - property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in - return - (xs.reversed().reversed() == xs) "Left identity" - ^&&^ - (xs == xs.reversed().reversed()) "Right identity" - } - - property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in - return - (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" - ^&&^ - ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") - }.expectFailure - - property("map behaves") <- forAll { (xs : Array) in - return forAll { (f : ArrowOf) in - return xs.map(f.getArrow) == xs.map(f.getArrow) - } - } - - property("filter behaves") <- forAll { (xs : Array) in - return forAll { (pred : ArrowOf) in - let f = pred.getArrow - return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) - } - } - } + property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in + return true + } + + property("Optionals behave") <- forAll { (xs : Int?) in + return true + } + + property("Sets behave") <- forAll { (xs : Set) in + return true + } + + property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in + return (xs.reversed().reversed() == xs) "Left identity" + ^&&^ + (xs == xs.reversed().reversed()) "Right identity" + } + + property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in + return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" + ^&&^ + ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") + }.expectFailure + + property("map behaves") <- forAll { (xs : Array) in + return forAll { (f : ArrowOf) in + return xs.map(f.getArrow) == xs.map(f.getArrow) + } + } + + property("filter behaves") <- forAll { (xs : Array) in + return forAll { (pred : ArrowOf) in + let f = pred.getArrow + return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + } + } } From 451ac6e7f49ba7710e5220fcb5e2e9e5d18dec80 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 21:07:06 -0700 Subject: [PATCH 335/460] Actually, we use tabs in this town --- Sources/Arbitrary.swift | 550 +++++++------- Sources/CoArbitrary.swift | 218 +++--- Sources/Gen.swift | 930 +++++++++++------------ Sources/Lattice.swift | 112 +-- Sources/Modifiers.swift | 1112 ++++++++++++++-------------- Sources/Operators.swift | 56 +- Sources/Property.swift | 1040 +++++++++++++------------- Sources/Random.swift | 494 ++++++------ Sources/Rose.swift | 172 ++--- Sources/State.swift | 160 ++-- Sources/SwiftCheck.h | 1 - Sources/Test.swift | 1012 ++++++++++++------------- Sources/TestOperators.swift | 246 +++--- Sources/Testable.swift | 110 +-- Sources/Witness.swift | 42 +- Sources/WitnessedArbitrary.swift | 518 ++++++------- Tests/BooleanIdentitySpec.swift | 94 +-- Tests/ComplexSpec.swift | 104 +-- Tests/DiscardSpec.swift | 24 +- Tests/FailureSpec.swift | 88 +-- Tests/GenSpec.swift | 590 +++++++-------- Tests/LambdaSpec.swift | 298 ++++---- Tests/ModifierSpec.swift | 100 +-- Tests/PathSpec.swift | 150 ++-- Tests/PropertySpec.swift | 268 +++---- Tests/RawRepresentableSpec.swift | 36 +- Tests/ReplaySpec.swift | 32 +- Tests/RoseSpec.swift | 236 +++--- Tests/ShrinkSpec.swift | 48 +- Tests/SimpleSpec.swift | 334 ++++----- Tests/TestSpec.swift | 80 +- Tutorial.playground/Contents.swift | 8 +- 32 files changed, 4631 insertions(+), 4632 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 8bec3e1..23d6482 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -36,358 +36,358 @@ /// `Modifiers.swift` for an example of how to define a "Modifier" type to /// implement it. public protocol Arbitrary { - /// The generator for this particular type. - /// - /// This function should call out to any sources of randomness or state - /// necessary to generate values. It should not, however, be written as a - /// deterministic function. If such a generator is needed, combinators are - /// provided in `Gen.swift`. - static var arbitrary : Gen { get } - - /// An optional shrinking function. If this function goes unimplemented, it - /// is the same as returning the empty list. - /// - /// Shrunken values must be less than or equal to the "size" of the original - /// type but never the same as the value provided to this function (or a loop - /// will form in the shrinker). It is recommended that they be presented - /// smallest to largest to speed up the overall shrinking process. - static func shrink(_ : Self) -> [Self] + /// The generator for this particular type. + /// + /// This function should call out to any sources of randomness or state + /// necessary to generate values. It should not, however, be written as a + /// deterministic function. If such a generator is needed, combinators are + /// provided in `Gen.swift`. + static var arbitrary : Gen { get } + + /// An optional shrinking function. If this function goes unimplemented, it + /// is the same as returning the empty list. + /// + /// Shrunken values must be less than or equal to the "size" of the original + /// type but never the same as the value provided to this function (or a loop + /// will form in the shrinker). It is recommended that they be presented + /// smallest to largest to speed up the overall shrinking process. + static func shrink(_ : Self) -> [Self] } extension Arbitrary { - /// The implementation of a shrink that returns no alternatives. - public static func shrink(_ : Self) -> [Self] { - return [] - } + /// The implementation of a shrink that returns no alternatives. + public static func shrink(_ : Self) -> [Self] { + return [] + } } extension Integer { - /// Shrinks any `IntegerType`. - public var shrinkIntegral : [Self] { - return unfoldr({ i in - if i <= 0 { - return .none - } - let n = i / 2 - return .some((n, n)) - }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) - } + /// Shrinks any `IntegerType`. + public var shrinkIntegral : [Self] { + return unfoldr({ i in + if i <= 0 { + return .none + } + let n = i / 2 + return .some((n, n)) + }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) + } } extension RawRepresentable where RawValue: Arbitrary { - /// Default implementation, maps arbitrary values of its `RawValue` type - /// until a valid representation is obtained. Naturally, you should strive - /// to override this with a more efficient version. - public static var arbitrary: Gen { - return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } - } + /// Default implementation, maps arbitrary values of its `RawValue` type + /// until a valid representation is obtained. Naturally, you should strive + /// to override this with a more efficient version. + public static var arbitrary: Gen { + return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } + } } extension Bool : Arbitrary { - /// Returns a generator of `Bool`ean values. - public static var arbitrary : Gen { - return Gen.choose((false, true)) - } - - /// The default shrinking function for `Bool`ean values. - public static func shrink(_ x : Bool) -> [Bool] { - if x { - return [false] - } - return [] - } + /// Returns a generator of `Bool`ean values. + public static var arbitrary : Gen { + return Gen.choose((false, true)) + } + + /// The default shrinking function for `Bool`ean values. + public static func shrink(_ x : Bool) -> [Bool] { + if x { + return [false] + } + return [] + } } extension Int : Arbitrary { - /// Returns a generator of `Int` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((-n, n)) - } - } - - /// The default shrinking function for `Int` values. - public static func shrink(_ x : Int) -> [Int] { - return x.shrinkIntegral - } + /// Returns a generator of `Int` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((-n, n)) + } + } + + /// The default shrinking function for `Int` values. + public static func shrink(_ x : Int) -> [Int] { + return x.shrinkIntegral + } } extension Int8 : Arbitrary { - /// Returns a generator of `Int8` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int8` values. - public static func shrink(_ x : Int8) -> [Int8] { - return x.shrinkIntegral - } + /// Returns a generator of `Int8` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int8` values. + public static func shrink(_ x : Int8) -> [Int8] { + return x.shrinkIntegral + } } extension Int16 : Arbitrary { - /// Returns a generator of `Int16` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int16` values. - public static func shrink(_ x : Int16) -> [Int16] { - return x.shrinkIntegral - } + /// Returns a generator of `Int16` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int16` values. + public static func shrink(_ x : Int16) -> [Int16] { + return x.shrinkIntegral + } } extension Int32 : Arbitrary { - /// Returns a generator of `Int32` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) - } - } - - /// The default shrinking function for `Int32` values. - public static func shrink(_ x : Int32) -> [Int32] { - return x.shrinkIntegral - } + /// Returns a generator of `Int32` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) + } + } + + /// The default shrinking function for `Int32` values. + public static func shrink(_ x : Int32) -> [Int32] { + return x.shrinkIntegral + } } extension Int64 : Arbitrary { - /// Returns a generator of `Int64` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.choose((Int64(-n), Int64(n))) - } - } - - /// The default shrinking function for `Int64` values. - public static func shrink(_ x : Int64) -> [Int64] { - return x.shrinkIntegral - } + /// Returns a generator of `Int64` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.choose((Int64(-n), Int64(n))) + } + } + + /// The default shrinking function for `Int64` values. + public static func shrink(_ x : Int64) -> [Int64] { + return x.shrinkIntegral + } } extension UInt : Arbitrary { - /// Returns a generator of `UInt` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt(n))) } - } - - /// The default shrinking function for `UInt` values. - public static func shrink(_ x : UInt) -> [UInt] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt(n))) } + } + + /// The default shrinking function for `UInt` values. + public static func shrink(_ x : UInt) -> [UInt] { + return x.shrinkIntegral + } } extension UInt8 : Arbitrary { - /// Returns a generator of `UInt8` values. - public static var arbitrary : Gen { - return Gen.sized { n in - return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } - } - } - - /// The default shrinking function for `UInt8` values. - public static func shrink(_ x : UInt8) -> [UInt8] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt8` values. + public static var arbitrary : Gen { + return Gen.sized { n in + return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } + } + } + + /// The default shrinking function for `UInt8` values. + public static func shrink(_ x : UInt8) -> [UInt8] { + return x.shrinkIntegral + } } extension UInt16 : Arbitrary { - /// Returns a generator of `UInt16` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } - } - - /// The default shrinking function for `UInt16` values. - public static func shrink(_ x : UInt16) -> [UInt16] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt16` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } + } + + /// The default shrinking function for `UInt16` values. + public static func shrink(_ x : UInt16) -> [UInt16] { + return x.shrinkIntegral + } } extension UInt32 : Arbitrary { - /// Returns a generator of `UInt32` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } - } - - /// The default shrinking function for `UInt32` values. - public static func shrink(_ x : UInt32) -> [UInt32] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt32` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } + } + + /// The default shrinking function for `UInt32` values. + public static func shrink(_ x : UInt32) -> [UInt32] { + return x.shrinkIntegral + } } extension UInt64 : Arbitrary { - /// Returns a generator of `UInt64` values. - public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt64(n))) } - } - - /// The default shrinking function for `UInt64` values. - public static func shrink(_ x : UInt64) -> [UInt64] { - return x.shrinkIntegral - } + /// Returns a generator of `UInt64` values. + public static var arbitrary : Gen { + return Gen.sized { n in Gen.choose((0, UInt64(n))) } + } + + /// The default shrinking function for `UInt64` values. + public static func shrink(_ x : UInt64) -> [UInt64] { + return x.shrinkIntegral + } } extension Float : Arbitrary { - /// Returns a generator of `Float` values. - public static var arbitrary : Gen { - let precision : Int64 = 9999999999999 - - return Gen.sized { n in - if n == 0 { - return Gen.pure(0.0) - } - - let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - let denominator = Gen.choose((1, precision)) - - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Float(a) / Float(b)) } } - } - } - - /// The default shrinking function for `Float` values. - public static func shrink(_ x : Float) -> [Float] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) - } + /// Returns a generator of `Float` values. + public static var arbitrary : Gen { + let precision : Int64 = 9999999999999 + + return Gen.sized { n in + if n == 0 { + return Gen.pure(0.0) + } + + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator + >>- { b in Gen.pure(Float(a) / Float(b)) } } + } + } + + /// The default shrinking function for `Float` values. + public static func shrink(_ x : Float) -> [Float] { + return unfoldr({ i in + if i == 0.0 { + return .none + } + let n = i / 2.0 + return .some((n, n)) + }, initial: x) + } } extension Double : Arbitrary { - /// Returns a generator of `Double` values. - public static var arbitrary : Gen { - let precision : Int64 = 9999999999999 - - return Gen.sized { n in - if n == 0 { - return Gen.pure(0.0) - } - - let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) - let denominator = Gen.choose((1, precision)) - - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Double(a) / Double(b)) } } - } - } - - /// The default shrinking function for `Double` values. - public static func shrink(_ x : Double) -> [Double] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) - } + /// Returns a generator of `Double` values. + public static var arbitrary : Gen { + let precision : Int64 = 9999999999999 + + return Gen.sized { n in + if n == 0 { + return Gen.pure(0.0) + } + + let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) + let denominator = Gen.choose((1, precision)) + + return numerator + >>- { a in denominator + >>- { b in Gen.pure(Double(a) / Double(b)) } } + } + } + + /// The default shrinking function for `Double` values. + public static func shrink(_ x : Double) -> [Double] { + return unfoldr({ i in + if i == 0.0 { + return .none + } + let n = i / 2.0 + return .some((n, n)) + }, initial: x) + } } extension UnicodeScalar : Arbitrary { - /// Returns a generator of `UnicodeScalar` values. - public static var arbitrary : Gen { - return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } - } - - /// The default shrinking function for `UnicodeScalar` values. - public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { - let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! - return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } - } + /// Returns a generator of `UnicodeScalar` values. + public static var arbitrary : Gen { + return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } + } + + /// The default shrinking function for `UnicodeScalar` values. + public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { + let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! + return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } + } } extension String : Arbitrary { - /// Returns a generator of `String` values. - public static var arbitrary : Gen { - let chars = Gen.sized(Character.arbitrary.proliferateSized) - return chars >>- { Gen.pure(String($0)) } - } - - /// The default shrinking function for `String` values. - public static func shrink(_ s : String) -> [String] { - return [Character].shrink([Character](s.characters)).map { String($0) } - } + /// Returns a generator of `String` values. + public static var arbitrary : Gen { + let chars = Gen.sized(Character.arbitrary.proliferateSized) + return chars >>- { Gen.pure(String($0)) } + } + + /// The default shrinking function for `String` values. + public static func shrink(_ s : String) -> [String] { + return [Character].shrink([Character](s.characters)).map { String($0) } + } } extension Character : Arbitrary { - /// Returns a generator of `Character` values. - public static var arbitrary : Gen { - return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - } - - /// The default shrinking function for `Character` values. - public static func shrink(_ x : Character) -> [Character] { - let ss = String(x).unicodeScalars - return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) - } + /// Returns a generator of `Character` values. + public static var arbitrary : Gen { + return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + } + + /// The default shrinking function for `Character` values. + public static func shrink(_ x : Character) -> [Character] { + let ss = String(x).unicodeScalars + return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) + } } extension AnyIndex : Arbitrary { - /// Returns a generator of `AnyForwardIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) - } + /// Returns a generator of `AnyForwardIndex` values. + public static var arbitrary : Gen { + return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) + } } extension Mirror : Arbitrary { - /// Returns a generator of `Mirror` values. - public static var arbitrary : Gen { - let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.map(asAny), - Int.arbitrary.map(asAny), - UInt.arbitrary.map(asAny), - Float.arbitrary.map(asAny), - Double.arbitrary.map(asAny), - Character.arbitrary.map(asAny), - ]) - - let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.map(asAny), - Array.arbitrary.map(asAny), - Set.arbitrary.map(asAny), - ]) - - return Gen.oneOf([ - genAny, - genAnyWitnessed, - ]).map(Mirror.init) - } + /// Returns a generator of `Mirror` values. + public static var arbitrary : Gen { + let genAny : Gen = Gen.oneOf([ + Bool.arbitrary.map(asAny), + Int.arbitrary.map(asAny), + UInt.arbitrary.map(asAny), + Float.arbitrary.map(asAny), + Double.arbitrary.map(asAny), + Character.arbitrary.map(asAny), + ]) + + let genAnyWitnessed : Gen = Gen.oneOf([ + Optional.arbitrary.map(asAny), + Array.arbitrary.map(asAny), + Set.arbitrary.map(asAny), + ]) + + return Gen.oneOf([ + genAny, + genAnyWitnessed, + ]).map(Mirror.init) + } } // MARK: - Implementation Details Follow private func asAny(_ x : T) -> Any { - return x + return x } extension Array where Element : Hashable { - fileprivate var nub : [Element] { - return [Element](Set(self)) - } + fileprivate var nub : [Element] { + return [Element](Set(self)) + } } private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { - var acc = [A]() - var ini = initial - while let next = f(ini) { - acc.insert(next.0, at: 0) - ini = next.1 - } - return acc + var acc = [A]() + var ini = initial + while let next = f(ini) { + acc.insert(next.0, at: 0) + ini = next.1 + } + return acc } #if os(Linux) - import Glibc + import Glibc #else - import Darwin + import Darwin #endif diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index e226fee..4ceb44e 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -17,183 +17,183 @@ /// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a - /// generator. - static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) + /// Uses an instance of the receiver to return a function that perturbs a + /// generator. + static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } extension Integer { - /// A coarbitrary implementation for any IntegerType - public func coarbitraryIntegral() -> (Gen) -> Gen { - return { $0.variant(self) } - } + /// A coarbitrary implementation for any IntegerType + public func coarbitraryIntegral() -> (Gen) -> Gen { + return { $0.variant(self) } + } } /// A coarbitrary implementation for any Printable type. Avoid using this /// function if you can, it can be quite an expensive operation given a detailed /// enough description. public func coarbitraryPrintable(_ x : A) -> (Gen) -> Gen { - return String.coarbitrary(String(describing: x)) + return String.coarbitrary(String(describing: x)) } extension Bool : CoArbitrary { - /// The default coarbitrary implementation for `Bool` values. - public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { - return { g in - if x { - return g.variant(1) - } - return g.variant(0) - } - } + /// The default coarbitrary implementation for `Bool` values. + public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { + return { g in + if x { + return g.variant(1) + } + return g.variant(0) + } + } } extension UnicodeScalar : CoArbitrary { - /// The default coarbitrary implementation for `UnicodeScalar` values. - public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { - return UInt32.coarbitrary(x.value) - } + /// The default coarbitrary implementation for `UnicodeScalar` values. + public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { + return UInt32.coarbitrary(x.value) + } } extension Character : CoArbitrary { - /// The default coarbitrary implementation for `Character` values. - public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { - let ss = String(x).unicodeScalars - return UnicodeScalar.coarbitrary(ss[ss.startIndex]) - } + /// The default coarbitrary implementation for `Character` values. + public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { + let ss = String(x).unicodeScalars + return UnicodeScalar.coarbitrary(ss[ss.startIndex]) + } } extension String : CoArbitrary { - /// The default coarbitrary implementation for `String` values. - public static func coarbitrary(_ x : String) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.characters.index(after: x.startIndex)..(_ x : String) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.characters.index(after: x.startIndex)..(_ x : Int) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int` values. + public static func coarbitrary(_ x : Int) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int8 : CoArbitrary { - /// The default coarbitrary implementation for `Int8` values. - public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int8` values. + public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int16 : CoArbitrary { - /// The default coarbitrary implementation for `Int16` values. - public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int16` values. + public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int32 : CoArbitrary { - /// The default coarbitrary implementation for `Int32` values. - public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int32` values. + public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension Int64 : CoArbitrary { - /// The default coarbitrary implementation for `Int64` values. - public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Int64` values. + public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt : CoArbitrary { - /// The default coarbitrary implementation for `UInt` values. - public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt` values. + public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt8 : CoArbitrary { - /// The default coarbitrary implementation for `UInt8` values. - public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt8` values. + public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt16 : CoArbitrary { - /// The default coarbitrary implementation for `UInt16` values. - public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt16` values. + public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt32 : CoArbitrary { - /// The default coarbitrary implementation for `UInt32` values. - public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt32` values. + public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } extension UInt64 : CoArbitrary { - /// The default coarbitrary implementation for `UInt64` values. - public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { - return x.coarbitraryIntegral() - } + /// The default coarbitrary implementation for `UInt64` values. + public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { + return x.coarbitraryIntegral() + } } // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { - /// The default coarbitrary implementation for `Float` values. - public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { - return Int64(x).coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Float` values. + public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { + return Int64(x).coarbitraryIntegral() + } } extension Double : CoArbitrary { - /// The default coarbitrary implementation for `Double` values. - public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { - return Int64(x).coarbitraryIntegral() - } + /// The default coarbitrary implementation for `Double` values. + public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { + return Int64(x).coarbitraryIntegral() + } } extension Array : CoArbitrary { - /// The default coarbitrary implementation for an `Array` of values. - public static func coarbitrary(_ a : [Element]) -> ((Gen) -> Gen) { - if a.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(_ a : [Element]) -> ((Gen) -> Gen) { + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(_ x : Dictionary) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for a `Dictionary` of values. + public static func coarbitrary(_ x : Dictionary) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } extension Optional : CoArbitrary { - /// The default coarbitrary implementation for `Optional` values. - public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { - if let _ = x { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for `Optional` values. + public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { + if let _ = x { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } extension Set : CoArbitrary { - /// The default coarbitrary implementation for `Set`s of values. - public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { - if x.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + /// The default coarbitrary implementation for `Set`s of values. + public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { + if x.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 0fc4667..0cdc0f6 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -13,400 +13,400 @@ /// generator relies on its size to help control aspects like the length of /// generated arrays and the magnitude of integral values. public struct Gen { - /// The function underlying the receiver. - /// - /// +--- An RNG - /// | +--- The size of generated values. - /// | | - /// v v - let unGen : (StdGen, Int) -> A - - /// Generates a value. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var generate : A { - let r = newStdGen() - return unGen(r, 30) - } - - /// Generates some example values. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var sample : [A] { - return sequence((2...20).map(self.resize)).generate - } - - /// Constructs a Generator that selects a random value from the given - /// collection and produces only that value. - /// - /// The input collection is required to be non-empty. - public static func fromElementsOf(_ xs : S) -> Gen - where S.Index : Comparable & RandomType - { - return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in - return xs[i] - } - } - - /// Constructs a Generator that selects a random value from the given - /// interval and produces only that value. - /// - /// The input interval is required to be non-empty. - public static func fromElementsIn(_ xs : ClosedRange) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") - - return choose((xs.lowerBound, xs.upperBound)) - } - - /// Constructs a Generator that uses a given array to produce smaller arrays - /// composed of its initial segments. The size of each initial segment - /// increases with the receiver's size parameter. - /// - /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { - assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") - - return Gen<[S]>.sized { n in - let ss = xs[xs.startIndex...pure([S](ss)) - } - } - - /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { - return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) - } - } - - /// Constructs a generator that depends on a size parameter. - public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { - return Gen(unGen: { r, n in - return f(n).unGen(r, n) - }) - } - - /// Constructs a random element in the range of two `RandomType`s. - /// - /// When using this function, it is necessary to explicitly specialize the - /// generic parameter `A`. For example: - /// - /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - public static func choose(_ rng : (A, A)) -> Gen { - return Gen(unGen: { s, _ in - return A.randomInRange(rng, gen: s).0 - }) - } - - /// Constructs a Generator that randomly selects and uses a particular - /// generator from the given sequence of Generators. - /// - /// If control over the distribution of generators is needed, see - /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf(_ gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType - { - assert(gs.count != 0, "oneOf used with empty list") - - return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in - return gs[x] - } - } - - /// Given a sequence of Generators and weights associated with them, this - /// function randomly selects and uses a Generator. - /// - /// Only use this function when you need to assign uneven "weights" to each - /// generator. If all generators need to have an equal chance of being - /// selected, use `Gen.oneOf`. - public static func frequency(_ xs : S) -> Gen - where S.Iterator.Element == (Int, Gen) - { - let xs: [(Int, Gen)] = Array(xs) - assert(xs.count != 0, "frequency used with empty list") - - return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in - return pick(l, xs) - } - } - - /// Given a list of values and weights associated with them, this function - /// randomly selects and uses a Generator wrapping one of the values. - /// - /// This function operates in exactly the same manner as `Gen.frequency`, - /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather - /// than only Generators. It can help in cases where your `Gen.from*` call - /// contains only `Gen.pure` calls by allowing you to remove every - /// `Gen.pure` in favor of a direct list of values. - public static func weighted(_ xs : S) -> Gen - where S.Iterator.Element == (Int, A) - { - return frequency(xs.map { ($0, Gen.pure($1)) }) - } + /// The function underlying the receiver. + /// + /// +--- An RNG + /// | +--- The size of generated values. + /// | | + /// v v + let unGen : (StdGen, Int) -> A + + /// Generates a value. + /// + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. + public var generate : A { + let r = newStdGen() + return unGen(r, 30) + } + + /// Generates some example values. + /// + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the + /// replay functionality and the robustness of tests in general. + public var sample : [A] { + return sequence((2...20).map(self.resize)).generate + } + + /// Constructs a Generator that selects a random value from the given + /// collection and produces only that value. + /// + /// The input collection is required to be non-empty. + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : Comparable & RandomType + { + return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in + return xs[i] + } + } + + /// Constructs a Generator that selects a random value from the given + /// interval and produces only that value. + /// + /// The input interval is required to be non-empty. + public static func fromElementsIn(_ xs : ClosedRange) -> Gen { + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") + + return choose((xs.lowerBound, xs.upperBound)) + } + + /// Constructs a Generator that uses a given array to produce smaller arrays + /// composed of its initial segments. The size of each initial segment + /// increases with the receiver's size parameter. + /// + /// The input array is required to be non-empty. + public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { + assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") + + return Gen<[S]>.sized { n in + let ss = xs[xs.startIndex...pure([S](ss)) + } + } + + /// Constructs a Generator that produces permutations of a given array. + public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { + return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in + return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) + } + } + + /// Constructs a generator that depends on a size parameter. + public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { + return Gen(unGen: { r, n in + return f(n).unGen(r, n) + }) + } + + /// Constructs a random element in the range of two `RandomType`s. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + public static func choose(_ rng : (A, A)) -> Gen { + return Gen(unGen: { s, _ in + return A.randomInRange(rng, gen: s).0 + }) + } + + /// Constructs a Generator that randomly selects and uses a particular + /// generator from the given sequence of Generators. + /// + /// If control over the distribution of generators is needed, see + /// `Gen.frequency` or `Gen.weighted`. + public static func oneOf(_ gs : S) -> Gen + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType + { + assert(gs.count != 0, "oneOf used with empty list") + + return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in + return gs[x] + } + } + + /// Given a sequence of Generators and weights associated with them, this + /// function randomly selects and uses a Generator. + /// + /// Only use this function when you need to assign uneven "weights" to each + /// generator. If all generators need to have an equal chance of being + /// selected, use `Gen.oneOf`. + public static func frequency(_ xs : S) -> Gen + where S.Iterator.Element == (Int, Gen) + { + let xs: [(Int, Gen)] = Array(xs) + assert(xs.count != 0, "frequency used with empty list") + + return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in + return pick(l, xs) + } + } + + /// Given a list of values and weights associated with them, this function + /// randomly selects and uses a Generator wrapping one of the values. + /// + /// This function operates in exactly the same manner as `Gen.frequency`, + /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather + /// than only Generators. It can help in cases where your `Gen.from*` call + /// contains only `Gen.pure` calls by allowing you to remove every + /// `Gen.pure` in favor of a direct list of values. + public static func weighted(_ xs : S) -> Gen + where S.Iterator.Element == (Int, A) + { + return frequency(xs.map { ($0, Gen.pure($1)) }) + } } extension Gen /*: Cartesian*/ { - /// Zips together 2 generators of type `A` and `B` into a generator of pairs. - public static func zip(_ gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { - return Gen<(A, B)>(unGen: { r, n in - let (r1, r2) = r.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n)) - }) - } - - /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of - /// triples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { - return Gen<(A, B, C)>(unGen: { r, n in - let (r1, r2_) = r.split - let (r2, r3) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) - }) - } - - /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a - /// generator of quadruples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { - return Gen<(A, B, C, D)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1, r2) = r1_.split - let (r3, r4) = r2_.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) - }) - } - - /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a - /// generator of quintuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { - return Gen<(A, B, C, D, E)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r1) = r1_.split - let (r2, r3) = r2_.split - let (r4, r5) = r1__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) - }) - } - - /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into - /// a generator of sextuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { - return Gen<(A, B, C, D, E, F)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1, r2) = r2_.split - let (r3, r4) = r1__.split - let (r5, r6) = r2__.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) - }) - } - - /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` - /// into a generator of septuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { - return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r1) = r2_.split - let (r2, r3) = r1__.split - let (r4, r5) = r2__.split - let (r6, r7) = r1___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) - }) - } - - /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and - /// `H` into a generator of octuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { - return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1, r2) = r1__.split - let (r3, r4) = r2__.split - let (r5, r6) = r1___.split - let (r7, r8) = r2___.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) - }) - } - - /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, and `I` into a generator of nonuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { - return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r1) = r1__.split - let (r2, r3) = r2__.split - let (r4, r5) = r1___.split - let (r6, r7) = r2___.split - let (r8, r9) = r1____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) - }) - } - - /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, - /// `H`, `I`, and `J` into a generator of decuples. - public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { - return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in - let (r1_, r2_) = r.split - let (r1__, r2__) = r1_.split - let (r1___, r2___) = r2_.split - let (r1____, r2____) = r1__.split - let (r1, r2) = r2__.split - let (r3, r4) = r1___.split - let (r5, r6) = r2___.split - let (r7, r8) = r1____.split - let (r9, r10) = r2____.split - return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) - }) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// three receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// four receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// five receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// six receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// seven receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// eight receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// nine receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// ten receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) - } + /// Zips together 2 generators of type `A` and `B` into a generator of pairs. + public static func zip(_ gen1 : Gen, _ gen2 : Gen) -> Gen<(A, B)> { + return Gen<(A, B)>(unGen: { r, n in + let (r1, r2) = r.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n)) + }) + } + + /// Zips together 3 generators of type `A`, `B`, and `C` into a generator of + /// triples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen) -> Gen<(A, B, C)> { + return Gen<(A, B, C)>(unGen: { r, n in + let (r1, r2_) = r.split + let (r2, r3) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n)) + }) + } + + /// Zips together 4 generators of type `A`, `B`, `C`, and `D` into a + /// generator of quadruples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen) -> Gen<(A, B, C, D)> { + return Gen<(A, B, C, D)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1, r2) = r1_.split + let (r3, r4) = r2_.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n)) + }) + } + + /// Zips together 5 generators of type `A`, `B`, `C`, `D`, and `E` into a + /// generator of quintuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen) -> Gen<(A, B, C, D, E)> { + return Gen<(A, B, C, D, E)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r1) = r1_.split + let (r2, r3) = r2_.split + let (r4, r5) = r1__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n)) + }) + } + + /// Zips together 6 generators of type `A`, `B`, `C`, `D` `E`, and `F` into + /// a generator of sextuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen) -> Gen<(A, B, C, D, E, F)> { + return Gen<(A, B, C, D, E, F)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1, r2) = r2_.split + let (r3, r4) = r1__.split + let (r5, r6) = r2__.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n)) + }) + } + + /// Zips together 7 generators of type `A`, `B`, `C`, `D` `E`, `F`, and `G` + /// into a generator of septuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen) -> Gen<(A, B, C, D, E, F, G)> { + return Gen<(A, B, C, D, E, F, G)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r1) = r2_.split + let (r2, r3) = r1__.split + let (r4, r5) = r2__.split + let (r6, r7) = r1___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n)) + }) + } + + /// Zips together 8 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, and + /// `H` into a generator of octuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen) -> Gen<(A, B, C, D, E, F, G, H)> { + return Gen<(A, B, C, D, E, F, G, H)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1, r2) = r1__.split + let (r3, r4) = r2__.split + let (r5, r6) = r1___.split + let (r7, r8) = r2___.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n)) + }) + } + + /// Zips together 9 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, and `I` into a generator of nonuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I)> { + return Gen<(A, B, C, D, E, F, G, H, I)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r1) = r1__.split + let (r2, r3) = r2__.split + let (r4, r5) = r1___.split + let (r6, r7) = r2___.split + let (r8, r9) = r1____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n)) + }) + } + + /// Zips together 10 generators of type `A`, `B`, `C`, `D` `E`, `F`, `G`, + /// `H`, `I`, and `J` into a generator of decuples. + public static func zip(_ gen1 : Gen, _ gen2 : Gen, _ gen3 : Gen, _ gen4 : Gen, _ gen5 : Gen, _ gen6 : Gen, _ gen7 : Gen, _ gen8 : Gen, _ gen9 : Gen, _ gen10 : Gen) -> Gen<(A, B, C, D, E, F, G, H, I, J)> { + return Gen<(A, B, C, D, E, F, G, H, I, J)>(unGen: { r, n in + let (r1_, r2_) = r.split + let (r1__, r2__) = r1_.split + let (r1___, r2___) = r2_.split + let (r1____, r2____) = r1__.split + let (r1, r2) = r2__.split + let (r3, r4) = r1___.split + let (r5, r6) = r2___.split + let (r7, r8) = r1____.split + let (r9, r10) = r2____.split + return (gen1.unGen(r1, n), gen2.unGen(r2, n), gen3.unGen(r3, n), gen4.unGen(r4, n), gen5.unGen(r5, n), gen6.unGen(r6, n), gen7.unGen(r7, n), gen8.unGen(r8, n), gen9.unGen(r9, n), gen10.unGen(r10, n)) + }) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// three receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { + return zip(ga1, ga2, ga3).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// four receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// five receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// six receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// seven receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// eight receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// nine receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// ten receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4: Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + } } // MARK: Generator Modifiers extension Gen { - /// Shakes up the receiver's internal Random Number Generator with a seed. - public func variant(_ seed : S) -> Gen { - return Gen(unGen: { rng, n in - return self.unGen(vary(seed, rng), n) - }) - } - - /// Modifies a Generator to always use a given size. - public func resize(_ n : Int) -> Gen { - return Gen(unGen: { r, _ in - return self.unGen(r, n) - }) - } - - /// Modifiers a Generator's size parameter by transforming it with the given - /// function. - public func scale(_ f : @escaping (Int) -> Int) -> Gen { - return Gen.sized { n in - return self.resize(f(n)) - } - } - - /// Modifies a Generator such that it only returns values that satisfy a - /// predicate. When the predicate fails the test case is treated as though - /// it never occured. - /// - /// Because the Generator will spin until it reaches a non-failing case, - /// executing a condition that fails more often than it succeeds may result - /// in a space leak. At that point, it is better to use `suchThatOptional` - /// or `.invert` the test case. - public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { - return self.suchThatOptional(p).flatMap { mx in - switch mx { - case .some(let x): - return Gen.pure(x) - case .none: - return Gen.sized { n in - return self.suchThat(p).resize((n + 1)) - } - } - } - } - - /// Modifies a Generator such that it attempts to generate values that - /// satisfy a predicate. All attempts are encoded in the form of an - /// `Optional` where values satisfying the predicate are wrapped in `.Some` - /// and failing values are `.None`. - public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { - return Gen>.sized { n in - return attemptBoundedTry(self, 0, max(n, 1), p) - } - } - - /// Modifies a Generator such that it produces arrays with a length - /// determined by the receiver's size parameter. - public var proliferate : Gen<[A]> { - return Gen<[A]>.sized { n in - return Gen.choose((0, n)) >>- self.proliferateSized - } - } - - /// Modifies a Generator such that it produces non-empty arrays with a - /// length determined by the receiver's size parameter. - public var proliferateNonEmpty : Gen<[A]> { - return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))) >>- self.proliferateSized - } - } - - /// Modifies a Generator such that it only produces arrays of a given length. - public func proliferateSized(_ k : Int) -> Gen<[A]> { - return sequence(Array>(repeating: self, count: k)) - } + /// Shakes up the receiver's internal Random Number Generator with a seed. + public func variant(_ seed : S) -> Gen { + return Gen(unGen: { rng, n in + return self.unGen(vary(seed, rng), n) + }) + } + + /// Modifies a Generator to always use a given size. + public func resize(_ n : Int) -> Gen { + return Gen(unGen: { r, _ in + return self.unGen(r, n) + }) + } + + /// Modifiers a Generator's size parameter by transforming it with the given + /// function. + public func scale(_ f : @escaping (Int) -> Int) -> Gen { + return Gen.sized { n in + return self.resize(f(n)) + } + } + + /// Modifies a Generator such that it only returns values that satisfy a + /// predicate. When the predicate fails the test case is treated as though + /// it never occured. + /// + /// Because the Generator will spin until it reaches a non-failing case, + /// executing a condition that fails more often than it succeeds may result + /// in a space leak. At that point, it is better to use `suchThatOptional` + /// or `.invert` the test case. + public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { + return self.suchThatOptional(p).flatMap { mx in + switch mx { + case .some(let x): + return Gen.pure(x) + case .none: + return Gen.sized { n in + return self.suchThat(p).resize((n + 1)) + } + } + } + } + + /// Modifies a Generator such that it attempts to generate values that + /// satisfy a predicate. All attempts are encoded in the form of an + /// `Optional` where values satisfying the predicate are wrapped in `.Some` + /// and failing values are `.None`. + public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { + return Gen>.sized { n in + return attemptBoundedTry(self, 0, max(n, 1), p) + } + } + + /// Modifies a Generator such that it produces arrays with a length + /// determined by the receiver's size parameter. + public var proliferate : Gen<[A]> { + return Gen<[A]>.sized { n in + return Gen.choose((0, n)) >>- self.proliferateSized + } + } + + /// Modifies a Generator such that it produces non-empty arrays with a + /// length determined by the receiver's size parameter. + public var proliferateNonEmpty : Gen<[A]> { + return Gen<[A]>.sized { n in + return Gen.choose((1, max(1, n))) >>- self.proliferateSized + } + } + + /// Modifies a Generator such that it only produces arrays of a given length. + public func proliferateSized(_ k : Int) -> Gen<[A]> { + return sequence(Array>(repeating: self, count: k)) + } } // MARK: Instances extension Gen /*: Functor*/ { - /// Returns a new generator that applies a given function to any outputs the - /// receiver creates. - public func map(_ f : @escaping (A) -> B) -> Gen { - return f <^> self - } + /// Returns a new generator that applies a given function to any outputs the + /// receiver creates. + public func map(_ f : @escaping (A) -> B) -> Gen { + return f <^> self + } } /// Fmap | Returns a new generator that applies a given function to any outputs @@ -418,24 +418,24 @@ extension Gen /*: Functor*/ { /// can then use `fmap` to convert that generator of `Array`s to a generator of /// `String`s. public func <^> (f : @escaping (A) -> B, g : Gen) -> Gen { - return Gen(unGen: { r, n in - return f(g.unGen(r, n)) - }) + return Gen(unGen: { r, n in + return f(g.unGen(r, n)) + }) } extension Gen /*: Applicative*/ { - /// Lifts a value into a generator that will only generate that value. - public static func pure(_ a : A) -> Gen { - return Gen(unGen: { _ in - return a - }) - } - - /// Given a generator of functions, applies any generated function to any - /// outputs the receiver creates. - public func ap(_ fn : Gen<(A) -> B>) -> Gen { - return fn <*> self - } + /// Lifts a value into a generator that will only generate that value. + public static func pure(_ a : A) -> Gen { + return Gen(unGen: { _ in + return a + }) + } + + /// Given a generator of functions, applies any generated function to any + /// outputs the receiver creates. + public func ap(_ fn : Gen<(A) -> B>) -> Gen { + return fn <*> self + } } /// Ap | Returns a Generator that uses the first given Generator to produce @@ -454,23 +454,23 @@ extension Gen /*: Applicative*/ { /// Promotes function application to a Generator of functions applied to a /// Generator of values. public func <*> (fn : Gen<(A) -> B>, g : Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - return fn.unGen(r1, n)(g.unGen(r2, n)) - }) + return Gen(unGen: { r, n in + let (r1, r2) = r.split + return fn.unGen(r1, n)(g.unGen(r2, n)) + }) } extension Gen /*: Monad*/ { - /// Applies the function to any generated values to yield a new generator. - /// This generator is then given a new random seed and returned. - /// - /// `flatMap` allows for the creation of Generators that depend on other - /// generators. One might, for example, use a Generator of integers to - /// control the length of a Generator of strings, or use it to choose a - /// random index into a Generator of arrays. - public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { - return self >>- fn - } + /// Applies the function to any generated values to yield a new generator. + /// This generator is then given a new random seed and returned. + /// + /// `flatMap` allows for the creation of Generators that depend on other + /// generators. One might, for example, use a Generator of integers to + /// control the length of a Generator of strings, or use it to choose a + /// random index into a Generator of arrays. + public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { + return self >>- fn + } } /// Flat Map | Applies the function to any generated values to yield a new @@ -481,11 +481,11 @@ extension Gen /*: Monad*/ { /// the length of a Generator of strings, or use it to choose a random index /// into a Generator of arrays. public func >>- (m : Gen, fn : @escaping (A) -> Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - let m2 = fn(m.unGen(r1, n)) - return m2.unGen(r2, n) - }) + return Gen(unGen: { r, n in + let (r1, r2) = r.split + let m2 = fn(m.unGen(r1, n)) + return m2.unGen(r2, n) + }) } /// Creates and returns a Generator of arrays of values drawn from each @@ -495,97 +495,97 @@ public func >>- (m : Gen, fn : @escaping (A) -> Gen) -> Gen { /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(_ ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), { n, m in - return m.flatMap { x in - return n.flatMap { xs in - return Gen<[A]>.pure(xs + [x]) - } - } - }) + return ms.reduce(Gen<[A]>.pure([]), { n, m in + return m.flatMap { x in + return n.flatMap { xs in + return Gen<[A]>.pure(xs + [x]) + } + } + }) } /// Flattens a generator of generators by one level. public func join(_ rs : Gen>) -> Gen { - return rs.flatMap { x in - return x - } + return rs.flatMap { x in + return x + } } /// Lifts a function from some A to some R to a function from generators of A to /// generators of R. public func liftM(_ f : @escaping (A) -> R, _ m1 : Gen) -> Gen { - return m1.flatMap{ x1 in - return Gen.pure(f(x1)) - } + return m1.flatMap{ x1 in + return Gen.pure(f(x1)) + } } /// Promotes a rose of generators to a generator of rose values. public func promote(_ x : Rose>) -> Gen> { - return delay().flatMap { eval in - return Gen>.pure(liftM(eval, x)) - } + return delay().flatMap { eval in + return Gen>.pure(liftM(eval, x)) + } } /// Promotes a function returning generators to a generator of functions. public func promote(_ m : @escaping (A) -> Gen) -> Gen<(A) -> B> { - return delay().flatMap { eval in - return Gen<(A) -> B>.pure(eval • m) - } + return delay().flatMap { eval in + return Gen<(A) -> B>.pure(eval • m) + } } // MARK: - Implementation Details private func delay() -> Gen<(Gen) -> A> { - return Gen(unGen: { r, n in - return { g in - return g.unGen(r, n) - } - }) + return Gen(unGen: { r, n in + return { g in + return g.unGen(r, n) + } + }) } private func vary(_ k : S, _ rng : StdGen) -> StdGen { - let s = rng.split - let gen = ((k % 2) == 0) ? s.0 : s.1 - return (k == (k / 2)) ? gen : vary(k / 2, rng) + let s = rng.split + let gen = ((k % 2) == 0) ? s.0 : s.1 + return (k == (k / 2)) ? gen : vary(k / 2, rng) } private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { - if bound == 0 { - return Gen.pure(.none) - } - return gen.resize(2 * k + bound).flatMap { x in - if pred(x) { - return Gen.pure(.some(x)) - } - return attemptBoundedTry(gen, (k + 1), bound - 1, pred) - } + if bound == 0 { + return Gen.pure(.none) + } + return gen.resize(2 * k + bound).flatMap { x in + if pred(x) { + return Gen.pure(.some(x)) + } + return attemptBoundedTry(gen, (k + 1), bound - 1, pred) + } } private func size(_ k : S, _ m : Int) -> Int { - let n = Double(m) - return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) + let n = Double(m) + return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } private func selectOne(_ xs : [A]) -> [(A, [A])] { - guard let y = xs.first else { return [] } + guard let y = xs.first else { return [] } - let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) - return [(y, ys)] + rec + let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) + return [(y, ys)] + rec } private func pick(_ n : Int, _ lst : [(Int, Gen)]) -> Gen { - let (k, x) = lst[0] - let tl = Array<(Int, Gen)>(lst[1..)>(lst[1.. : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying value. - public let getBlind : A - - public init(_ blind : A) { - self.getBlind = blind - } - - /// A default short description for the blind value. - /// - /// By default, the value of this property is `(*)`. - public var description : String { - return "(*)" - } - - /// Returns a generator of `Blind` values. - public static var arbitrary : Gen> { - return Blind.init <^> A.arbitrary - } - - /// The default shrinking function for `Blind` values. - public static func shrink(_ bl : Blind) -> [Blind] { - return A.shrink(bl.getBlind).map(Blind.init) - } + /// Retrieves the underlying value. + public let getBlind : A + + public init(_ blind : A) { + self.getBlind = blind + } + + /// A default short description for the blind value. + /// + /// By default, the value of this property is `(*)`. + public var description : String { + return "(*)" + } + + /// Returns a generator of `Blind` values. + public static var arbitrary : Gen> { + return Blind.init <^> A.arbitrary + } + + /// The default shrinking function for `Blind` values. + public static func shrink(_ bl : Blind) -> [Blind] { + return A.shrink(bl.getBlind).map(Blind.init) + } } extension Blind : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Guarantees test cases for its underlying type will not be shrunk. public struct Static : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying value. - public let getStatic : A - - public init(_ fixed : A) { - self.getStatic = fixed - } - - /// A textual representation of `self`. - public var description : String { - return "Static( \(self.getStatic) )" - } - - /// Returns a generator of `Static` values. - public static var arbitrary : Gen> { - return Static.init <^> A.arbitrary - } + /// Retrieves the underlying value. + public let getStatic : A + + public init(_ fixed : A) { + self.getStatic = fixed + } + + /// A textual representation of `self`. + public var description : String { + return "Static( \(self.getStatic) )" + } + + /// Returns a generator of `Static` values. + public static var arbitrary : Gen> { + return Static.init <^> A.arbitrary + } } extension Static : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Generates an array of arbitrary values of type A. public struct ArrayOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying array of values. - public let getArray : [A] - - /// Retrieves the underlying array of values as a contiguous array. - public var getContiguousArray : ContiguousArray { - return ContiguousArray(self.getArray) - } - - public init(_ array : [A]) { - self.getArray = array - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getArray)" - } - - /// Returns a generator of `ArrayOf` values. - public static var arbitrary : Gen> { - return ArrayOf.init <^> Array.arbitrary - } - - /// The default shrinking function for an `ArrayOf` values. - public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { - return Array.shrink(bl.getArray).map(ArrayOf.init) - } + /// Retrieves the underlying array of values. + public let getArray : [A] + + /// Retrieves the underlying array of values as a contiguous array. + public var getContiguousArray : ContiguousArray { + return ContiguousArray(self.getArray) + } + + public init(_ array : [A]) { + self.getArray = array + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getArray)" + } + + /// Returns a generator of `ArrayOf` values. + public static var arbitrary : Gen> { + return ArrayOf.init <^> Array.arbitrary + } + + /// The default shrinking function for an `ArrayOf` values. + public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { + return Array.shrink(bl.getArray).map(ArrayOf.init) + } } extension ArrayOf : CoArbitrary { - public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { - let a = x.getArray - if a.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1..(_ x : ArrayOf) -> ((Gen) -> Gen) { + let a = x.getArray + if a.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1.. : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying sorted array of values. - public let getOrderedArray : [A] - - /// Retrieves the underlying sorted array of values as a contiguous - /// array. - public var getContiguousArray : ContiguousArray { - return ContiguousArray(self.getOrderedArray) - } - - public init(_ array : [A]) { - self.getOrderedArray = array.sorted() - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getOrderedArray)" - } - - /// Returns a generator for an `OrderedArrayOf` values. - public static var arbitrary : Gen> { - return OrderedArrayOf.init <^> Array.arbitrary - } - - /// The default shrinking function for an `OrderedArrayOf` values. - public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { - return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) - } + /// Retrieves the underlying sorted array of values. + public let getOrderedArray : [A] + + /// Retrieves the underlying sorted array of values as a contiguous + /// array. + public var getContiguousArray : ContiguousArray { + return ContiguousArray(self.getOrderedArray) + } + + public init(_ array : [A]) { + self.getOrderedArray = array.sorted() + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getOrderedArray)" + } + + /// Returns a generator for an `OrderedArrayOf` values. + public static var arbitrary : Gen> { + return OrderedArrayOf.init <^> Array.arbitrary + } + + /// The default shrinking function for an `OrderedArrayOf` values. + public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { + return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) + } } /// Generates an dictionary of arbitrary keys and values. public struct DictionaryOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying dictionary of values. - public let getDictionary : Dictionary - - public init(_ dict : Dictionary) { - self.getDictionary = dict - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getDictionary)" - } - - /// Returns a generator for a `DictionaryOf` values. - public static var arbitrary : Gen> { - return DictionaryOf.init <^> Dictionary.arbitrary - } - - /// The default shrinking function for a `DictionaryOf` values. - public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { - return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) - } + /// Retrieves the underlying dictionary of values. + public let getDictionary : Dictionary + + public init(_ dict : Dictionary) { + self.getDictionary = dict + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getDictionary)" + } + + /// Returns a generator for a `DictionaryOf` values. + public static var arbitrary : Gen> { + return DictionaryOf.init <^> Dictionary.arbitrary + } + + /// The default shrinking function for a `DictionaryOf` values. + public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { + return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) + } } extension DictionaryOf : CoArbitrary { - public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { - return Dictionary.coarbitrary(x.getDictionary) - } + public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { + return Dictionary.coarbitrary(x.getDictionary) + } } /// Generates an Optional of arbitrary values of type A. public struct OptionalOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying optional value. - public let getOptional : A? - - public init(_ opt : A?) { - self.getOptional = opt - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getOptional)" - } - - /// Returns a generator for `OptionalOf` values. - public static var arbitrary : Gen> { - return OptionalOf.init <^> Optional.arbitrary - } - - /// The default shrinking function for `OptionalOf` values. - public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { - return Optional.shrink(bl.getOptional).map(OptionalOf.init) - } + /// Retrieves the underlying optional value. + public let getOptional : A? + + public init(_ opt : A?) { + self.getOptional = opt + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getOptional)" + } + + /// Returns a generator for `OptionalOf` values. + public static var arbitrary : Gen> { + return OptionalOf.init <^> Optional.arbitrary + } + + /// The default shrinking function for `OptionalOf` values. + public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { + return Optional.shrink(bl.getOptional).map(OptionalOf.init) + } } extension OptionalOf : CoArbitrary { - public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { - if let _ = x.getOptional { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { + if let _ = x.getOptional { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } /// Generates a set of arbitrary values of type A. public struct SetOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying set of values. - public let getSet : Set - - public init(_ set : Set) { - self.getSet = set - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getSet)" - } - - /// Returns a generator for a `SetOf` values. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure(SetOf(Set([]))) - } - - return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) - } - } - } - - /// The default shrinking function for a `SetOf` values. - public static func shrink(_ s : SetOf) -> [SetOf] { - return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) - } + /// Retrieves the underlying set of values. + public let getSet : Set + + public init(_ set : Set) { + self.getSet = set + } + + /// A textual representation of `self`. + public var description : String { + return "\(self.getSet)" + } + + /// Returns a generator for a `SetOf` values. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure(SetOf(Set([]))) + } + + return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) + } + } + } + + /// The default shrinking function for a `SetOf` values. + public static func shrink(_ s : SetOf) -> [SetOf] { + return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) + } } extension SetOf : CoArbitrary { - public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { - if x.getSet.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } + public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { + if x.getSet.isEmpty { + return { $0.variant(0) } + } + return { $0.variant(1) } + } } /// Generates pointers of varying size of random values of type T. public struct PointerOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : PointerOfImpl - - /// Retrieves the underlying pointer value. - public var getPointer : UnsafePointer { - return UnsafePointer(self._impl.ptr!) - } - - public var size : Int { - return self._impl.size - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for a `PointerOf` values. - public static var arbitrary : Gen> { - return PointerOfImpl.arbitrary.map(PointerOf.init) - } + fileprivate let _impl : PointerOfImpl + + /// Retrieves the underlying pointer value. + public var getPointer : UnsafePointer { + return UnsafePointer(self._impl.ptr!) + } + + public var size : Int { + return self._impl.size + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for a `PointerOf` values. + public static var arbitrary : Gen> { + return PointerOfImpl.arbitrary.map(PointerOf.init) + } } /// Generates a Swift function from T to U. public struct ArrowOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : ArrowOfImpl - - /// Retrieves the underlying function value, `T -> U`. - public var getArrow : (T) -> U { - return self._impl.arr - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for an `ArrowOf` function values. - public static var arbitrary : Gen> { - return ArrowOfImpl.arbitrary.map(ArrowOf.init) - } + fileprivate let _impl : ArrowOfImpl + + /// Retrieves the underlying function value, `T -> U`. + public var getArrow : (T) -> U { + return self._impl.arr + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for an `ArrowOf` function values. + public static var arbitrary : Gen> { + return ArrowOfImpl.arbitrary.map(ArrowOf.init) + } } extension ArrowOf : CustomReflectable { - public var customMirror : Mirror { - return Mirror(self, children: [ - "types": "\(T.self) -> \(U.self)", - "currentMap": self._impl.table, - ]) - } + public var customMirror : Mirror { + return Mirror(self, children: [ + "types": "\(T.self) -> \(U.self)", + "currentMap": self._impl.table, + ]) + } } /// Generates two isomorphic Swift functions from `T` to `U` and back again. public struct IsoOf : Arbitrary, CustomStringConvertible { - fileprivate let _impl : IsoOfImpl - - /// Retrieves the underlying embedding function, `T -> U`. - public var getTo : (T) -> U { - return self._impl.embed - } - - /// Retrieves the underlying projecting function, `U -> T`. - public var getFrom : (U) -> T { - return self._impl.project - } - - /// A textual representation of `self`. - public var description : String { - return self._impl.description - } - - /// Returns a generator for an `IsoOf` function values. - public static var arbitrary : Gen> { - return IsoOfImpl.arbitrary.map(IsoOf.init) - } + fileprivate let _impl : IsoOfImpl + + /// Retrieves the underlying embedding function, `T -> U`. + public var getTo : (T) -> U { + return self._impl.embed + } + + /// Retrieves the underlying projecting function, `U -> T`. + public var getFrom : (U) -> T { + return self._impl.project + } + + /// A textual representation of `self`. + public var description : String { + return self._impl.description + } + + /// Returns a generator for an `IsoOf` function values. + public static var arbitrary : Gen> { + return IsoOfImpl.arbitrary.map(IsoOf.init) + } } extension IsoOf : CustomReflectable { - public var customMirror : Mirror { - return Mirror(self, children: [ - "embed": "\(T.self) -> \(U.self)", - "project": "\(U.self) -> \(T.self)", - "currentMap": self._impl.table, - ]) - } + public var customMirror : Mirror { + return Mirror(self, children: [ + "embed": "\(T.self) -> \(U.self)", + "project": "\(U.self) -> \(T.self)", + "currentMap": self._impl.table, + ]) + } } /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. public struct Large : Arbitrary { - /// Retrieves the underlying large value. - public let getLarge : A - - public init(_ lrg : A) { - self.getLarge = lrg - } - - /// A textual representation of `self`. - public var description : String { - return "Large( \(self.getLarge) )" - } - - /// Returns a generator of `Large` values. - public static var arbitrary : Gen> { - return Gen.choose((A.min, A.max)).map(Large.init) - } - - /// The default shrinking function for `Large` values. - public static func shrink(_ bl : Large) -> [Large] { - return bl.getLarge.shrinkIntegral.map(Large.init) - } + /// Retrieves the underlying large value. + public let getLarge : A + + public init(_ lrg : A) { + self.getLarge = lrg + } + + /// A textual representation of `self`. + public var description : String { + return "Large( \(self.getLarge) )" + } + + /// Returns a generator of `Large` values. + public static var arbitrary : Gen> { + return Gen.choose((A.min, A.max)).map(Large.init) + } + + /// The default shrinking function for `Large` values. + public static func shrink(_ bl : Large) -> [Large] { + return bl.getLarge.shrinkIntegral.map(Large.init) + } } /// Guarantees that every generated integer is greater than 0. public struct Positive : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying positive value. - public let getPositive : A - - public init(_ pos : A) { - self.getPositive = pos - } - - /// A textual representation of `self`. - public var description : String { - return "Positive( \(self.getPositive) )" - } - - /// Returns a generator of `Positive` values. - public static var arbitrary : Gen> { - return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } - } - - /// The default shrinking function for `Positive` values. - public static func shrink(_ bl : Positive) -> [Positive] { - return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) - } + /// Retrieves the underlying positive value. + public let getPositive : A + + public init(_ pos : A) { + self.getPositive = pos + } + + /// A textual representation of `self`. + public var description : String { + return "Positive( \(self.getPositive) )" + } + + /// Returns a generator of `Positive` values. + public static var arbitrary : Gen> { + return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } + } + + /// The default shrinking function for `Positive` values. + public static func shrink(_ bl : Positive) -> [Positive] { + return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) + } } extension Positive : CoArbitrary { - // Take the lazy way out. - public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { - return coarbitraryPrintable(x) - } + // Take the lazy way out. + public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { + return coarbitraryPrintable(x) + } } /// Guarantees that every generated integer is never 0. public struct NonZero : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying non-zero value. - public let getNonZero : A - - public init(_ non : A) { - self.getNonZero = non - } - - /// A textual representation of `self`. - public var description : String { - return "NonZero( \(self.getNonZero) )" - } - - /// Returns a generator of `NonZero` values. - public static var arbitrary : Gen> { - return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } - } - - /// The default shrinking function for `NonZero` values. - public static func shrink(_ bl : NonZero) -> [NonZero] { - return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) - } + /// Retrieves the underlying non-zero value. + public let getNonZero : A + + public init(_ non : A) { + self.getNonZero = non + } + + /// A textual representation of `self`. + public var description : String { + return "NonZero( \(self.getNonZero) )" + } + + /// Returns a generator of `NonZero` values. + public static var arbitrary : Gen> { + return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } + } + + /// The default shrinking function for `NonZero` values. + public static func shrink(_ bl : NonZero) -> [NonZero] { + return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) + } } extension NonZero : CoArbitrary { - public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { - return x.getNonZero.coarbitraryIntegral() - } + public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { + return x.getNonZero.coarbitraryIntegral() + } } /// Guarantees that every generated integer is greater than or equal to 0. public struct NonNegative : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying non-negative value. - public let getNonNegative : A - - public init(_ non : A) { - self.getNonNegative = non - } - - /// A textual representation of `self`. - public var description : String { - return "NonNegative( \(self.getNonNegative) )" - } - - /// Returns a generator of `NonNegative` values. - public static var arbitrary : Gen> { - return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } - } - - /// The default shrinking function for `NonNegative` values. - public static func shrink(_ bl : NonNegative) -> [NonNegative] { - return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) - } + /// Retrieves the underlying non-negative value. + public let getNonNegative : A + + public init(_ non : A) { + self.getNonNegative = non + } + + /// A textual representation of `self`. + public var description : String { + return "NonNegative( \(self.getNonNegative) )" + } + + /// Returns a generator of `NonNegative` values. + public static var arbitrary : Gen> { + return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } + } + + /// The default shrinking function for `NonNegative` values. + public static func shrink(_ bl : NonNegative) -> [NonNegative] { + return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) + } } extension NonNegative : CoArbitrary { - public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { - return x.getNonNegative.coarbitraryIntegral() - } + public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { + return x.getNonNegative.coarbitraryIntegral() + } } @@ -503,151 +503,151 @@ extension NonNegative : CoArbitrary { private func undefined() -> A { - fatalError("") + fatalError("") } fileprivate final class ArrowOfImpl : Arbitrary, CustomStringConvertible { - fileprivate var table : Dictionary - fileprivate var arr : (T) -> U - - init (_ table : Dictionary, _ arr : ((T) -> U)) { - self.table = table - self.arr = arr - } - - convenience init(_ arr : ((T) -> U)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }) - - self.arr = { [unowned self] x in - if let v = self.table[x] { - return v - } - let y = arr(x) - self.table[x] = y - return y - } - } - - var description : String { - return "\(T.self) -> \(U.self)" - } - - static var arbitrary : Gen> { - return ArrowOfImpl.init <^> promote { a in - return T.coarbitrary(a)(U.arbitrary) - } - } - - static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { - return f.table.flatMap { (x, y) in - return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in - return ArrowOfImpl({ (z : T) -> U in - if x == z { - return y2 - } - return f.arr(z) - }) - }) - } - } + fileprivate var table : Dictionary + fileprivate var arr : (T) -> U + + init (_ table : Dictionary, _ arr : ((T) -> U)) { + self.table = table + self.arr = arr + } + + convenience init(_ arr : ((T) -> U)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }) + + self.arr = { [unowned self] x in + if let v = self.table[x] { + return v + } + let y = arr(x) + self.table[x] = y + return y + } + } + + var description : String { + return "\(T.self) -> \(U.self)" + } + + static var arbitrary : Gen> { + return ArrowOfImpl.init <^> promote { a in + return T.coarbitrary(a)(U.arbitrary) + } + } + + static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { + return f.table.flatMap { (x, y) in + return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in + return ArrowOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.arr(z) + }) + }) + } + } } fileprivate final class IsoOfImpl : Arbitrary, CustomStringConvertible { - fileprivate var table : Dictionary - fileprivate var embed : (T) -> U - fileprivate var project : (U) -> T - - init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { - self.table = table - self.embed = embed - self.project = project - } - - convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - - self.embed = { [unowned self] t in - if let v = self.table[t] { - return v - } - let y = embed(t) - self.table[t] = y - return y - } - - self.project = { [unowned self] u in - let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, let _ = self.table[k] { - return k - } - let y = project(u) - self.table[y] = u - return y - } - } - - var description : String { - return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" - } - - static var arbitrary : Gen> { - return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in - return T.coarbitrary(a)(U.arbitrary) - }), promote({ a in - return U.coarbitrary(a)(T.arbitrary) - })).map(IsoOfImpl.init) - } - - static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { - return f.table.flatMap { (x, y) in - return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in - return IsoOfImpl({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) - }, { (z : U) -> T in - if y == z { - return y1 - } - return f.project(z) - }) - }) - } - } + fileprivate var table : Dictionary + fileprivate var embed : (T) -> U + fileprivate var project : (U) -> T + + init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { + self.table = table + self.embed = embed + self.project = project + } + + convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { + self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + + self.embed = { [unowned self] t in + if let v = self.table[t] { + return v + } + let y = embed(t) + self.table[t] = y + return y + } + + self.project = { [unowned self] u in + let ts = self.table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, let _ = self.table[k] { + return k + } + let y = project(u) + self.table[y] = u + return y + } + } + + var description : String { + return "IsoOf<\(T.self) -> \(U.self), \(U.self) -> \(T.self)>" + } + + static var arbitrary : Gen> { + return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in + return T.coarbitrary(a)(U.arbitrary) + }), promote({ a in + return U.coarbitrary(a)(T.arbitrary) + })).map(IsoOfImpl.init) + } + + static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { + return f.table.flatMap { (x, y) in + return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return IsoOfImpl({ (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) + }, { (z : U) -> T in + if y == z { + return y1 + } + return f.project(z) + }) + }) + } + } } private final class PointerOfImpl : Arbitrary { - var ptr : UnsafeMutablePointer? - let size : Int - - var description : String { - return "\(self.ptr)" - } - - init(_ ptr : UnsafeMutablePointer, _ size : Int) { - self.ptr = ptr - self.size = size - } - - deinit { - if self.size > 0 && self.ptr != nil { - self.ptr?.deallocate(capacity: self.size) - self.ptr = nil - } - } - - static var arbitrary : Gen> { - return Gen.sized { n in - if n <= 0 { - let size = 1 - return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) - } - let pt = UnsafeMutablePointer.allocate(capacity: n) - let gt = pt.initialize <^> sequence(Array((0..? + let size : Int + + var description : String { + return "\(self.ptr)" + } + + init(_ ptr : UnsafeMutablePointer, _ size : Int) { + self.ptr = ptr + self.size = size + } + + deinit { + if self.size > 0 && self.ptr != nil { + self.ptr?.deallocate(capacity: self.size) + self.ptr = nil + } + } + + static var arbitrary : Gen> { + return Gen.sized { n in + if n <= 0 { + let size = 1 + return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) + } + let pt = UnsafeMutablePointer.allocate(capacity: n) + let gt = pt.initialize <^> sequence(Array((0.. : Arbitrary { /// /// - seealso: Gen.compose public final class GenComposer { - private var stdgen: StdGen - private var size: Int - - init(stdgen: StdGen, size: Int) { - self.stdgen = stdgen - self.size = size - } - - // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. - private func split() -> StdGen { - let old = stdgen - stdgen = old.split.0 - return old - } - - /// Generate a new `T` with a specific generator. - /// - /// - parameter gen: The generator used to create a random value. - /// - /// - returns: A random `T` using the receiver's stdgen and size. - public func generate(using gen: Gen) -> T { - return gen.unGen(split(), size) - } - - /// Generate a new `T` with its default `arbitrary` generator. - /// - /// - returns: A random `T`. - /// - /// - seealso: generate\(gen:) - public func generate() -> T - where T: Arbitrary - { - return generate(using: T.arbitrary) - } + private var stdgen: StdGen + private var size: Int + + init(stdgen: StdGen, size: Int) { + self.stdgen = stdgen + self.size = size + } + + // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. + private func split() -> StdGen { + let old = stdgen + stdgen = old.split.0 + return old + } + + /// Generate a new `T` with a specific generator. + /// + /// - parameter gen: The generator used to create a random value. + /// + /// - returns: A random `T` using the receiver's stdgen and size. + public func generate(using gen: Gen) -> T { + return gen.unGen(split(), size) + } + + /// Generate a new `T` with its default `arbitrary` generator. + /// + /// - returns: A random `T`. + /// + /// - seealso: generate\(gen:) + public func generate() -> T + where T: Arbitrary + { + return generate(using: T.arbitrary) + } } extension Gen { - /// Create a generator by procedurally composing generated values from other generators. - /// - /// This is useful in cases where it's cumbersome to functionally compose multiple - /// generators using `zip` and `map`. For example: - /// - /// public static var arbitrary: Gen { - /// return Gen.compose { c in - /// return ArbitraryLargeFoo( - /// // use the nullary method to get an `arbitrary` value - /// a: c.generate(), - /// - /// // or pass a custom generator - /// b: c.generate(Bool.suchThat { $0 == false }), - /// - /// // .. and so on, for as many values & types as you need - /// c: c.generate(), ... - /// ) - /// } - /// } - /// - /// - parameter build: Function which is passed a GenComposer which can be used - /// - /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. - public static func compose(build: @escaping (GenComposer) -> A) -> Gen { - return Gen(unGen: { (stdgen, size) -> A in - let composer = GenComposer(stdgen: stdgen, size: size) - return build(composer) - }) - } + /// Create a generator by procedurally composing generated values from other generators. + /// + /// This is useful in cases where it's cumbersome to functionally compose multiple + /// generators using `zip` and `map`. For example: + /// + /// public static var arbitrary: Gen { + /// return Gen.compose { c in + /// return ArbitraryLargeFoo( + /// // use the nullary method to get an `arbitrary` value + /// a: c.generate(), + /// + /// // or pass a custom generator + /// b: c.generate(Bool.suchThat { $0 == false }), + /// + /// // .. and so on, for as many values & types as you need + /// c: c.generate(), ... + /// ) + /// } + /// } + /// + /// - parameter build: Function which is passed a GenComposer which can be used + /// + /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. + public static func compose(build: @escaping (GenComposer) -> A) -> Gen { + return Gen(unGen: { (stdgen, size) -> A in + let composer = GenComposer(stdgen: stdgen, size: size) + return build(composer) + }) + } } diff --git a/Sources/Operators.swift b/Sources/Operators.swift index 19681d7..a2dafaa 100644 --- a/Sources/Operators.swift +++ b/Sources/Operators.swift @@ -13,21 +13,21 @@ // MARK: Combinators precedencegroup CompositionPrecedence { - associativity: right - higherThan: BitwiseShiftPrecedence + associativity: right + higherThan: BitwiseShiftPrecedence } /// Compose | Applies one function to the result of another function to produce a third function. infix operator • : CompositionPrecedence precedencegroup RightAssociativeCombinatorPrecedence { - associativity: right - lowerThan: DefaultPrecedence + associativity: right + lowerThan: DefaultPrecedence } precedencegroup LeftAssociativeCombinatorPrecedence { - associativity: left - lowerThan: DefaultPrecedence + associativity: left + lowerThan: DefaultPrecedence } /// Apply | Applies an argument to a function. @@ -47,23 +47,23 @@ infix operator |*| : LeftAssociativeCombinatorPrecedence // MARK: Control.* precedencegroup FunctorPrecedence { - associativity: left - higherThan: DefaultPrecedence + associativity: left + higherThan: DefaultPrecedence } precedencegroup FunctorSequencePrecedence { - associativity: left - higherThan: FunctorPrecedence + associativity: left + higherThan: FunctorPrecedence } precedencegroup MonadPrecedenceLeft { - associativity: left - higherThan: FunctorSequencePrecedence + associativity: left + higherThan: FunctorSequencePrecedence } precedencegroup MonadPrecedenceRight { - associativity: right - higherThan: FunctorSequencePrecedence + associativity: right + higherThan: FunctorSequencePrecedence } /// Fmap | Maps a function over the value encapsulated by a functor. @@ -110,8 +110,8 @@ infix operator <<-<< : MonadPrecedenceRight infix operator ->> : MonadPrecedenceLeft precedencegroup FunctorExtrasPrecedence { - associativity: left - higherThan: FunctorSequencePrecedence + associativity: left + higherThan: FunctorSequencePrecedence } /// Imap | Maps covariantly over the index of a right-leaning bifunctor. @@ -123,8 +123,8 @@ infix operator : FunctorExtrasPrecedence // MARK: Data.Result precedencegroup ResultPrecedence { - associativity: none - higherThan: FunctorPrecedence + associativity: none + higherThan: FunctorPrecedence } /// From | Creates a Result given a function that can possibly fail with an error. @@ -138,8 +138,8 @@ infix operator <> : AdditionPrecedence // MARK: Control.Category precedencegroup CategoryPrecedence { - associativity: right - higherThan: MonadPrecedenceRight + associativity: right + higherThan: MonadPrecedenceRight } /// Right-to-Left Composition | Composes two categories to form a new category with the source of @@ -157,8 +157,8 @@ infix operator >>> : CategoryPrecedence // MARK: Control.Arrow precedencegroup ArrowPrecedence { - associativity: right - higherThan: CategoryPrecedence + associativity: right + higherThan: CategoryPrecedence } /// Split | Splits two computations and combines the result into one Arrow yielding a tuple of @@ -173,8 +173,8 @@ infix operator &&& : ArrowPrecedence // MARK: Control.Arrow.Choice precedencegroup ArrowChoicePrecedence { - associativity: right - higherThan: ArrowPrecedence + associativity: right + higherThan: ArrowPrecedence } /// Splat | Splits two computations and combines the results into Eithers on the left and right. @@ -187,8 +187,8 @@ infix operator ||| : ArrowChoicePrecedence // MARK: Control.Arrow.Plus precedencegroup ArrowPlusPrecedence { - associativity: right - higherThan: ArrowChoicePrecedence + associativity: right + higherThan: ArrowChoicePrecedence } /// Op | Combines two ArrowZero monoids. @@ -197,8 +197,8 @@ infix operator <+> : ArrowPlusPrecedence // MARK: Data.JSON precedencegroup JSONPrecedence { - associativity: right - higherThan: ArrowPlusPrecedence + associativity: right + higherThan: ArrowPlusPrecedence } /// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. diff --git a/Sources/Property.swift b/Sources/Property.swift index 4f68c34..1d76f77 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -17,11 +17,11 @@ /// /// When conjoining properties all calls to `expectFailure` will fail. public func conjoin(_ ps : Testable...) -> Property { - return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.map { $0.unProp } - })).flatMap({ roses in - return Gen.pure(Prop(unProp: conj(id, xs: roses))) - })) + return Property(sequence(ps.map({ (p : Testable) in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in + return Gen.pure(Prop(unProp: conj(id, xs: roses))) + })) } /// Takes the disjunction of multiple properties and reports all successes and @@ -36,11 +36,11 @@ public func conjoin(_ ps : Testable...) -> Property { /// When disjoining properties all calls to `expectFailure` will fail. You can, /// however, `invert` the property. public func disjoin(_ ps : Testable...) -> Property { - return Property(sequence(ps.map({ (p : Testable) in - return p.property.unProperty.map { $0.unProp } - })).flatMap({ roses in - return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) - })) + return Property(sequence(ps.map({ (p : Testable) in + return p.property.unProperty.map { $0.unProp } + })).flatMap({ roses in + return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) + })) } /// Takes the nondeterministic conjunction of multiple properties and treats @@ -50,236 +50,236 @@ public func disjoin(_ ps : Testable...) -> Property { /// properties. Thus, running multiple test cases will result in distinct /// arbitrary sequences of each property being tested. public func conjamb(_ ps : () -> Testable...) -> Property { - let ls = ps.lazy.map { $0().property.unProperty } - return Property(Gen.oneOf(ls)) + let ls = ps.lazy.map { $0().property.unProperty } + return Property(Gen.oneOf(ls)) } extension Testable { - /// Modifies a property so it will not shrink when it fails. - public var noShrinking : Property { - return self.mapRoseResult { rs in - return rs.onRose { res, _ in - return .mkRose({ res }, { [] }) - } - } - } - - /// Inverts the result of a test. That is, test cases that would pass now - /// fail and vice versa. - /// - /// Discarded tests remain discarded under inversion. - public var invert : Property { - return self.mapResult { res in - return TestResult(ok: res.ok.map(!) - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Modifies a property so that it only will be tested once. - public var once : Property { - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: true - , quantifier: res.quantifier) - } - } - - /// Attaches a callback to a test case. - public func withCallback(_ cb : Callback) -> Property { - return self.mapResult { (res) in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: [cb] + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Adds the given string to the counterexamples of a failing property. - public func counterexample(_ s : String) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in - return print(s) - }) - } - - /// Executes an action after the last failure of the property. - public func whenFail(_ m : @escaping () -> ()) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in - return m() - }) - } - - /// Executes an action after the every failure of the property. - /// - /// Because the action is executed after every failing test it can be used - /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(_ m : @escaping () -> ()) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in - if res.ok == .some(false) { - m() - } - }) - } - - /// Modifies a property so it prints out every generated test case and the - /// result of the property every time it is tested. - /// - /// This function maps AfterFinalFailure callbacks that have the - /// `.Counterexample` kind to `.AfterTest` callbacks. - public var verbose : Property { - func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { - let c = Callback.afterTest(kind: .counterexample) { (st, res) in - switch res.ok { - case .some(true): - print("\nPassed: ", terminator: "") - printLabels(res) - case .some(false): - print("\nFailed: ", terminator: "") - printLabels(res) - print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") - default: - print("\nDiscarded: ", terminator: "") - printLabels(res) - } - } - - return [c] + cbs.map { (c : Callback) -> Callback in - switch c { - case let .afterFinalFailure(.counterexample, f): - return .afterTest(kind: .counterexample, f: f) - default: - return c - } - } - } - - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks + chattyCallbacks(res.callbacks) - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Modifies a property to indicate that it is expected to fail. - /// - /// If the property does not fail, SwiftCheck will report an error. - public var expectFailure : Property { - return self.mapTotalResult { res in - return TestResult(ok: res.ok - , expect: false - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - - /// Attaches a label to a property. - /// - /// Labelled properties aid in testing conjunctions and disjunctions, or any - /// other cases where test cases need to be distinct from one another. In - /// addition to shrunken test cases, upon failure SwiftCheck will print a - /// distribution map for the property that shows a percentage success rate - /// for the property. - public func label(_ s : String) -> Property { - return self.classify(true, label: s) - } - - /// Labels a property with a printable value. - public func collect(_ x : A) -> Property { - return self.label(String(describing: x)) - } - - /// Conditionally labels a property with a value. - public func classify(_ b : Bool, label : String) -> Property { - return self.cover(b, percentage: 0, label: label) - } - - /// Checks that at least the given proportion of successful test cases - /// belong to the given class. - /// - /// Discarded tests (i.e. ones with a false precondition) do not affect - /// coverage. - public func cover(_ b : Bool, percentage : Int, label : String) -> Property { - if b { - return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: insertWith(max, k: label, v: percentage, m: res.labels) - , stamp: res.stamp.union([label]) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } - } - return self.property - } - - /// Applies a function that modifies the property generator's inner `Prop`. - /// - /// This function can be used to completely change the evaluation schema of - /// generated test cases by replacing the test's rose tree with a custom - /// one. - public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { - return Property(f <^> self.property.unProperty) - } - - /// Applies a function that modifies the test case generator's size. - public func mapSize(_ f : @escaping (Int) -> Int) -> Property { - return Property(Gen.sized { n in - return self.property.unProperty.resize(f(n)) - }) - } - - /// Applies a function that modifies the result of a test case. - public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { - return self.mapRoseResult { rs in - return protectResults(f <^> rs) - } - } - - /// Applies a function that modifies the result of a test case. - public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { - return self.mapRoseResult { rs in - return f <^> rs - } - } - - /// Applies a function that modifies the underlying Rose Tree that a test - /// case has generated. - public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { - return self.mapProp { t in - return Prop(unProp: f(t.unProp)) - } - } + /// Modifies a property so it will not shrink when it fails. + public var noShrinking : Property { + return self.mapRoseResult { rs in + return rs.onRose { res, _ in + return .mkRose({ res }, { [] }) + } + } + } + + /// Inverts the result of a test. That is, test cases that would pass now + /// fail and vice versa. + /// + /// Discarded tests remain discarded under inversion. + public var invert : Property { + return self.mapResult { res in + return TestResult(ok: res.ok.map(!) + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Modifies a property so that it only will be tested once. + public var once : Property { + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: true + , quantifier: res.quantifier) + } + } + + /// Attaches a callback to a test case. + public func withCallback(_ cb : Callback) -> Property { + return self.mapResult { (res) in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: [cb] + res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Adds the given string to the counterexamples of a failing property. + public func counterexample(_ s : String) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in + return print(s) + }) + } + + /// Executes an action after the last failure of the property. + public func whenFail(_ m : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in + return m() + }) + } + + /// Executes an action after the every failure of the property. + /// + /// Because the action is executed after every failing test it can be used + /// to track the list of failures generated by the shrinking mechanism. + public func whenEachFail(_ m : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in + if res.ok == .some(false) { + m() + } + }) + } + + /// Modifies a property so it prints out every generated test case and the + /// result of the property every time it is tested. + /// + /// This function maps AfterFinalFailure callbacks that have the + /// `.Counterexample` kind to `.AfterTest` callbacks. + public var verbose : Property { + func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { + let c = Callback.afterTest(kind: .counterexample) { (st, res) in + switch res.ok { + case .some(true): + print("\nPassed: ", terminator: "") + printLabels(res) + case .some(false): + print("\nFailed: ", terminator: "") + printLabels(res) + print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") + default: + print("\nDiscarded: ", terminator: "") + printLabels(res) + } + } + + return [c] + cbs.map { (c : Callback) -> Callback in + switch c { + case let .afterFinalFailure(.counterexample, f): + return .afterTest(kind: .counterexample, f: f) + default: + return c + } + } + } + + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + chattyCallbacks(res.callbacks) + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Modifies a property to indicate that it is expected to fail. + /// + /// If the property does not fail, SwiftCheck will report an error. + public var expectFailure : Property { + return self.mapTotalResult { res in + return TestResult(ok: res.ok + , expect: false + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + + /// Attaches a label to a property. + /// + /// Labelled properties aid in testing conjunctions and disjunctions, or any + /// other cases where test cases need to be distinct from one another. In + /// addition to shrunken test cases, upon failure SwiftCheck will print a + /// distribution map for the property that shows a percentage success rate + /// for the property. + public func label(_ s : String) -> Property { + return self.classify(true, label: s) + } + + /// Labels a property with a printable value. + public func collect(_ x : A) -> Property { + return self.label(String(describing: x)) + } + + /// Conditionally labels a property with a value. + public func classify(_ b : Bool, label : String) -> Property { + return self.cover(b, percentage: 0, label: label) + } + + /// Checks that at least the given proportion of successful test cases + /// belong to the given class. + /// + /// Discarded tests (i.e. ones with a false precondition) do not affect + /// coverage. + public func cover(_ b : Bool, percentage : Int, label : String) -> Property { + if b { + return self.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: insertWith(max, k: label, v: percentage, m: res.labels) + , stamp: res.stamp.union([label]) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } + } + return self.property + } + + /// Applies a function that modifies the property generator's inner `Prop`. + /// + /// This function can be used to completely change the evaluation schema of + /// generated test cases by replacing the test's rose tree with a custom + /// one. + public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { + return Property(f <^> self.property.unProperty) + } + + /// Applies a function that modifies the test case generator's size. + public func mapSize(_ f : @escaping (Int) -> Int) -> Property { + return Property(Gen.sized { n in + return self.property.unProperty.resize(f(n)) + }) + } + + /// Applies a function that modifies the result of a test case. + public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + return self.mapRoseResult { rs in + return protectResults(f <^> rs) + } + } + + /// Applies a function that modifies the result of a test case. + public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + return self.mapRoseResult { rs in + return f <^> rs + } + } + + /// Applies a function that modifies the underlying Rose Tree that a test + /// case has generated. + public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { + return self.mapProp { t in + return Prop(unProp: f(t.unProp)) + } + } } /// Using a shrinking function, shrinks a given argument to a property if it @@ -288,11 +288,11 @@ extension Testable { /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : @escaping (A) -> Testable) -> Property { - return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in - return Prop(unProp: joinRose(rs.map { x in - return x.unProp - })) - }) + return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in + return Prop(unProp: joinRose(rs.map { x in + return x.unProp + })) + }) } /// A `Callback` is a block of code that can be run after a test case has @@ -300,155 +300,155 @@ public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : /// given the state SwiftCheck ran the test case with and the result of the test /// to do with as it sees fit. public enum Callback { - /// A callback that is posted after a test case has completed. - case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) - /// The callback is posted after all cases in the test have failed. - case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + /// A callback that is posted after a test case has completed. + case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + /// The callback is posted after all cases in the test have failed. + case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { - /// Affected by the verbose combinator. - case counterexample - /// Not affected by the verbose combinator - case notCounterexample + /// Affected by the verbose combinator. + case counterexample + /// Not affected by the verbose combinator + case notCounterexample } /// The types of quantification SwiftCheck can perform. public enum Quantification { - /// Universal Quantification ("for all"). - case universal - /// Existential Quanfication ("there exists"). - case existential - /// Uniqueness Quantification ("there exists one and only one") - // case Uniqueness - /// Counting Quantification ("there exist exactly k") - // case Counting + /// Universal Quantification ("for all"). + case universal + /// Existential Quanfication ("there exists"). + case existential + /// Uniqueness Quantification ("there exists one and only one") + // case Uniqueness + /// Counting Quantification ("there exist exactly k") + // case Counting } /// A `TestResult` represents the result of performing a single test. public struct TestResult { - /// The result of executing the test case. For Discarded test cases the - /// value of this property is `.None`. - let ok : Optional - /// Indicates what the expected result of the property is. - let expect : Bool - /// A message indicating the reason a test case failed. - let reason : String - /// The exception that was thrown if one occured during testing. - let theException : Optional - /// All the labels used during the test case. - let labels : Dictionary - /// The collected values for the test case. - let stamp : Set - /// Callbacks attached to the test case. - let callbacks : [Callback] - /// Indicates that any further testing of the property should cease. - let abort : Bool - /// The quantifier being applied to this test case. - let quantifier : Quantification - - /// Provides a pattern-match-friendly view of the current state of a test - /// result. - public enum TestResultMatcher { - /// A case-able view of the current state of a test result. - case matchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification - ) - } - - /// Destructures a test case into a matcher that can be used in switch - /// statement. - public var match : TestResultMatcher { - return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) - } - - /// Creates and returns a new test result initialized with the given - /// parameters. - public init( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - , quantifier : Quantification) - { - self.ok = ok - self.expect = expect - self.reason = reason - self.theException = theException - self.labels = labels - self.stamp = stamp - self.callbacks = callbacks - self.abort = abort - self.quantifier = quantifier - } - - /// Convenience constructor for a passing `TestResult`. - public static var succeeded : TestResult { - return result(Optional.some(true)) - } - - /// Convenience constructor for a failing `TestResult`. - public static func failed(_ reason : String = "") -> TestResult { - return result(Optional.some(false), reason: reason) - } - - /// Convenience constructor for a discarded `TestResult`. - public static var rejected : TestResult { - return result(Optional.none) - } - - /// Lifts a `Bool`ean value to a TestResult by mapping true to - /// `TestResult.suceeded` and false to `TestResult.failed`. - public static func liftBool(_ b : Bool) -> TestResult { - if b { - return TestResult.succeeded - } - return result(Optional.some(false), reason: "Falsifiable") - } + /// The result of executing the test case. For Discarded test cases the + /// value of this property is `.None`. + let ok : Optional + /// Indicates what the expected result of the property is. + let expect : Bool + /// A message indicating the reason a test case failed. + let reason : String + /// The exception that was thrown if one occured during testing. + let theException : Optional + /// All the labels used during the test case. + let labels : Dictionary + /// The collected values for the test case. + let stamp : Set + /// Callbacks attached to the test case. + let callbacks : [Callback] + /// Indicates that any further testing of the property should cease. + let abort : Bool + /// The quantifier being applied to this test case. + let quantifier : Quantification + + /// Provides a pattern-match-friendly view of the current state of a test + /// result. + public enum TestResultMatcher { + /// A case-able view of the current state of a test result. + case matchResult( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : Array + , abort : Bool + , quantifier : Quantification + ) + } + + /// Destructures a test case into a matcher that can be used in switch + /// statement. + public var match : TestResultMatcher { + return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) + } + + /// Creates and returns a new test result initialized with the given + /// parameters. + public init( ok : Optional + , expect : Bool + , reason : String + , theException : Optional + , labels : Dictionary + , stamp : Set + , callbacks : [Callback] + , abort : Bool + , quantifier : Quantification) + { + self.ok = ok + self.expect = expect + self.reason = reason + self.theException = theException + self.labels = labels + self.stamp = stamp + self.callbacks = callbacks + self.abort = abort + self.quantifier = quantifier + } + + /// Convenience constructor for a passing `TestResult`. + public static var succeeded : TestResult { + return result(Optional.some(true)) + } + + /// Convenience constructor for a failing `TestResult`. + public static func failed(_ reason : String = "") -> TestResult { + return result(Optional.some(false), reason: reason) + } + + /// Convenience constructor for a discarded `TestResult`. + public static var rejected : TestResult { + return result(Optional.none) + } + + /// Lifts a `Bool`ean value to a TestResult by mapping true to + /// `TestResult.suceeded` and false to `TestResult.failed`. + public static func liftBool(_ b : Bool) -> TestResult { + if b { + return TestResult.succeeded + } + return result(Optional.some(false), reason: "Falsifiable") + } } // MARK: - Implementation Details private func exception(_ msg : String) -> (Error) -> TestResult { - return { e in TestResult.failed(String(describing: e)) } + return { e in TestResult.failed(String(describing: e)) } } private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @escaping (A) -> Testable) -> Rose> { - return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in - return props(shrinker, original: x1, pf: pf) - }}) + return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in + return props(shrinker, original: x1, pf: pf) + }}) } private func result(_ ok : Bool?, reason : String = "") -> TestResult { - return TestResult( ok: ok - , expect: true - , reason: reason - , theException: .none - , labels: [:] - , stamp: Set() - , callbacks: [] - , abort: false - , quantifier: .universal - ) + return TestResult( ok: ok + , expect: true + , reason: reason + , theException: .none + , labels: [:] + , stamp: Set() + , callbacks: [] + , abort: false + , quantifier: .universal + ) } private func protectResults(_ rs : Rose) -> Rose { - return rs.onRose { x, rs in - return .ioRose({ - return .mkRose(protectResult({ x }), { rs.map(protectResults) }) - }) - } + return rs.onRose { x, rs in + return .ioRose({ + return .mkRose(protectResult({ x }), { rs.map(protectResults) }) + }) + } } //internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { @@ -456,197 +456,197 @@ private func protectResults(_ rs : Rose) -> Rose { //} internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { - do { - return try x() - } catch let e { - return f(e) - } + do { + return try x() + } catch let e { + return f(e) + } } internal func id(_ x : A) -> A { - return x + return x } internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { - return { f(g($0)) } + return { f(g($0)) } } private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> TestResult) { - return { protect(exception("Exception"), x: r) } + return { protect(exception("Exception"), x: r) } } internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { - var map = l - r.forEach { (k, v) in - if let val = map.updateValue(v, forKey: k) { - map.updateValue(f(val, v), forKey: k) - } - } - return map + var map = l + r.forEach { (k, v) in + if let val = map.updateValue(v, forKey: k) { + map.updateValue(f(val, v), forKey: k) + } + } + return map } private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { - var res = m - let oldV = res[k] - if let existV = oldV { - res[k] = f(existV, v) - } else { - res[k] = v - } - return res + var res = m + let oldV = res[k] + if let existV = oldV { + res[k] = f(existV, v) + } else { + res[k] = v + } + return res } private func sep(_ l : String, r : String) -> String { - if l.isEmpty { - return r - } - - if r.isEmpty { - return l - } - return l + ", " + r + if l.isEmpty { + return r + } + + if r.isEmpty { + return l + } + return l + ", " + r } private func mplus(_ l : Optional, r : Optional) -> Optional { - if let ls = l, let rs = r { - return .some(ls + rs) - } + if let ls = l, let rs = r { + return .some(ls + rs) + } - if l == nil { - return r - } + if l == nil { + return r + } - return l + return l } private func addCallbacks(_ result : TestResult) -> (TestResult) -> TestResult { - return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: result.callbacks + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } + return { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: result.callbacks + res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } } private func addLabels(_ result : TestResult) -> (TestResult) -> TestResult { - return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: unionWith(max, l: res.labels, r: result.labels) - , stamp: res.stamp.union(result.stamp) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) - } + return { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: unionWith(max, l: res.labels, r: result.labels) + , stamp: res.stamp.union(result.stamp) + , callbacks: res.callbacks + , abort: res.abort + , quantifier: res.quantifier) + } } private func printLabels(_ st : TestResult) { - if st.labels.isEmpty { - print("(.)") - } else if st.labels.count == 1, let pt = st.labels.first { - print("(\(pt.0))") - } else { - let gAllLabels = st.labels.map({ (l, _) in - return l + ", " - }).reduce("", +) - print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { - if xs.isEmpty { - return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) - } else if let p = xs.first { - return .ioRose(/*protectRose*/({ - let rose = p.reduce - switch rose { - case .mkRose(let result, _): - if !result().expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) - } - - switch result().ok { - case .some(true): - return conj(addLabels(result()) • addCallbacks(result()) • k, xs: [Rose](xs[1..](xs[1..](xs[1..](xs[1.., q : Rose) -> Rose { - return p.flatMap { result1 in - if !result1.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result1.ok { - case .some(true): - return Rose.pure(result1) - case .some(false): - return q.flatMap { (result2 : TestResult) in - if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result2.ok { - case .some(true): - return Rose.pure(result2) - case .some(false): - let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, - f: { _ in - return print("") - })] - return Rose.pure(TestResult(ok: .some(false), - expect: true, - reason: sep(result1.reason, r: result2.reason), - theException: mplus(result1.theException, r: result2.theException), - labels: [:], - stamp: Set(), - callbacks: result1.callbacks + callbacks + result2.callbacks, - abort: false, - quantifier: .universal)) - case .none: - return Rose.pure(result2) - } - } - case .none: - return q.flatMap { (result2 : TestResult) in - if !result2.expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) - } - switch result2.ok { - case .some(true): - return Rose.pure(result2) - default: - return Rose.pure(result1) - } - } - } - } + return p.flatMap { result1 in + if !result1.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result1.ok { + case .some(true): + return Rose.pure(result1) + case .some(false): + return q.flatMap { (result2 : TestResult) in + if !result2.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result2.ok { + case .some(true): + return Rose.pure(result2) + case .some(false): + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, + f: { _ in + return print("") + })] + return Rose.pure(TestResult(ok: .some(false), + expect: true, + reason: sep(result1.reason, r: result2.reason), + theException: mplus(result1.theException, r: result2.theException), + labels: [:], + stamp: Set(), + callbacks: result1.callbacks + callbacks + result2.callbacks, + abort: false, + quantifier: .universal)) + case .none: + return Rose.pure(result2) + } + } + case .none: + return q.flatMap { (result2 : TestResult) in + if !result2.expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) + } + switch result2.ok { + case .some(true): + return Rose.pure(result2) + default: + return Rose.pure(result1) + } + } + } + } } diff --git a/Sources/Random.swift b/Sources/Random.swift index 7379a0a..0fcfb6b 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -10,17 +10,17 @@ /// type. It is analogous to `GeneratorType`, but rather than consume a /// sequence it uses sources of randomness to generate values indefinitely. public protocol RandomGeneneratorType { - /// The next operation returns an Int that is uniformly distributed in the - /// range returned by `genRange` (including both end points), and a new - /// generator. - var next : (Int, Self) { get } - /// The genRange operation yields the range of values returned by the - /// generator. - /// - /// This property must return integers in ascending order. - var genRange : (Int, Int) { get } - /// Splits the receiver into two distinct random value generators. - var split : (Self, Self) { get } + /// The next operation returns an Int that is uniformly distributed in the + /// range returned by `genRange` (including both end points), and a new + /// generator. + var next : (Int, Self) { get } + /// The genRange operation yields the range of values returned by the + /// generator. + /// + /// This property must return integers in ascending order. + var genRange : (Int, Int) { get } + /// Splits the receiver into two distinct random value generators. + var split : (Self, Self) { get } } /// `StdGen` represents a pseudo-random number generator. The library makes it @@ -29,322 +29,322 @@ public protocol RandomGeneneratorType { /// using the system-initialised generator or by supplying a seed from some /// other source. public struct StdGen : RandomGeneneratorType { - let seed1 : Int - let seed2 : Int - - /// Creates a `StdGen` initialized at the given seeds that is suitable for - /// replaying of tests. - public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { - self.seed1 = replaySeed1 - self.seed2 = replaySeed2 - } - - /// Convenience to create a `StdGen` from a given integer. - public init(_ o : Int) { - func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { - let s = sMaybeNegative & Int.max - let (q, s1) = (s / 2147483562, s % 2147483562) - let s2 = q % 2147483398 - return StdGen((s1 + 1), (s2 + 1)) - } - self = mkStdGen32(o) - } - - /// Returns an `Int` generated uniformly within the bounds of the generator - /// and a new distinct random number generator. - public var next : (Int, StdGen) { - let s1 = self.seed1 - let s2 = self.seed2 - - let k = s1 / 53668 - let s1_ = 40014 * (s1 - k * 53668) - k * 12211 - let s1__ = s1_ < 0 ? s1_ + 2147483563 : s1_ - - let k_ = s2 / 52774 - let s2_ = 40692 * (s2 - k_ * 52774) - k_ * 3791 - let s2__ = s2_ < 0 ? s2_ + 2147483399 : s2_ - - let z = s1__ - s2__ - let z_ = z < 1 ? z + 2147483562 : z - return (z_, StdGen(s1__, s2__)) - } - - /// Splits the receiver and returns two distinct random number generators. - public var split : (StdGen, StdGen) { - let s1 = self.seed1 - let s2 = self.seed2 - let std = self.next.1 - return (StdGen(s1 == 2147483562 ? 1 : s1 + 1, std.seed2), StdGen(std.seed1, s2 == 1 ? 2147483398 : s2 - 1)) - } - - public var genRange : (Int, Int) { - return (Int.min, Int.max) - } + let seed1 : Int + let seed2 : Int + + /// Creates a `StdGen` initialized at the given seeds that is suitable for + /// replaying of tests. + public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { + self.seed1 = replaySeed1 + self.seed2 = replaySeed2 + } + + /// Convenience to create a `StdGen` from a given integer. + public init(_ o : Int) { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen((s1 + 1), (s2 + 1)) + } + self = mkStdGen32(o) + } + + /// Returns an `Int` generated uniformly within the bounds of the generator + /// and a new distinct random number generator. + public var next : (Int, StdGen) { + let s1 = self.seed1 + let s2 = self.seed2 + + let k = s1 / 53668 + let s1_ = 40014 * (s1 - k * 53668) - k * 12211 + let s1__ = s1_ < 0 ? s1_ + 2147483563 : s1_ + + let k_ = s2 / 52774 + let s2_ = 40692 * (s2 - k_ * 52774) - k_ * 3791 + let s2__ = s2_ < 0 ? s2_ + 2147483399 : s2_ + + let z = s1__ - s2__ + let z_ = z < 1 ? z + 2147483562 : z + return (z_, StdGen(s1__, s2__)) + } + + /// Splits the receiver and returns two distinct random number generators. + public var split : (StdGen, StdGen) { + let s1 = self.seed1 + let s2 = self.seed2 + let std = self.next.1 + return (StdGen(s1 == 2147483562 ? 1 : s1 + 1, std.seed2), StdGen(std.seed1, s2 == 1 ? 2147483398 : s2 - 1)) + } + + public var genRange : (Int, Int) { + return (Int.min, Int.max) + } } extension StdGen : Equatable, CustomStringConvertible { - public var description : String { - return "\(self.seed1) \(self.seed2)" - } + public var description : String { + return "\(self.seed1) \(self.seed2)" + } } /// Equality over random number generators. /// /// Two `StdGen`s are equal iff their seeds match. public func == (l : StdGen, r : StdGen) -> Bool { - return l.seed1 == r.seed1 && l.seed2 == r.seed2 + return l.seed1 == r.seed1 && l.seed2 == r.seed2 } private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. public func newStdGen() -> StdGen { - let (left, right) = theStdGen.split - theStdGen = left - return right + let (left, right) = theStdGen.split + theStdGen = left + return right } /// Types that can generate random versions of themselves. public protocol RandomType { - /// Takes a range `(lo, hi)` and a random number generator `G`, and returns - /// a random value uniformly distributed in the closed interval `[lo,hi]`, - /// together with a new generator. It is unspecified what happens if lo>hi. - /// - /// For continuous types there is no requirement that the values `lo` and - /// `hi` are ever produced, but they may be, depending on the implementation - /// and the interval. - static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) + /// Takes a range `(lo, hi)` and a random number generator `G`, and returns + /// a random value uniformly distributed in the closed interval `[lo,hi]`, + /// together with a new generator. It is unspecified what happens if lo>hi. + /// + /// For continuous types there is no requirement that the values `lo` and + /// `hi` are ever produced, but they may be, depending on the implementation + /// and the interval. + static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) } /// Generates a random value from a LatticeType random type. public func randomBound(_ gen : G) -> (A, G) { - return A.randomInRange((A.min, A.max), gen: gen) + return A.randomInRange((A.min, A.max), gen: gen) } extension Bool : RandomType { - /// Returns a random `Bool`ean value using the given range and generator. - public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { - let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) - return (x == 1, gg) - } + /// Returns a random `Bool`ean value using the given range and generator. + public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { + let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) + return (x == 1, gg) + } } extension Character : RandomType { - /// Returns a random `Character` value using the given range and generator. - public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { - let (min, max) = range - let minc = String(min).unicodeScalars.first! - let maxc = String(max).unicodeScalars.first! - - let (val, gg) = UnicodeScalar.randomInRange((minc, maxc), gen: gen) - return (Character(val), gg) - } + /// Returns a random `Character` value using the given range and generator. + public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { + let (min, max) = range + let minc = String(min).unicodeScalars.first! + let maxc = String(max).unicodeScalars.first! + + let (val, gg) = UnicodeScalar.randomInRange((minc, maxc), gen: gen) + return (Character(val), gg) + } } extension UnicodeScalar : RandomType { - /// Returns a random `UnicodeScalar` value using the given range and generator. - public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { - let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) - return (UnicodeScalar(val)!, gg) - } + /// Returns a random `UnicodeScalar` value using the given range and generator. + public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) + return (UnicodeScalar(val)!, gg) + } } extension Int : RandomType { - /// Returns a random `Int` value using the given range and generator. - public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int` value using the given range and generator. + public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int(truncatingBitPattern: bb), gg) + } } extension Int8 : RandomType { - /// Returns a random `Int8` value using the given range and generator. - public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int8(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int8` value using the given range and generator. + public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int8(truncatingBitPattern: bb), gg) + } } extension Int16 : RandomType { - /// Returns a random `Int16` value using the given range and generator. - public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int16(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int16` value using the given range and generator. + public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int16(truncatingBitPattern: bb), gg) + } } extension Int32 : RandomType { - /// Returns a random `Int32` value using the given range and generator. - public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int32(truncatingBitPattern: bb), gg) - } + /// Returns a random `Int32` value using the given range and generator. + public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (Int32(truncatingBitPattern: bb), gg) + } } extension Int64 : RandomType { - /// Returns a random `Int64` value using the given range and generator. - public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { - let (l, h) = range - if l > h { - return Int64.randomInRange((h, l), gen: gen) - } else { - let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) - let b = Double(genhi - genlo + 1) - let q : Double = 1000 - let k = Double(h) - Double(l) + 1 - let magtgt = k * q - - func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { - if mag >= magtgt { - return (v, g) - } else { - let (x, g_) = g.next - let v_ = (v * b + (Double(x) - Double(genlo))) - return entropize(mag * b, v_, g_) - } - } - - let (v, rng_) = entropize(1, 0, gen) - return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) - } - } + /// Returns a random `Int64` value using the given range and generator. + public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { + let (l, h) = range + if l > h { + return Int64.randomInRange((h, l), gen: gen) + } else { + let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 + let magtgt = k * q + + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { + if mag >= magtgt { + return (v, g) + } else { + let (x, g_) = g.next + let v_ = (v * b + (Double(x) - Double(genlo))) + return entropize(mag * b, v_, g_) + } + } + + let (v, rng_) = entropize(1, 0, gen) + return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) + } + } } extension UInt : RandomType { - /// Returns a random `UInt` value using the given range and generator. - public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) - return (UInt(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt` value using the given range and generator. + public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) + return (UInt(truncatingBitPattern: bb), gg) + } } extension UInt8 : RandomType { - /// Returns a random `UInt8` value using the given range and generator. - public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt8(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt8` value using the given range and generator. + public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt8(truncatingBitPattern: bb), gg) + } } extension UInt16 : RandomType { - /// Returns a random `UInt16` value using the given range and generator. - public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt16(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt16` value using the given range and generator. + public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt16(truncatingBitPattern: bb), gg) + } } extension UInt32 : RandomType { - /// Returns a random `UInt32` value using the given range and generator. - public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt32(truncatingBitPattern: bb), gg) - } + /// Returns a random `UInt32` value using the given range and generator. + public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt32(truncatingBitPattern: bb), gg) + } } extension UInt64 : RandomType { - /// Returns a random `UInt64` value using the given range and generator. - public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt64(bb), gg) - } + /// Returns a random `UInt64` value using the given range and generator. + public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { + let (minl, maxl) = range + let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + return (UInt64(bb), gg) + } } extension Float : RandomType { - /// Produces a random `Float` value in the range `[Float.min, Float.max]`. - public static func random(_ rng : G) -> (Float, G) { - let (x, rng_) : (Int32, G) = randomBound(rng) - let twoto24 = Int32(2) ^ Int32(24) - let mask24 = twoto24 - 1 - - return (Float(mask24 & (x)) / Float(twoto24), rng_) - } - - /// Returns a random `Float` value using the given range and generator. - public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { - let (l, h) = range - if l > h { - return Float.randomInRange((h , l), gen: gen) - } else { - let (coef, g_) = Float.random(gen) - return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) - } - } + /// Produces a random `Float` value in the range `[Float.min, Float.max]`. + public static func random(_ rng : G) -> (Float, G) { + let (x, rng_) : (Int32, G) = randomBound(rng) + let twoto24 = Int32(2) ^ Int32(24) + let mask24 = twoto24 - 1 + + return (Float(mask24 & (x)) / Float(twoto24), rng_) + } + + /// Returns a random `Float` value using the given range and generator. + public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { + let (l, h) = range + if l > h { + return Float.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Float.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } + } } extension Double : RandomType { - /// Produces a random `Float` value in the range `[Double.min, Double.max]`. - public static func random(_ rng : G) -> (Double, G) { - let (x, rng_) : (Int64, G) = randomBound(rng) - let twoto53 = Int64(2) ^ Int64(53) - let mask53 = twoto53 - 1 - - return (Double(mask53 & (x)) / Double(twoto53), rng_) - } - - /// Returns a random `Double` value using the given range and generator. - public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { - let (l, h) = range - if l > h { - return Double.randomInRange((h , l), gen: gen) - } else { - let (coef, g_) = Double.random(gen) - return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) - } - } + /// Produces a random `Float` value in the range `[Double.min, Double.max]`. + public static func random(_ rng : G) -> (Double, G) { + let (x, rng_) : (Int64, G) = randomBound(rng) + let twoto53 = Int64(2) ^ Int64(53) + let mask53 = twoto53 - 1 + + return (Double(mask53 & (x)) / Double(twoto53), rng_) + } + + /// Returns a random `Double` value using the given range and generator. + public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { + let (l, h) = range + if l > h { + return Double.randomInRange((h , l), gen: gen) + } else { + let (coef, g_) = Double.random(gen) + return (2.0 * (0.5 * l + coef * (0.5 * h - 0.5 * l)), g_) + } + } } /// Implementation Details Follow private enum ClockTimeResult { - case success - case failure(Int) + case success + case failure(Int) } private func mkStdRNG(_ o : Int) -> StdGen { - func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { - let s = sMaybeNegative & Int.max - let (q, s1) = (s / 2147483562, s % 2147483562) - let s2 = q % 2147483398 - return StdGen(s1 + 1, s2 + 1) - } - - let ct = Int(clock()) - var tt = timespec() - switch clock_gettime(0, &tt) { - case .success: - break - case let .failure(error): - fatalError("call to `clock_gettime` failed. error: \(error)") - } - - let (sec, psec) = (tt.tv_sec, tt.tv_nsec) - let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) - return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { + let s = sMaybeNegative & Int.max + let (q, s1) = (s / 2147483562, s % 2147483562) + let s2 = q % 2147483398 + return StdGen(s1 + 1, s2 + 1) + } + + let ct = Int(clock()) + var tt = timespec() + switch clock_gettime(0, &tt) { + case .success: + break + case let .failure(error): + fatalError("call to `clock_gettime` failed. error: \(error)") + } + + let (sec, psec) = (tt.tv_sec, tt.tv_nsec) + let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) + return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> ClockTimeResult { - var now : timeval = timeval() - let rv = gettimeofday(&now, nil) - if rv != 0 { - return .failure(Int(rv)) - } - t.pointee.tv_sec = now.tv_sec - t.pointee.tv_nsec = Int(now.tv_usec) * 1000 - - return .success + var now : timeval = timeval() + let rv = gettimeofday(&now, nil) + if rv != 0 { + return .failure(Int(rv)) + } + t.pointee.tv_sec = now.tv_sec + t.pointee.tv_nsec = Int(now.tv_usec) * 1000 + + return .success } #if os(Linux) - import Glibc + import Glibc #else - import Darwin + import Darwin #endif diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 04365a3..e99a02f 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -15,103 +15,103 @@ /// In practice SwiftCheck will minimize the side-effects performed in a given /// `IORose` to printing values to the console and executing callbacks. public enum Rose { - /// A normal branch in the Rose Tree. - case mkRose(() -> A, () -> [Rose]) - /// An IO branch in the Rose Tree. That is, a branch that must execute - /// side effects before revealing further structure. - case ioRose(() -> Rose) + /// A normal branch in the Rose Tree. + case mkRose(() -> A, () -> [Rose]) + /// An IO branch in the Rose Tree. That is, a branch that must execute + /// side effects before revealing further structure. + case ioRose(() -> Rose) - /// Case analysis for a Rose Tree. - public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { - switch self { - case .mkRose(let x, let rs): - return f(x(), rs()) - case .ioRose(let m): - return .ioRose({ m().onRose(f) }) - } - } + /// Case analysis for a Rose Tree. + public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { + switch self { + case .mkRose(let x, let rs): + return f(x(), rs()) + case .ioRose(let m): + return .ioRose({ m().onRose(f) }) + } + } - /// Reduces a rose tree by evaluating all `.IORose` branches until the first - /// `.MkRose` branch is encountered. That branch is then returned. - public var reduce : Rose { - switch self { - case .mkRose(_, _): - return self - case .ioRose(let m): - return m().reduce - } - } + /// Reduces a rose tree by evaluating all `.IORose` branches until the first + /// `.MkRose` branch is encountered. That branch is then returned. + public var reduce : Rose { + switch self { + case .mkRose(_, _): + return self + case .ioRose(let m): + return m().reduce + } + } } extension Rose /*: Functor*/ { - /// Maps a function over all the nodes of a Rose Tree. - /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` branches - /// the map is suspended. - public func map(_ f : @escaping (A) -> B) -> Rose { - return f <^> self - } + /// Maps a function over all the nodes of a Rose Tree. + /// + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` branches + /// the map is suspended. + public func map(_ f : @escaping (A) -> B) -> Rose { + return f <^> self + } } /// Fmap | Maps a function over all the nodes of a Rose Tree. public func <^> (f : @escaping (A) -> B, g : Rose) -> Rose { - switch g { - case .mkRose(let root, let children): - return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) - case .ioRose(let rs): - return .ioRose({ rs().map(f) }) - } + switch g { + case .mkRose(let root, let children): + return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) + case .ioRose(let rs): + return .ioRose({ rs().map(f) }) + } } extension Rose /*: Applicative*/ { - /// Lifts a value into a Rose Tree. - public static func pure(_ a : A) -> Rose { - return .mkRose({ a }, { [] }) - } + /// Lifts a value into a Rose Tree. + public static func pure(_ a : A) -> Rose { + return .mkRose({ a }, { [] }) + } - /// Applies a Rose Tree of functions to the receiver to yield a new Rose - /// Tree of values. - /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` the branch - /// is reduced to a `.MkRose` and applied, executing all side-effects along - /// the way. - public func ap(_ fn : Rose<(A) -> B>) -> Rose { - return fn <*> self - } + /// Applies a Rose Tree of functions to the receiver to yield a new Rose + /// Tree of values. + /// + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` the branch + /// is reduced to a `.MkRose` and applied, executing all side-effects along + /// the way. + public func ap(_ fn : Rose<(A) -> B>) -> Rose { + return fn <*> self + } } /// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose /// Tree of values. public func <*> (fn : Rose<(A) -> B>, g : Rose) -> Rose { - switch fn { - case .mkRose(let f, _): - return g.map(f()) - case .ioRose(let rs): - return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW - } + switch fn { + case .mkRose(let f, _): + return g.map(f()) + case .ioRose(let rs): + return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + } } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all - /// together. - public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { - return self >>- fn - } + /// Maps the values in the receiver to Rose Trees and joins them all + /// together. + public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { + return self >>- fn + } } /// Flat Map | Maps the values in the receiver to Rose Trees and joins them all /// together. public func >>- (m : Rose, fn : @escaping (A) -> Rose) -> Rose { - return joinRose(m.map(fn)) + return joinRose(m.map(fn)) } /// Lifts functions to functions over Rose Trees. public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { - return m1.flatMap { x1 in - return Rose.pure(f(x1)) - } + return m1.flatMap { x1 in + return Rose.pure(f(x1)) + } } /// Flattens a Rose Tree of Rose Trees by a single level. @@ -122,32 +122,32 @@ public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { /// value at the sub-tree node and a recursive call to join the branch's tree to /// its sub-trees. public func joinRose(_ rs : Rose>) -> Rose { - switch rs { - case .ioRose(let rs): - return .ioRose({ joinRose(rs()) }) - case .mkRose(let bx , let rs): - switch bx() { - case .ioRose(let rm): - return .ioRose({ joinRose(.mkRose(rm, rs)) }) - case .mkRose(let x, let ts): - return .mkRose(x, { rs().map(joinRose) + ts() }) - } - } + switch rs { + case .ioRose(let rs): + return .ioRose({ joinRose(rs()) }) + case .mkRose(let bx , let rs): + switch bx() { + case .ioRose(let rm): + return .ioRose({ joinRose(.mkRose(rm, rs)) }) + case .mkRose(let x, let ts): + return .mkRose(x, { rs().map(joinRose) + ts() }) + } + } } /// Sequences an array of Rose Trees into a Rose Tree of an array. public func sequence(_ ms : [Rose]) -> Rose<[A]> { - return ms.reduce(Rose<[A]>.pure([]), { n, m in - return m.flatMap { x in - return n.flatMap { xs in - return Rose<[A]>.pure(xs + [x]) - } - } - }) + return ms.reduce(Rose<[A]>.pure([]), { n, m in + return m.flatMap { x in + return n.flatMap { xs in + return Rose<[A]>.pure(xs + [x]) + } + } + }) } /// Sequences the result of mapping values to Rose trees into a single rose tree /// of an array of values. public func mapM(_ f : (A) -> Rose, xs : [A]) -> Rose<[B]> { - return sequence(xs.map(f)) + return sequence(xs.map(f)) } diff --git a/Sources/State.swift b/Sources/State.swift index c7e2d00..b9e96f2 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -8,86 +8,86 @@ /// The internal state of the testing system. public struct CheckerState { - /// The name bound to the current property (not labels). - let name : String - /// The maximum number of successful tests before SwiftCheck gives up. - /// Defaults to 100. - let maxAllowableSuccessfulTests : Int - /// The maximum number of discarded tests before SwiftCheck gives up. - let maxAllowableDiscardedTests : Int - /// The function that generates the sizes fed to the generators for each - /// test case. - let computeSize : (Int, Int) -> Int - /// The count of the number of successful test cases seen so far. - let successfulTestCount : Int - /// The count of the number of discarded test cases seen so far. - let discardedTestCount : Int - /// A dictionary of labels collected inside the test case. Each maps to an - /// integer describing the number of passed tests. It is used in - /// conjunction with the number of successful tests to print a coverage - /// percentage. - let labels : Dictionary - /// A uniqued collection of all the labels collected during the test case. - let collected : [Set] - /// Returns whether the test case has fulfilled its expected failure - /// outcome. If the test case fails and it was expected this property - /// returns true. If the test case doesn't fail and it was not expected to - /// fail this property returns true. Only when the test case's outcome and - /// its failure fulfillment expectation do not match does this property - /// return false. - let hasFulfilledExpectedFailure : Bool - /// The Random Number Generator backing the testing session. - let randomSeedGenerator : StdGen - /// Returns the number of successful shrinking steps performed so far. - let successfulShrinkCount : Int - /// Returns the number of failed shrinking steps since the last successful - /// shrink. - let failedShrinkStepDistance : Int - /// Returns the number of failed shrink steps. - let failedShrinkStepCount : Int - /// Returns whether the testing system should cease testing altogether. - let shouldAbort : Bool - /// The quantifier being applied to this test case. - let quantifier : Quantification - /// The arguments currently being applied to the testing driver. - let arguments : CheckerArguments + /// The name bound to the current property (not labels). + let name : String + /// The maximum number of successful tests before SwiftCheck gives up. + /// Defaults to 100. + let maxAllowableSuccessfulTests : Int + /// The maximum number of discarded tests before SwiftCheck gives up. + let maxAllowableDiscardedTests : Int + /// The function that generates the sizes fed to the generators for each + /// test case. + let computeSize : (Int, Int) -> Int + /// The count of the number of successful test cases seen so far. + let successfulTestCount : Int + /// The count of the number of discarded test cases seen so far. + let discardedTestCount : Int + /// A dictionary of labels collected inside the test case. Each maps to an + /// integer describing the number of passed tests. It is used in + /// conjunction with the number of successful tests to print a coverage + /// percentage. + let labels : Dictionary + /// A uniqued collection of all the labels collected during the test case. + let collected : [Set] + /// Returns whether the test case has fulfilled its expected failure + /// outcome. If the test case fails and it was expected this property + /// returns true. If the test case doesn't fail and it was not expected to + /// fail this property returns true. Only when the test case's outcome and + /// its failure fulfillment expectation do not match does this property + /// return false. + let hasFulfilledExpectedFailure : Bool + /// The Random Number Generator backing the testing session. + let randomSeedGenerator : StdGen + /// Returns the number of successful shrinking steps performed so far. + let successfulShrinkCount : Int + /// Returns the number of failed shrinking steps since the last successful + /// shrink. + let failedShrinkStepDistance : Int + /// Returns the number of failed shrink steps. + let failedShrinkStepCount : Int + /// Returns whether the testing system should cease testing altogether. + let shouldAbort : Bool + /// The quantifier being applied to this test case. + let quantifier : Quantification + /// The arguments currently being applied to the testing driver. + let arguments : CheckerArguments - let silence : Bool + let silence : Bool - public init( name : String - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , computeSize : @escaping (Int, Int) -> Int - , successfulTestCount : Int - , discardedTestCount : Int - , labels : Dictionary - , collected : [Set] - , hasFulfilledExpectedFailure : Bool - , randomSeedGenerator : StdGen - , successfulShrinkCount : Int - , failedShrinkStepDistance : Int - , failedShrinkStepCount : Int - , shouldAbort : Bool - , quantifier : Quantification - , arguments : CheckerArguments - , silence : Bool) - { - self.name = name - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.computeSize = computeSize - self.successfulTestCount = successfulTestCount - self.discardedTestCount = discardedTestCount - self.labels = labels - self.collected = collected - self.hasFulfilledExpectedFailure = hasFulfilledExpectedFailure - self.randomSeedGenerator = randomSeedGenerator - self.successfulShrinkCount = successfulShrinkCount - self.failedShrinkStepDistance = failedShrinkStepDistance - self.failedShrinkStepCount = failedShrinkStepCount - self.shouldAbort = shouldAbort - self.quantifier = quantifier - self.arguments = arguments - self.silence = silence - } + public init( name : String + , maxAllowableSuccessfulTests : Int + , maxAllowableDiscardedTests : Int + , computeSize : @escaping (Int, Int) -> Int + , successfulTestCount : Int + , discardedTestCount : Int + , labels : Dictionary + , collected : [Set] + , hasFulfilledExpectedFailure : Bool + , randomSeedGenerator : StdGen + , successfulShrinkCount : Int + , failedShrinkStepDistance : Int + , failedShrinkStepCount : Int + , shouldAbort : Bool + , quantifier : Quantification + , arguments : CheckerArguments + , silence : Bool) + { + self.name = name + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.computeSize = computeSize + self.successfulTestCount = successfulTestCount + self.discardedTestCount = discardedTestCount + self.labels = labels + self.collected = collected + self.hasFulfilledExpectedFailure = hasFulfilledExpectedFailure + self.randomSeedGenerator = randomSeedGenerator + self.successfulShrinkCount = successfulShrinkCount + self.failedShrinkStepDistance = failedShrinkStepDistance + self.failedShrinkStepCount = failedShrinkStepCount + self.shouldAbort = shouldAbort + self.quantifier = quantifier + self.arguments = arguments + self.silence = silence + } } diff --git a/Sources/SwiftCheck.h b/Sources/SwiftCheck.h index 1c17d82..a6bd494 100644 --- a/Sources/SwiftCheck.h +++ b/Sources/SwiftCheck.h @@ -6,4 +6,3 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/Test.swift b/Sources/Test.swift index f684e13..412a645 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -98,97 +98,97 @@ /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. public func forAll(_ pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) + return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property { - return forAll { t in forAll { b in try pf(t, b) } } + return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAll { t in forAll { b, c in try pf(t, b, c) } } + return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } + return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } + return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } + return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } + return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } + return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(gen, shrinker: A.shrink, f: pf) + return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) + return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) + return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator, converts a function to a universally quantified @@ -197,7 +197,7 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { - return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) + return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified @@ -206,7 +206,7 @@ public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified @@ -215,7 +215,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escapin /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified @@ -224,7 +224,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : G /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified @@ -233,7 +233,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified @@ -242,7 +242,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ ge /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified @@ -251,7 +251,7 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified @@ -260,21 +260,21 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { - return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) + return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : @escaping (A) throws -> Testable) -> Property { - return Property(gen.flatMap { x in - return shrinking(shrinker, initial: x, prop: { xs in - do { - return (try f(xs)).counterexample(String(describing: xs)) - } catch let e { - return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) - } - }).unProperty - }) + return Property(gen.flatMap { x in + return shrinking(shrinker, initial: x, prop: { xs in + do { + return (try f(xs)).counterexample(String(describing: xs)) + } catch let e { + return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) + } + }).unProperty + }) } /// Converts a function into an existentially quantified property using the @@ -296,96 +296,96 @@ public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : /// existential value, taking any other parameters being quantified over as /// needed. public func exists(_ pf : @escaping (A) throws -> Testable) -> Property { - return exists(A.arbitrary, pf: pf) + return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { - return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: .existential) - } + return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in + return TestResult(ok: res.ok + , expect: res.expect + , reason: res.reason + , theException: res.theException + , labels: res.labels + , stamp: res.stamp + , callbacks: res.callbacks + , abort: res.abort + , quantifier: .existential) + } } /// Tests a property and prints the results to stdout. public func quickCheck(_ prop : Testable, name : String = "") { - _ = quickCheckWithResult(CheckerArguments(name: name), prop) + _ = quickCheckWithResult(CheckerArguments(name: name), prop) } // MARK: - Implementation Details internal enum Result { - case success(numTests : Int - , labels : [(String, Int)] - , output : String - ) - case gaveUp(numTests : Int - , labels : [(String,Int)] - , output : String - ) - case failure(numTests : Int - , numShrinks : Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - ) - case existentialFailure(numTests: Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - , lastResult : TestResult - ) - case noExpectedFailure(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String - ) - case insufficientCoverage(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String - ) + case success(numTests : Int + , labels : [(String, Int)] + , output : String + ) + case gaveUp(numTests : Int + , labels : [(String,Int)] + , output : String + ) + case failure(numTests : Int + , numShrinks : Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String + ) + case existentialFailure(numTests: Int + , usedSeed : StdGen + , usedSize : Int + , reason : String + , labels : [(String,Int)] + , output : String + , lastResult : TestResult + ) + case noExpectedFailure(numTests : Int + , usedSeed : StdGen + , usedSize : Int + , labels : [(String,Int)] + , output : String + ) + case insufficientCoverage(numTests : Int + , usedSeed : StdGen + , usedSize : Int + , labels : [(String,Int)] + , output : String + ) } private indirect enum Either { - case left(L) - case right(R) + case left(L) + case right(R) } internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { - let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: { computeSize(args, vals: $0) } - , successfulTestCount: 0 - , discardedTestCount: 0 - , labels: [:] - , collected: [] - , hasFulfilledExpectedFailure: false - , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() - , successfulShrinkCount: 0 - , failedShrinkStepDistance: 0 - , failedShrinkStepCount: 0 - , shouldAbort: false - , quantifier: .universal - , arguments: args - , silence: args.silence) - let modP : Property = (p.exhaustive ? p.property.once : p.property) - return test(istate, caseGen: modP.unProperty.unGen) + let istate = CheckerState(name: args.name + , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests + , computeSize: { computeSize(args, vals: $0) } + , successfulTestCount: 0 + , discardedTestCount: 0 + , labels: [:] + , collected: [] + , hasFulfilledExpectedFailure: false + , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() + , successfulShrinkCount: 0 + , failedShrinkStepDistance: 0 + , failedShrinkStepCount: 0 + , shouldAbort: false + , quantifier: .universal + , arguments: args + , silence: args.silence) + let modP : Property = (p.exhaustive ? p.property.once : p.property) + return test(istate, caseGen: modP.unProperty.unGen) } // Main Testing Loop: @@ -402,39 +402,39 @@ internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> // arguments we just give up turning the run loop to prevent excessive // generation. private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { - var state = st - while true { - switch runATest(state, caseGen: caseGen) { - case let .left(fail): - switch (fail.0, doneTesting(fail.1)) { - case (.success(_, _, _), _): - return fail.0 - case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): - return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) - // Existential Failures need explicit propagation. Existentials increment the - // discard count so we check if it has been surpassed. If it has with any kind - // of success we're done. If no successes are found we've failed checking the - // existential and report it as such. Otherwise turn the testing loop. - case (.existentialFailure(_, _, _, _, _, _, _), _): - if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { - return reportExistentialFailure(fail.1, res: fail.0) - } else { - state = fail.1 - break - } - default: - return fail.0 - } - case let .right(lsta): - if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { - return doneTesting(lsta) - } - if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { - return giveUp(lsta) - } - state = lsta - } - } + var state = st + while true { + switch runATest(state, caseGen: caseGen) { + case let .left(fail): + switch (fail.0, doneTesting(fail.1)) { + case (.success(_, _, _), _): + return fail.0 + case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): + return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) + // Existential Failures need explicit propagation. Existentials increment the + // discard count so we check if it has been surpassed. If it has with any kind + // of success we're done. If no successes are found we've failed checking the + // existential and report it as such. Otherwise turn the testing loop. + case (.existentialFailure(_, _, _, _, _, _, _), _): + if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { + return reportExistentialFailure(fail.1, res: fail.0) + } else { + state = fail.1 + break + } + default: + return fail.0 + } + case let .right(lsta): + if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { + return doneTesting(lsta) + } + if lsta.discardedTestCount >= lsta.maxAllowableDiscardedTests || lsta.shouldAbort { + return giveUp(lsta) + } + state = lsta + } + } } // Executes a single test of the property given an initial state and the @@ -443,175 +443,175 @@ private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Resul // On success the next state is returned. On failure the final result and state // are returned. private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { - let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) - let (rnd1, rnd2) = st.randomSeedGenerator.split - - // Execute the Rose Tree for the test and reduce to .MkRose. - switch caseGen(rnd1, size).unProp.reduce { - case .mkRose(let resC, let ts): - let res = resC() // Force the result only once. - dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks - - switch res.match { - // Success - case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: (st.successfulTestCount + 1) - , discardedTestCount: st.discardedTestCount - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .right(nstate) - // Discard - case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .right(nstate) - // Fail - case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): - if quantifier == .existential { - // print("") - } else if !expect { - printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") - } else { - printCond(st.silence, "*** Failed! ", terminator: "") - } - - // Failure of an existential is not necessarily failure of the whole - // test case, so treat this like a discard. - if quantifier == .existential { - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - - /// However, some existentials outlive their usefulness - if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: "Could not satisfy existential" - , labels: summary(st) - , output: "*** Failed! " - , lastResult: res) - return .left((resul, nstate)) - } - return .right(nstate) - } - - // Attempt a shrink. - let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) - - if !expect { - let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") - return .left((s, st)) - } - - let stat = Result.failure(numTests: (st.successfulTestCount + 1) - , numShrinks: numShrinks - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: res.expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .left((stat, nstate)) - } - default: - fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") - break - } + let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) + let (rnd1, rnd2) = st.randomSeedGenerator.split + + // Execute the Rose Tree for the test and reduce to .MkRose. + switch caseGen(rnd1, size).unProp.reduce { + case .mkRose(let resC, let ts): + let res = resC() // Force the result only once. + dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks + + switch res.match { + // Success + case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: (st.successfulTestCount + 1) + , discardedTestCount: st.discardedTestCount + , labels: unionWith(max, l: st.labels, r: labels) + , collected: [stamp] + st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .right(nstate) + // Discard + case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: unionWith(max, l: st.labels, r: labels) + , collected: st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .right(nstate) + // Fail + case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): + if quantifier == .existential { + // print("") + } else if !expect { + printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") + } else { + printCond(st.silence, "*** Failed! ", terminator: "") + } + + // Failure of an existential is not necessarily failure of the whole + // test case, so treat this like a discard. + if quantifier == .existential { + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + + /// However, some existentials outlive their usefulness + if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { + let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , reason: "Could not satisfy existential" + , labels: summary(st) + , output: "*** Failed! " + , lastResult: res) + return .left((resul, nstate)) + } + return .right(nstate) + } + + // Attempt a shrink. + let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) + + if !expect { + let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") + return .left((s, st)) + } + + let stat = Result.failure(numTests: (st.successfulTestCount + 1) + , numShrinks: numShrinks + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , reason: res.reason + , labels: summary(st) + , output: "*** Failed! ") + + let nstate = CheckerState(name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: (st.discardedTestCount + 1) + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: res.expect + , randomSeedGenerator: rnd2 + , successfulShrinkCount: st.successfulShrinkCount + , failedShrinkStepDistance: st.failedShrinkStepDistance + , failedShrinkStepCount: st.failedShrinkStepCount + , shouldAbort: abort + , quantifier: quantifier + , arguments: st.arguments + , silence: st.silence) + return .left((stat, nstate)) + } + default: + fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") + break + } } private func doneTesting(_ st : CheckerState) -> Result { - if !st.hasFulfilledExpectedFailure { - if insufficientCoverage(st) { - printCond(st.silence, "+++ OK, failed as expected. ") - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") - } - - printDistributionGraph(st) - return .noExpectedFailure(numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") - } else if insufficientCoverage(st) { - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .insufficientCoverage( numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") - } else { - printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) - printDistributionGraph(st) - return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") - } + if !st.hasFulfilledExpectedFailure { + if insufficientCoverage(st) { + printCond(st.silence, "+++ OK, failed as expected. ") + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") + } + + printDistributionGraph(st) + return .noExpectedFailure(numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") + } else if insufficientCoverage(st) { + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .insufficientCoverage( numTests: st.successfulTestCount + , usedSeed: st.randomSeedGenerator + , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) + , labels: summary(st) + , output: "") + } else { + printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printDistributionGraph(st) + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") + } } private func giveUp(_ st: CheckerState) -> Result { - printDistributionGraph(st) - return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") + printDistributionGraph(st) + return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of @@ -626,254 +626,254 @@ private func giveUp(_ st: CheckerState) -> Result { // a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 // megabytes for truly horrendous tests that used to eat 8 gigs. private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { - if let e = res.theException { - fatalError("Test failed due to exception: \(e)") - } - - var lastResult = res - var branches = ts - var successfulShrinkCount = st.successfulShrinkCount - var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) - var failedShrinkStepCount = st.failedShrinkStepCount - - // cont is a sanity check so we don't fall into an infinite loop. It is set - // to false at each new iteration and true when we select a new set of - // branches to test. If the branch selection doesn't change then we have - // exhausted our possibilities and so must have reached a minimal case. - var cont = true - while cont { - /// If we're out of branches we're out of options. - if branches.isEmpty { - break - } - - cont = false - failedShrinkStepDistance = 0 - - // Try all possible courses of action in this Rose Tree - branches.forEach { r in - switch r.reduce { - case .mkRose(let resC, let ts1): - let res1 = resC() - dispatchAfterTestCallbacks(st, res: res1) - - // Did we fail? Good! Failure is healthy. - // Try the next set of branches. - if res1.ok == .some(false) { - lastResult = res1 - branches = ts1() - cont = true - break - } - - // Otherwise increment the tried shrink counter and the failed - // shrink counter. - failedShrinkStepDistance = (failedShrinkStepDistance + 1) - failedShrinkStepCount = (failedShrinkStepCount + 1) - default: - fatalError("Rose should not have reduced to IO") - } - } - - successfulShrinkCount = (successfulShrinkCount + 1) - } - - let state = CheckerState( name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure - , randomSeedGenerator: st.randomSeedGenerator - , successfulShrinkCount: successfulShrinkCount - , failedShrinkStepDistance: failedShrinkStepDistance - , failedShrinkStepCount: failedShrinkStepCount - , shouldAbort: st.shouldAbort - , quantifier: st.quantifier - , arguments: st.arguments - , silence: st.silence) - return reportMinimumCaseFound(state, res: lastResult) + if let e = res.theException { + fatalError("Test failed due to exception: \(e)") + } + + var lastResult = res + var branches = ts + var successfulShrinkCount = st.successfulShrinkCount + var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) + var failedShrinkStepCount = st.failedShrinkStepCount + + // cont is a sanity check so we don't fall into an infinite loop. It is set + // to false at each new iteration and true when we select a new set of + // branches to test. If the branch selection doesn't change then we have + // exhausted our possibilities and so must have reached a minimal case. + var cont = true + while cont { + /// If we're out of branches we're out of options. + if branches.isEmpty { + break + } + + cont = false + failedShrinkStepDistance = 0 + + // Try all possible courses of action in this Rose Tree + branches.forEach { r in + switch r.reduce { + case .mkRose(let resC, let ts1): + let res1 = resC() + dispatchAfterTestCallbacks(st, res: res1) + + // Did we fail? Good! Failure is healthy. + // Try the next set of branches. + if res1.ok == .some(false) { + lastResult = res1 + branches = ts1() + cont = true + break + } + + // Otherwise increment the tried shrink counter and the failed + // shrink counter. + failedShrinkStepDistance = (failedShrinkStepDistance + 1) + failedShrinkStepCount = (failedShrinkStepCount + 1) + default: + fatalError("Rose should not have reduced to IO") + } + } + + successfulShrinkCount = (successfulShrinkCount + 1) + } + + let state = CheckerState( name: st.name + , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests + , computeSize: st.computeSize + , successfulTestCount: st.successfulTestCount + , discardedTestCount: st.discardedTestCount + , labels: st.labels + , collected: st.collected + , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure + , randomSeedGenerator: st.randomSeedGenerator + , successfulShrinkCount: successfulShrinkCount + , failedShrinkStepDistance: failedShrinkStepDistance + , failedShrinkStepCount: failedShrinkStepCount + , shouldAbort: st.shouldAbort + , quantifier: st.quantifier + , arguments: st.arguments + , silence: st.silence) + return reportMinimumCaseFound(state, res: lastResult) } private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \((st.successfulTestCount + 1)) test" - let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" + let testMsg = " (after \((st.successfulTestCount + 1)) test" + let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" - printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") - dispatchAfterFinalFailureCallbacks(st, res: res) - return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + dispatchAfterFinalFailureCallbacks(st, res: res) + return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result { - switch res { - case let .existentialFailure(_, _, _, reason, _, _, lastTest): - let testMsg = " (after \(st.discardedTestCount) test" + switch res { + case let .existentialFailure(_, _, _, reason, _, _, lastTest): + let testMsg = " (after \(st.discardedTestCount) test" - printCond(st.silence, "*** Failed! ", terminator: "") - printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") - dispatchAfterFinalFailureCallbacks(st, res: lastTest) - return res - default: - fatalError("Cannot report existential failure on non-failure type \(res)") - } + printCond(st.silence, "*** Failed! ", terminator: "") + printCond(st.silence, "Proposition: " + st.name) + printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") + dispatchAfterFinalFailureCallbacks(st, res: lastTest) + return res + default: + fatalError("Cannot report existential failure on non-failure type \(res)") + } } private func dispatchAfterTestCallbacks(_ st : CheckerState, res : TestResult) { - guard !st.silence else { - return - } + guard !st.silence else { + return + } - res.callbacks.forEach { c in - switch c { - case let .afterTest(_, f): - f(st, res) - default: - break - } - } + res.callbacks.forEach { c in + switch c { + case let .afterTest(_, f): + f(st, res) + default: + break + } + } } private func dispatchAfterFinalFailureCallbacks(_ st : CheckerState, res : TestResult) { - guard !st.silence else { - return - } + guard !st.silence else { + return + } - res.callbacks.forEach { c in - switch c { - case let .afterFinalFailure(_, f): - f(st, res) - default: - break - } - } + res.callbacks.forEach { c in + switch c { + case let .afterFinalFailure(_, f): + f(st, res) + default: + break + } + } } private func summary(_ s : CheckerState) -> [(String, Int)] { - let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) - let l : [[String]] = lff.sorted().groupBy(==) - return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } + let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) + let l : [[String]] = lff.sorted().groupBy(==) + return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } private func labelPercentage(_ l : String, st : CheckerState) -> Int { - let occur = st.collected.flatMap(Array.init).filter { $0 == l } - return (100 * occur.count) / st.maxAllowableSuccessfulTests + let occur = st.collected.flatMap(Array.init).filter { $0 == l } + return (100 * occur.count) / st.maxAllowableSuccessfulTests } private func printDistributionGraph(_ st : CheckerState) { - func showP(_ n : Int) -> String { - return (n < 10 ? " " : "") + "\(n)" + "%" - } - - let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) - }) - let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) - let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) - let allLabels : [String] = Array(gPrint.sorted().reversed()) - - var covers = [String]() - st.labels.forEach { (l, reqP) in - let p = labelPercentage(l, st: st) - if p < reqP { - covers += ["only \(p)% " + l + ", not \(reqP)%"] - } - } - - let all = covers + allLabels - if all.isEmpty { - printCond(st.silence, ".") - } else if all.count == 1, let pt = all.first { - printCond(st.silence, "(\(pt))") - } else { - printCond(st.silence, ":") - all.forEach { pt in - printCond(st.silence, pt) - } - } + func showP(_ n : Int) -> String { + return (n < 10 ? " " : "") + "\(n)" + "%" + } + + let gAllLabels : [String] = st.collected.map({ (s : Set) in + return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) + }) + let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) + let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) + let allLabels : [String] = Array(gPrint.sorted().reversed()) + + var covers = [String]() + st.labels.forEach { (l, reqP) in + let p = labelPercentage(l, st: st) + if p < reqP { + covers += ["only \(p)% " + l + ", not \(reqP)%"] + } + } + + let all = covers + allLabels + if all.isEmpty { + printCond(st.silence, ".") + } else if all.count == 1, let pt = all.first { + printCond(st.silence, "(\(pt))") + } else { + printCond(st.silence, ":") + all.forEach { pt in + printCond(st.silence, pt) + } + } } private func pluralize(_ s : String, i : Int) -> String { - if i == 1 { - return s - } - return s + "s" + if i == 1 { + return s + } + return s + "s" } private func insufficientCoverage(_ st : CheckerState) -> Bool { - return st.labels - .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) - .reduce(false, { $0 || $1 }) + return st.labels + .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) + .reduce(false, { $0 || $1 }) } private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n") { - if !cond { - print(str, terminator: terminator) - } + if !cond { + print(str, terminator: terminator) + } } extension Array { - fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { - var result = [[Element]]() - var accumulator = [Element]() - self.forEach { current in - if let prev = accumulator.last { - if p(prev, current) { - accumulator.append(current) - } else { - result.append(accumulator) - accumulator = [ current ] - } - } else { - return accumulator.append(current) - } - } - if !accumulator.isEmpty { - result.append(accumulator); - } - return result - } + fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { + var result = [[Element]]() + var accumulator = [Element]() + self.forEach { current in + if let prev = accumulator.last { + if p(prev, current) { + accumulator.append(current) + } else { + result.append(accumulator) + accumulator = [ current ] + } + } else { + return accumulator.append(current) + } + } + if !accumulator.isEmpty { + result.append(accumulator); + } + return result + } } /// Testing loop stuff private func computeSize(_ args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { - func computeSize_(_ successes : Int, _ discards : Int) -> Int { - func roundTo(_ n : Int, _ m : Int) -> Int { - return (n / m) * m - } - - if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else if successes >= args.maxAllowableSuccessfulTests { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else if args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { - return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) - } else { - return min((successes % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + discards / 10, args.maxTestCaseSize) - } - } - - func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { - if successes == 0 && discards == 0 { - return defaultSize - } else { - return computeSize(successes, discards) - } - } - - - if let (_, argSize) = args.replay { - return initialSizeForTest( argSize - , successes: vals.successes - , discards: vals.discards - , computeSize: computeSize_ - ) - } - return computeSize_(vals.successes, vals.discards) + func computeSize_(_ successes : Int, _ discards : Int) -> Int { + func roundTo(_ n : Int, _ m : Int) -> Int { + return (n / m) * m + } + + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if successes >= args.maxAllowableSuccessfulTests { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else if args.maxAllowableSuccessfulTests % args.maxTestCaseSize == 0 { + return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) + } else { + return min((successes % args.maxTestCaseSize) * args.maxTestCaseSize / (args.maxAllowableSuccessfulTests % args.maxTestCaseSize) + discards / 10, args.maxTestCaseSize) + } + } + + func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + if successes == 0 && discards == 0 { + return defaultSize + } else { + return computeSize(successes, discards) + } + } + + + if let (_, argSize) = args.replay { + return initialSizeForTest( argSize + , successes: vals.successes + , discards: vals.discards + , computeSize: computeSize_ + ) + } + return computeSize_(vals.successes, vals.discards) } diff --git a/Sources/TestOperators.swift b/Sources/TestOperators.swift index c8e8f31..a0dd515 100644 --- a/Sources/TestOperators.swift +++ b/Sources/TestOperators.swift @@ -34,152 +34,152 @@ /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that uses XCTest to assert all testing failures and /// display them in both the testing log and Xcode. public struct AssertiveQuickCheck { - fileprivate let msg : String - fileprivate let file : StaticString - fileprivate let line : UInt - fileprivate let args : CheckerArguments - - fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) + return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that only reports failures to the testing log but does /// not assert when a property fails. public struct ReportiveQuickCheck { - fileprivate let msg : String - fileprivate let file : StaticString - fileprivate let line : UInt - fileprivate let args : CheckerArguments - - fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { - self.msg = msg - self.file = file - self.line = line - self.args = { var chk = args; chk.name = msg; return chk }() - } + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + self.msg = msg + self.file = file + self.line = line + self.args = { var chk = args; chk.name = msg; return chk }() + } } /// Represents the arguments the test driver will use while performing testing, /// shrinking, and printing results. public struct CheckerArguments { - /// Provides a way of re-doing a test at the given size with a new generator. - let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself - /// passes. - /// - /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` - /// on the property instead. - let maxAllowableSuccessfulTests : Int - /// The maximum number of tests cases that can be discarded before testing gives up on the - /// property. - /// - /// The default value of this property is 500. In general, most tests will require less than - /// this amount. `Discard`ed test cases do not affect the passing or failing status of the - /// property as a whole. - let maxAllowableDiscardedTests : Int - /// The limit to the size of all generators in the test. - /// - /// The default value of this property is 100. If "large" values, in magnitude or - /// size, are necessary then increase this value, else keep it relatively near the default. If - /// it becomes too small the samples present in the test case will lose diversity. - let maxTestCaseSize : Int - - internal let silence : Bool - - public init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - ) - { - self = CheckerArguments( replay: replay - , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: maxAllowableDiscardedTests - , maxTestCaseSize: maxTestCaseSize - , name: "" - ) - } - - internal init(replay : Optional<(StdGen, Int)> = nil - , maxAllowableSuccessfulTests : Int = 100 - , maxAllowableDiscardedTests : Int = 500 - , maxTestCaseSize : Int = 100 - , name : String - , silence : Bool = false - ) - { - - self.replay = replay - self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests - self.maxAllowableDiscardedTests = maxAllowableDiscardedTests - self.maxTestCaseSize = maxTestCaseSize - self.name = name - self.silence = silence - } - - internal var name : String + /// Provides a way of re-doing a test at the given size with a new generator. + let replay : Optional<(StdGen, Int)> + /// The maximum number of test cases that must pass before the property itself + /// passes. + /// + /// The default value of this property is 100. In general, some tests may require more than + /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// on the property instead. + let maxAllowableSuccessfulTests : Int + /// The maximum number of tests cases that can be discarded before testing gives up on the + /// property. + /// + /// The default value of this property is 500. In general, most tests will require less than + /// this amount. `Discard`ed test cases do not affect the passing or failing status of the + /// property as a whole. + let maxAllowableDiscardedTests : Int + /// The limit to the size of all generators in the test. + /// + /// The default value of this property is 100. If "large" values, in magnitude or + /// size, are necessary then increase this value, else keep it relatively near the default. If + /// it becomes too small the samples present in the test case will lose diversity. + let maxTestCaseSize : Int + + internal let silence : Bool + + public init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + ) + { + self = CheckerArguments( replay: replay + , maxAllowableSuccessfulTests: maxAllowableSuccessfulTests + , maxAllowableDiscardedTests: maxAllowableDiscardedTests + , maxTestCaseSize: maxTestCaseSize + , name: "" + ) + } + + internal init(replay : Optional<(StdGen, Int)> = nil + , maxAllowableSuccessfulTests : Int = 100 + , maxAllowableDiscardedTests : Int = 500 + , maxTestCaseSize : Int = 100 + , name : String + , silence : Bool = false + ) + { + + self.replay = replay + self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests + self.maxAllowableDiscardedTests = maxAllowableDiscardedTests + self.maxTestCaseSize = maxTestCaseSize + self.name = name + self.silence = silence + } + + internal var name : String } infix operator <- /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () -> Testable) { - switch quickCheckWithResult(checker.args, test()) { - case let .failure(_, _, seed, sz, reason, _, _): - XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .noExpectedFailure(_, seed, sz, _, _): - XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return - } + switch quickCheckWithResult(checker.args, test()) { + case let .failure(_, _, seed, sz, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .noExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .insufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + default: + return + } } /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { - switch quickCheckWithResult(checker.args, test()) { - case let .failure(_, _, seed, sz, reason, _, _): - XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .noExpectedFailure(_, seed, sz, _, _): - XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return - } + switch quickCheckWithResult(checker.args, test()) { + case let .failure(_, _, seed, sz, reason, _, _): + XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .noExpectedFailure(_, seed, sz, _, _): + XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + case let .insufficientCoverage(_, seed, sz, _, _): + XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + default: + return + } } /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { - _ = quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () -> Testable) { - _ = quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } precedencegroup SwiftCheckImplicationPrecedence { - associativity: right - lowerThan: ComparisonPrecedence + associativity: right + lowerThan: ComparisonPrecedence } infix operator ==> : SwiftCheckImplicationPrecedence @@ -188,34 +188,34 @@ infix operator ==> : SwiftCheckImplicationPrecedence /// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : @autoclosure() -> Testable) -> Property { - if b { - return p().property - } - return Discard().property + if b { + return p().property + } + return Discard().property } /// Models implication for properties. That is, the property holds if the first /// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : () -> Testable) -> Property { - if b { - return p().property - } - return Discard().property + if b { + return p().property + } + return Discard().property } infix operator ==== : ComparisonPrecedence /// Like equality but prints a verbose description when it fails. public func ==== (x : A, y : A) -> Property - where A : Equatable + where A : Equatable { - return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) + return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) } precedencegroup SwiftCheckLabelPrecedence { - associativity: right - higherThan: BitwiseShiftPrecedence + associativity: right + higherThan: BitwiseShiftPrecedence } infix operator : SwiftCheckLabelPrecedence @@ -228,13 +228,13 @@ infix operator : SwiftCheckLabelPrecedence /// distribution map for the property that shows a percentage success rate for /// the property. public func (p : Testable, s : String) -> Property { - return p.label(s) + return p.label(s) } precedencegroup SwiftCheckLogicalPrecedence { - associativity: left - higherThan: LogicalConjunctionPrecedence - lowerThan: ComparisonPrecedence + associativity: left + higherThan: LogicalConjunctionPrecedence + lowerThan: ComparisonPrecedence } infix operator ^&&^ : SwiftCheckLogicalPrecedence @@ -245,7 +245,7 @@ infix operator ^&&^ : SwiftCheckLogicalPrecedence /// Conjoined properties succeed only when both sub-properties succeed and fail /// when one or more sub-properties fail. public func ^&&^ (p1 : Testable, p2 : Testable) -> Property { - return conjoin(p1.property, p2.property) + return conjoin(p1.property, p2.property) } @@ -257,7 +257,7 @@ infix operator ^||^ : SwiftCheckLogicalPrecedence /// Disjoined properties succeed only when one or more sub-properties succeed /// and fail when both sub-properties fail. public func ^||^ (p1 : Testable, p2 : Testable) -> Property { - return disjoin(p1.property, p2.property) + return disjoin(p1.property, p2.property) } import XCTest diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 88975f4..a6158c2 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -16,36 +16,36 @@ /// and `Property`. The last of these enables `forAll`s to return further /// `forAll`s that can depend on previously generated values. public protocol Testable { - /// Returns true iff a single test case is exhaustive i.e. adequately covers - /// the search space. - /// - /// If true, the property will only be tested once. Defaults to false. - var exhaustive : Bool { get } - - /// Returns a `Property`, which SwiftCheck uses to perform test case - /// generation. - var property : Property { get } + /// Returns true iff a single test case is exhaustive i.e. adequately covers + /// the search space. + /// + /// If true, the property will only be tested once. Defaults to false. + var exhaustive : Bool { get } + + /// Returns a `Property`, which SwiftCheck uses to perform test case + /// generation. + var property : Property { get } } extension Testable { - /// By default, all `Testable` types are non-exhaustive. - public var exhaustive : Bool { - return false - } + /// By default, all `Testable` types are non-exhaustive. + public var exhaustive : Bool { + return false + } } /// A property is anything that generates `Prop`s. public struct Property : Testable { - let unProperty : Gen + let unProperty : Gen - public init(_ val : Gen) { - self.unProperty = val - } + public init(_ val : Gen) { + self.unProperty = val + } - /// Yields self. - public var property : Property { - return self - } + /// Yields self. + public var property : Property { + return self + } } /// A `Prop` describes a strategy for evaluating a test case to a final @@ -56,56 +56,56 @@ public struct Property : Testable { /// As a testable value, it creates a Property that generates only its testing /// tree. public struct Prop : Testable { - var unProp : Rose + var unProp : Rose - /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive - /// property tests. - public var exhaustive : Bool { return true } + /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive + /// property tests. + public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. - public var property : Property { - // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) - return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) - } + /// Returns a property that tests the receiver. + public var property : Property { + // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) + return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) + } } /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { - /// `Discard`s are trivially exhaustive. - public var exhaustive : Bool { return true } + /// `Discard`s are trivially exhaustive. + public var exhaustive : Bool { return true } - /// Create a `Discard` suitable for - public init() { } + /// Create a `Discard` suitable for + public init() { } - /// Returns a property that always rejects whatever result occurs. - public var property : Property { - return TestResult.rejected.property - } + /// Returns a property that always rejects whatever result occurs. + public var property : Property { + return TestResult.rejected.property + } } extension TestResult : Testable { - /// `TestResult`s are trivially exhaustive. - public var exhaustive : Bool { return true } + /// `TestResult`s are trivially exhaustive. + public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. - public var property : Property { - return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) - } + /// Returns a property that tests the receiver. + public var property : Property { + return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) + } } extension Bool : Testable { - /// `Bool`ean values are trivially exhaustive. - public var exhaustive : Bool { return true } - - /// Returns a property that evaluates to a test success if the receiver is - /// `true`, else returns a property that evaluates to a test failure. - public var property : Property { - return TestResult.liftBool(self).property - } + /// `Bool`ean values are trivially exhaustive. + public var exhaustive : Bool { return true } + + /// Returns a property that evaluates to a test success if the receiver is + /// `true`, else returns a property that evaluates to a test failure. + public var property : Property { + return TestResult.liftBool(self).property + } } extension Gen /*: Testable*/ where A : Testable { - public var property : Property { - return Property(self >>- { $0.property.unProperty }) - } + public var property : Property { + return Property(self >>- { $0.property.unProperty }) + } } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index 2e804a8..a110363 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -56,74 +56,74 @@ /// } /// } public protocol WitnessedArbitrary { - /// The witnessing type parameter. - associatedtype Param + /// The witnessing type parameter. + associatedtype Param - /// A property test that relies on a witness that the given type parameter - /// is actually `Arbitrary`. - static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property + /// A property test that relies on a witness that the given type parameter + /// is actually `Arbitrary`. + static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. public func forAll(_ pf : ((A) -> Testable)) -> Property - where A.Param : Arbitrary + where A.Param : Arbitrary { - return A.forAllWitnessed(id, pf: pf) + return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary { - return forAll { t in forAll { b in pf(t, b) } } + return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary { - return forAll { t in forAll { b, c in pf(t, b, c) } } + return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary { - return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } + return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } + return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } + return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } + return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary { - return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } + return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 791bd4d..b3eb5f5 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -7,351 +7,351 @@ // extension Array where Element : Arbitrary { - /// Returns a generator of `Array`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure([]) - } - - return sequence((0...k).map { _ in Element.arbitrary }) - } - } - } - - /// The default shrinking function for `Array`s of arbitrary `Element`s. - public static func shrink(_ bl : Array) -> [[Element]] { - let rec : [[Element]] = shrinkOne(bl) - return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec - } + /// Returns a generator of `Array`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure([]) + } + + return sequence((0...k).map { _ in Element.arbitrary }) + } + } + } + + /// The default shrinking function for `Array`s of arbitrary `Element`s. + public static func shrink(_ bl : Array) -> [[Element]] { + let rec : [[Element]] = shrinkOne(bl) + return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec + } } extension Array : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Array`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { - return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in - return pf(bl.map(wit)) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Array`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { + return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in + return pf(bl.map(wit)) + }) + } } extension AnyBidirectionalCollection where Element : Arbitrary { - /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return AnyBidirectionalCollection.init <^> [Element].arbitrary - } - - /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { - return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) - } + /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return AnyBidirectionalCollection.init <^> [Element].arbitrary + } + + /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. + public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) + } } extension AnyBidirectionalCollection : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { - return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in - return pf(AnyBidirectionalCollection(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnyBidirectionalCollection`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { + return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in + return pf(AnyBidirectionalCollection(bl.map(wit))) + }) + } } extension AnySequence where Element : Arbitrary { - /// Returns a generator of `AnySequence`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return AnySequence.init <^> [Element].arbitrary - } - - /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. - public static func shrink(_ bl : AnySequence) -> [AnySequence] { - return [Element].shrink([Element](bl)).map(AnySequence.init) - } + /// Returns a generator of `AnySequence`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return AnySequence.init <^> [Element].arbitrary + } + + /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. + public static func shrink(_ bl : AnySequence) -> [AnySequence] { + return [Element].shrink([Element](bl)).map(AnySequence.init) + } } extension AnySequence : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnySequence`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { - return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in - return pf(AnySequence(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `AnySequence`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { + return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in + return pf(AnySequence(bl.map(wit))) + }) + } } extension ArraySlice where Element : Arbitrary { - /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return ArraySlice.init <^> [Element].arbitrary - } - - /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. - public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { - return [Element].shrink([Element](bl)).map(ArraySlice.init) - } + /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return ArraySlice.init <^> [Element].arbitrary + } + + /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. + public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { + return [Element].shrink([Element](bl)).map(ArraySlice.init) + } } extension ArraySlice : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { - return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in - return pf(ArraySlice(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ArraySlice`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { + return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in + return pf(ArraySlice(bl.map(wit))) + }) + } } extension CollectionOfOne where Element : Arbitrary { - /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return CollectionOfOne.init <^> Element.arbitrary - } + /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return CollectionOfOne.init <^> Element.arbitrary + } } extension CollectionOfOne : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { - return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in - return pf(CollectionOfOne(wit(bl[bl.startIndex]))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `CollectionOfOne`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { + return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in + return pf(CollectionOfOne(wit(bl[bl.startIndex]))) + }) + } } /// Generates an Optional of arbitrary values of type A. extension Optional where Wrapped : Arbitrary { - /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. - public static var arbitrary : Gen> { - return Gen>.frequency([ - (1, Gen>.pure(.none)), - (3, liftM(Optional.some, Wrapped.arbitrary)), - ]) - } - - /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. - public static func shrink(_ bl : Optional) -> [Optional] { - if let x = bl { - let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) - return [.none] + rec - } - return [] - } + /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. + public static var arbitrary : Gen> { + return Gen>.frequency([ + (1, Gen>.pure(.none)), + (3, liftM(Optional.some, Wrapped.arbitrary)), + ]) + } + + /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. + public static func shrink(_ bl : Optional) -> [Optional] { + if let x = bl { + let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) + return [.none] + rec + } + return [] + } } extension Optional : WitnessedArbitrary { - public typealias Param = Wrapped - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Optional`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { - return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } + public typealias Param = Wrapped + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Optional`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { + return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in + return pf(bl.map(wit)) + }) + } } extension ContiguousArray where Element : Arbitrary { - /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return ContiguousArray.init <^> [Element].arbitrary - } - - /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. - public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { - return [Element].shrink([Element](bl)).map(ContiguousArray.init) - } + /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return ContiguousArray.init <^> [Element].arbitrary + } + + /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. + public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { + return [Element].shrink([Element](bl)).map(ContiguousArray.init) + } } extension ContiguousArray : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { - return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in - return pf(ContiguousArray(bl.map(wit))) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `ContiguousArray`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { + return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in + return pf(ContiguousArray(bl.map(wit))) + }) + } } /// Generates an dictionary of arbitrary keys and values. extension Dictionary where Key : Arbitrary, Value : Arbitrary { - /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. - public static var arbitrary : Gen> { - return [Key].arbitrary.flatMap { (k : [Key]) in - return [Value].arbitrary.flatMap { (v : [Value]) in - return Gen.pure(Dictionary(zip(k, v))) - } - } - } - - /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and - /// `Value`s. - public static func shrink(_ d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in - (key: k, value: v) - })) } - } + /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. + public static var arbitrary : Gen> { + return [Key].arbitrary.flatMap { (k : [Key]) in + return [Value].arbitrary.flatMap { (v : [Value]) in + return Gen.pure(Dictionary(zip(k, v))) + } + } + } + + /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and + /// `Value`s. + public static func shrink(_ d : Dictionary) -> [Dictionary] { + return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in + (key: k, value: v) + })) } + } } extension EmptyCollection : Arbitrary { - /// Returns a generator of `EmptyCollection`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.pure(EmptyCollection()) - } + /// Returns a generator of `EmptyCollection`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.pure(EmptyCollection()) + } } extension Range where Bound : Comparable & Arbitrary { - /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. - public static var arbitrary : Gen> { - return Bound.arbitrary.flatMap { l in - return Bound.arbitrary.flatMap { r in - return Gen.pure((min(l, r) ..< max(l, r))) - } - } - } - - /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. - public static func shrink(_ bl : Range) -> [Range] { - return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) - } + /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. + public static var arbitrary : Gen> { + return Bound.arbitrary.flatMap { l in + return Bound.arbitrary.flatMap { r in + return Gen.pure((min(l, r) ..< max(l, r))) + } + } + } + + /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. + public static func shrink(_ bl : Range) -> [Range] { + return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) + } } extension LazyCollection where Base : Collection & Arbitrary, Base.Index : Comparable { - /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. - public static var arbitrary : Gen> { - return LazyCollection.arbitrary - } + /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. + public static var arbitrary : Gen> { + return LazyCollection.arbitrary + } } extension LazySequence where Base : Sequence & Arbitrary { - /// Returns a generator of `LazySequence`s of arbitrary `Base`s. - public static var arbitrary : Gen> { - return LazySequence.arbitrary - } + /// Returns a generator of `LazySequence`s of arbitrary `Base`s. + public static var arbitrary : Gen> { + return LazySequence.arbitrary + } } extension Repeated where Element : Arbitrary { - /// Returns a generator of `Repeat`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - let constructor: (Element, Int) -> Repeated = { (element, count) in - return repeatElement(element , count: count) - } - - return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) - } + /// Returns a generator of `Repeat`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + let constructor: (Element, Int) -> Repeated = { (element, count) in + return repeatElement(element , count: count) + } + + return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) + } } extension Repeated : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Repeat`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { - return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in - let xs = bl.map(wit) - return pf(repeatElement(xs.first!, count: xs.count)) - }) - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Repeat`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { + return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in + let xs = bl.map(wit) + return pf(repeatElement(xs.first!, count: xs.count)) + }) + } } extension Set where Element : Arbitrary & Hashable { - /// Returns a generator of `Set`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure(Set([])) - } - - return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) - } - } - } - - /// The default shrinking function for `Set`s of arbitrary `Element`s. - public static func shrink(_ s : Set) -> [Set] { - return [Element].shrink([Element](s)).map(Set.init) - } + /// Returns a generator of `Set`s of arbitrary `Element`s. + public static var arbitrary : Gen> { + return Gen.sized { n in + return Gen.choose((0, n)).flatMap { k in + if k == 0 { + return Gen.pure(Set([])) + } + + return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) + } + } + } + + /// The default shrinking function for `Set`s of arbitrary `Element`s. + public static func shrink(_ s : Set) -> [Set] { + return [Element].shrink([Element](s)).map(Set.init) + } } extension Set : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Set`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { - return forAll { (xs : [A]) in - return pf(Set(xs.map(wit))) - } - } + public typealias Param = Element + + /// Given a witness and a function to test, converts them into a universally + /// quantified property over `Set`s. + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { + return forAll { (xs : [A]) in + return pf(Set(xs.map(wit))) + } + } } // MARK: - Implementation Details Follow private func bits(_ n : N) -> Int { - if n / 2 == 0 { - return 0 - } - return 1 + bits(n / 2) + if n / 2 == 0 { + return 0 + } + return 1 + bits(n / 2) } private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 : [A] = take(k, xs: xs) - let xs2 : [A] = drop(k, xs: xs) - - if k > n { - return [] - } else if xs2.isEmpty { - return [[]] - } else { - let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) - return [xs2] + rec - } + let xs1 : [A] = take(k, xs: xs) + let xs2 : [A] = drop(k, xs: xs) + + if k > n { + return [] + } else if xs2.isEmpty { + return [[]] + } else { + let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) + return [xs2] + rec + } } private func take(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n..(_ xs : [A]) -> [[A]] { - if xs.isEmpty { - return [[A]]() - } else if let x : A = xs.first { - let xss = [A](xs[1..(_ pairs : S) - where S.Iterator.Element == (Key, Value) - { - self.init() - var g = pairs.makeIterator() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } + fileprivate init(_ pairs : S) + where S.Iterator.Element == (Key, Value) + { + self.init() + var g = pairs.makeIterator() + while let (k, v): (Key, Value) = g.next() { + self[k] = v + } + } } diff --git a/Tests/BooleanIdentitySpec.swift b/Tests/BooleanIdentitySpec.swift index f2c3036..d8954b8 100644 --- a/Tests/BooleanIdentitySpec.swift +++ b/Tests/BooleanIdentitySpec.swift @@ -10,51 +10,51 @@ import SwiftCheck import XCTest class BooleanIdentitySpec : XCTestCase { - func testAll() { - property("Law of complements") <- forAll { (x : Bool) in - return ((x || !x) == true) && ((x && !x) == false) - } - - property("Law of double negation") <- forAll { (x : Bool) in - return !(!x) == x - } - - property("Law of idempotency") <- forAll { (x : Bool) in - return ((x || x) == x) && ((x && x) == x) - } - - property("Law of dominance") <- forAll { (x : Bool) in - return ((x || false) == x) && ((x && true) == x) - } - - property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x || y) == (y || x)) && ((x && y) == (y && x)) - } - - property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) - } - - property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = !(x && y) == (!x || !y) - let r = !(x || y) == (!x && !y) - return l && r - } - - property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x && (x || y)) == x - let r = (x || (x && y)) == x - return l && r - } - - property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x && (!x || y)) == (x && y) - let r = (x || (!x && y)) == (x || y) - return l && r - } - - property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) - } - } + func testAll() { + property("Law of complements") <- forAll { (x : Bool) in + return ((x || !x) == true) && ((x && !x) == false) + } + + property("Law of double negation") <- forAll { (x : Bool) in + return !(!x) == x + } + + property("Law of idempotency") <- forAll { (x : Bool) in + return ((x || x) == x) && ((x && x) == x) + } + + property("Law of dominance") <- forAll { (x : Bool) in + return ((x || false) == x) && ((x && true) == x) + } + + property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x || y) == (y || x)) && ((x && y) == (y && x)) + } + + property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) + } + + property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r + } + + property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x && (x || y)) == x + let r = (x || (x && y)) == x + return l && r + } + + property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x && (!x || y)) == (x && y) + let r = (x || (!x && y)) == (x || y) + return l && r + } + + property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) + } + } } diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index a9e9432..e3ecfc6 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -14,66 +14,66 @@ let lower : Gen = Gen.fromElementsIn("a"..."z") let numeric : Gen = Gen.fromElementsIn("0"..."9") let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) let hexDigits = Gen.oneOf([ - Gen.fromElementsIn("A"..."F"), - numeric, - ]) + Gen.fromElementsIn("A"..."F"), + numeric, + ]) class ComplexSpec : XCTestCase { - func testEmailAddressProperties() { - let localEmail = Gen.oneOf([ - upper, - lower, - numeric, - special, - ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) - - let hostname = Gen.oneOf([ - lower, - numeric, - Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) - - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) - - let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) - - let args = CheckerArguments(maxTestCaseSize: 10) - - property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in - return e.characters.filter({ $0 == "@" }).count == 1 - }.once - } - - func testIPv6Properties() { - - let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } - let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } - let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } - let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } - - let ipHexDigits = Gen.oneOf([ - gen1, - gen2, - gen3, - gen4 - ]) - - let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) - - property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in - return e.characters.filter({ $0 == ":" }).count == 3 - } - } + func testEmailAddressProperties() { + let localEmail = Gen.oneOf([ + upper, + lower, + numeric, + special, + ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) + + let hostname = Gen.oneOf([ + lower, + numeric, + Gen.pure("-"), + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) + + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) + + let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) + + let args = CheckerArguments(maxTestCaseSize: 10) + + property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in + return e.characters.filter({ $0 == "@" }).count == 1 + }.once + } + + func testIPv6Properties() { + + let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } + let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } + let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } + let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } + + let ipHexDigits = Gen.oneOf([ + gen1, + gen2, + gen3, + gen4 + ]) + + let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) + + property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in + return e.characters.filter({ $0 == ":" }).count == 3 + } + } } // MARK: String Conveniences func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", +) } + return sequence(parts).map { $0.reduce("", +) } } extension String { - fileprivate var initial : String { - return self[self.startIndex.. (x + 1) }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x + c < y + c }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x - c < y - c }, - forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, - forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, - forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, - forAll { (a : Float, b : Float, c : Float) in - return exists { (x : Float) in - return exists { (y : Float) in - return (x != y) ==> { a * pow(x, 2) + b * x + c == a * pow(y, 2) + b * y + c } - } - } - }, - forAll { (_ : Int) in throw SwiftCheckError.bogus }, - forAll { (_ : Int, _ : Float, _ : Int) in throw SwiftCheckError.bogus }.expectFailure.expectFailure, - exists { (_ : Int) in throw SwiftCheckError.bogus }, - ] + private var failCount : Int = 0 + private let tests : [Property] = [ + forAll { (_ : Int) in false }.expectFailure.expectFailure, + forAll { (_ : Int) in false }, + exists { (x : Int) in x != x }, + exists { (x : Int) in x != 0 }, + forAll { (x : Int) in x != x }, + forAll { (b : Bool) in !(b || !b) }, + forAll { (x : Int) in x > (x + 1) }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x + c < y + c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x - c < y - c }, + forAll { (x : Int, y : Int, c : Int) in (x > y) ==> x * c < y * c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / c < y / c }, + forAll { (x : Int, y : Int, c : Int) in (x > y && c != 0) ==> x / (-c) > y / (-c) }, + forAll { (a : Float, b : Float, c : Float) in + return exists { (x : Float) in + return exists { (y : Float) in + return (x != y) ==> { a * pow(x, 2) + b * x + c == a * pow(y, 2) + b * y + c } + } + } + }, + forAll { (_ : Int) in throw SwiftCheckError.bogus }, + forAll { (_ : Int, _ : Float, _ : Int) in throw SwiftCheckError.bogus }.expectFailure.expectFailure, + exists { (_ : Int) in throw SwiftCheckError.bogus }, + ] - func testProperties() { - self.tests.forEach { t in - property("Fail") <- t - } - } + func testProperties() { + self.tests.forEach { t in + property("Fail") <- t + } + } - /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) - /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) - override func recordFailure(withDescription message : String, inFile file : String, atLine line : UInt, expected : Bool) { - if !expected { - assert(false, "Assertion should never throw.") - } else { - // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) - failCount = (failCount + 1) - } - } + /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) + /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) + override func recordFailure(withDescription message : String, inFile file : String, atLine line : UInt, expected : Bool) { + if !expected { + assert(false, "Assertion should never throw.") + } else { + // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) + failCount = (failCount + 1) + } + } - override func tearDown() { - XCTAssert(failCount == tests.count) - } + override func tearDown() { + XCTAssert(failCount == tests.count) + } } diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 9e21732..7dafebb 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -10,301 +10,301 @@ import SwiftCheck import XCTest class GenSpec : XCTestCase { - func testAll() { - property("Gen.frequency behaves") <- { - let g = Gen.frequency([ - (10, Gen.pure(0)), - (5, Gen.pure(1)), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } - } - - property("Gen.weighted behaves") <- { - let g = Gen.weighted([ - (10, 0), - (5, 1), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } - } - - property("The only value Gen.pure generates is the given value") <- { - let g = Gen.pure(0) - return forAll(g) { $0 == 0 } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in - if xss.isEmpty { - return Discard() - } - let l = Set(xss) - return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } - } - - property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in - return (n1 < n2) ==> { - let interval = n1...n2 - return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } - } - } - - property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in - return !xs.isEmpty ==> { - return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in - return xs.starts(with: ys) - } - } - } - - property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in - return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in - return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) - } - } - - property("oneOf n") <- forAll { (xss : ArrayOf) in - if xss.getArray.isEmpty { - return Discard() - } - let l = Set(xss.getArray) - return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } - } - - property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in - let g1 = Gen.pure(n1) - let g2 = Gen.pure(n2) - return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } - } - - property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) - return forAll(g) { $0.getArray.count == n } - } - - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { - return $0.getArray.isEmpty - } - - property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in - var n : Int = 0 - return forAll(Gen.sized { xx in - n = xx - return Int.arbitrary - }.resize(n)) { (x : Int) in - return x <= n - } - } - - property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in - var n : Int = 0 - return forAllNoShrink(Gen<[Int]>.sized({ xx in - n = xx - return [Int].arbitrary - }).resize(n)) { (xs : [Int]) in - return xs.count <= n - } - } - - property("Gen.suchThat in series obeys both predicates") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !(str.isEmpty || str.range(of: ",") != nil) - } - } - - property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !str.isEmpty - } - } - - property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return str.range(of: ",") == nil - } - } - - property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in - return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in - return ss == xs - } - } - - property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in - let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) - return forAllNoShrink(g) { (x1, y1) in - return (x1, y1) == (x, y) - } - } - - property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in - let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) - let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) - return rightBiasedZip ~= leftBiasedZip - } - - property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in - let fx = Gen.pure(x) - let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } - } - - property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in - Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) - } - - property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in - Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) - } - - property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in - let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) - return forAllNoShrink(g) { (x1, y1, z1) in - return (x1, y1, z1) == (x, y, z) - } - } - - property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in - let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) - return forAllNoShrink(g) { (x1, y1, z1, w1) in - return (x1, y1, z1, w1) == (x, y, z, w) - } - } - - property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in - let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in - return (x1, y1, z1, w1, a1) == (x, y, z, w, a) - } - } - - property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - } - } - - property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && c1 == c - } - } - - property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1) == (c, d) - } - } - - property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1) == (c, d, e) - } - } - } - - property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int, f : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1, f1) == (c, d, e, f) - } - } - } - } - - func testLaws() { - /// Turns out Gen is a really sketchy monad because of the underlying randomness. - let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) - let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) - - property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.map(id)) == id(x) - } - - property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in - return forAllNoShrink(lawfulGen) { (x : Gen) in - return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) - } - } - - property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (Gen.pure(id) <*> x) == x - } - - property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) - } - - property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) - } - - property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - return (Gen.pure(a) >>- f) == f(a) - } - - property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in - return (m >>- Gen.pure) == m - } - - property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - let g : (Int) -> Gen = Gen.pure • ga.getArrow - return forAllNoShrink(lawfulGen) { (m : Gen) in - return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) - } - } - } + func testAll() { + property("Gen.frequency behaves") <- { + let g = Gen.frequency([ + (10, Gen.pure(0)), + (5, Gen.pure(1)), + ]) + + return forAll(g) { (i : Int) in + return true + } + } + + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } + } + + property("Gen.weighted behaves") <- { + let g = Gen.weighted([ + (10, 0), + (5, 1), + ]) + + return forAll(g) { (i : Int) in + return true + } + } + + property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } + } + + property("The only value Gen.pure generates is the given value") <- { + let g = Gen.pure(0) + return forAll(g) { $0 == 0 } + } + + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in + if xss.isEmpty { + return Discard() + } + let l = Set(xss) + return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } + } + + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in + return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } + } + + property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + return (n1 < n2) ==> { + let interval = n1...n2 + return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } + } + } + + property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in + return !xs.isEmpty ==> { + return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in + return xs.starts(with: ys) + } + } + } + + property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in + return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in + return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) + } + } + + property("oneOf n") <- forAll { (xss : ArrayOf) in + if xss.getArray.isEmpty { + return Discard() + } + let l = Set(xss.getArray) + return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } + } + + property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in + let g1 = Gen.pure(n1) + let g2 = Gen.pure(n2) + return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } + } + + property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in + let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) + return forAll(g) { $0.getArray.count == n } + } + + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { + return $0.getArray.isEmpty + } + + property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in + var n : Int = 0 + return forAll(Gen.sized { xx in + n = xx + return Int.arbitrary + }.resize(n)) { (x : Int) in + return x <= n + } + } + + property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in + var n : Int = 0 + return forAllNoShrink(Gen<[Int]>.sized({ xx in + n = xx + return [Int].arbitrary + }).resize(n)) { (xs : [Int]) in + return xs.count <= n + } + } + + property("Gen.suchThat in series obeys both predicates") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !(str.isEmpty || str.range(of: ",") != nil) + } + } + + property("Gen.suchThat in series obeys its first property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !str.isEmpty + } + } + + property("Gen.suchThat in series obeys its last property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return str.range(of: ",") == nil + } + } + + property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in + return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in + return ss == xs + } + } + + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in + let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) + return forAllNoShrink(g) { (x1, y1) in + return (x1, y1) == (x, y) + } + } + + property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in + let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) + let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) + return rightBiasedZip ~= leftBiasedZip + } + + property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in + let fx = Gen.pure(x) + let ff = Gen>.pure(f).map { $0.getArrow } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + } + + property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in + Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) + } + + property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in + Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) + } + + property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in + let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) + return forAllNoShrink(g) { (x1, y1, z1) in + return (x1, y1, z1) == (x, y, z) + } + } + + property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in + let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) + return forAllNoShrink(g) { (x1, y1, z1, w1) in + return (x1, y1, z1, w1) == (x, y, z, w) + } + } + + property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in + let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in + return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + } + } + + property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + } + } + + property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && c1 == c + } + } + + property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1) == (c, d) + } + } + + property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1) == (c, d, e) + } + } + } + + property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int, f : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1, f1) == (c, d, e, f) + } + } + } + } + + func testLaws() { + /// Turns out Gen is a really sketchy monad because of the underlying randomness. + let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) + let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) + + property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.map(id)) == id(x) + } + + property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAllNoShrink(lawfulGen) { (x : Gen) in + return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) + } + } + + property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (Gen.pure(id) <*> x) == x + } + + property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) + } + + property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + return (Gen.pure(a) >>- f) == f(a) + } + + property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in + return (m >>- Gen.pure) == m + } + + property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + let g : (Int) -> Gen = Gen.pure • ga.getArrow + return forAllNoShrink(lawfulGen) { (m : Gen) in + return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) + } + } + } } internal func curry(_ f : @escaping (A, B) -> C) -> (A) -> (B) -> C { - return { a in { b in f(a, b) } } + return { a in { b in f(a, b) } } } internal func id(_ x : A) -> A { - return x + return x } internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { - return { f(g($0)) } + return { f(g($0)) } } private func ==(l : Gen, r : Gen) -> Bool { - return l.proliferateSized(10).generate == r.proliferateSized(10).generate + return l.proliferateSized(10).generate == r.proliferateSized(10).generate } /// `Gen` product is associative and has a natural isomorphism. @@ -312,16 +312,16 @@ private func ==(l : Gen, r : Gen) -> Bool { /// - Returns: True *iff* `(a1, a2, a3) == (b1, b2, b3)` /// where `lhs = Gen((a1, (a2, a3)))` and `rhs = Gen(((b1, b2), b3))`. private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> Bool { - let normalizedL = lhs.map { ($0, $1.0, $1.1) } - let normalizedR = rhs.map { ($0.0, $0.1, $1) } - - let sampleSize = 10 - let sampleL = normalizedL.proliferateSized(sampleSize).generate - let sampleR = normalizedR.proliferateSized(sampleSize).generate - - for (tupleL, tupleR) in zip(sampleL, sampleR) { - guard tupleL == tupleR else { return false } - } - - return true + let normalizedL = lhs.map { ($0, $1.0, $1.1) } + let normalizedR = rhs.map { ($0.0, $0.1, $1) } + + let sampleSize = 10 + let sampleL = normalizedL.proliferateSized(sampleSize).generate + let sampleR = normalizedR.proliferateSized(sampleSize).generate + + for (tupleL, tupleR) in zip(sampleL, sampleR) { + guard tupleL == tupleR else { return false } + } + + return true } diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index ba60a2c..10fe577 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -10,183 +10,183 @@ import SwiftCheck import XCTest struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { - let unName : String + let unName : String - static var arbitrary : Gen { - let gc : Gen = Gen.fromElementsIn("a"..."z") - return gc.map { Name(unName: String($0)) } - } + static var arbitrary : Gen { + let gc : Gen = Gen.fromElementsIn("a"..."z") + return gc.map { Name(unName: String($0)) } + } - var description : String { - return self.unName - } + var description : String { + return self.unName + } - var hashValue : Int { - return self.unName.hashValue - } + var hashValue : Int { + return self.unName.hashValue + } } func == (l : Name, r : Name) -> Bool { - return l.unName == r.unName + return l.unName == r.unName } private func liftM2(_ f : @escaping (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { - return m1.flatMap { x1 in - return m2.flatMap { x2 in - return Gen.pure(f(x1, x2)) - } - } + return m1.flatMap { x1 in + return m2.flatMap { x2 in + return Gen.pure(f(x1, x2)) + } + } } indirect enum Exp : Equatable { - case lam(Name, Exp) - case app(Exp, Exp) - case `var`(Name) + case lam(Name, Exp) + case app(Exp, Exp) + case `var`(Name) } func == (l : Exp, r : Exp) -> Bool { - switch (l, r) { - case let (.lam(ln, le), .lam(rn, re)): - return ln == rn && le == re - case let (.app(ln, le), .app(rn, re)): - return ln == rn && le == re - case let (.var(n1), .var(n2)): - return n1 == n2 - default: - return false - } + switch (l, r) { + case let (.lam(ln, le), .lam(rn, re)): + return ln == rn && le == re + case let (.app(ln, le), .app(rn, re)): + return ln == rn && le == re + case let (.var(n1), .var(n2)): + return n1 == n2 + default: + return false + } } extension Exp : Arbitrary { - private static func arbExpr(_ n : Int) -> Gen { - return Gen.frequency([ - (2, liftM(Exp.var, Name.arbitrary)), - ] + ((n <= 0) ? [] : [ - (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), - (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), - ])) - } - - static var arbitrary : Gen { - return Gen.sized(self.arbExpr) - } - - static func shrink(_ e : Exp) -> [Exp] { - switch e { - case .var(_): - return [] - case let .lam(x, a): - return [a] + Exp.shrink(a).map { .lam(x, $0) } - case let .app(a, b): - let part1 : [Exp] = [a, b] - + [a].flatMap({ (expr : Exp) -> Exp? in - if case let .lam(x, a) = expr { - return a.subst(x, b) - } - return nil - }) - - let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } - + Exp.shrink(b).map { app(a, $0) } - return part1 + part2 - } - } - - var free : Set { - switch self { - case let .var(x): - return Set([x]) - case let .lam(x, a): - return a.free.subtracting([x]) - case let .app(a, b): - return a.free.union(b.free) - } - } - - func rename(_ x : Name, _ y : Name) -> Exp { - if x == y { - return self - } - return self.subst(x, .var(y)) - } - - func subst(_ x : Name, _ c : Exp) -> Exp { - switch self { - case let .var(y) where x == y : - return c - case let .lam(y, a) where x != y: - return .lam(y, a.subst(x, c)) - case let .app(a, b): - return .app(a.subst(x, c), b.subst(x, c)) - default: - return self - } - } - - var eval : Exp { - switch self { - case .var(_): - fatalError("Cannot evaluate free variable!") - case let .app(a, b): - switch a.eval { - case let .lam(x, aPrime): - return aPrime.subst(x, b) - default: - return .app(a.eval, b.eval) - } - default: - return self - } - } + private static func arbExpr(_ n : Int) -> Gen { + return Gen.frequency([ + (2, liftM(Exp.var, Name.arbitrary)), + ] + ((n <= 0) ? [] : [ + (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), + (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), + ])) + } + + static var arbitrary : Gen { + return Gen.sized(self.arbExpr) + } + + static func shrink(_ e : Exp) -> [Exp] { + switch e { + case .var(_): + return [] + case let .lam(x, a): + return [a] + Exp.shrink(a).map { .lam(x, $0) } + case let .app(a, b): + let part1 : [Exp] = [a, b] + + [a].flatMap({ (expr : Exp) -> Exp? in + if case let .lam(x, a) = expr { + return a.subst(x, b) + } + return nil + }) + + let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } + + Exp.shrink(b).map { app(a, $0) } + return part1 + part2 + } + } + + var free : Set { + switch self { + case let .var(x): + return Set([x]) + case let .lam(x, a): + return a.free.subtracting([x]) + case let .app(a, b): + return a.free.union(b.free) + } + } + + func rename(_ x : Name, _ y : Name) -> Exp { + if x == y { + return self + } + return self.subst(x, .var(y)) + } + + func subst(_ x : Name, _ c : Exp) -> Exp { + switch self { + case let .var(y) where x == y : + return c + case let .lam(y, a) where x != y: + return .lam(y, a.subst(x, c)) + case let .app(a, b): + return .app(a.subst(x, c), b.subst(x, c)) + default: + return self + } + } + + var eval : Exp { + switch self { + case .var(_): + fatalError("Cannot evaluate free variable!") + case let .app(a, b): + switch a.eval { + case let .lam(x, aPrime): + return aPrime.subst(x, b) + default: + return .app(a.eval, b.eval) + } + default: + return self + } + } } extension Exp : CustomStringConvertible { - var description : String { - switch self { - case let .var(x): - return "$" + x.description - case let .lam(x, t): - return "(λ $\(x.description).\(t.description))" - case let .app(a, b): - return "(\(a.description) \(b.description))" - } - } + var description : String { + switch self { + case let .var(x): + return "$" + x.description + case let .lam(x, t): + return "(λ $\(x.description).\(t.description))" + case let .app(a, b): + return "(\(a.description) \(b.description))" + } + } } extension Name { - func fresh(_ ys : Set) -> Name { - let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } - return Set(zz).subtracting(ys).first ?? self - } + func fresh(_ ys : Set) -> Name { + let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } + return Set(zz).subtracting(ys).first ?? self + } } private func showResult(_ x : A, f : (A) -> Testable) -> Property { - return f(x).whenFail { - print("Result: \(x)") - } + return f(x).whenFail { + print("Result: \(x)") + } } class LambdaSpec : XCTestCase { - func testAll() { - let tiny = CheckerArguments(maxTestCaseSize: 10) - - property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return a.free.contains(x) - ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) - } - }.expectFailure - - property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return !a.free.contains(x) ==> subst_x_b_a == a - } - } - - property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in - return showResult(a.subst(x, b)) { subst_x_b_a in - return !a.free.contains(x) ==> subst_x_b_a.free == a.free - } - } - } + func testAll() { + let tiny = CheckerArguments(maxTestCaseSize: 10) + + property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return a.free.contains(x) + ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) + } + }.expectFailure + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a == a + } + } + + property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in + return showResult(a.subst(x, b)) { subst_x_b_a in + return !a.free.contains(x) ==> subst_x_b_a.free == a.free + } + } + } } diff --git a/Tests/ModifierSpec.swift b/Tests/ModifierSpec.swift index 7deb624..6b6cf35 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/ModifierSpec.swift @@ -10,54 +10,54 @@ import SwiftCheck import XCTest class ModifierSpec : XCTestCase { - func testModifiers() { - property("All blind variables print '(*)'") <- forAll { (x : Blind) in - return x.description == "(*)" - } - - property("Static propositions never shrink") <- forAll { (x : Static) in - return Static.shrink(x).isEmpty - } - - property("Pointers behave") <- forAll { (x : PointerOf) in - return x.size != 0 - } - - property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in - return x.getPositive > 0 - } - - property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in - return x.getNonZero != 0 - } - - property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in - return x.getNonNegative >= 0 - } - - property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in - return true - } - - property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in - return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" - ^&&^ - (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" - } - - property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in - return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) - } - - property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in - return iso.getFrom(iso.getTo(x)) == x - ^&&^ - iso.getTo(iso.getFrom(y)) == y - } - - property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in - let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) - } - } + func testModifiers() { + property("All blind variables print '(*)'") <- forAll { (x : Blind) in + return x.description == "(*)" + } + + property("Static propositions never shrink") <- forAll { (x : Static) in + return Static.shrink(x).isEmpty + } + + property("Pointers behave") <- forAll { (x : PointerOf) in + return x.size != 0 + } + + property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in + return x.getPositive > 0 + } + + property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in + return x.getNonZero != 0 + } + + property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in + return x.getNonNegative >= 0 + } + + property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in + return true + } + + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in + return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" + ^&&^ + (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" + } + + property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in + return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) + } + + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in + return iso.getFrom(iso.getTo(x)) == x + ^&&^ + iso.getTo(iso.getFrom(y)) == y + } + + property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in + let f = pred.getArrow + return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + } } diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index 75bfb5b..040752d 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -10,92 +10,92 @@ import SwiftCheck import XCTest struct Path : Arbitrary { - let unPath : [A] - - private static func pathFrom(_ x : A) -> Gen<[A]> { - return Gen.sized { n in - return Gen<[A]>.oneOf( - [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } - ).map { [x] + $0 } - } - } - - static var arbitrary : Gen> { - return A.arbitrary >>- { x in - return pathFrom(x).map(Path.init) - } - } + let unPath : [A] + + private static func pathFrom(_ x : A) -> Gen<[A]> { + return Gen.sized { n in + return Gen<[A]>.oneOf( + [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } + ).map { [x] + $0 } + } + } + + static var arbitrary : Gen> { + return A.arbitrary >>- { x in + return pathFrom(x).map(Path.init) + } + } } func path(_ p : (A) -> Bool, _ pth : Path) -> Bool { - return pth.unPath.reduce(true, { $0 && p($1) }) + return pth.unPath.reduce(true, { $0 && p($1) }) } func somePath(_ p : (A) -> Bool, _ pth : Path) -> Property { - return path({ !p($0) }, pth).expectFailure + return path({ !p($0) }, pth).expectFailure } struct Extremal : Arbitrary { - let getExtremal : A - - static var arbitrary : Gen> { - return Gen.frequency([ - (1, Gen.pure(A.min)), - (1, Gen.pure(A.max)), - (8, A.arbitrary) - ]).map(Extremal.init) - } - - static func shrink(_ x : Extremal) -> [Extremal] { - return A.shrink(x.getExtremal).map(Extremal.init) - } + let getExtremal : A + + static var arbitrary : Gen> { + return Gen.frequency([ + (1, Gen.pure(A.min)), + (1, Gen.pure(A.max)), + (8, A.arbitrary) + ]).map(Extremal.init) + } + + static func shrink(_ x : Extremal) -> [Extremal] { + return A.shrink(x.getExtremal).map(Extremal.init) + } } class PathSpec : XCTestCase { - private static func smallProp(_ pth : Path) -> Bool { - return path({ x in - return (x >= -100 || -100 >= 0) && x <= 100 - }, pth) - } - - private static func largeProp(_ pth : Path) -> Property { - return somePath({ x in - return (x < -1000000 || x > 1000000) - }, pth) - } - - func testAll() { - property("Int") <- forAll { (x : Path) in - return somePath({ x in - return (x < 1000000 || x > -1000000) - }, x) - } - - property("Int32") <- forAll { (x : Path) in - return path({ x in - return (x >= -100 || -100 >= 0) && x <= 100 - }, x) - } - - property("UInt") <- forAll { (x : Path) in - return somePath({ x in - return (x < 1000000 || x > 0) - }, x) - } - - property("UInt32") <- forAll { (x : Path) in - return path({ x in - return (x >= 0 || -100 >= 0) && x <= 100 - }, x) - } - - property("Large Int") <- forAll { (x : Path>) in - return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) - } - - property("Large UInt") <- forAll { (x : Path>) in - return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) - } - } + private static func smallProp(_ pth : Path) -> Bool { + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, pth) + } + + private static func largeProp(_ pth : Path) -> Property { + return somePath({ x in + return (x < -1000000 || x > 1000000) + }, pth) + } + + func testAll() { + property("Int") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > -1000000) + }, x) + } + + property("Int32") <- forAll { (x : Path) in + return path({ x in + return (x >= -100 || -100 >= 0) && x <= 100 + }, x) + } + + property("UInt") <- forAll { (x : Path) in + return somePath({ x in + return (x < 1000000 || x > 0) + }, x) + } + + property("UInt32") <- forAll { (x : Path) in + return path({ x in + return (x >= 0 || -100 >= 0) && x <= 100 + }, x) + } + + property("Large Int") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + + property("Large UInt") <- forAll { (x : Path>) in + return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) + } + } } diff --git a/Tests/PropertySpec.swift b/Tests/PropertySpec.swift index f6e113f..c15c8ad 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/PropertySpec.swift @@ -10,144 +10,144 @@ import XCTest func ==(l : Property, r : Property) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) - let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) - - switch (res1, res2) { - case (.success(_, _, _), .success(_, _, _)): - return true - case (.gaveUp(_, _, _), .gaveUp(_, _, _)): - return true - case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): - return true - case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): - return true - case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): - return true - case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): - return true - default: - return false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) + + switch (res1, res2) { + case (.success(_, _, _), .success(_, _, _)): + return true + case (.gaveUp(_, _, _), .gaveUp(_, _, _)): + return true + case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): + return true + case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): + return true + case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): + return true + case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): + return true + default: + return false + } } func ==(l : Property, r : Bool) -> Bool { - let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) - switch res1 { - case .success(_, _, _): - return r == true - default: - return r == false - } + let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) + switch res1 { + case .success(_, _, _): + return r == true + default: + return r == false + } } class PropertySpec : XCTestCase { - func testProperties() { - property("Once really only tests a property once") <- forAll { (n : Int) in - var bomb : Optional = .some(n) - return forAll { (_ : Int) in - let b = bomb! // Will explode if we test more than once - bomb = nil - return b == n - }.once - } - - property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in - return conjamb({ - return true "picked 1" - }, { - return true "picked 2" - }, { - return true "picked 3" - }) - } - - property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in - return n == n - }.invert.expectFailure - - property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in - return n != n - }.invert - - property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in - throw SwiftCheckError.bogus - }.invert - - property("Invert does not affect discards") <- forAll { (n : Int) in - return Discard() - }.invert - - property("Existential Quantification works") <- exists { (x : Int) in - return true - } - - property("Cover reports failures properly") <- forAll { (s : Set) in - return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") - }.expectFailure - - property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in - let p = p2 ==> p1 - return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) - } - - property("==> Short Circuits") <- forAll { (n : Int) in - func isPositive(_ n : Int) -> Bool { - if n > 0 { - return true - } else if (n & 1) == 0 { - fatalError("Should never get here") - } else { - return isPositive(n) // or here - } - } - return (n > 0) ==> isPositive(n) - } - - property("Prop Law of complements") <- forAll { (x : Bool) in - return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) - } - - property("Prop Law of double negation") <- forAll { (x : Bool) in - return x.invert.invert == x - } - - property("Prop Law of idempotency") <- forAll { (x : Bool) in - return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) - } - - property("Prop Law of dominance") <- forAll { (x : Bool) in - return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) - } - - property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) - } - - property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) - } - - property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) - let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) - return l ^&&^ r - } - - property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x ^||^ y)) == x - let r = (x ^||^ (x ^&&^ y)) == x - return l ^&&^ r - } - - property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) - let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) - return l ^&&^ r - } - - property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) - } - } + func testProperties() { + property("Once really only tests a property once") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.once + } + + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in + return conjamb({ + return true "picked 1" + }, { + return true "picked 2" + }, { + return true "picked 3" + }) + } + + property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in + return n == n + }.invert.expectFailure + + property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in + return n != n + }.invert + + property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in + throw SwiftCheckError.bogus + }.invert + + property("Invert does not affect discards") <- forAll { (n : Int) in + return Discard() + }.invert + + property("Existential Quantification works") <- exists { (x : Int) in + return true + } + + property("Cover reports failures properly") <- forAll { (s : Set) in + return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") + }.expectFailure + + property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in + let p = p2 ==> p1 + return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) + } + + property("==> Short Circuits") <- forAll { (n : Int) in + func isPositive(_ n : Int) -> Bool { + if n > 0 { + return true + } else if (n & 1) == 0 { + fatalError("Should never get here") + } else { + return isPositive(n) // or here + } + } + return (n > 0) ==> isPositive(n) + } + + property("Prop Law of complements") <- forAll { (x : Bool) in + return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) + } + + property("Prop Law of double negation") <- forAll { (x : Bool) in + return x.invert.invert == x + } + + property("Prop Law of idempotency") <- forAll { (x : Bool) in + return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) + } + + property("Prop Law of dominance") <- forAll { (x : Bool) in + return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) + } + + property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) + } + + property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) + } + + property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) + let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) + return l ^&&^ r + } + + property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x ^||^ y)) == x + let r = (x ^||^ (x ^&&^ y)) == x + return l ^&&^ r + } + + property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) + let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) + return l ^&&^ r + } + + property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) + } + } } diff --git a/Tests/RawRepresentableSpec.swift b/Tests/RawRepresentableSpec.swift index 64b15f0..b753514 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/RawRepresentableSpec.swift @@ -10,9 +10,9 @@ import XCTest import SwiftCheck enum ImplicitRawValues : Int { - case foo - case bar - case baz + case foo + case bar + case baz } // Declaring the extension allows Swift to know this particular enum can be Arbitrary @@ -20,23 +20,23 @@ enum ImplicitRawValues : Int { extension ImplicitRawValues: Arbitrary {} enum ExplicitRawValues : Int { - case zero = 0 - case one = 1 - case two = 2 + case zero = 0 + case one = 1 + case two = 2 } class RawRepresentable_ArbitrarySpec: XCTestCase { - func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { - property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in - return [.foo, .bar, .baz].contains(e) - } - } + func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { + property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in + return [.foo, .bar, .baz].contains(e) + } + } - func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { - // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically - // infer protocol conformance - property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in - return [.zero, .one, .two].contains(e) - } - } + func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { + // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically + // infer protocol conformance + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in + return [.zero, .one, .two].contains(e) + } + } } diff --git a/Tests/ReplaySpec.swift b/Tests/ReplaySpec.swift index 20c496a..9723d6d 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/ReplaySpec.swift @@ -10,22 +10,22 @@ import SwiftCheck import XCTest class ReplaySpec : XCTestCase { - func testProperties() { - property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) - var foundArgs : [Int] = [] - property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in - foundArgs.append(x) - return true - } + func testProperties() { + property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in + let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) + var foundArgs : [Int] = [] + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs.append(x) + return true + } - var foundArgs2 : [Int] = [] - property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in - foundArgs2.append(x) - return foundArgs.contains(x) - } + var foundArgs2 : [Int] = [] + property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in + foundArgs2.append(x) + return foundArgs.contains(x) + } - return foundArgs == foundArgs2 - } - } + return foundArgs == foundArgs2 + } + } } diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index eca2917..3b0cde1 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -10,136 +10,136 @@ import SwiftCheck import XCTest class RoseSpec : XCTestCase { - private static func intRoseTree(_ v : Int) -> Rose { - return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) - } - - private static func depthOneChildren(_ rose : Rose) -> [A] { - return rose.children.map { $0.root } - } - - private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { - let topChildren = rose.children - let vs = topChildren.map { $0.root } - let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) - return vs + cs - } - - func testAll() { - property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in - let tree = RoseSpec.intRoseTree(i) - return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) - } - } - - func testLaws() { - let smallArgs = CheckerArguments(maxTestCaseSize: 5) - property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (x.getRose.map(id)) == id(x.getRose) - } - - property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in - return forAll { (x : RoseTreeOf) in - return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) - } - } - - property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (Rose.pure(id) <*> x.getRose) == x.getRose - } - - property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in - let f = fl.getRose.map({ $0.getArrow }) - let g = gl.getRose.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) - } - - property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in - let f = fl.getRose.map({ $0.getArrow }) - let g = gl.getRose.map({ $0.getArrow }) - return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) - } - - property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in - return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose - } - - property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in - return (m.getRose >>- Rose.pure) == m.getRose - } - - property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in - return forAll { (m : RoseTreeOf) in - return ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) - == - (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) - } - } - } + private static func intRoseTree(_ v : Int) -> Rose { + return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + } + + private static func depthOneChildren(_ rose : Rose) -> [A] { + return rose.children.map { $0.root } + } + + private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { + let topChildren = rose.children + let vs = topChildren.map { $0.root } + let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) + return vs + cs + } + + func testAll() { + property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in + let tree = RoseSpec.intRoseTree(i) + return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) + } + } + + func testLaws() { + let smallArgs = CheckerArguments(maxTestCaseSize: 5) + property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (x.getRose.map(id)) == id(x.getRose) + } + + property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAll { (x : RoseTreeOf) in + return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) + } + } + + property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in + return (Rose.pure(id) <*> x.getRose) == x.getRose + } + + property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in + let f = fl.getRose.map({ $0.getArrow }) + let g = gl.getRose.map({ $0.getArrow }) + return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + } + + property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in + return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose + } + + property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in + return (m.getRose >>- Rose.pure) == m.getRose + } + + property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in + return forAll { (m : RoseTreeOf) in + return ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) + == + (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) + } + } + } } struct RoseTreeOf : Arbitrary { - let getRose : Rose + let getRose : Rose - init(_ rose : Rose) { - self.getRose = rose - } + init(_ rose : Rose) { + self.getRose = rose + } - static var arbitrary : Gen> { - return Gen.sized { n in - return arbTree(n) - } - } + static var arbitrary : Gen> { + return Gen.sized { n in + return arbTree(n) + } + } } private func arbTree(_ n : Int) -> Gen> { - if n == 0 { - return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } - } - return Positive.arbitrary.flatMap { m in - let n2 = n / (m.getPositive + 1) - return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in - return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) - } - } + if n == 0 { + return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } + } + return Positive.arbitrary.flatMap { m in + let n2 = n / (m.getPositive + 1) + return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in + return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) + } + } } private func == (l : Rose, r : Rose) -> Bool { - switch (l, r) { - case let (.mkRose(l1, r1), .mkRose(l2, r2)): - return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } - case (.ioRose(_), .ioRose(_)): - return true - default: - return false - } + switch (l, r) { + case let (.mkRose(l1, r1), .mkRose(l2, r2)): + return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } + case (.ioRose(_), .ioRose(_)): + return true + default: + return false + } } extension Rose { - var root : A { - switch self.reduce { - case let .mkRose(root, _): - return root() - default: - fatalError("Rose should not have reduced to .IORose") - } - } - - var children : [Rose] { - switch self.reduce { - case let .mkRose(_, children): - return children() - default: - fatalError("Rose should not have reduced to .IORose") - } - } - - var collapse : Rose { - let children = self.children - - let vs = children.map { $0.collapse } - let cs = children.flatMap({ $0.children }).map { $0.collapse } - - return .mkRose({ self.root }, { vs + cs }) - } + var root : A { + switch self.reduce { + case let .mkRose(root, _): + return root() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var children : [Rose] { + switch self.reduce { + case let .mkRose(_, children): + return children() + default: + fatalError("Rose should not have reduced to .IORose") + } + } + + var collapse : Rose { + let children = self.children + + let vs = children.map { $0.collapse } + let cs = children.flatMap({ $0.children }).map { $0.collapse } + + return .mkRose({ self.root }, { vs + cs }) + } } diff --git a/Tests/ShrinkSpec.swift b/Tests/ShrinkSpec.swift index 11c7a7f..ae8ac83 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/ShrinkSpec.swift @@ -10,32 +10,32 @@ import SwiftCheck import XCTest class ShrinkSpec : XCTestCase { - func shrinkArbitrary(_ x : A) -> [A] { - let xs = A.shrink(x) - if let x = xs.first { - return xs + [x].flatMap(self.shrinkArbitrary) - } - return xs - } + func shrinkArbitrary(_ x : A) -> [A] { + let xs = A.shrink(x) + if let x = xs.first { + return xs + [x].flatMap(self.shrinkArbitrary) + } + return xs + } - func testAll() { - property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in - return !Set(Int.shrink(n)).contains(n) - } + func testAll() { + property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in + return !Set(Int.shrink(n)).contains(n) + } - property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in - return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) - } + property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in + return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) + } - property("Shrinking an array never gives back the original") <- forAll { (l : Array) in - return Array.shrink(l).filter({ $0 == l }).isEmpty - } + property("Shrinking an array never gives back the original") <- forAll { (l : Array) in + return Array.shrink(l).filter({ $0 == l }).isEmpty + } - property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in - return (!l.getArray.isEmpty && l.getArray != [0]) ==> { - let ls = self.shrinkArbitrary(l).map { $0.getArray } - return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) - } - } - } + property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in + return (!l.getArray.isEmpty && l.getArray != [0]) ==> { + let ls = self.shrinkArbitrary(l).map { $0.getArray } + return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) + } + } + } } diff --git a/Tests/SimpleSpec.swift b/Tests/SimpleSpec.swift index 035f054..57fb9fb 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SimpleSpec.swift @@ -10,201 +10,201 @@ import SwiftCheck import XCTest public struct ArbitraryFoo { - let x : Int - let y : Int + let x : Int + let y : Int - public var description : String { - return "Arbitrary Foo!" - } + public var description : String { + return "Arbitrary Foo!" + } } extension ArbitraryFoo : Arbitrary { - public static var arbitrary : Gen { - return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) - } + public static var arbitrary : Gen { + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) + } } public struct ArbitraryMutableFoo : Arbitrary { - var a: Int8 - var b: Int16 - - public init() { - a = 0 - b = 0 - } - - public static var arbitrary: Gen { - return Gen.compose { c in - var foo = ArbitraryMutableFoo() - foo.a = c.generate() - foo.b = c.generate() - return foo - } - } + var a: Int8 + var b: Int16 + + public init() { + a = 0 + b = 0 + } + + public static var arbitrary: Gen { + return Gen.compose { c in + var foo = ArbitraryMutableFoo() + foo.a = c.generate() + foo.b = c.generate() + return foo + } + } } extension ArbitraryMutableFoo: Equatable {} public func == (lhs: ArbitraryMutableFoo, rhs: ArbitraryMutableFoo) -> Bool { - return lhs.a == rhs.a && lhs.b == rhs.b + return lhs.a == rhs.a && lhs.b == rhs.b } public struct ArbitraryLargeFoo { - let a : Int8 - let b : Int16 - let c : Int32 - let d : Int64 - let e : UInt8 - let f : UInt16 - let g : UInt32 - let h : UInt64 - let i : Int - let j : UInt - let k : Bool - let l : (Bool, Bool) - let m : (Bool, Bool, Bool) - let n : (Bool, Bool, Bool, Bool) + let a : Int8 + let b : Int16 + let c : Int32 + let d : Int64 + let e : UInt8 + let f : UInt16 + let g : UInt32 + let h : UInt64 + let i : Int + let j : UInt + let k : Bool + let l : (Bool, Bool) + let m : (Bool, Bool, Bool) + let n : (Bool, Bool, Bool, Bool) } extension ArbitraryLargeFoo: Equatable {} public func ==(i: ArbitraryLargeFoo, j: ArbitraryLargeFoo) -> Bool { - return - i.a == j.a - && i.b == j.b - && i.c == j.c - && i.d == j.d - && i.e == j.e - && i.f == j.f - && i.g == j.g - && i.h == j.h - && i.i == j.i - && i.j == j.j - && i.k == j.k - && i.l == j.l - && i.m == j.m - && i.n == j.n + return + i.a == j.a + && i.b == j.b + && i.c == j.c + && i.d == j.d + && i.e == j.e + && i.f == j.f + && i.g == j.g + && i.h == j.h + && i.i == j.i + && i.j == j.j + && i.k == j.k + && i.l == j.l + && i.m == j.m + && i.n == j.n } extension ArbitraryLargeFoo : Arbitrary { - public static var arbitrary : Gen { - return Gen<(Int8, Int16, Int32, Int64 - , UInt8, UInt16, UInt32, UInt64 - , Int , UInt)> - .zip( Int8.arbitrary, Int16.arbitrary, Int32.arbitrary, Int64.arbitrary - , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary - , Int.arbitrary, UInt.arbitrary) - .flatMap { t in - return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> - .map( - Bool.arbitrary, - Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), - Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), - Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) - ) { t2 in - (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) - }.map(ArbitraryLargeFoo.init) - } - } + public static var arbitrary : Gen { + return Gen<(Int8, Int16, Int32, Int64 + , UInt8, UInt16, UInt32, UInt64 + , Int , UInt)> + .zip( Int8.arbitrary, Int16.arbitrary, Int32.arbitrary, Int64.arbitrary + , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary + , Int.arbitrary, UInt.arbitrary) + .flatMap { t in + return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> + .map( + Bool.arbitrary, + Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), + Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) + ) { t2 in + (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) + }.map(ArbitraryLargeFoo.init) + } + } } let composedArbitraryLargeFoo = Gen.compose { c in - let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } - return ArbitraryLargeFoo( - a: c.generate(), - b: c.generate(using: evenInt16), - c: c.generate(), - d: c.generate(), - e: c.generate(), - f: c.generate(), - g: c.generate(), - h: c.generate(), - i: c.generate(), - j: c.generate(), - k: c.generate(), - l: (c.generate(), c.generate()), - m: (c.generate(), c.generate(), c.generate()), - n: (c.generate(), c.generate(), c.generate(), c.generate()) - ) + let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } + return ArbitraryLargeFoo( + a: c.generate(), + b: c.generate(using: evenInt16), + c: c.generate(), + d: c.generate(), + e: c.generate(), + f: c.generate(), + g: c.generate(), + h: c.generate(), + i: c.generate(), + j: c.generate(), + k: c.generate(), + l: (c.generate(), c.generate()), + m: (c.generate(), c.generate(), c.generate()), + n: (c.generate(), c.generate(), c.generate(), c.generate()) + ) } class SimpleSpec : XCTestCase { - func testAll() { - property("Integer Equality is Reflexive") <- forAll { (i : Int8) in - return i == i - } - - property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in - return i == i - } - - property("Float Equality is Reflexive") <- forAll { (i : Float) in - return i == i - } - - property("Double Equality is Reflexive") <- forAll { (i : Double) in - return i == i - } - - property("String Equality is Reflexive") <- forAll { (s : String) in - return s == s - } - - property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in - return i.x == i.x && i.y == i.y - } - - property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in - return i.a == i.a - && i.b == i.b - && i.c == i.c - && i.d == i.d - && i.e == i.e - && i.f == i.f - && i.g == i.g - && i.h == i.h - && i.i == i.i - && i.j == i.j - && i.k == i.k - && i.l == i.l - && i.m == i.m - && i.n == i.n - } - - property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in - return - (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) - || - (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) - } - - let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) - let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) - let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) - let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ - greaterThan_lessThanEqualTo, - lessThan_greaterThanEqualTo, - equalTo_notEqualTo, - ]) - - property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in - return forAll { (x : UInt8, y : UInt8) in - return op(x, y) ==== !iop(x, y) - } - } - - property("composition generates high-entropy, arbitrary values") - <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in - return a != b - } - } - - func testComposeWithMutableType() { - property("composition allows setting values on mutable types") - <- (forAll { (a: ArbitraryMutableFoo, b: ArbitraryMutableFoo) in - return a != b - // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size - }.mapSize { $0 + 100 }) - } + func testAll() { + property("Integer Equality is Reflexive") <- forAll { (i : Int8) in + return i == i + } + + property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in + return i == i + } + + property("Float Equality is Reflexive") <- forAll { (i : Float) in + return i == i + } + + property("Double Equality is Reflexive") <- forAll { (i : Double) in + return i == i + } + + property("String Equality is Reflexive") <- forAll { (s : String) in + return s == s + } + + property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in + return i.x == i.x && i.y == i.y + } + + property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in + return i.a == i.a + && i.b == i.b + && i.c == i.c + && i.d == i.d + && i.e == i.e + && i.f == i.f + && i.g == i.g + && i.h == i.h + && i.i == i.i + && i.j == i.j + && i.k == i.k + && i.l == i.l + && i.m == i.m + && i.n == i.n + } + + property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in + return + (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) + || + (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) + } + + let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) + let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) + let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) + let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ + greaterThan_lessThanEqualTo, + lessThan_greaterThanEqualTo, + equalTo_notEqualTo, + ]) + + property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in + return forAll { (x : UInt8, y : UInt8) in + return op(x, y) ==== !iop(x, y) + } + } + + property("composition generates high-entropy, arbitrary values") + <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in + return a != b + } + } + + func testComposeWithMutableType() { + property("composition allows setting values on mutable types") + <- (forAll { (a: ArbitraryMutableFoo, b: ArbitraryMutableFoo) in + return a != b + // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size + }.mapSize { $0 + 100 }) + } } diff --git a/Tests/TestSpec.swift b/Tests/TestSpec.swift index ebbd567..74e80b2 100644 --- a/Tests/TestSpec.swift +++ b/Tests/TestSpec.swift @@ -10,45 +10,45 @@ import SwiftCheck import class XCTest.XCTestCase class TestSpec : XCTestCase { - func testAll() { - let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } - - property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in - return true - } - - property("Optionals behave") <- forAll { (xs : Int?) in - return true - } - - property("Sets behave") <- forAll { (xs : Set) in - return true - } - - property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in - return (xs.reversed().reversed() == xs) "Left identity" - ^&&^ - (xs == xs.reversed().reversed()) "Right identity" - } - - property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in - return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" - ^&&^ - ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") - }.expectFailure - - property("map behaves") <- forAll { (xs : Array) in - return forAll { (f : ArrowOf) in - return xs.map(f.getArrow) == xs.map(f.getArrow) - } - } - - property("filter behaves") <- forAll { (xs : Array) in - return forAll { (pred : ArrowOf) in - let f = pred.getArrow - return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) - } - } - } + func testAll() { + let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } + + property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in + return true + } + + property("Optionals behave") <- forAll { (xs : Int?) in + return true + } + + property("Sets behave") <- forAll { (xs : Set) in + return true + } + + property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in + return (xs.reversed().reversed() == xs) "Left identity" + ^&&^ + (xs == xs.reversed().reversed()) "Right identity" + } + + property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in + return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" + ^&&^ + ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") + }.expectFailure + + property("map behaves") <- forAll { (xs : Array) in + return forAll { (f : ArrowOf) in + return xs.map(f.getArrow) == xs.map(f.getArrow) + } + } + + property("filter behaves") <- forAll { (xs : Array) in + return forAll { (pred : ArrowOf) in + let f = pred.getArrow + return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + } + } } diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 7c82048..1fc6d8d 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -246,8 +246,8 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ let localEmail = allowedLocalCharacters .proliferateNonEmpty // Make a non-empty array of characters - .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) // Such that the last character isn't a dot. - .map { String($0) } // Then make a string. + .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) // Such that the last character isn't a dot. + .map { String($0) } // Then make a string. //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine them all into one big generator. @@ -487,7 +487,7 @@ func sieve(n : Int) -> [Int] { marked[1] = true for p in 2.. [Int] { for p in 2.. Date: Thu, 25 Aug 2016 21:20:34 -0700 Subject: [PATCH 336/460] Fixup poor indentation around array literals --- Sources/Arbitrary.swift | 6 +++--- Sources/Modifiers.swift | 4 ++-- Sources/WitnessedArbitrary.swift | 2 +- Tests/ComplexSpec.swift | 10 +++++----- Tests/GenSpec.swift | 2 +- Tests/LambdaSpec.swift | 2 +- Tests/PathSpec.swift | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 23d6482..4352d12 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -348,18 +348,18 @@ extension Mirror : Arbitrary { Float.arbitrary.map(asAny), Double.arbitrary.map(asAny), Character.arbitrary.map(asAny), - ]) + ]) let genAnyWitnessed : Gen = Gen.oneOf([ Optional.arbitrary.map(asAny), Array.arbitrary.map(asAny), Set.arbitrary.map(asAny), - ]) + ]) return Gen.oneOf([ genAny, genAnyWitnessed, - ]).map(Mirror.init) + ]).map(Mirror.init) } } diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 37bf3e2..11775f1 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -339,7 +339,7 @@ extension ArrowOf : CustomReflectable { return Mirror(self, children: [ "types": "\(T.self) -> \(U.self)", "currentMap": self._impl.table, - ]) + ]) } } @@ -374,7 +374,7 @@ extension IsoOf : CustomReflectable { "embed": "\(T.self) -> \(U.self)", "project": "\(U.self) -> \(T.self)", "currentMap": self._impl.table, - ]) + ]) } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index b3eb5f5..c7e7762 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -137,7 +137,7 @@ extension Optional where Wrapped : Arbitrary { return Gen>.frequency([ (1, Gen>.pure(.none)), (3, liftM(Optional.some, Wrapped.arbitrary)), - ]) + ]) } /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index e3ecfc6..641df9c 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -16,7 +16,7 @@ let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%" let hexDigits = Gen.oneOf([ Gen.fromElementsIn("A"..."F"), numeric, - ]) +]) class ComplexSpec : XCTestCase { func testEmailAddressProperties() { @@ -25,13 +25,13 @@ class ComplexSpec : XCTestCase { lower, numeric, special, - ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) + ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) let hostname = Gen.oneOf([ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) @@ -41,7 +41,7 @@ class ComplexSpec : XCTestCase { property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in return e.characters.filter({ $0 == "@" }).count == 1 - }.once + }.once } func testIPv6Properties() { @@ -56,7 +56,7 @@ class ComplexSpec : XCTestCase { gen2, gen3, gen4 - ]) + ]) let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 7dafebb..0eb7ce5 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -30,7 +30,7 @@ class GenSpec : XCTestCase { let g = Gen.weighted([ (10, 0), (5, 1), - ]) + ]) return forAll(g) { (i : Int) in return true diff --git a/Tests/LambdaSpec.swift b/Tests/LambdaSpec.swift index 10fe577..e9a5c0e 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/LambdaSpec.swift @@ -64,7 +64,7 @@ extension Exp : Arbitrary { ] + ((n <= 0) ? [] : [ (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), - ])) + ])) } static var arbitrary : Gen { diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index 040752d..a448aa5 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -16,7 +16,7 @@ struct Path : Arbitrary { return Gen.sized { n in return Gen<[A]>.oneOf( [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } - ).map { [x] + $0 } + ).map { [x] + $0 } } } From 4b95818a34b63a4e0bb0eb7517ee8e7c720e15d0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 21:23:01 -0700 Subject: [PATCH 337/460] Remove extraneous 'break' statements --- Sources/Arbitrary.swift | 6 +++--- Sources/Test.swift | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 4352d12..54ff13e 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -70,7 +70,7 @@ extension Integer { } let n = i / 2 return .some((n, n)) - }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) + }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) } } @@ -257,7 +257,7 @@ extension Float : Arbitrary { } let n = i / 2.0 return .some((n, n)) - }, initial: x) + }, initial: x) } } @@ -288,7 +288,7 @@ extension Double : Arbitrary { } let n = i / 2.0 return .some((n, n)) - }, initial: x) + }, initial: x) } } diff --git a/Sources/Test.swift b/Sources/Test.swift index 412a645..355dbed 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -420,7 +420,6 @@ private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Resul return reportExistentialFailure(fail.1, res: fail.0) } else { state = fail.1 - break } default: return fail.0 @@ -575,7 +574,6 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E } default: fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") - break } } @@ -651,7 +649,7 @@ private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, t failedShrinkStepDistance = 0 // Try all possible courses of action in this Rose Tree - branches.forEach { r in + for r in branches { switch r.reduce { case .mkRose(let resC, let ts1): let res1 = resC() From 867584611513ac50d34b797198db74fb73f478b7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 21:24:45 -0700 Subject: [PATCH 338/460] Move Gen.compose into its own file --- Sources/Compose.swift | 82 ++++++++++++++++++++++++++++ Sources/Modifiers.swift | 75 ------------------------- SwiftCheck.xcodeproj/project.pbxproj | 8 +++ 3 files changed, 90 insertions(+), 75 deletions(-) create mode 100644 Sources/Compose.swift diff --git a/Sources/Compose.swift b/Sources/Compose.swift new file mode 100644 index 0000000..171e8e0 --- /dev/null +++ b/Sources/Compose.swift @@ -0,0 +1,82 @@ +// +// Compose.swift +// SwiftCheck +// +// Created by Robert Widmann on 8/25/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +extension Gen { + /// Create a generator by procedurally composing generated values from other generators. + /// + /// This is useful in cases where it's cumbersome to functionally compose multiple + /// generators using `zip` and `map`. For example: + /// + /// public static var arbitrary: Gen { + /// return Gen.compose { c in + /// return ArbitraryLargeFoo( + /// // use the nullary method to get an `arbitrary` value + /// a: c.generate(), + /// + /// // or pass a custom generator + /// b: c.generate(Bool.suchThat { $0 == false }), + /// + /// // .. and so on, for as many values & types as you need + /// c: c.generate(), ... + /// ) + /// } + /// } + /// + /// - parameter build: Function which is passed a GenComposer which can be used + /// + /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. + public static func compose(build: @escaping (GenComposer) -> A) -> Gen { + return Gen(unGen: { (stdgen, size) -> A in + let composer = GenComposer(stdgen: stdgen, size: size) + return build(composer) + }) + } +} + +/// Class used to generate values from mulitple `Gen` instances. +/// +/// Given a StdGen and size, generate values from other generators, splitting the StdGen +/// after each call to `generate`, ensuring sufficient entropy across generators. +/// +/// - seealso: Gen.compose +public final class GenComposer { + private var stdgen: StdGen + private var size: Int + + init(stdgen: StdGen, size: Int) { + self.stdgen = stdgen + self.size = size + } + + // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. + private func split() -> StdGen { + let old = stdgen + stdgen = old.split.0 + return old + } + + /// Generate a new `T` with a specific generator. + /// + /// - parameter gen: The generator used to create a random value. + /// + /// - returns: A random `T` using the receiver's stdgen and size. + public func generate(using gen: Gen) -> T { + return gen.unGen(split(), size) + } + + /// Generate a new `T` with its default `arbitrary` generator. + /// + /// - returns: A random `T`. + /// + /// - seealso: generate\(gen:) + public func generate() -> T + where T: Arbitrary + { + return generate(using: T.arbitrary) + } +} diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 11775f1..210638d 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -649,78 +649,3 @@ private final class PointerOfImpl : Arbitrary { } } } - -/// Class used to generate values from mulitple `Gen` instances. -/// -/// Given a StdGen and size, generate values from other generators, splitting the StdGen -/// after each call to `generate`, ensuring sufficient entropy across generators. -/// -/// - seealso: Gen.compose -public final class GenComposer { - private var stdgen: StdGen - private var size: Int - - init(stdgen: StdGen, size: Int) { - self.stdgen = stdgen - self.size = size - } - - // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. - private func split() -> StdGen { - let old = stdgen - stdgen = old.split.0 - return old - } - - /// Generate a new `T` with a specific generator. - /// - /// - parameter gen: The generator used to create a random value. - /// - /// - returns: A random `T` using the receiver's stdgen and size. - public func generate(using gen: Gen) -> T { - return gen.unGen(split(), size) - } - - /// Generate a new `T` with its default `arbitrary` generator. - /// - /// - returns: A random `T`. - /// - /// - seealso: generate\(gen:) - public func generate() -> T - where T: Arbitrary - { - return generate(using: T.arbitrary) - } -} - -extension Gen { - /// Create a generator by procedurally composing generated values from other generators. - /// - /// This is useful in cases where it's cumbersome to functionally compose multiple - /// generators using `zip` and `map`. For example: - /// - /// public static var arbitrary: Gen { - /// return Gen.compose { c in - /// return ArbitraryLargeFoo( - /// // use the nullary method to get an `arbitrary` value - /// a: c.generate(), - /// - /// // or pass a custom generator - /// b: c.generate(Bool.suchThat { $0 == false }), - /// - /// // .. and so on, for as many values & types as you need - /// c: c.generate(), ... - /// ) - /// } - /// } - /// - /// - parameter build: Function which is passed a GenComposer which can be used - /// - /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. - public static func compose(build: @escaping (GenComposer) -> A) -> Gen { - return Gen(unGen: { (stdgen, size) -> A in - let composer = GenComposer(stdgen: stdgen, size: size) - return build(composer) - }) - } -} diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index f333996..c051535 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -102,6 +102,9 @@ 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; + 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; + 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; + 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; @@ -190,6 +193,7 @@ 826D819A1C953D2D0022266C /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; 826D819B1C953D2D0022266C /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -273,6 +277,7 @@ children = ( 826D81461C953D070022266C /* Arbitrary.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, + 82BA08CE1D6FFBD20068D32F /* Compose.swift */, 826D81491C953D070022266C /* Gen.swift */, 826D814B1C953D070022266C /* Lattice.swift */, 826D814C1C953D070022266C /* Modifiers.swift */, @@ -591,6 +596,7 @@ 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, 826D81631C953D070022266C /* Gen.swift in Sources */, 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */, 826D817B1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -635,6 +641,7 @@ 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */, 826D81791C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -679,6 +686,7 @@ 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, 826D81621C953D070022266C /* Gen.swift in Sources */, 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */, 826D817A1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From abf1a7f2f4d512091776a2f1ede00d8baf3fe555 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 22:18:21 -0700 Subject: [PATCH 339/460] Swap the alignment of large function calls --- Sources/Compose.swift | 4 +- Sources/Property.swift | 259 +++++++++++++++------------- Sources/State.swift | 63 +++---- Sources/Test.swift | 371 ++++++++++++++++++++++------------------ Tests/DiscardSpec.swift | 11 +- 5 files changed, 380 insertions(+), 328 deletions(-) diff --git a/Sources/Compose.swift b/Sources/Compose.swift index 171e8e0..d917db3 100644 --- a/Sources/Compose.swift +++ b/Sources/Compose.swift @@ -32,7 +32,7 @@ extension Gen { /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. public static func compose(build: @escaping (GenComposer) -> A) -> Gen { return Gen(unGen: { (stdgen, size) -> A in - let composer = GenComposer(stdgen: stdgen, size: size) + let composer = GenComposer(stdgen, size) return build(composer) }) } @@ -48,7 +48,7 @@ public final class GenComposer { private var stdgen: StdGen private var size: Int - init(stdgen: StdGen, size: Int) { + fileprivate init(_ stdgen : StdGen, _ size : Int) { self.stdgen = stdgen self.size = size } diff --git a/Sources/Property.swift b/Sources/Property.swift index 1d76f77..c9b9086 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -70,45 +70,51 @@ extension Testable { /// Discarded tests remain discarded under inversion. public var invert : Property { return self.mapResult { res in - return TestResult(ok: res.ok.map(!) - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok.map(!), + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } /// Modifies a property so that it only will be tested once. public var once : Property { return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: true - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: true, + quantifier: res.quantifier + ) } } /// Attaches a callback to a test case. public func withCallback(_ cb : Callback) -> Property { return self.mapResult { (res) in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: [cb] + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: [cb] + res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } @@ -171,15 +177,17 @@ extension Testable { } return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks + chattyCallbacks(res.callbacks) - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks + chattyCallbacks(res.callbacks), + abort: res.abort, + quantifier: res.quantifier + ) } } @@ -188,15 +196,17 @@ extension Testable { /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { return self.mapTotalResult { res in - return TestResult(ok: res.ok - , expect: false - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: false, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } @@ -229,15 +239,17 @@ extension Testable { public func cover(_ b : Bool, percentage : Int, label : String) -> Property { if b { return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: insertWith(max, k: label, v: percentage, m: res.labels) - , stamp: res.stamp.union([label]) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: insertWith(max, k: label, v: percentage, m: res.labels), + stamp: res.stamp.union([label]), + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } return self.property @@ -330,37 +342,38 @@ public enum Quantification { public struct TestResult { /// The result of executing the test case. For Discarded test cases the /// value of this property is `.None`. - let ok : Optional + let ok : Optional /// Indicates what the expected result of the property is. - let expect : Bool + let expect : Bool /// A message indicating the reason a test case failed. - let reason : String + let reason : String /// The exception that was thrown if one occured during testing. - let theException : Optional + let theException : Optional /// All the labels used during the test case. - let labels : Dictionary + let labels : Dictionary /// The collected values for the test case. - let stamp : Set + let stamp : Set /// Callbacks attached to the test case. - let callbacks : [Callback] + let callbacks : [Callback] /// Indicates that any further testing of the property should cease. - let abort : Bool + let abort : Bool /// The quantifier being applied to this test case. - let quantifier : Quantification + let quantifier : Quantification /// Provides a pattern-match-friendly view of the current state of a test /// result. public enum TestResultMatcher { /// A case-able view of the current state of a test result. - case matchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification + case matchResult( + ok : Optional, + expect : Bool, + reason : String, + theException : Optional, + labels : Dictionary, + stamp : Set, + callbacks : Array, + abort : Bool, + quantifier : Quantification ) } @@ -372,16 +385,17 @@ public struct TestResult { /// Creates and returns a new test result initialized with the given /// parameters. - public init( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - , quantifier : Quantification) - { + public init( + ok : Optional, + expect : Bool, + reason : String, + theException : Optional, + labels : Dictionary, + stamp : Set, + callbacks : [Callback], + abort : Bool, + quantifier : Quantification + ) { self.ok = ok self.expect = expect self.reason = reason @@ -427,19 +441,20 @@ private func exception(_ msg : String) -> (Error) -> TestResult { private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @escaping (A) -> Testable) -> Rose> { return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) - }}) + }}) } private func result(_ ok : Bool?, reason : String = "") -> TestResult { - return TestResult( ok: ok - , expect: true - , reason: reason - , theException: .none - , labels: [:] - , stamp: Set() - , callbacks: [] - , abort: false - , quantifier: .universal + return TestResult( + ok: ok, + expect: true, + reason: reason, + theException: .none, + labels: [:], + stamp: Set(), + callbacks: [], + abort: false, + quantifier: .universal ) } @@ -521,29 +536,33 @@ private func mplus(_ l : Optional, r : Optional) -> Optional (TestResult) -> TestResult { return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: result.callbacks + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: result.callbacks + res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } private func addLabels(_ result : TestResult) -> (TestResult) -> TestResult { return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: unionWith(max, l: res.labels, r: result.labels) - , stamp: res.stamp.union(result.stamp) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: unionWith(max, l: res.labels, r: result.labels), + stamp: res.stamp.union(result.stamp), + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } @@ -622,15 +641,17 @@ private func disj(_ p : Rose, q : Rose) -> Rose.pure(TestResult(ok: .some(false), - expect: true, - reason: sep(result1.reason, r: result2.reason), - theException: mplus(result1.theException, r: result2.theException), - labels: [:], - stamp: Set(), - callbacks: result1.callbacks + callbacks + result2.callbacks, - abort: false, - quantifier: .universal)) + return Rose.pure(TestResult( + ok: .some(false), + expect: true, + reason: sep(result1.reason, r: result2.reason), + theException: mplus(result1.theException, r: result2.theException), + labels: [:], + stamp: Set(), + callbacks: result1.callbacks + callbacks + result2.callbacks, + abort: false, + quantifier: .universal + )) case .none: return Rose.pure(result2) } diff --git a/Sources/State.swift b/Sources/State.swift index b9e96f2..314a275 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -9,24 +9,24 @@ /// The internal state of the testing system. public struct CheckerState { /// The name bound to the current property (not labels). - let name : String + let name : String /// The maximum number of successful tests before SwiftCheck gives up. /// Defaults to 100. - let maxAllowableSuccessfulTests : Int + let maxAllowableSuccessfulTests : Int /// The maximum number of discarded tests before SwiftCheck gives up. - let maxAllowableDiscardedTests : Int + let maxAllowableDiscardedTests : Int /// The function that generates the sizes fed to the generators for each /// test case. - let computeSize : (Int, Int) -> Int + let computeSize : (Int, Int) -> Int /// The count of the number of successful test cases seen so far. - let successfulTestCount : Int + let successfulTestCount : Int /// The count of the number of discarded test cases seen so far. - let discardedTestCount : Int + let discardedTestCount : Int /// A dictionary of labels collected inside the test case. Each maps to an /// integer describing the number of passed tests. It is used in /// conjunction with the number of successful tests to print a coverage /// percentage. - let labels : Dictionary + let labels : Dictionary /// A uniqued collection of all the labels collected during the test case. let collected : [Set] /// Returns whether the test case has fulfilled its expected failure @@ -35,43 +35,44 @@ public struct CheckerState { /// fail this property returns true. Only when the test case's outcome and /// its failure fulfillment expectation do not match does this property /// return false. - let hasFulfilledExpectedFailure : Bool + let hasFulfilledExpectedFailure : Bool /// The Random Number Generator backing the testing session. - let randomSeedGenerator : StdGen + let randomSeedGenerator : StdGen /// Returns the number of successful shrinking steps performed so far. let successfulShrinkCount : Int /// Returns the number of failed shrinking steps since the last successful /// shrink. - let failedShrinkStepDistance : Int + let failedShrinkStepDistance : Int /// Returns the number of failed shrink steps. let failedShrinkStepCount : Int /// Returns whether the testing system should cease testing altogether. - let shouldAbort : Bool + let shouldAbort : Bool /// The quantifier being applied to this test case. - let quantifier : Quantification + let quantifier : Quantification /// The arguments currently being applied to the testing driver. let arguments : CheckerArguments - let silence : Bool + let silence : Bool - public init( name : String - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , computeSize : @escaping (Int, Int) -> Int - , successfulTestCount : Int - , discardedTestCount : Int - , labels : Dictionary - , collected : [Set] - , hasFulfilledExpectedFailure : Bool - , randomSeedGenerator : StdGen - , successfulShrinkCount : Int - , failedShrinkStepDistance : Int - , failedShrinkStepCount : Int - , shouldAbort : Bool - , quantifier : Quantification - , arguments : CheckerArguments - , silence : Bool) - { + public init( + name : String, + maxAllowableSuccessfulTests : Int, + maxAllowableDiscardedTests : Int, + computeSize : @escaping (Int, Int) -> Int, + successfulTestCount : Int, + discardedTestCount : Int, + labels : Dictionary, + collected : [Set], + hasFulfilledExpectedFailure : Bool, + randomSeedGenerator : StdGen, + successfulShrinkCount : Int, + failedShrinkStepDistance : Int, + failedShrinkStepCount : Int, + shouldAbort : Bool, + quantifier : Quantification, + arguments : CheckerArguments, + silence : Bool + ) { self.name = name self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests self.maxAllowableDiscardedTests = maxAllowableDiscardedTests diff --git a/Sources/Test.swift b/Sources/Test.swift index 355dbed..d521c6f 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -303,15 +303,17 @@ public func exists(_ pf : @escaping (A) throws -> Testable) -> Pr /// quantified property using the default shrinker for that type. public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: .existential) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: .existential + ) } } @@ -323,41 +325,47 @@ public func quickCheck(_ prop : Testable, name : String = "") { // MARK: - Implementation Details internal enum Result { - case success(numTests : Int - , labels : [(String, Int)] - , output : String + case success( + numTests : Int, + labels : [(String, Int)], + output : String ) - case gaveUp(numTests : Int - , labels : [(String,Int)] - , output : String + case gaveUp( + numTests : Int, + labels : [(String,Int)], + output : String ) - case failure(numTests : Int - , numShrinks : Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String + case failure( + numTests : Int, + numShrinks : Int, + usedSeed : StdGen, + usedSize : Int, + reason : String, + labels : [(String,Int)], + output : String ) - case existentialFailure(numTests: Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - , lastResult : TestResult + case existentialFailure( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + reason : String, + labels : [(String,Int)], + output : String, + lastResult : TestResult ) - case noExpectedFailure(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String + case noExpectedFailure( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + labels : [(String,Int)], + output : String ) - case insufficientCoverage(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String + case insufficientCoverage( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + labels : [(String,Int)], + output : String ) } @@ -367,23 +375,25 @@ private indirect enum Either { } internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { - let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: { computeSize(args, vals: $0) } - , successfulTestCount: 0 - , discardedTestCount: 0 - , labels: [:] - , collected: [] - , hasFulfilledExpectedFailure: false - , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() - , successfulShrinkCount: 0 - , failedShrinkStepDistance: 0 - , failedShrinkStepCount: 0 - , shouldAbort: false - , quantifier: .universal - , arguments: args - , silence: args.silence) + let istate = CheckerState( + name: args.name, + maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: args.maxAllowableDiscardedTests, + computeSize: { computeSize(args, vals: $0) }, + successfulTestCount: 0, + discardedTestCount: 0, + labels: [:], + collected: [], + hasFulfilledExpectedFailure: false, + randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen(), + successfulShrinkCount: 0, + failedShrinkStepDistance: 0, + failedShrinkStepCount: 0, + shouldAbort: false, + quantifier: .universal, + arguments: args, + silence: args.silence + ) let modP : Property = (p.exhaustive ? p.property.once : p.property) return test(istate, caseGen: modP.unProperty.unGen) } @@ -454,43 +464,47 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E switch res.match { // Success case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: (st.successfulTestCount + 1) - , discardedTestCount: st.discardedTestCount - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: (st.successfulTestCount + 1), + discardedTestCount: st.discardedTestCount, + labels: unionWith(max, l: st.labels, r: labels), + collected: [stamp] + st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) return .right(nstate) // Discard case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: unionWith(max, l: st.labels, r: labels), + collected: st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) return .right(nstate) // Fail case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): @@ -505,33 +519,37 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E // Failure of an existential is not necessarily failure of the whole // test case, so treat this like a discard. if quantifier == .existential { - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.existentialFailure(numTests: (st.successfulTestCount + 1) - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: "Could not satisfy existential" - , labels: summary(st) - , output: "*** Failed! " - , lastResult: res) + let resul = Result.existentialFailure( + numTests: (st.successfulTestCount + 1), + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + reason: "Could not satisfy existential", + labels: summary(st), + output: "*** Failed! ", + lastResult: res + ) return .left((resul, nstate)) } return .right(nstate) @@ -545,31 +563,35 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E return .left((s, st)) } - let stat = Result.failure(numTests: (st.successfulTestCount + 1) - , numShrinks: numShrinks - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: (st.discardedTestCount + 1) - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: res.expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) + let stat = Result.failure( + numTests: (st.successfulTestCount + 1), + numShrinks: numShrinks, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + reason: res.reason, + labels: summary(st), + output: "*** Failed! " + ) + + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: res.expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) return .left((stat, nstate)) } default: @@ -587,19 +609,23 @@ private func doneTesting(_ st : CheckerState) -> Result { } printDistributionGraph(st) - return .noExpectedFailure(numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") + return .noExpectedFailure( + numTests: st.successfulTestCount, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + labels: summary(st), + output: "" + ) } else if insufficientCoverage(st) { printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) - return .insufficientCoverage( numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") + return .insufficientCoverage( + numTests: st.successfulTestCount, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + labels: summary(st), + output: "" + ) } else { printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) @@ -676,23 +702,25 @@ private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, t successfulShrinkCount = (successfulShrinkCount + 1) } - let state = CheckerState( name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure - , randomSeedGenerator: st.randomSeedGenerator - , successfulShrinkCount: successfulShrinkCount - , failedShrinkStepDistance: failedShrinkStepDistance - , failedShrinkStepCount: failedShrinkStepCount - , shouldAbort: st.shouldAbort - , quantifier: st.quantifier - , arguments: st.arguments - , silence: st.silence) + let state = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: st.discardedTestCount, + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure, + randomSeedGenerator: st.randomSeedGenerator, + successfulShrinkCount: successfulShrinkCount, + failedShrinkStepDistance: failedShrinkStepDistance, + failedShrinkStepCount: failedShrinkStepCount, + shouldAbort: st.shouldAbort, + quantifier: st.quantifier, + arguments: st.arguments, + silence: st.silence + ) return reportMinimumCaseFound(state, res: lastResult) } @@ -856,7 +884,7 @@ private func computeSize(_ args : CheckerArguments, vals : (successes : Int, dis } } - func initialSizeForTest(_ defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + func initialSizeForTest(default defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { if successes == 0 && discards == 0 { return defaultSize } else { @@ -866,10 +894,11 @@ private func computeSize(_ args : CheckerArguments, vals : (successes : Int, dis if let (_, argSize) = args.replay { - return initialSizeForTest( argSize - , successes: vals.successes - , discards: vals.discards - , computeSize: computeSize_ + return initialSizeForTest( + default: argSize, + successes: vals.successes, + discards: vals.discards, + computeSize: computeSize_ ) } return computeSize_(vals.successes, vals.discards) diff --git a/Tests/DiscardSpec.swift b/Tests/DiscardSpec.swift index de9fa10..c6f40f0 100644 --- a/Tests/DiscardSpec.swift +++ b/Tests/DiscardSpec.swift @@ -14,14 +14,15 @@ class DiscardSpec : XCTestCase { property("P != NP") <- Discard() property("P = NP") <- Discard().expectFailure - let args = CheckerArguments( replay: Optional.some((newStdGen(), 10)) - , maxAllowableSuccessfulTests: 200 - , maxAllowableDiscardedTests: 0 - , maxTestCaseSize: 1000 + let args = CheckerArguments( + replay: Optional.some((newStdGen(), 10)), + maxAllowableSuccessfulTests: 200, + maxAllowableDiscardedTests: 0, + maxTestCaseSize: 1000 ) property("Discards forbidden", arguments: args) <- forAll { (x : UInt) in return Discard() - }.expectFailure + }.expectFailure } } From 522f703eb27481c9acdad0dfb0e4a7a09214204a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 23:20:05 -0700 Subject: [PATCH 340/460] Hop on that doc comment hype train --- Sources/Compose.swift | 53 +++++++----- Sources/Gen.swift | 2 +- Sources/Property.swift | 134 +++++++++++++++++++++++------ Sources/Test.swift | 191 ++++++++++++++++++++++++++++++++++++++++- Sources/Witness.swift | 32 +++++++ 5 files changed, 362 insertions(+), 50 deletions(-) diff --git a/Sources/Compose.swift b/Sources/Compose.swift index d917db3..dc6b80d 100644 --- a/Sources/Compose.swift +++ b/Sources/Compose.swift @@ -7,15 +7,18 @@ // extension Gen { - /// Create a generator by procedurally composing generated values from other generators. + /// Construct a `Gen`erator suitable for initializing an aggregate value. /// - /// This is useful in cases where it's cumbersome to functionally compose multiple - /// generators using `zip` and `map`. For example: + /// When using SwiftCheck with most classes and structures that contain more + /// than one field that conforms to `Arbitrary`, the monadic and applicative + /// syntax can be unwieldy. `Gen.compose` simplifies the construction of + /// these values by exposing a simple, natural, and imperative interface to + /// instance generation. For example: /// - /// public static var arbitrary: Gen { - /// return Gen.compose { c in - /// return ArbitraryLargeFoo( - /// // use the nullary method to get an `arbitrary` value + /// public static var arbitrary : Gen { + /// return Gen.compose { c in + /// return MyClass( + /// // Use the nullary method to get an `arbitrary` value. /// a: c.generate(), /// /// // or pass a custom generator @@ -27,9 +30,11 @@ extension Gen { /// } /// } /// - /// - parameter build: Function which is passed a GenComposer which can be used + /// - parameter build: A closure with a `GenComposer` that uses an + /// underlying `Gen`erator to construct arbitrary values. /// - /// - returns: A generator which uses the `build` function to create arbitrary instances of `A`. + /// - returns: A generator which uses the `build` function to build + /// instances of `A`. public static func compose(build: @escaping (GenComposer) -> A) -> Gen { return Gen(unGen: { (stdgen, size) -> A in let composer = GenComposer(stdgen, size) @@ -38,10 +43,10 @@ extension Gen { } } -/// Class used to generate values from mulitple `Gen` instances. +/// `GenComposer` presents an imperative interface over top of `Gen`. /// -/// Given a StdGen and size, generate values from other generators, splitting the StdGen -/// after each call to `generate`, ensuring sufficient entropy across generators. +/// Instances of this class may not be constructed manually. +/// Use `Gen.compose` instead. /// /// - seealso: Gen.compose public final class GenComposer { @@ -53,25 +58,21 @@ public final class GenComposer { self.size = size } - // Split internal StdGen to ensure sufficient entropy over multiple `generate` calls. - private func split() -> StdGen { - let old = stdgen - stdgen = old.split.0 - return old - } /// Generate a new `T` with a specific generator. /// /// - parameter gen: The generator used to create a random value. /// - /// - returns: A random `T` using the receiver's stdgen and size. - public func generate(using gen: Gen) -> T { - return gen.unGen(split(), size) + /// - returns: A random value of type `T` using the given `Gen`erator + /// for that type. + public func generate(using gen : Gen) -> T { + return gen.unGen(self.split, size) } - /// Generate a new `T` with its default `arbitrary` generator. + /// Generate a new value of type `T` with the default `Gen`erator + /// for that type. /// - /// - returns: A random `T`. + /// - returns: An arbitrary value of type `T`. /// /// - seealso: generate\(gen:) public func generate() -> T @@ -79,4 +80,10 @@ public final class GenComposer { { return generate(using: T.arbitrary) } + + private var split : StdGen { + let old = stdgen + stdgen = old.split.0 + return old + } } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 0cdc0f6..adba8cd 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -549,7 +549,7 @@ private func vary(_ k : S, _ rng : StdGen) -> StdGen { return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(_ gen: Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { +private func attemptBoundedTry(_ gen : Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { if bound == 0 { return Gen.pure(.none) } diff --git a/Sources/Property.swift b/Sources/Property.swift index c9b9086..9b8fcfd 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -16,6 +16,11 @@ /// `disjoin(_:)` and `verbose(_:)`. /// /// When conjoining properties all calls to `expectFailure` will fail. +/// +/// - parameter ps: A variadic list of properties to be conjoined. +/// +/// - returns: A `Property` that evaluates to the result of conjoining each +/// of the given `Testable` expressions. public func conjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } @@ -35,6 +40,11 @@ public func conjoin(_ ps : Testable...) -> Property { /// /// When disjoining properties all calls to `expectFailure` will fail. You can, /// however, `invert` the property. +/// +/// - parameter ps: A variadic list of properties to be disjoined. +/// +/// - returns: A `Property` that evaluates to the result of disjoining each +/// of the given `Testable` expressions. public func disjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } @@ -49,6 +59,11 @@ public func disjoin(_ ps : Testable...) -> Property { /// The resulting property makes 100 random choices to test any of the given /// properties. Thus, running multiple test cases will result in distinct /// arbitrary sequences of each property being tested. +/// +/// - parameter ps: A variadic list of properties to be randomly conjoined. +/// +/// - returns: A `Property` that evaluates to the result of randomly conjoining +/// any of the given `Testable` expressions. public func conjamb(_ ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } return Property(Gen.oneOf(ls)) @@ -119,16 +134,26 @@ extension Testable { } /// Adds the given string to the counterexamples of a failing property. - public func counterexample(_ s : String) -> Property { + /// + /// - parameter example: A string describing a counteraxmple that causes + /// this property to fail. + /// + /// - returns: A `Property` that prints the counterexample value on failure. + public func counterexample(_ example : String) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in - return print(s) + return print(example) }) } /// Executes an action after the last failure of the property. - public func whenFail(_ m : @escaping () -> ()) -> Property { + /// + /// - parameter callback: A callback block to be executed after all failures + /// have been processed. + /// + /// - returns: A `Property` that executes the given callback block on failure. + public func whenFail(_ callback : @escaping () -> ()) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in - return m() + return callback() }) } @@ -136,10 +161,13 @@ extension Testable { /// /// Because the action is executed after every failing test it can be used /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(_ m : @escaping () -> ()) -> Property { + /// + /// - parameter callback: A callback block to be executed after each + /// failing case of the property has been processed. + public func whenEachFail(_ callback : @escaping () -> ()) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in if res.ok == .some(false) { - m() + callback() } }) } @@ -217,18 +245,34 @@ extension Testable { /// addition to shrunken test cases, upon failure SwiftCheck will print a /// distribution map for the property that shows a percentage success rate /// for the property. - public func label(_ s : String) -> Property { - return self.classify(true, label: s) + /// + /// - parameter label: The label to apply to the property. + /// + /// - returns: A `Property` with the given label attached. + public func label(_ label : String) -> Property { + return self.classify(true, label: label) } /// Labels a property with a printable value. - public func collect(_ x : A) -> Property { - return self.label(String(describing: x)) + /// + /// - parameter value: The value whose reflected representation will label + /// the property. + /// + /// - returns: A `Property` labelled with the reflected representation of + /// the given value. + public func collect(_ value : A) -> Property { + return self.label(String(describing: value)) } /// Conditionally labels a property with a value. - public func classify(_ b : Bool, label : String) -> Property { - return self.cover(b, percentage: 0, label: label) + /// + /// - parameter condition: The condition to evaluate. + /// - parameter label: The label to apply to the property if the given + /// condition evaluates to true. + /// + /// - returns: A property that carries a label dependent upon the condition. + public func classify(_ condition : Bool, label : String) -> Property { + return self.cover(condition, percentage: 0, label: label) } /// Checks that at least the given proportion of successful test cases @@ -236,8 +280,16 @@ extension Testable { /// /// Discarded tests (i.e. ones with a false precondition) do not affect /// coverage. - public func cover(_ b : Bool, percentage : Int, label : String) -> Property { - if b { + /// + /// - parameter condition: The condition to evaluate. + /// - parameter percentage: A value from 0-100 inclusive that describes + /// the expected percentage the given condition will evaluate to true. + /// - parameter label: The label to apply to the property if the given + /// condition evaluates to true. + /// + /// - returns: A property that carries a label dependent upon the condition. + public func cover(_ condition : Bool, percentage : Int, label : String) -> Property { + if condition { return self.mapResult { res in return TestResult( ok: res.ok, @@ -260,36 +312,64 @@ extension Testable { /// This function can be used to completely change the evaluation schema of /// generated test cases by replacing the test's rose tree with a custom /// one. - public func mapProp(_ f : @escaping (Prop) -> Prop) -> Property { - return Property(f <^> self.property.unProperty) + /// + /// - parameter transform: The transformation function to apply to the + /// `Prop`s of this `Property`. + /// + /// - returns: A `Property` that applies the given transformation upon evaluation. + public func mapProp(_ transform : @escaping (Prop) -> Prop) -> Property { + return Property(transform <^> self.property.unProperty) } /// Applies a function that modifies the test case generator's size. - public func mapSize(_ f : @escaping (Int) -> Int) -> Property { + /// + /// - parameter transform: The transformation function to apply to the size + /// of the generators underlying this `Property`. + /// + /// - returns: A `Property` that applies the given transformation upon evaluation. + public func mapSize(_ transform : @escaping (Int) -> Int) -> Property { return Property(Gen.sized { n in - return self.property.unProperty.resize(f(n)) + return self.property.unProperty.resize(transform(n)) }) } /// Applies a function that modifies the result of a test case. - public func mapTotalResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// result of executing this `Property`. + /// + /// - returns: A `Property` that modifies its final result by executing the + /// given transformation block. + public func mapTotalResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return protectResults(f <^> rs) + return protectResults(transform <^> rs) } } /// Applies a function that modifies the result of a test case. - public func mapResult(_ f : @escaping (TestResult) -> TestResult) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// result of executing this `Property`. + /// + /// - returns: A `Property` that modifies its final result by executing the + /// given transformation block. + public func mapResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return f <^> rs + return transform <^> rs } } /// Applies a function that modifies the underlying Rose Tree that a test /// case has generated. - public func mapRoseResult(_ f : @escaping (Rose) -> Rose) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// rose tree used to execute this `Property`. + /// + /// - returns: A `Property` that modifies its evaluation strategy by + /// executing the given transformation block. + public func mapRoseResult(_ transform : @escaping (Rose) -> Rose) -> Property { return self.mapProp { t in - return Prop(unProp: f(t.unProp)) + return Prop(unProp: transform(t.unProp)) } } } @@ -299,6 +379,12 @@ extension Testable { /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. +/// +/// - parameter shrinker: The custom shrinking function to use for this type. +/// - parameter initial: The initial value that kicks off the shrinking process. +/// - parameter prop: The property to be tested. +/// +/// - returns: A `Property` that shrinks its arguments with the given function. public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : @escaping (A) -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in return Prop(unProp: joinRose(rs.map { x in diff --git a/Sources/Test.swift b/Sources/Test.swift index d521c6f..520b243 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -97,96 +97,196 @@ /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : ((A) throws -> Testable)) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property { return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. +/// +/// - parameter gen: A generator for values of type `A`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter genH: A generator for values of type `H`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -196,6 +296,11 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } @@ -205,6 +310,12 @@ public func forAllNoShrink(_ gen : Gen, pf : ((A) throws -> Testable)) -> /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } @@ -214,6 +325,13 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escapin /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -223,6 +341,14 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : G /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -232,6 +358,15 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -241,6 +376,16 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ ge /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -250,6 +395,17 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -259,12 +415,32 @@ public func forAllNoShrink(_ genA : Gen, _ genB : Gen /// /// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter genH: A generator for values of type `H`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } /// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. +/// +/// - parameter gen: A generator for values of type `A`. +/// - parameter shrinker: The shrinking function. +/// - parameter f: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block against values +/// generated with the given generator and shrunk on failure by the given +/// shrinking function. public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : @escaping (A) throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in @@ -295,12 +471,20 @@ public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : /// `SNF` involves turning every `exists` into a function returning the /// existential value, taking any other parameters being quantified over as /// needed. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func exists(_ pf : @escaping (A) throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } /// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in return TestResult( @@ -318,6 +502,9 @@ public func exists(_ gen : Gen, pf : @escaping (A) throws -> T } /// Tests a property and prints the results to stdout. +/// +/// - parameter prop: The property to be tested. +/// - parameter name: The name of the property being tested. public func quickCheck(_ prop : Testable, name : String = "") { _ = quickCheckWithResult(CheckerArguments(name: name), prop) } @@ -620,7 +807,7 @@ private func doneTesting(_ st : CheckerState) -> Result { printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) printDistributionGraph(st) return .insufficientCoverage( - numTests: st.successfulTestCount, + numTests: st.successfulTestCount, usedSeed: st.randomSeedGenerator, usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), labels: summary(st), @@ -633,7 +820,7 @@ private func doneTesting(_ st : CheckerState) -> Result { } } -private func giveUp(_ st: CheckerState) -> Result { +private func giveUp(_ st : CheckerState) -> Result { printDistributionGraph(st) return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index a110363..ff7d725 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -66,6 +66,10 @@ public protocol WitnessedArbitrary { /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : ((A) -> Testable)) -> Property where A.Param : Arbitrary { @@ -74,6 +78,10 @@ public func forAll(_ pf : ((A) -> Testable)) -> Property /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary { @@ -82,6 +90,10 @@ public func forAll(_ pf : @escap /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary { @@ -90,6 +102,10 @@ public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary { @@ -98,6 +114,10 @@ public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary { @@ -106,6 +126,10 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary { @@ -114,6 +138,10 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary { @@ -122,6 +150,10 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary { From 63a0c00f80df3f0502e7f37d8e3e08d62d321d30 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 25 Aug 2016 23:31:31 -0700 Subject: [PATCH 341/460] Restrict RawRepresentable extensions to Integers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is dangerous to do otherwise. The implementations for Strings and FloatingPoint numbers have incredibly poor performance because they cannot guess the user’s intent. The String implementation will most certainly not construct english words that could ever initialize anything. The FloatingPoint implementation will never guess the right combination of bits that will produce the “exact float” - whatever that could mean - to match the initializer expression. --- Sources/Arbitrary.swift | 9 ++++----- Tests/RawRepresentableSpec.swift | 16 +++++----------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 54ff13e..0413721 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -74,11 +74,10 @@ extension Integer { } } -extension RawRepresentable where RawValue: Arbitrary { - /// Default implementation, maps arbitrary values of its `RawValue` type - /// until a valid representation is obtained. Naturally, you should strive - /// to override this with a more efficient version. - public static var arbitrary: Gen { +extension RawRepresentable where RawValue : Arbitrary & Integer { + /// Uses the default generator for `Integer` values to search for a value + /// that can construct an instance of the reciever's type. + public static var arbitrary : Gen { return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } } } diff --git a/Tests/RawRepresentableSpec.swift b/Tests/RawRepresentableSpec.swift index b753514..6203fb8 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/RawRepresentableSpec.swift @@ -15,27 +15,21 @@ enum ImplicitRawValues : Int { case baz } -// Declaring the extension allows Swift to know this particular enum can be Arbitrary -// ...but it doesn't need to be implemented since the protocol extension gives us a default implementation! -extension ImplicitRawValues: Arbitrary {} +extension ImplicitRawValues : Arbitrary {} -enum ExplicitRawValues : Int { +enum ExplicitRawIntValues : Int { case zero = 0 case one = 1 case two = 2 } -class RawRepresentable_ArbitrarySpec: XCTestCase { - func testDefaultRawRepresentableGeneratorWithImplicitRawValues() { +class RawRepresentableSpec: XCTestCase { + func testRepresentable() { property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in return [.foo, .bar, .baz].contains(e) } - } - func testDeafultRawRepresentableGeneratorWithExplicitRawValues() { - // when no extension is given, the user has to call `forAllNoShrink` since the compiler doesn't automatically - // infer protocol conformance - property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawValues.arbitrary) { e in + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawIntValues.arbitrary) { e in return [.zero, .one, .two].contains(e) } } From 4217b6a9fe12d7884b812f9fe8a6f0e2709fe333 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 26 Aug 2016 00:05:18 -0700 Subject: [PATCH 342/460] Bump the build script. --- .travis.yml | 16 ++++++---------- Package.swift | 2 -- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6c40df6..74a2a7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode7.3 + osx_image: xcode8 before_install: - git submodule update --init --recursive script: @@ -13,7 +13,7 @@ matrix: - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode7.3 + osx_image: xcode8 before_install: - git submodule update --init --recursive script: @@ -22,7 +22,7 @@ matrix: # -- Start iOS -- # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - iOS_DEVICE_NAME="iPad Pro" - - iOS_RUNTIME_VERSION="9.3" + - iOS_RUNTIME_VERSION="10.0" # Get simulator identifier for desired device/runtime pair - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") - echo $SIMULATOR_ID @@ -40,13 +40,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" - - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz + - tar xzf swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-3.0-PREVIEW-6-ubuntu14.04/usr/bin:"${PATH}" script: - swift build notifications: diff --git a/Package.swift b/Package.swift index 682f4a3..b9b0e29 100644 --- a/Package.swift +++ b/Package.swift @@ -4,8 +4,6 @@ let package = Package( name: "SwiftCheck", targets: [ Target(name: "SwiftCheck"), - Target(name: "SwiftCheck-iOS"), - Target(name: "SwiftCheck-tvOS"), ] ) From f972a63c5f297bbbfe45e172c967a57e7b2bf610 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Aug 2016 12:58:20 -0400 Subject: [PATCH 343/460] Ignore package manager build products --- .gitignore | 1 + .travis.yml | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2e900d7..22d997b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Xcode .DS_Store +.build/* */build/* *.pbxuser !default.pbxuser diff --git a/.travis.yml b/.travis.yml index 74a2a7f..90513ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,8 @@ matrix: before_install: - git submodule update --init --recursive script: - - pod lib lint + # Restore pod build before shipping for 3.0 + # - pod lib lint - carthage build --no-skip-current - os: osx language: objective-c @@ -21,7 +22,7 @@ matrix: - xcodebuild test -scheme SwiftCheck | xcpretty -c # -- Start iOS -- # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - - iOS_DEVICE_NAME="iPad Pro" + - iOS_DEVICE_NAME="iPad Pro (12.9 inch)" - iOS_RUNTIME_VERSION="10.0" # Get simulator identifier for desired device/runtime pair - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") From 37e13fe7be26077da76c88e206cf1607f4a06dfe Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Aug 2016 19:50:37 -0400 Subject: [PATCH 344/460] Remove operator exports --- Sources/Arbitrary.swift | 19 +- Sources/{TestOperators.swift => Check.swift} | 2 +- Sources/CoArbitrary.swift | 7 +- Sources/Gen.swift | 82 ++----- Sources/Modifiers.swift | 28 +-- Sources/Operators.swift | 224 ------------------- Sources/Property.swift | 12 +- Sources/Rose.swift | 43 ++-- Sources/Testable.swift | 2 +- Sources/WitnessedArbitrary.swift | 14 +- SwiftCheck.xcodeproj/project.pbxproj | 24 +- Tests/ComplexSpec.swift | 2 +- Tests/GenSpec.swift | 20 +- Tests/PathSpec.swift | 2 +- Tests/RoseSpec.swift | 20 +- Tutorial.playground/Contents.swift | 22 -- 16 files changed, 111 insertions(+), 412 deletions(-) rename Sources/{TestOperators.swift => Check.swift} (99%) delete mode 100644 Sources/Operators.swift diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 0413721..0399a58 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -242,9 +242,9 @@ extension Float : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Float(a) / Float(b)) } } + return numerator.flatMap { a in + return denominator.flatMap { b in Gen.pure(Float(a) / Float(b)) } + } } } @@ -273,9 +273,10 @@ extension Double : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Double(a) / Double(b)) } } + return numerator.flatMap { a in + return denominator.flatMap { b in Gen.pure(Double(a) / Double(b)) + } + } } } @@ -308,7 +309,7 @@ extension String : Arbitrary { /// Returns a generator of `String` values. public static var arbitrary : Gen { let chars = Gen.sized(Character.arbitrary.proliferateSized) - return chars >>- { Gen.pure(String($0)) } + return chars.flatMap { Gen.pure(String($0)) } } /// The default shrinking function for `String` values. @@ -320,7 +321,7 @@ extension String : Arbitrary { extension Character : Arbitrary { /// Returns a generator of `Character` values. public static var arbitrary : Gen { - return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + return Gen.choose((32, 255)).flatMap(comp(Gen.pure, comp(Character.init, UnicodeScalar.init))) } /// The default shrinking function for `Character` values. @@ -333,7 +334,7 @@ extension Character : Arbitrary { extension AnyIndex : Arbitrary { /// Returns a generator of `AnyForwardIndex` values. public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyIndex.init) + return Gen.choose((1, Int64.max)).flatMap(comp(Gen.pure, AnyIndex.init)) } } diff --git a/Sources/TestOperators.swift b/Sources/Check.swift similarity index 99% rename from Sources/TestOperators.swift rename to Sources/Check.swift index a0dd515..01bbbda 100644 --- a/Sources/TestOperators.swift +++ b/Sources/Check.swift @@ -1,5 +1,5 @@ // -// Operators.swift +// Check.swift // SwiftCheck // // Created by Robert Widmann on 5/4/15. diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index 4ceb44e..e0a3089 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -69,7 +69,10 @@ extension String : CoArbitrary { if x.isEmpty { return { $0.variant(0) } } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.characters.index(after: x.startIndex).. { /// When using this function, it is necessary to explicitly specialize the /// generic parameter `A`. For example: /// - /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + /// Gen.choose((32, 255)).flatMap(Gen.pure • Character.init • UnicodeScalar.init) public static func choose(_ rng : (A, A)) -> Gen { return Gen(unGen: { s, _ in return A.randomInRange(rng, gen: s).0 @@ -112,7 +112,7 @@ public struct Gen { { assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.startIndex, gs.index(before: gs.endIndex))) >>- { x in + return choose((gs.startIndex, gs.index(before: gs.endIndex))).flatMap { x in return gs[x] } } @@ -381,7 +381,7 @@ extension Gen { /// determined by the receiver's size parameter. public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((0, n)) >>- self.proliferateSized + return Gen.choose((0, n)).flatMap(self.proliferateSized) } } @@ -389,7 +389,7 @@ extension Gen { /// length determined by the receiver's size parameter. public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))) >>- self.proliferateSized + return Gen.choose((1, max(1, n))).flatMap(self.proliferateSized) } } @@ -404,25 +404,19 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the /// receiver creates. + /// + /// This function is most useful for converting between generators of inter- + /// related types. For example, you might have a Generator of `Character` + /// values that you then `.proliferate` into an `Array` of `Character`s. You + /// can then use `fmap` to convert that generator of `Array`s to a generator of + /// `String`s. public func map(_ f : @escaping (A) -> B) -> Gen { - return f <^> self + return Gen(unGen: { r, n in + return f(self.unGen(r, n)) + }) } } -/// Fmap | Returns a new generator that applies a given function to any outputs -/// the given generator creates. -/// -/// This function is most useful for converting between generators of inter- -/// related types. For example, you might have a Generator of `Character` -/// values that you then `.proliferate` into an `Array` of `Character`s. You -/// can then use `fmap` to convert that generator of `Array`s to a generator of -/// `String`s. -public func <^> (f : @escaping (A) -> B, g : Gen) -> Gen { - return Gen(unGen: { r, n in - return f(g.unGen(r, n)) - }) -} - extension Gen /*: Applicative*/ { /// Lifts a value into a generator that will only generate that value. public static func pure(_ a : A) -> Gen { @@ -434,32 +428,13 @@ extension Gen /*: Applicative*/ { /// Given a generator of functions, applies any generated function to any /// outputs the receiver creates. public func ap(_ fn : Gen<(A) -> B>) -> Gen { - return fn <*> self + return Gen(unGen: { r, n in + let (r1, r2) = r.split + return fn.unGen(r1, n)(self.unGen(r2, n)) + }) } } -/// Ap | Returns a Generator that uses the first given Generator to produce -/// functions and the second given Generator to produce values that it applies -/// to those functions. It can be used in conjunction with <^> to simplify the -/// application of "combining" functions to a large amount of sub-generators. -/// For example: -/// -/// struct Foo { let b : Int; let c : Int; let d : Int } -/// -/// let genFoo = curry(Foo.init) <^> Int.arbitrary <*> Int.arbitrary <*> Int.arbitrary -/// -/// This combinator acts like `zip`, but instead of creating pairs it creates -/// values after applying the zipped function to the zipped value. -/// -/// Promotes function application to a Generator of functions applied to a -/// Generator of values. -public func <*> (fn : Gen<(A) -> B>, g : Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - return fn.unGen(r1, n)(g.unGen(r2, n)) - }) -} - extension Gen /*: Monad*/ { /// Applies the function to any generated values to yield a new generator. /// This generator is then given a new random seed and returned. @@ -469,25 +444,14 @@ extension Gen /*: Monad*/ { /// control the length of a Generator of strings, or use it to choose a /// random index into a Generator of arrays. public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { - return self >>- fn + return Gen(unGen: { r, n in + let (r1, r2) = r.split + let m2 = fn(self.unGen(r1, n)) + return m2.unGen(r2, n) + }) } } -/// Flat Map | Applies the function to any generated values to yield a new -/// generator. This generator is then given a new random seed and returned. -/// -/// `flatMap` allows for the creation of Generators that depend on other -/// generators. One might, for example, use a Generator of integers to control -/// the length of a Generator of strings, or use it to choose a random index -/// into a Generator of arrays. -public func >>- (m : Gen, fn : @escaping (A) -> Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - let m2 = fn(m.unGen(r1, n)) - return m2.unGen(r2, n) - }) -} - /// Creates and returns a Generator of arrays of values drawn from each /// generator in the given array. /// @@ -529,7 +493,7 @@ public func promote(_ x : Rose>) -> Gen> { /// Promotes a function returning generators to a generator of functions. public func promote(_ m : @escaping (A) -> Gen) -> Gen<(A) -> B> { return delay().flatMap { eval in - return Gen<(A) -> B>.pure(eval • m) + return Gen<(A) -> B>.pure(comp(eval, m)) } } diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 210638d..247c4c7 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -68,7 +68,7 @@ public struct Blind : Arbitrary, CustomStringConvertible { /// Returns a generator of `Blind` values. public static var arbitrary : Gen> { - return Blind.init <^> A.arbitrary + return A.arbitrary.map(Blind.init) } /// The default shrinking function for `Blind` values. @@ -100,7 +100,7 @@ public struct Static : Arbitrary, CustomStringConvertible { /// Returns a generator of `Static` values. public static var arbitrary : Gen> { - return Static.init <^> A.arbitrary + return A.arbitrary.map(Static.init) } } @@ -132,7 +132,7 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { /// Returns a generator of `ArrayOf` values. public static var arbitrary : Gen> { - return ArrayOf.init <^> Array.arbitrary + return Array.arbitrary.map(ArrayOf.init) } /// The default shrinking function for an `ArrayOf` values. @@ -147,7 +147,7 @@ extension ArrayOf : CoArbitrary { if a.isEmpty { return { $0.variant(0) } } - return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1.. : Arbitrary, CustomStri /// Returns a generator for an `OrderedArrayOf` values. public static var arbitrary : Gen> { - return OrderedArrayOf.init <^> Array.arbitrary + return Array.arbitrary.map(OrderedArrayOf.init) } /// The default shrinking function for an `OrderedArrayOf` values. @@ -199,7 +199,7 @@ public struct DictionaryOf : Arbitrary, /// Returns a generator for a `DictionaryOf` values. public static var arbitrary : Gen> { - return DictionaryOf.init <^> Dictionary.arbitrary + return Dictionary.arbitrary.map(DictionaryOf.init) } /// The default shrinking function for a `DictionaryOf` values. @@ -230,7 +230,7 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { /// Returns a generator for `OptionalOf` values. public static var arbitrary : Gen> { - return OptionalOf.init <^> Optional.arbitrary + return Optional.arbitrary.map(OptionalOf.init) } /// The default shrinking function for `OptionalOf` values. @@ -270,7 +270,7 @@ public struct SetOf : Arbitrary, CustomStringConvertib return Gen.pure(SetOf(Set([]))) } - return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) + return sequence(Array((0...k)).map { _ in A.arbitrary }).map(comp(SetOf.init, Set.init)) } } } @@ -420,7 +420,7 @@ public struct Positive : Arbitrary, CustomStringCo /// Returns a generator of `Positive` values. public static var arbitrary : Gen> { - return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } + return A.arbitrary.map(comp(Positive.init, abs)).suchThat { $0.getPositive > 0 } } /// The default shrinking function for `Positive` values. @@ -452,7 +452,7 @@ public struct NonZero : Arbitrary, CustomStringConverti /// Returns a generator of `NonZero` values. public static var arbitrary : Gen> { - return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } + return A.arbitrary.suchThat({ $0 != 0 }).map(NonZero.init) } /// The default shrinking function for `NonZero` values. @@ -483,7 +483,7 @@ public struct NonNegative : Arbitrary, CustomStringConv /// Returns a generator of `NonNegative` values. public static var arbitrary : Gen> { - return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } + return A.arbitrary.suchThat({ $0 >= 0 }).map(NonNegative.init) } /// The default shrinking function for `NonNegative` values. @@ -533,9 +533,9 @@ fileprivate final class ArrowOfImpl : } static var arbitrary : Gen> { - return ArrowOfImpl.init <^> promote { a in + return promote({ a in return T.coarbitrary(a)(U.arbitrary) - } + }).map(ArrowOfImpl.init) } static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { @@ -644,7 +644,7 @@ private final class PointerOfImpl : Arbitrary { return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) } let pt = UnsafeMutablePointer.allocate(capacity: n) - let gt = pt.initialize <^> sequence(Array((0.. : LeftAssociativeCombinatorPrecedence - -/// On | Given a "combining" function and a function that converts arguments to the target of the -/// combiner, returns a function that applies the right hand side to two arguments, then runs both -/// results through the combiner. -infix operator |*| : LeftAssociativeCombinatorPrecedence - -// MARK: Control.* - -precedencegroup FunctorPrecedence { - associativity: left - higherThan: DefaultPrecedence -} - -precedencegroup FunctorSequencePrecedence { - associativity: left - higherThan: FunctorPrecedence -} - -precedencegroup MonadPrecedenceLeft { - associativity: left - higherThan: FunctorSequencePrecedence -} - -precedencegroup MonadPrecedenceRight { - associativity: right - higherThan: FunctorSequencePrecedence -} - -/// Fmap | Maps a function over the value encapsulated by a functor. -infix operator <^> : FunctorPrecedence - -/// Replace | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator <^ : FunctorSequencePrecedence - -/// Replace Backwards | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator ^> : FunctorSequencePrecedence - - -/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. -infix operator <*> : FunctorPrecedence - -/// Sequence Right | Disregards the Functor on the Left. -/// -/// Default definition: -/// `const(id) <^> a <*> b` -infix operator *> : FunctorSequencePrecedence - -/// Sequence Left | Disregards the Functor on the Right. -/// -/// Default definition: -/// `const <^> a <*> b` -infix operator <* : FunctorSequencePrecedence - -/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the -/// left to a function on the right yielding a new monad. -infix operator >>- : MonadPrecedenceLeft - -/// Bind Backwards | Composes two monadic actions by passing the value inside the monad on the -/// right to the funciton on the left. -infix operator -<< : MonadPrecedenceRight - -/// Left-to-Right Kleisli | Composition for monads. -infix operator >>->> : MonadPrecedenceRight - -/// Right-to-Left Kleisli | Composition for monads. -infix operator <<-<< : MonadPrecedenceRight - -/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the -/// original context. -infix operator ->> : MonadPrecedenceLeft - -precedencegroup FunctorExtrasPrecedence { - associativity: left - higherThan: FunctorSequencePrecedence -} - -/// Imap | Maps covariantly over the index of a right-leaning bifunctor. -infix operator <^^> : FunctorExtrasPrecedence - -/// Contramap | Contravariantly maps a function over the value encapsulated by a functor. -infix operator : FunctorExtrasPrecedence - -// MARK: Data.Result - -precedencegroup ResultPrecedence { - associativity: none - higherThan: FunctorPrecedence -} - -/// From | Creates a Result given a function that can possibly fail with an error. -infix operator !! : ResultPrecedence - -// MARK: Data.Monoid - -/// Append | Alias for a Semigroup's operation. -infix operator <> : AdditionPrecedence - -// MARK: Control.Category - -precedencegroup CategoryPrecedence { - associativity: right - higherThan: MonadPrecedenceRight -} - -/// Right-to-Left Composition | Composes two categories to form a new category with the source of -/// the second category and the target of the first category. -/// -/// This function is literally `•`, but for Categories. -infix operator <<< : CategoryPrecedence - -/// Left-to-Right Composition | Composes two categories to form a new category with the source of -/// the first category and the target of the second category. -/// -/// Function composition with the arguments flipped. -infix operator >>> : CategoryPrecedence - -// MARK: Control.Arrow - -precedencegroup ArrowPrecedence { - associativity: right - higherThan: CategoryPrecedence -} - -/// Split | Splits two computations and combines the result into one Arrow yielding a tuple of -/// the result of each side. -infix operator *** : ArrowPrecedence - -/// Fanout | Given two functions with the same source but different targets, this function -/// splits the computation and combines the result of each Arrow into a tuple of the result of -/// each side. -infix operator &&& : ArrowPrecedence - -// MARK: Control.Arrow.Choice - -precedencegroup ArrowChoicePrecedence { - associativity: right - higherThan: ArrowPrecedence -} - -/// Splat | Splits two computations and combines the results into Eithers on the left and right. -infix operator +++ : ArrowChoicePrecedence - -/// Fanin | Given two functions with the same target but different sources, this function splits -/// the input between the two and merges the output. -infix operator ||| : ArrowChoicePrecedence - -// MARK: Control.Arrow.Plus - -precedencegroup ArrowPlusPrecedence { - associativity: right - higherThan: ArrowChoicePrecedence -} - -/// Op | Combines two ArrowZero monoids. -infix operator <+> : ArrowPlusPrecedence - -// MARK: Data.JSON - -precedencegroup JSONPrecedence { - associativity: right - higherThan: ArrowPlusPrecedence -} - -/// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. -/// -/// If the given keypath is not present or the retrieved value is not of the appropriate type, this -/// function returns `.None`. -infix operator Prop) -> Property { - return Property(transform <^> self.property.unProperty) + return Property(self.property.unProperty.map(transform)) } /// Applies a function that modifies the test case generator's size. @@ -342,7 +342,7 @@ extension Testable { /// given transformation block. public func mapTotalResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return protectResults(transform <^> rs) + return protectResults(rs.map(transform)) } } @@ -355,7 +355,7 @@ extension Testable { /// given transformation block. public func mapResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return transform <^> rs + return rs.map(transform) } } @@ -568,7 +568,7 @@ internal func id(_ x : A) -> A { return x } -internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { +internal func comp(_ f : @escaping (B) -> C, _ g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } @@ -679,11 +679,11 @@ private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose](xs[1..](xs[1..](xs[1..](xs[1..(_ f : @escaping (A) -> B) -> Rose { - return f <^> self - } -} - -/// Fmap | Maps a function over all the nodes of a Rose Tree. -public func <^> (f : @escaping (A) -> B, g : Rose) -> Rose { - switch g { - case .mkRose(let root, let children): - return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) - case .ioRose(let rs): - return .ioRose({ rs().map(f) }) + switch self { + case .mkRose(let root, let children): + return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) + case .ioRose(let rs): + return .ioRose({ rs().map(f) }) + } } } @@ -78,18 +73,12 @@ extension Rose /*: Applicative*/ { /// is reduced to a `.MkRose` and applied, executing all side-effects along /// the way. public func ap(_ fn : Rose<(A) -> B>) -> Rose { - return fn <*> self - } -} - -/// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose -/// Tree of values. -public func <*> (fn : Rose<(A) -> B>, g : Rose) -> Rose { - switch fn { - case .mkRose(let f, _): - return g.map(f()) - case .ioRose(let rs): - return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + switch fn { + case .mkRose(let f, _): + return self.map(f()) + case .ioRose(let rs): + return self.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + } } } @@ -97,16 +86,10 @@ extension Rose /*: Monad*/ { /// Maps the values in the receiver to Rose Trees and joins them all /// together. public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { - return self >>- fn + return joinRose(self.map(fn)) } } -/// Flat Map | Maps the values in the receiver to Rose Trees and joins them all -/// together. -public func >>- (m : Rose, fn : @escaping (A) -> Rose) -> Rose { - return joinRose(m.map(fn)) -} - /// Lifts functions to functions over Rose Trees. public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { return m1.flatMap { x1 in diff --git a/Sources/Testable.swift b/Sources/Testable.swift index a6158c2..eb2b79c 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -106,6 +106,6 @@ extension Bool : Testable { extension Gen /*: Testable*/ where A : Testable { public var property : Property { - return Property(self >>- { $0.property.unProperty }) + return Property(self.flatMap { $0.property.unProperty }) } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index c7e7762..c90ee3d 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -42,7 +42,7 @@ extension Array : WitnessedArbitrary { extension AnyBidirectionalCollection where Element : Arbitrary { /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return AnyBidirectionalCollection.init <^> [Element].arbitrary + return [Element].arbitrary.map(AnyBidirectionalCollection.init) } /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. @@ -66,7 +66,7 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { extension AnySequence where Element : Arbitrary { /// Returns a generator of `AnySequence`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return AnySequence.init <^> [Element].arbitrary + return [Element].arbitrary.map(AnySequence.init) } /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. @@ -90,7 +90,7 @@ extension AnySequence : WitnessedArbitrary { extension ArraySlice where Element : Arbitrary { /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return ArraySlice.init <^> [Element].arbitrary + return [Element].arbitrary.map(ArraySlice.init) } /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. @@ -114,7 +114,7 @@ extension ArraySlice : WitnessedArbitrary { extension CollectionOfOne where Element : Arbitrary { /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return CollectionOfOne.init <^> Element.arbitrary + return Element.arbitrary.map(CollectionOfOne.init) } } @@ -165,7 +165,7 @@ extension Optional : WitnessedArbitrary { extension ContiguousArray where Element : Arbitrary { /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return ContiguousArray.init <^> [Element].arbitrary + return [Element].arbitrary.map(ContiguousArray.init) } /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. @@ -250,7 +250,7 @@ extension Repeated where Element : Arbitrary { return repeatElement(element , count: count) } - return constructor <^> Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary) + return Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary).map(constructor) } } @@ -276,7 +276,7 @@ extension Set where Element : Arbitrary & Hashable { return Gen.pure(Set([])) } - return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) + return sequence(Array((0...k)).map { _ in Element.arbitrary }).map(Set.init) } } } diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index c051535..898498a 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -27,9 +27,6 @@ 826D816A1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; 826D816B1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; 826D816C1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816D1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; - 826D816E1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; - 826D816F1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; 826D81701C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; 826D81711C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; 826D81721C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; @@ -51,9 +48,9 @@ 826D81821C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; 826D81831C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; 826D81841C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81851C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; - 826D81861C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; - 826D81871C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; + 826D81851C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; + 826D81861C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; + 826D81871C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; 826D81881C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; 826D81891C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; 826D818A1C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; @@ -167,7 +164,6 @@ 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; 826D814B1C953D070022266C /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lattice.swift; path = Sources/Lattice.swift; sourceTree = SOURCE_ROOT; }; 826D814C1C953D070022266C /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = Sources/Modifiers.swift; sourceTree = SOURCE_ROOT; }; - 826D814D1C953D070022266C /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/Operators.swift; sourceTree = SOURCE_ROOT; }; 826D814E1C953D070022266C /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = SOURCE_ROOT; }; 826D814F1C953D070022266C /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Random.swift; path = Sources/Random.swift; sourceTree = SOURCE_ROOT; }; 826D81501C953D070022266C /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Rose.swift; path = Sources/Rose.swift; sourceTree = SOURCE_ROOT; }; @@ -175,7 +171,7 @@ 826D81521C953D070022266C /* SwiftCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = Sources/SwiftCheck.h; sourceTree = SOURCE_ROOT; }; 826D81531C953D070022266C /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Test.swift; path = Sources/Test.swift; sourceTree = SOURCE_ROOT; }; 826D81541C953D070022266C /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Testable.swift; path = Sources/Testable.swift; sourceTree = SOURCE_ROOT; }; - 826D81551C953D070022266C /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestOperators.swift; path = Sources/TestOperators.swift; sourceTree = SOURCE_ROOT; }; + 826D81551C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; @@ -276,19 +272,18 @@ isa = PBXGroup; children = ( 826D81461C953D070022266C /* Arbitrary.swift */, + 826D81551C953D070022266C /* Check.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 82BA08CE1D6FFBD20068D32F /* Compose.swift */, 826D81491C953D070022266C /* Gen.swift */, 826D814B1C953D070022266C /* Lattice.swift */, 826D814C1C953D070022266C /* Modifiers.swift */, - 826D814D1C953D070022266C /* Operators.swift */, 826D814E1C953D070022266C /* Property.swift */, 826D814F1C953D070022266C /* Random.swift */, 826D81501C953D070022266C /* Rose.swift */, 826D81511C953D070022266C /* State.swift */, 826D81531C953D070022266C /* Test.swift */, 826D81541C953D070022266C /* Testable.swift */, - 826D81551C953D070022266C /* TestOperators.swift */, 826D81561C953D070022266C /* Witness.swift */, 826D81571C953D070022266C /* WitnessedArbitrary.swift */, 844FCC90198B320500EB242A /* Supporting Files */, @@ -586,12 +581,11 @@ 826D81691C953D070022266C /* Lattice.swift in Sources */, 826D81751C953D070022266C /* Random.swift in Sources */, 826D81841C953D070022266C /* Testable.swift in Sources */, - 826D816F1C953D070022266C /* Operators.swift in Sources */, 826D818A1C953D070022266C /* Witness.swift in Sources */, 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, 826D816C1C953D070022266C /* Modifiers.swift in Sources */, 826D81811C953D070022266C /* Test.swift in Sources */, - 826D81871C953D070022266C /* TestOperators.swift in Sources */, + 826D81871C953D070022266C /* Check.swift in Sources */, 826D81781C953D070022266C /* Rose.swift in Sources */, 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, 826D81631C953D070022266C /* Gen.swift in Sources */, @@ -631,12 +625,11 @@ 826D81671C953D070022266C /* Lattice.swift in Sources */, 826D81731C953D070022266C /* Random.swift in Sources */, 826D81821C953D070022266C /* Testable.swift in Sources */, - 826D816D1C953D070022266C /* Operators.swift in Sources */, 826D81881C953D070022266C /* Witness.swift in Sources */, 826D81581C953D070022266C /* Arbitrary.swift in Sources */, 826D816A1C953D070022266C /* Modifiers.swift in Sources */, 826D817F1C953D070022266C /* Test.swift in Sources */, - 826D81851C953D070022266C /* TestOperators.swift in Sources */, + 826D81851C953D070022266C /* Check.swift in Sources */, 826D81761C953D070022266C /* Rose.swift in Sources */, 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, @@ -676,12 +669,11 @@ 826D81681C953D070022266C /* Lattice.swift in Sources */, 826D81741C953D070022266C /* Random.swift in Sources */, 826D81831C953D070022266C /* Testable.swift in Sources */, - 826D816E1C953D070022266C /* Operators.swift in Sources */, 826D81891C953D070022266C /* Witness.swift in Sources */, 826D81591C953D070022266C /* Arbitrary.swift in Sources */, 826D816B1C953D070022266C /* Modifiers.swift in Sources */, 826D81801C953D070022266C /* Test.swift in Sources */, - 826D81861C953D070022266C /* TestOperators.swift in Sources */, + 826D81861C953D070022266C /* Check.swift in Sources */, 826D81771C953D070022266C /* Rose.swift in Sources */, 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, 826D81621C953D070022266C /* Gen.swift in Sources */, diff --git a/Tests/ComplexSpec.swift b/Tests/ComplexSpec.swift index 641df9c..7acfd67 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/ComplexSpec.swift @@ -58,7 +58,7 @@ class ComplexSpec : XCTestCase { gen4 ]) - let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) + let ipGen = glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]).map { $0.initial } property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 0eb7ce5..50beae3 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -94,11 +94,11 @@ class GenSpec : XCTestCase { } property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) + let g = Int.arbitrary.proliferateSized(n).map(ArrayOf.init) return forAll(g) { $0.getArray.count == n } } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferateSized(0).map(ArrayOf.init)) { return $0.getArray.isEmpty } @@ -252,40 +252,40 @@ class GenSpec : XCTestCase { property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in return forAllNoShrink(lawfulGen) { (x : Gen) in - return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) + return (x.map(f.getArrow • g.getArrow)) == (x.map(g.getArrow).map(f.getArrow)) } } property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (Gen.pure(id) <*> x) == x + return (x.ap(Gen.pure(id))) == x } property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in let f = fl.map({ $0.getArrow }) let g = gl.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) + return x.ap(g.ap(f.map(curry(•)))) == x.ap(g).ap(f) } property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in let f = fl.map({ $0.getArrow }) let g = gl.map({ $0.getArrow }) - return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) + return x.ap(g.ap(f.ap(Gen.pure(curry(•))))) == x.ap(g).ap(f) } property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in let f : (Int) -> Gen = Gen.pure • fa.getArrow - return (Gen.pure(a) >>- f) == f(a) + return Gen.pure(a).flatMap(f) == f(a) } property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in - return (m >>- Gen.pure) == m + return (m.flatMap(Gen.pure)) == m } property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in let f : (Int) -> Gen = Gen.pure • fa.getArrow let g : (Int) -> Gen = Gen.pure • ga.getArrow return forAllNoShrink(lawfulGen) { (m : Gen) in - return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) + return m.flatMap(f).flatMap(g) == m.flatMap({ x in f(x).flatMap(g) }) } } } @@ -299,6 +299,8 @@ internal func id(_ x : A) -> A { return x } +infix operator • : NilCoalescingPrecedence + internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } diff --git a/Tests/PathSpec.swift b/Tests/PathSpec.swift index a448aa5..c98d01e 100644 --- a/Tests/PathSpec.swift +++ b/Tests/PathSpec.swift @@ -21,7 +21,7 @@ struct Path : Arbitrary { } static var arbitrary : Gen> { - return A.arbitrary >>- { x in + return A.arbitrary.flatMap { x in return pathFrom(x).map(Path.init) } } diff --git a/Tests/RoseSpec.swift b/Tests/RoseSpec.swift index 3b0cde1..a2a5506 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/RoseSpec.swift @@ -40,39 +40,39 @@ class RoseSpec : XCTestCase { property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in return forAll { (x : RoseTreeOf) in - return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) + return x.getRose.map(f.getArrow • g.getArrow) == x.getRose.map(g.getArrow).map(f.getArrow) } } property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (Rose.pure(id) <*> x.getRose) == x.getRose + return x.getRose.ap(Rose.pure(id)) == x.getRose } property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in let f = fl.getRose.map({ $0.getArrow }) let g = gl.getRose.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + return x.getRose.ap(g.ap(f.map(curry(•)))) == x.getRose.ap(g).ap(f) } property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in let f = fl.getRose.map({ $0.getArrow }) let g = gl.getRose.map({ $0.getArrow }) - return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + return x.getRose.ap(g.ap(f.ap(Rose.pure(curry(•))))) == x.getRose.ap(g).ap(f) } property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in - return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose + return (Rose.pure(a).flatMap { f.getArrow($0).getRose }) == f.getArrow(a).getRose } property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in - return (m.getRose >>- Rose.pure) == m.getRose + return m.getRose.flatMap(Rose.pure) == m.getRose } property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in return forAll { (m : RoseTreeOf) in - return ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) - == - (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) + return m.getRose.flatMap({ f.getArrow($0).getRose }).flatMap({ g.getArrow($0).getRose }) + == + m.getRose.flatMap({ x in f.getArrow(x).getRose.flatMap({ g.getArrow($0).getRose }) }) } } } @@ -94,7 +94,7 @@ struct RoseTreeOf : Arbitrary { private func arbTree(_ n : Int) -> Gen> { if n == 0 { - return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } + return A.arbitrary.flatMap { Gen.pure(RoseTreeOf(Rose.pure($0))) } } return Positive.arbitrary.flatMap { m in let n2 = n / (m.getPositive + 1) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 1fc6d8d..4f9f301 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -197,28 +197,6 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate - -//: Because SwiftCheck is based on the functional concepts in our other library -//: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: -//: -//: * `<^>` is an alias for `map` -//: * `<*>` is an alias for `ap` -//: * `>>-` is an alias for `flatMap` - -let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive - -fromTwoToSix_.generate -fromTwoToSix_.generate -fromTwoToSix_.generate - -let generatorBoundedSizeArrays_ = fromOnetoFive >>- { len in - return characterArray.suchThat { xs in xs.count <= len } -} - -generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate - //: # Practical Generators //: For our purposes, we will say that an email address consists of 3 parts: A local part, a From fba761979d15afc11a780756b02a22fac3bf6cb5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Aug 2016 19:55:05 -0400 Subject: [PATCH 345/460] Update README --- README.md | 71 +++++++++++++++++-------------------------------------- 1 file changed, 22 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index a66c0ea..cae5198 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ SwiftCheck is a testing library that automatically generates random data for testing of program properties. A property is a particular facet of an algorithm or data structure that must be invariant under a given set of input data, basically an `XCTAssert` on steroids. Where before all we could do was define -methods prefixed by `test` and assert, SwiftCheck allows program properties and tests to be treated like *data*. +methods prefixed by `test` and assert, SwiftCheck allows program properties and +tests to be treated like *data*. To define a program property the `forAll` quantifier is used with a type signature like `(A, B, C, ... Z) -> Testable where A : Arbitrary, B : Arbitrary ... @@ -156,8 +157,8 @@ func isPrime(n : Int) -> Bool { ``` -We would like to test whether our sieve works properly, so we run it through SwiftCheck -with the following property: +We would like to test whether our sieve works properly, so we run it through +SwiftCheck with the following property: ```swift import SwiftCheck @@ -206,10 +207,6 @@ public struct ArbitraryFoo { let x : Int let y : Int - public static func create(x : Int) -> Int -> ArbitraryFoo { - return { y in ArbitraryFoo(x: x, y: y) } - } - public var description : String { return "Arbitrary Foo!" } @@ -217,7 +214,7 @@ public struct ArbitraryFoo { extension ArbitraryFoo : Arbitrary { public static var arbitrary : Gen { - return ArbitraryFoo.create <^> Int.arbitrary <*> Int.arbitrary + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) } } @@ -230,48 +227,24 @@ class SimpleSpec : XCTestCase { } ``` -There's also a `Gen.compose` method which allows you to procedurally compose values from multiple generators to construct instances of a type: +There's also a `Gen.compose` method which allows you to procedurally compose +values from multiple generators to construct instances of a type: ``` swift -public struct ArbitraryLargeFoo { - let a : Int8 - let b : Int16 - let c : Int32 - let d : Int64 - let e : UInt8 - let f : UInt16 - let g : UInt32 - let h : UInt64 - let i : Int - let j : UInt - let k : Bool - let l : (Bool, Bool) - let m : (Bool, Bool, Bool) - let n : (Bool, Bool, Bool, Bool) - - public static var arbitrary: Gen = Gen.compose { c in - // c is a `GenComposer` which will generate the values you need, either from the default `arbitrary` member of the - // type or a given generator - let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } - return ArbitraryLargeFoo( - a: c.generate(), // `generate()` infers the type to return a value from `Int8.arbitrary` - b: c.generate(evenInt16), // returns a value from `evenInt16` - c: c.generate(), - d: c.generate(), - e: c.generate(), - f: c.generate(), - g: c.generate(), - h: c.generate(), - i: c.generate(), - j: c.generate(), - k: c.generate(), - l: (c.generate(), c.generate()), - m: (c.generate(), c.generate(), c.generate()), - n: (c.generate(), c.generate(), c.generate(), c.generate()) - ) +public static var arbitrary : Gen { + return Gen.compose { c in + return MyClass( + // Use the nullary method to get an `arbitrary` value. + a: c.generate(), + + // or pass a custom generator + b: c.generate(Bool.suchThat { $0 == false }), + + // .. and so on, for as many values and types as you need. + c: c.generate(), ... + ) } } - ``` `Gen.compose` can also be used with types that can only be customized with setters: @@ -311,11 +284,11 @@ let uppers : Gen= Gen.fromElementsIn("A"..."Z") let lowers : Gen = Gen.fromElementsIn("a"..."z") let numbers : Gen = Gen.fromElementsIn("0"..."9") -/// This generator will generate `.None` 1/4 of the time and an arbitrary -/// `.Some` 3/4 of the time +/// This generator will generate `.none` 1/4 of the time and an arbitrary +/// `.some` 3/4 of the time let weightedOptionals = Gen.frequency([ (1, Gen.pure(nil)), - (3, Optional.Some <^> Int.arbitrary) + (3, Int.arbitrary.map(Optional.some)) ]) ``` From 697b48613d18346b1f6ba7b2cf1be4efb4bb2f8d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Aug 2016 19:57:39 -0400 Subject: [PATCH 346/460] Remove dead submodule --- Cartfile.private | 1 - Cartfile.resolved | 1 - Carthage/Checkouts/Operadics | 1 - 3 files changed, 3 deletions(-) delete mode 100644 Cartfile.private delete mode 160000 Carthage/Checkouts/Operadics diff --git a/Cartfile.private b/Cartfile.private deleted file mode 100644 index 077b243..0000000 --- a/Cartfile.private +++ /dev/null @@ -1 +0,0 @@ -github "typelift/Operadics" diff --git a/Cartfile.resolved b/Cartfile.resolved index 42bd8b3..e69de29 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +0,0 @@ -github "typelift/Operadics" "0.2.0" diff --git a/Carthage/Checkouts/Operadics b/Carthage/Checkouts/Operadics deleted file mode 160000 index 8117a84..0000000 --- a/Carthage/Checkouts/Operadics +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8117a84bb4111814c35af80285f3f9baff290d7e From 0ac44e3c8ec2f7d502196f6a1e1d738a60a315de Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 29 Aug 2016 11:29:36 -0400 Subject: [PATCH 347/460] Fix legacy swift version setting in targets --- SwiftCheck.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index daad3a3..fecc1f7 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -749,6 +749,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -781,6 +782,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -800,6 +802,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -816,6 +819,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -1044,6 +1048,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1077,6 +1082,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1104,6 +1110,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -1123,6 +1130,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; VALIDATE_PRODUCT = YES; }; name = Release; From c43f392b2540b8cea699ef61218873fade3f5010 Mon Sep 17 00:00:00 2001 From: Gordon Fontenot Date: Mon, 29 Aug 2016 11:10:49 -0500 Subject: [PATCH 348/460] Remove gitmodules This submodule was removed but we never cleaned up the gitmodules file. This resulted in errors when trying to check out the project using Carthage. --- .gitmodules | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index bf0c263..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "Carthage/Checkouts/Operadics"] - path = Carthage/Checkouts/Operadics - url = https://github.com/typelift/Operadics.git From 8346724cf1ab222f2f7d2eb530588160d0a3fb1e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 29 Aug 2016 12:57:45 -0400 Subject: [PATCH 349/460] Bump the podspec --- .gitignore | 1 + SwiftCheck.podspec | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2e900d7..22d997b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Xcode .DS_Store +.build/* */build/* *.pbxuser !default.pbxuser diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index d12c0ff..dfdce2e 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.6.1" + s.version = "0.6.2" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 13073cacd0a834c4522636d0892f6fc0feb9e00f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 31 Aug 2016 01:11:50 -0400 Subject: [PATCH 350/460] Bring out featureset up to par with QuickCheck --- Sources/Check.swift | 2 +- Sources/Gen.swift | 20 +++++++++++- Sources/Property.swift | 55 ++++++++++++++++++++++---------- Sources/Test.swift | 5 ++- Sources/Testable.swift | 26 --------------- Sources/WitnessedArbitrary.swift | 10 +----- Tests/GenSpec.swift | 6 ++-- Tests/PropertySpec.swift | 20 +++++++++++- 8 files changed, 83 insertions(+), 61 deletions(-) diff --git a/Sources/Check.swift b/Sources/Check.swift index 01bbbda..710575f 100644 --- a/Sources/Check.swift +++ b/Sources/Check.swift @@ -84,7 +84,7 @@ public struct CheckerArguments { /// passes. /// /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// this amount, but less is rare. If you need a value of 1, use `.once` /// on the property instead. let maxAllowableSuccessfulTests : Int /// The maximum number of tests cases that can be discarded before testing gives up on the diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 7512c40..eea5264 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -90,6 +90,12 @@ public struct Gen { }) } + /// Constructs a generator by applying the given function to the minimum + /// and maximum bounds of a bounded type. + public static func withBounds(_ f : @escaping (A, A) -> Gen) -> Gen { + return f(A.min, A.max) + } + /// Constructs a random element in the range of two `RandomType`s. /// /// When using this function, it is necessary to explicitly specialize the @@ -101,6 +107,18 @@ public struct Gen { return A.randomInRange(rng, gen: s).0 }) } + + /// Constructs a random element in the range of a bounded `RandomType`. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.chooseAny().flatMap(Gen.pure • Character.init • UnicodeScalar.init) + public static func chooseAny() -> Gen { + return Gen(unGen: { (s, _) in + return randomBound(s).0 + }) + } /// Constructs a Generator that randomly selects and uses a particular /// generator from the given sequence of Generators. @@ -108,7 +126,7 @@ public struct Gen { /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. public static func oneOf(_ gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType & Comparable, S.Index : RandomType + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable { assert(gs.count != 0, "oneOf used with empty list") diff --git a/Sources/Property.swift b/Sources/Property.swift index 98120c5..63b8d60 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -26,7 +26,7 @@ public func conjoin(_ ps : Testable...) -> Property { return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in return Gen.pure(Prop(unProp: conj(id, xs: roses))) - })) + })).again } /// Takes the disjunction of multiple properties and reports all successes and @@ -50,7 +50,7 @@ public func disjoin(_ ps : Testable...) -> Property { return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) - })) + })).again } /// Takes the nondeterministic conjunction of multiple properties and treats @@ -66,7 +66,7 @@ public func disjoin(_ ps : Testable...) -> Property { /// any of the given `Testable` expressions. public func conjamb(_ ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } - return Property(Gen.oneOf(ls)) + return Property(Gen.oneOf(ls)).again } extension Testable { @@ -100,6 +100,8 @@ extension Testable { } /// Modifies a property so that it only will be tested once. + /// + /// Undoes the effect of `.again`. public var once : Property { return self.mapResult { res in return TestResult( @@ -115,6 +117,25 @@ extension Testable { ) } } + + /// Modifies a property so that it will be tested many times. + /// + /// Undoes the effect of `.once`. + public var again : Property { + return self.mapResult { res in + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: false, + quantifier: res.quantifier + ) + } + } /// Attaches a callback to a test case. public func withCallback(_ cb : Callback) -> Property { @@ -516,6 +537,20 @@ public struct TestResult { } return result(Optional.some(false), reason: "Falsifiable") } + + private static func result(_ ok : Bool?, reason : String = "") -> TestResult { + return TestResult( + ok: ok, + expect: true, + reason: reason, + theException: .none, + labels: [:], + stamp: Set(), + callbacks: [], + abort: false, + quantifier: .universal + ) + } } // MARK: - Implementation Details @@ -530,20 +565,6 @@ private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @esc }}) } -private func result(_ ok : Bool?, reason : String = "") -> TestResult { - return TestResult( - ok: ok, - expect: true, - reason: reason, - theException: .none, - labels: [:], - stamp: Set(), - callbacks: [], - abort: false, - quantifier: .universal - ) -} - private func protectResults(_ rs : Rose) -> Rose { return rs.onRose { x, rs in return .ioRose({ diff --git a/Sources/Test.swift b/Sources/Test.swift index 520b243..9cfe6de 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -450,7 +450,7 @@ public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) } }).unProperty - }) + }).again } /// Converts a function into an existentially quantified property using the @@ -581,8 +581,7 @@ internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> arguments: args, silence: args.silence ) - let modP : Property = (p.exhaustive ? p.property.once : p.property) - return test(istate, caseGen: modP.unProperty.unGen) + return test(istate, caseGen: p.property.unProperty.unGen) } // Main Testing Loop: diff --git a/Sources/Testable.swift b/Sources/Testable.swift index eb2b79c..1e35fe2 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -16,24 +16,11 @@ /// and `Property`. The last of these enables `forAll`s to return further /// `forAll`s that can depend on previously generated values. public protocol Testable { - /// Returns true iff a single test case is exhaustive i.e. adequately covers - /// the search space. - /// - /// If true, the property will only be tested once. Defaults to false. - var exhaustive : Bool { get } - /// Returns a `Property`, which SwiftCheck uses to perform test case /// generation. var property : Property { get } } -extension Testable { - /// By default, all `Testable` types are non-exhaustive. - public var exhaustive : Bool { - return false - } -} - /// A property is anything that generates `Prop`s. public struct Property : Testable { let unProperty : Gen @@ -58,10 +45,6 @@ public struct Property : Testable { public struct Prop : Testable { var unProp : Rose - /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive - /// property tests. - public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. public var property : Property { // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) @@ -71,9 +54,6 @@ public struct Prop : Testable { /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { - /// `Discard`s are trivially exhaustive. - public var exhaustive : Bool { return true } - /// Create a `Discard` suitable for public init() { } @@ -84,9 +64,6 @@ public struct Discard : Testable { } extension TestResult : Testable { - /// `TestResult`s are trivially exhaustive. - public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. public var property : Property { return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) @@ -94,9 +71,6 @@ extension TestResult : Testable { } extension Bool : Testable { - /// `Bool`ean values are trivially exhaustive. - public var exhaustive : Bool { return true } - /// Returns a property that evaluates to a test success if the receiver is /// `true`, else returns a property that evaluates to a test failure. public var property : Property { diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index c90ee3d..e35c366 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -9,15 +9,7 @@ extension Array where Element : Arbitrary { /// Returns a generator of `Array`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure([]) - } - - return sequence((0...k).map { _ in Element.arbitrary }) - } - } + return Element.arbitrary.proliferate } /// The default shrinking function for `Array`s of arbitrary `Element`s. diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index 50beae3..a0ac9df 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -15,7 +15,7 @@ class GenSpec : XCTestCase { let g = Gen.frequency([ (10, Gen.pure(0)), (5, Gen.pure(1)), - ]) + ]) return forAll(g) { (i : Int) in return true @@ -107,8 +107,8 @@ class GenSpec : XCTestCase { return forAll(Gen.sized { xx in n = xx return Int.arbitrary - }.resize(n)) { (x : Int) in - return x <= n + }.resize(n)) { (x : Int) in + return x <= n } } diff --git a/Tests/PropertySpec.swift b/Tests/PropertySpec.swift index c15c8ad..1d9183c 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/PropertySpec.swift @@ -49,9 +49,27 @@ class PropertySpec : XCTestCase { let b = bomb! // Will explode if we test more than once bomb = nil return b == n - }.once + }.once } + property("Again undoes once") <- forAll { (n : Int) in + var counter : Int = 0 + quickCheck(forAll { (_ : Int) in + counter += 1 + return true + }.once.again) + return counter > 1 + } + + property("Once undoes again") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.again.once + } + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in return conjamb({ return true "picked 1" From 25443bc28e94f5041c51a679cd6708914a5b5fa8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 31 Aug 2016 01:26:13 -0400 Subject: [PATCH 351/460] Test everything --- Sources/Gen.swift | 8 +------- Sources/Random.swift | 26 +++++++++++++++++++++++--- Tests/GenSpec.swift | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index eea5264..0d53a6f 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -90,13 +90,7 @@ public struct Gen { }) } - /// Constructs a generator by applying the given function to the minimum - /// and maximum bounds of a bounded type. - public static func withBounds(_ f : @escaping (A, A) -> Gen) -> Gen { - return f(A.min, A.max) - } - - /// Constructs a random element in the range of two `RandomType`s. + /// Constructs a random element in the inclusive range of two `RandomType`s. /// /// When using this function, it is necessary to explicitly specialize the /// generic parameter `A`. For example: diff --git a/Sources/Random.swift b/Sources/Random.swift index 0fcfb6b..be2181d 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -253,9 +253,29 @@ extension UInt32 : RandomType { extension UInt64 : RandomType { /// Returns a random `UInt64` value using the given range and generator. public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt64(bb), gg) + let (l, h) = range + if l > h { + return UInt64.randomInRange((h, l), gen: gen) + } else { + let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 + let magtgt = k * q + + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { + if mag >= magtgt { + return (v, g) + } else { + let (x, g_) = g.next + let v_ = (v * b + (Double(x) - Double(genlo))) + return entropize(mag * b, v_, g_) + } + } + + let (v, rng_) = entropize(1, 0, gen) + return (UInt64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) + } } } diff --git a/Tests/GenSpec.swift b/Tests/GenSpec.swift index a0ac9df..033dd39 100644 --- a/Tests/GenSpec.swift +++ b/Tests/GenSpec.swift @@ -22,6 +22,25 @@ class GenSpec : XCTestCase { } } + property("Gen.choose stays in bounds") <- forAll { (x : Int, y : Int) in + let (mx, mn) = (Swift.max(x, y), Swift.min(x, y)) + return forAll(Gen.choose((mn, mx))) { n in + return mn <= n && n <= mx + } + } + + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int.min <= x && x <= Int.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int8.min <= x && x <= Int8.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int16.min <= x && x <= Int16.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int32.min <= x && x <= Int32.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int64.min <= x && x <= Int64.max } + + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt.min <= x && x <= UInt.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt8.min <= x && x <= UInt8.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt16.min <= x && x <= UInt16.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt32.min <= x && x <= UInt32.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt64.min <= x && x <= UInt64.max } + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } } From 4753f000f0dbd105f060a7c3d6ac800e98c2ffb7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 31 Aug 2016 01:27:05 -0400 Subject: [PATCH 352/460] A comma --- Sources/Check.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Check.swift b/Sources/Check.swift index 710575f..455ae07 100644 --- a/Sources/Check.swift +++ b/Sources/Check.swift @@ -84,7 +84,7 @@ public struct CheckerArguments { /// passes. /// /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value of 1, use `.once` + /// this amount, but less is rare. If you need a value of 1 use `.once` /// on the property instead. let maxAllowableSuccessfulTests : Int /// The maximum number of tests cases that can be discarded before testing gives up on the From a3355e991b32a9d01423896537e940bd9837774a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 2 Sep 2016 15:16:18 -0400 Subject: [PATCH 353/460] Swift all the unsigned things to the unsigned random generator --- Sources/Random.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/Random.swift b/Sources/Random.swift index be2181d..5fd3a12 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -218,7 +218,7 @@ extension UInt : RandomType { /// Returns a random `UInt` value using the given range and generator. public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt(truncatingBitPattern: bb), gg) } } @@ -227,7 +227,7 @@ extension UInt8 : RandomType { /// Returns a random `UInt8` value using the given range and generator. public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt8(truncatingBitPattern: bb), gg) } } @@ -236,7 +236,7 @@ extension UInt16 : RandomType { /// Returns a random `UInt16` value using the given range and generator. public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt16(truncatingBitPattern: bb), gg) } } @@ -245,7 +245,7 @@ extension UInt32 : RandomType { /// Returns a random `UInt32` value using the given range and generator. public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt32(truncatingBitPattern: bb), gg) } } From 2a1402832ea4f2b87b752717638c3a89aee6ad38 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 8 Sep 2016 09:50:51 -0400 Subject: [PATCH 354/460] More escaping annotations --- Sources/Gen.swift | 2 +- Sources/Modifiers.swift | 8 ++++---- Sources/Test.swift | 6 +++--- Sources/Witness.swift | 4 ++-- Sources/WitnessedArbitrary.swift | 18 +++++++++--------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 0d53a6f..35bd153 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,7 +44,7 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf(_ xs : S) -> Gen + public static func fromElementsOf(_ xs : S) -> Gen where S.Index : Comparable & RandomType { return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 247c4c7..85356b0 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -510,12 +510,12 @@ fileprivate final class ArrowOfImpl : fileprivate var table : Dictionary fileprivate var arr : (T) -> U - init (_ table : Dictionary, _ arr : ((T) -> U)) { + init (_ table : Dictionary, _ arr : @escaping (T) -> U) { self.table = table self.arr = arr } - convenience init(_ arr : ((T) -> U)) { + convenience init(_ arr : @escaping (T) -> U) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) self.arr = { [unowned self] x in @@ -557,13 +557,13 @@ fileprivate final class IsoOfImpl U fileprivate var project : (U) -> T - init (_ table : Dictionary, _ embed : ((T) -> U), _ project : ((U) -> T)) { + init (_ table : Dictionary, _ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) { self.table = table self.embed = embed self.project = project } - convenience init(_ embed : ((T) -> U), _ project : ((U) -> T)) { + convenience init(_ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) self.embed = { [unowned self] t in diff --git a/Sources/Test.swift b/Sources/Test.swift index 9cfe6de..61731b4 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -101,7 +101,7 @@ /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : ((A) throws -> Testable)) -> Property { +public func forAll(_ pf : @escaping (A) throws -> Testable) -> Property { return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } @@ -182,7 +182,7 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { +public func forAll(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllShrink(gen, shrinker: A.shrink, f: pf) } @@ -301,7 +301,7 @@ public func forAll(_ gen : Gen, pf : ((A) throws -> Testable)) -> Property { +public func forAllNoShrink(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index ff7d725..29c750d 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -61,7 +61,7 @@ public protocol WitnessedArbitrary { /// A property test that relies on a witness that the given type parameter /// is actually `Arbitrary`. - static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : ((Self) -> Testable)) -> Property + static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : @escaping (Self) -> Testable) -> Property } /// Converts a function into a universally quantified property using the default @@ -70,7 +70,7 @@ public protocol WitnessedArbitrary { /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : ((A) -> Testable)) -> Property +public func forAll(_ pf : @escaping (A) -> Testable) -> Property where A.Param : Arbitrary { return A.forAllWitnessed(id, pf: pf) diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index e35c366..546a994 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -24,7 +24,7 @@ extension Array : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Array`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : (([Element]) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping ([Element]) -> Testable) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) }) @@ -48,7 +48,7 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnyBidirectionalCollection) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnyBidirectionalCollection) -> Testable) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) }) @@ -72,7 +72,7 @@ extension AnySequence : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnySequence`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((AnySequence) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnySequence) -> Testable) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) }) @@ -96,7 +96,7 @@ extension ArraySlice : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ArraySlice) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ArraySlice) -> Testable) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) }) @@ -115,7 +115,7 @@ extension CollectionOfOne : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((CollectionOfOne) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (CollectionOfOne) -> Testable) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in return pf(CollectionOfOne(wit(bl[bl.startIndex]))) }) @@ -147,7 +147,7 @@ extension Optional : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Optional`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : ((Optional) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : @escaping (Optional) -> Testable) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -171,7 +171,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((ContiguousArray) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ContiguousArray) -> Testable) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) }) @@ -251,7 +251,7 @@ extension Repeated : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Repeat`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Repeated) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Repeated) -> Testable) -> Property { return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) return pf(repeatElement(xs.first!, count: xs.count)) @@ -284,7 +284,7 @@ extension Set : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Set`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : ((Set) -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Set) -> Testable) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) } From c04904c15ccec88fd345c5c7a856279f3a735733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Miranda?= Date: Tue, 13 Sep 2016 17:42:16 -0300 Subject: [PATCH 355/460] Fix type in documentation markdown Silly `;` -> `:` --- Tutorial.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 37c057a..fc8f6a0 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -672,7 +672,7 @@ property("All Prime") <- forAll { (n : Positive) in return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } -//; # One More Thing +//: # One More Thing //: When working with failing tests, it's often tough to be able to replicate the exact conditions //: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework From 659ea26c8c615936c2ea581201416bc73f875b43 Mon Sep 17 00:00:00 2001 From: Michael Koukoullis Date: Thu, 15 Sep 2016 12:09:32 +1000 Subject: [PATCH 356/460] Disbale bitcode for Switch-Check-iOS Target --- SwiftCheck.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index fecc1f7..0f8a3f2 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -1027,6 +1027,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", @@ -1064,6 +1065,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", From 5f935be635d092611415094b1cf5e3fa481d72d0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 15 Sep 2016 10:16:46 -0400 Subject: [PATCH 357/460] Shuffle the furniture around a bit Drops a number of private functions obviated by recent changes in Swift 3.0 --- Sources/Arbitrary.swift | 22 ++++----- Sources/Property.swift | 13 +----- Sources/Test.swift | 76 +++++++++++++++++++++++--------- Sources/WitnessedArbitrary.swift | 22 +-------- 4 files changed, 66 insertions(+), 67 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 0399a58..703573e 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -342,18 +342,18 @@ extension Mirror : Arbitrary { /// Returns a generator of `Mirror` values. public static var arbitrary : Gen { let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.map(asAny), - Int.arbitrary.map(asAny), - UInt.arbitrary.map(asAny), - Float.arbitrary.map(asAny), - Double.arbitrary.map(asAny), - Character.arbitrary.map(asAny), + Bool.arbitrary.map { x in x as Any }, + Int.arbitrary.map { x in x as Any }, + UInt.arbitrary.map { x in x as Any }, + Float.arbitrary.map { x in x as Any }, + Double.arbitrary.map { x in x as Any }, + Character.arbitrary.map { x in x as Any }, ]) let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.map(asAny), - Array.arbitrary.map(asAny), - Set.arbitrary.map(asAny), + Optional.arbitrary.map { x in x as Any }, + Array.arbitrary.map { x in x as Any }, + Set.arbitrary.map { x in x as Any }, ]) return Gen.oneOf([ @@ -366,10 +366,6 @@ extension Mirror : Arbitrary { // MARK: - Implementation Details Follow -private func asAny(_ x : T) -> Any { - return x -} - extension Array where Element : Hashable { fileprivate var nub : [Element] { return [Element](Set(self)) diff --git a/Sources/Property.swift b/Sources/Property.swift index 63b8d60..d44d698 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -618,17 +618,6 @@ private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Di return res } -private func sep(_ l : String, r : String) -> String { - if l.isEmpty { - return r - } - - if r.isEmpty { - return l - } - return l + ", " + r -} - private func mplus(_ l : Optional, r : Optional) -> Optional { if let ls = l, let rs = r { return .some(ls + rs) @@ -751,7 +740,7 @@ private func disj(_ p : Rose, q : Rose) -> Rose.pure(TestResult( ok: .some(false), expect: true, - reason: sep(result1.reason, r: result2.reason), + reason: [result1.reason, result2.reason].joined(separator: ", "), theException: mplus(result1.theException, r: result2.theException), labels: [:], stamp: Set(), diff --git a/Sources/Test.swift b/Sources/Test.swift index 61731b4..bb38892 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -101,7 +101,9 @@ /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A) throws -> Testable) -> Property + where A : Arbitrary +{ return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } @@ -111,7 +113,9 @@ public func forAll(_ pf : @escaping (A) throws -> Testable) -> Pr /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary +{ return forAll { t in forAll { b in try pf(t, b) } } } @@ -121,7 +125,9 @@ public func forAll(_ pf : @escaping (A, B) throws /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary +{ return forAll { t in forAll { b, c in try pf(t, b, c) } } } @@ -131,7 +137,9 @@ public func forAll(_ pf : @escaping /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary +{ return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } @@ -141,7 +149,9 @@ public func forAll(_ /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary +{ return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } @@ -151,7 +161,9 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } @@ -161,7 +173,9 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } @@ -171,7 +185,9 @@ public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary, H : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } @@ -182,7 +198,9 @@ public func forAll(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { +public func forAll(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property + where A : Arbitrary +{ return forAllShrink(gen, shrinker: A.shrink, f: pf) } @@ -194,7 +212,9 @@ public func forAll(_ gen : Gen, pf : @escaping (A) throws -> T /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } @@ -207,7 +227,9 @@ public func forAll(_ genA : Gen, _ genB : Gen(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } @@ -221,7 +243,9 @@ public func forAll(_ genA : Gen, /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } @@ -236,7 +260,9 @@ public func forAll(_ /// - parameter pf: A block that carries the property or invariant to be tested. /// /// - returns: A `Property` that executes the given testing block. -public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } @@ -252,7 +278,9 @@ public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } @@ -269,7 +297,9 @@ public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } @@ -287,7 +317,9 @@ public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary, H : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -789,7 +821,7 @@ private func doneTesting(_ st : CheckerState) -> Result { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { printCond(st.silence, "+++ OK, failed as expected. ") - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -803,7 +835,7 @@ private func doneTesting(_ st : CheckerState) -> Result { output: "" ) } else if insufficientCoverage(st) { - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) return .insufficientCoverage( numTests: st.successfulTestCount, @@ -813,7 +845,7 @@ private func doneTesting(_ st : CheckerState) -> Result { output: "" ) } else { - printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -915,7 +947,7 @@ private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (I let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, res.reason + pluralize(testMsg, i: (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + printCond(st.silence, res.reason + pluralize(testMsg, (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, st.successfulShrinkCount) : "") + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } @@ -927,7 +959,7 @@ private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Resu printCond(st.silence, "*** Failed! ", terminator: "") printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") + printCond(st.silence, reason + pluralize(testMsg, st.discardedTestCount) + "):") dispatchAfterFinalFailureCallbacks(st, res: lastTest) return res default: @@ -1009,7 +1041,7 @@ private func printDistributionGraph(_ st : CheckerState) { } } -private func pluralize(_ s : String, i : Int) -> String { +private func pluralize(_ s : String, _ i : Int) -> String { if i == 1 { return s } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 546a994..f99b1fa 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -293,37 +293,19 @@ extension Set : WitnessedArbitrary { // MARK: - Implementation Details Follow -private func bits(_ n : N) -> Int { - if n / 2 == 0 { - return 0 - } - return 1 + bits(n / 2) -} - private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 : [A] = take(k, xs: xs) - let xs2 : [A] = drop(k, xs: xs) - + let xs2 : [A] = Array(xs.suffix(max(0, xs.count - k))) if k > n { return [] } else if xs2.isEmpty { return [[]] } else { + let xs1 : [A] = Array(xs.prefix(k)) let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) return [xs2] + rec } } -private func take(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(_ num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n..(_ xs : [A]) -> [[A]] { if xs.isEmpty { return [[A]]() From 2f762b94fd2c874f17c2ce0872807ae82bd938a0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 15 Sep 2016 10:25:03 -0400 Subject: [PATCH 358/460] Remove explicit function argument label from callback --- Sources/Property.swift | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Sources/Property.swift b/Sources/Property.swift index d44d698..6ed35b2 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -218,7 +218,7 @@ extension Testable { return [c] + cbs.map { (c : Callback) -> Callback in switch c { case let .afterFinalFailure(.counterexample, f): - return .afterTest(kind: .counterexample, f: f) + return .afterTest(kind: .counterexample, f) default: return c } @@ -420,9 +420,9 @@ public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : /// to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. - case afterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterTest(kind : CallbackKind, (CheckerState, TestResult) -> ()) /// The callback is posted after all cases in the test have failed. - case afterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterFinalFailure(kind : CallbackKind, (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. @@ -733,10 +733,7 @@ private func disj(_ p : Rose, q : Rose) -> Rose.pure(result2) case .some(false): - let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, - f: { _ in - return print("") - })] + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { _ in return print("") })] return Rose.pure(TestResult( ok: .some(false), expect: true, From d6a8bdca0e44049ca0d3aba149a3b4c22f6eb176 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 18 Sep 2016 11:11:20 -0400 Subject: [PATCH 359/460] Try testing on linux --- .travis.yml | 8 +- Package.swift | 3 + SwiftCheck.xcodeproj/project.pbxproj | 242 +++++++++--------- Tests/LinuxMain.swift | 31 +++ .../BooleanIdentitySpec.swift | 6 + Tests/{ => SwiftCheckTests}/ComplexSpec.swift | 7 + Tests/{ => SwiftCheckTests}/DiscardSpec.swift | 7 + Tests/{ => SwiftCheckTests}/FailureSpec.swift | 13 + Tests/{ => SwiftCheckTests}/GenSpec.swift | 8 + Tests/{ => SwiftCheckTests}/LambdaSpec.swift | 7 + .../{ => SwiftCheckTests}/ModifierSpec.swift | 6 + Tests/{ => SwiftCheckTests}/PathSpec.swift | 10 +- .../{ => SwiftCheckTests}/PropertySpec.swift | 6 + .../RawRepresentableSpec.swift | 10 +- Tests/{ => SwiftCheckTests}/ReplaySpec.swift | 8 +- Tests/{ => SwiftCheckTests}/RoseSpec.swift | 7 + Tests/{ => SwiftCheckTests}/ShrinkSpec.swift | 6 + Tests/{ => SwiftCheckTests}/SimpleSpec.swift | 8 +- Tests/{ => SwiftCheckTests}/TestSpec.swift | 9 +- 19 files changed, 270 insertions(+), 132 deletions(-) create mode 100644 Tests/LinuxMain.swift rename Tests/{ => SwiftCheckTests}/BooleanIdentitySpec.swift (92%) rename Tests/{ => SwiftCheckTests}/ComplexSpec.swift (92%) rename Tests/{ => SwiftCheckTests}/DiscardSpec.swift (80%) rename Tests/{ => SwiftCheckTests}/FailureSpec.swift (91%) rename Tests/{ => SwiftCheckTests}/GenSpec.swift (98%) rename Tests/{ => SwiftCheckTests}/LambdaSpec.swift (97%) rename Tests/{ => SwiftCheckTests}/ModifierSpec.swift (93%) rename Tests/{ => SwiftCheckTests}/PathSpec.swift (94%) rename Tests/{ => SwiftCheckTests}/PropertySpec.swift (97%) rename Tests/{ => SwiftCheckTests}/RawRepresentableSpec.swift (78%) rename Tests/{ => SwiftCheckTests}/ReplaySpec.swift (84%) rename Tests/{ => SwiftCheckTests}/RoseSpec.swift (96%) rename Tests/{ => SwiftCheckTests}/ShrinkSpec.swift (89%) rename Tests/{ => SwiftCheckTests}/SimpleSpec.swift (96%) rename Tests/{ => SwiftCheckTests}/TestSpec.swift (91%) diff --git a/.travis.yml b/.travis.yml index 90513ee..995d71a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,11 +41,11 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-3.0-preview-6/ubuntu1404/swift-3.0-PREVIEW-6/swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz - - tar xzf swift-3.0-PREVIEW-6-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-3.0-PREVIEW-6-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" script: - - swift build + - swift test notifications: webhooks: urls: diff --git a/Package.swift b/Package.swift index b9b0e29..e807210 100644 --- a/Package.swift +++ b/Package.swift @@ -4,6 +4,9 @@ let package = Package( name: "SwiftCheck", targets: [ Target(name: "SwiftCheck"), + Target( + name: "SwiftCheckTests", + dependencies: ["SwiftCheck"]), ] ) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 00fb642..9287bbe 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,11 +7,53 @@ objects = { /* Begin PBXBuildFile section */ - 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; - 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; - 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; + 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; + 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; @@ -57,48 +99,6 @@ 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; - 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; - 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; @@ -155,9 +155,24 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 825C9AC81D8EE445003313E1 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = SOURCE_ROOT; }; + 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/SwiftCheckTests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/SwiftCheckTests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/SwiftCheckTests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/SwiftCheckTests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD41D8EE86E003313E1 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/SwiftCheckTests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/SwiftCheckTests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD71D8EE86E003313E1 /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/SwiftCheckTests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/SwiftCheckTests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/SwiftCheckTests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/SwiftCheckTests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/SwiftCheckTests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/SwiftCheckTests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; @@ -174,20 +189,6 @@ 826D81551C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D818F1C953D2D0022266C /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81901C953D2D0022266C /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81911C953D2D0022266C /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81921C953D2D0022266C /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81931C953D2D0022266C /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81941C953D2D0022266C /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81951C953D2D0022266C /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81961C953D2D0022266C /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81971C953D2D0022266C /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81981C953D2D0022266C /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81991C953D2D0022266C /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D819A1C953D2D0022266C /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D819B1C953D2D0022266C /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -302,21 +303,22 @@ 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { isa = PBXGroup; children = ( - 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */, - 826D818F1C953D2D0022266C /* ComplexSpec.swift */, - 826D81901C953D2D0022266C /* DiscardSpec.swift */, - 826D81911C953D2D0022266C /* FailureSpec.swift */, - 826D81921C953D2D0022266C /* GenSpec.swift */, - 826D81931C953D2D0022266C /* LambdaSpec.swift */, - 826D81941C953D2D0022266C /* ModifierSpec.swift */, - 826D81951C953D2D0022266C /* PathSpec.swift */, - 826D81961C953D2D0022266C /* PropertySpec.swift */, - 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */, - 826D81971C953D2D0022266C /* ReplaySpec.swift */, - 826D81981C953D2D0022266C /* RoseSpec.swift */, - 826D81991C953D2D0022266C /* ShrinkSpec.swift */, - 826D819A1C953D2D0022266C /* SimpleSpec.swift */, - 826D819B1C953D2D0022266C /* TestSpec.swift */, + 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, + 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, + 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, + 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, + 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, + 825C9AD41D8EE86E003313E1 /* GenSpec.swift */, + 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */, + 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, + 825C9AD71D8EE86E003313E1 /* PathSpec.swift */, + 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */, + 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */, + 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */, + 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */, + 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */, + 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */, + 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); path = SwiftCheckTests; @@ -599,21 +601,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -643,21 +645,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -687,21 +689,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..286346b --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,31 @@ +// +// LinuxMain.swift +// SwiftCheck +// +// Created by Robert Widmann on 9/18/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +import XCTest + +@testable import SwiftCheckTests + +#if !os(macOS) +XCTMain([ + BooleanIdentitySpec.allTests, + ComplexSpec.allTests, + DiscardSpec.allTests, + FailureSpec.allTests, + GenSpec.allTests, + LambdaSpec.allTests, + ModifierSpec.allTests, + PathSpec.allTests, + PropertySpec.allTests, + RawRepresentableSpec.allTests, + ReplaySpec.allTests, + RoseSpec.allTests, + ShrinkSpec.allTests, + SimpleSpec.allTests, + TestSpec.allTests, +]) +#endif diff --git a/Tests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift similarity index 92% rename from Tests/BooleanIdentitySpec.swift rename to Tests/SwiftCheckTests/BooleanIdentitySpec.swift index d8954b8..57ab3cb 100644 --- a/Tests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -57,4 +57,10 @@ class BooleanIdentitySpec : XCTestCase { return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift similarity index 92% rename from Tests/ComplexSpec.swift rename to Tests/SwiftCheckTests/ComplexSpec.swift index 7acfd67..56da96f 100644 --- a/Tests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -64,6 +64,13 @@ class ComplexSpec : XCTestCase { return e.characters.filter({ $0 == ":" }).count == 3 } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testEmailAddressProperties", testEmailAddressProperties), + ("testIPv6Properties", testIPv6Properties), + ]) + #endif } // MARK: String Conveniences diff --git a/Tests/DiscardSpec.swift b/Tests/SwiftCheckTests/DiscardSpec.swift similarity index 80% rename from Tests/DiscardSpec.swift rename to Tests/SwiftCheckTests/DiscardSpec.swift index c6f40f0..efb4601 100644 --- a/Tests/DiscardSpec.swift +++ b/Tests/SwiftCheckTests/DiscardSpec.swift @@ -25,4 +25,11 @@ class DiscardSpec : XCTestCase { return Discard() }.expectFailure } + + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testDiscardFailure", testDiscardFailure), + ]) + #endif } diff --git a/Tests/FailureSpec.swift b/Tests/SwiftCheckTests/FailureSpec.swift similarity index 91% rename from Tests/FailureSpec.swift rename to Tests/SwiftCheckTests/FailureSpec.swift index 2f7c3df..8db81cc 100644 --- a/Tests/FailureSpec.swift +++ b/Tests/SwiftCheckTests/FailureSpec.swift @@ -9,6 +9,12 @@ import SwiftCheck import XCTest +#if os(Linux) + import Glibc +#else + import Darwin +#endif + enum SwiftCheckError : Error { case bogus } @@ -60,4 +66,11 @@ class FailureSpec : XCTestCase { override func tearDown() { XCTAssert(failCount == tests.count) } + + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testProperties", testProperties), + ]) + #endif } diff --git a/Tests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift similarity index 98% rename from Tests/GenSpec.swift rename to Tests/SwiftCheckTests/GenSpec.swift index 033dd39..c3f57ed 100644 --- a/Tests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -8,6 +8,7 @@ import SwiftCheck import XCTest +import Foundation class GenSpec : XCTestCase { func testAll() { @@ -308,6 +309,13 @@ class GenSpec : XCTestCase { } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testLaws", testLaws), + ]) + #endif } internal func curry(_ f : @escaping (A, B) -> C) -> (A) -> (B) -> C { diff --git a/Tests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift similarity index 97% rename from Tests/LambdaSpec.swift rename to Tests/SwiftCheckTests/LambdaSpec.swift index e9a5c0e..f38692b 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -189,4 +189,11 @@ class LambdaSpec : XCTestCase { } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } + diff --git a/Tests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift similarity index 93% rename from Tests/ModifierSpec.swift rename to Tests/SwiftCheckTests/ModifierSpec.swift index 6b6cf35..fb9dd4e 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -60,4 +60,10 @@ class ModifierSpec : XCTestCase { return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testModifiers", testModifiers), + ]) + #endif } diff --git a/Tests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift similarity index 94% rename from Tests/PathSpec.swift rename to Tests/SwiftCheckTests/PathSpec.swift index c98d01e..f49fc9b 100644 --- a/Tests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -55,13 +55,13 @@ class PathSpec : XCTestCase { private static func smallProp(_ pth : Path) -> Bool { return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 - }, pth) + }, pth) } private static func largeProp(_ pth : Path) -> Property { return somePath({ x in return (x < -1000000 || x > 1000000) - }, pth) + }, pth) } func testAll() { @@ -97,5 +97,11 @@ class PathSpec : XCTestCase { return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift similarity index 97% rename from Tests/PropertySpec.swift rename to Tests/SwiftCheckTests/PropertySpec.swift index 1d9183c..f0acdfd 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -168,4 +168,10 @@ class PropertySpec : XCTestCase { return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testProperties", testProperties), + ]) + #endif } diff --git a/Tests/RawRepresentableSpec.swift b/Tests/SwiftCheckTests/RawRepresentableSpec.swift similarity index 78% rename from Tests/RawRepresentableSpec.swift rename to Tests/SwiftCheckTests/RawRepresentableSpec.swift index 6203fb8..bef8bdf 100644 --- a/Tests/RawRepresentableSpec.swift +++ b/Tests/SwiftCheckTests/RawRepresentableSpec.swift @@ -23,8 +23,8 @@ enum ExplicitRawIntValues : Int { case two = 2 } -class RawRepresentableSpec: XCTestCase { - func testRepresentable() { +class RawRepresentableSpec : XCTestCase { + func testAll() { property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in return [.foo, .bar, .baz].contains(e) } @@ -33,4 +33,10 @@ class RawRepresentableSpec: XCTestCase { return [.zero, .one, .two].contains(e) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/ReplaySpec.swift b/Tests/SwiftCheckTests/ReplaySpec.swift similarity index 84% rename from Tests/ReplaySpec.swift rename to Tests/SwiftCheckTests/ReplaySpec.swift index 9723d6d..7d02134 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/SwiftCheckTests/ReplaySpec.swift @@ -10,7 +10,7 @@ import SwiftCheck import XCTest class ReplaySpec : XCTestCase { - func testProperties() { + func testAll() { property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) var foundArgs : [Int] = [] @@ -28,4 +28,10 @@ class ReplaySpec : XCTestCase { return foundArgs == foundArgs2 } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift similarity index 96% rename from Tests/RoseSpec.swift rename to Tests/SwiftCheckTests/RoseSpec.swift index a2a5506..6885e01 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -76,6 +76,13 @@ class RoseSpec : XCTestCase { } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testLaws", testLaws), + ]) + #endif } struct RoseTreeOf : Arbitrary { diff --git a/Tests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift similarity index 89% rename from Tests/ShrinkSpec.swift rename to Tests/SwiftCheckTests/ShrinkSpec.swift index ae8ac83..6df6452 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -38,4 +38,10 @@ class ShrinkSpec : XCTestCase { } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift similarity index 96% rename from Tests/SimpleSpec.swift rename to Tests/SwiftCheckTests/SimpleSpec.swift index 57fb9fb..145c1eb 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -206,5 +206,11 @@ class SimpleSpec : XCTestCase { // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size }.mapSize { $0 + 100 }) } -} + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testComposeWithMutableType", testComposeWithMutableType), + ]) + #endif +} diff --git a/Tests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift similarity index 91% rename from Tests/TestSpec.swift rename to Tests/SwiftCheckTests/TestSpec.swift index 74e80b2..f1c78ce 100644 --- a/Tests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -7,7 +7,7 @@ // import SwiftCheck -import class XCTest.XCTestCase +import XCTest class TestSpec : XCTestCase { func testAll() { @@ -50,5 +50,10 @@ class TestSpec : XCTestCase { } } } -} + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif +} From c120190cc4e6b67d866065ce2983aab02982c364 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Tue, 20 Sep 2016 12:13:18 -0700 Subject: [PATCH 360/460] Merge branch master and update template to swift 3 --- .gitignore | 1 + .gitmodules | 3 - .travis.yml | 33 +- Cartfile.private | 1 - Cartfile.resolved | 1 - Package.swift | 5 +- README.md | 62 +- Sources/Arbitrary.swift | 157 ++- Sources/Cartesian.swift.gyb | 50 +- Sources/{TestOperators.swift => Check.swift} | 145 +-- Sources/CoArbitrary.swift | 113 +- Sources/Compose.swift | 89 ++ Sources/Gen.swift | 272 +++-- Sources/Lattice.swift | 44 +- Sources/Modifiers.swift | 194 ++-- Sources/Operators.swift | 246 ----- Sources/Property.swift | 650 +++++++----- Sources/Random.swift | 132 ++- Sources/Rose.swift | 127 +-- Sources/State.swift | 91 +- Sources/SwiftCheck.h | 1 - Sources/Test.swift | 982 +++++++++++------- Sources/Testable.swift | 56 +- Sources/Witness.swift | 90 +- Sources/WitnessedArbitrary.swift | 156 ++- SwiftCheck.podspec | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 345 +++--- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcschemes/SwiftCheck.xcscheme | 10 +- Tests/LinuxMain.swift | 31 + Tests/RawRepresentableSpec.swift | 42 - .../BooleanIdentitySpec.swift | 6 + Tests/{ => SwiftCheckTests}/ComplexSpec.swift | 39 +- Tests/{ => SwiftCheckTests}/DiscardSpec.swift | 18 +- Tests/{ => SwiftCheckTests}/FailureSpec.swift | 31 +- Tests/{ => SwiftCheckTests}/GenSpec.swift | 107 +- Tests/{ => SwiftCheckTests}/LambdaSpec.swift | 97 +- .../{ => SwiftCheckTests}/ModifierSpec.swift | 18 +- Tests/{ => SwiftCheckTests}/PathSpec.swift | 76 +- .../{ => SwiftCheckTests}/PropertySpec.swift | 62 +- .../RawRepresentableSpec.swift | 42 + Tests/{ => SwiftCheckTests}/ReplaySpec.swift | 10 +- Tests/{ => SwiftCheckTests}/RoseSpec.swift | 84 +- Tests/{ => SwiftCheckTests}/ShrinkSpec.swift | 17 +- Tests/{ => SwiftCheckTests}/SimpleSpec.swift | 97 +- Tests/{ => SwiftCheckTests}/TestSpec.swift | 34 +- Tutorial.playground/Contents.swift | 107 +- 48 files changed, 2687 insertions(+), 2293 deletions(-) delete mode 100644 .gitmodules delete mode 100644 Cartfile.private rename Sources/{TestOperators.swift => Check.swift} (73%) create mode 100644 Sources/Compose.swift delete mode 100644 Sources/Operators.swift create mode 100644 Tests/LinuxMain.swift delete mode 100644 Tests/RawRepresentableSpec.swift rename Tests/{ => SwiftCheckTests}/BooleanIdentitySpec.swift (92%) rename Tests/{ => SwiftCheckTests}/ComplexSpec.swift (57%) rename Tests/{ => SwiftCheckTests}/DiscardSpec.swift (57%) rename Tests/{ => SwiftCheckTests}/FailureSpec.swift (72%) rename Tests/{ => SwiftCheckTests}/GenSpec.swift (77%) rename Tests/{ => SwiftCheckTests}/LambdaSpec.swift (61%) rename Tests/{ => SwiftCheckTests}/ModifierSpec.swift (78%) rename Tests/{ => SwiftCheckTests}/PathSpec.swift (59%) rename Tests/{ => SwiftCheckTests}/PropertySpec.swift (76%) create mode 100644 Tests/SwiftCheckTests/RawRepresentableSpec.swift rename Tests/{ => SwiftCheckTests}/ReplaySpec.swift (77%) rename Tests/{ => SwiftCheckTests}/RoseSpec.swift (69%) rename Tests/{ => SwiftCheckTests}/ShrinkSpec.swift (66%) rename Tests/{ => SwiftCheckTests}/SimpleSpec.swift (57%) rename Tests/{ => SwiftCheckTests}/TestSpec.swift (60%) diff --git a/.gitignore b/.gitignore index 08490e1..4bb4329 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Xcode .DS_Store +.build/* */build/* *.pbxuser !default.pbxuser diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index bf0c263..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "Carthage/Checkouts/Operadics"] - path = Carthage/Checkouts/Operadics - url = https://github.com/typelift/Operadics.git diff --git a/.travis.yml b/.travis.yml index 5a93f50..995d71a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,21 +5,34 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode7.3 + osx_image: xcode8 before_install: - git submodule update --init --recursive script: - - pod lib lint + # Restore pod build before shipping for 3.0 + # - pod lib lint - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode7.3 + osx_image: xcode8 before_install: - git submodule update --init --recursive script: - set -o pipefail - xcodebuild test -scheme SwiftCheck | xcpretty -c - - xcodebuild test -scheme SwiftCheck-iOS -destination 'platform=iOS Simulator,name=iPad Pro' | xcpretty -c + # -- Start iOS -- + # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image + - iOS_DEVICE_NAME="iPad Pro (12.9 inch)" + - iOS_RUNTIME_VERSION="10.0" + # Get simulator identifier for desired device/runtime pair + - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") + - echo $SIMULATOR_ID + - echo $iOS_DEVICE_NAME + - echo $iOS_RUNTIME_VERSION + # !!!: Start simulator w/ desired device—helps avoid issues w/ Xcode timing out when waiting for simulator to become ready + - open -b com.apple.iphonesimulator --args -CurrentDeviceUDID $SIMULATOR_ID + - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c + # -- End iOS -- - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - os: linux language: generic @@ -28,15 +41,11 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" - - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" script: - - swift build + - swift test notifications: webhooks: urls: diff --git a/Cartfile.private b/Cartfile.private deleted file mode 100644 index 077b243..0000000 --- a/Cartfile.private +++ /dev/null @@ -1 +0,0 @@ -github "typelift/Operadics" diff --git a/Cartfile.resolved b/Cartfile.resolved index 1dd0fd1..e69de29 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +0,0 @@ -github "typelift/Operadics" "0.1.4" diff --git a/Package.swift b/Package.swift index 682f4a3..e807210 100644 --- a/Package.swift +++ b/Package.swift @@ -4,8 +4,9 @@ let package = Package( name: "SwiftCheck", targets: [ Target(name: "SwiftCheck"), - Target(name: "SwiftCheck-iOS"), - Target(name: "SwiftCheck-tvOS"), + Target( + name: "SwiftCheckTests", + dependencies: ["SwiftCheck"]), ] ) diff --git a/README.md b/README.md index 5d3e3ab..cae5198 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ SwiftCheck is a testing library that automatically generates random data for testing of program properties. A property is a particular facet of an algorithm or data structure that must be invariant under a given set of input data, basically an `XCTAssert` on steroids. Where before all we could do was define -methods prefixed by `test` and assert, SwiftCheck allows program properties and tests to be treated like *data*. +methods prefixed by `test` and assert, SwiftCheck allows program properties and +tests to be treated like *data*. To define a program property the `forAll` quantifier is used with a type signature like `(A, B, C, ... Z) -> Testable where A : Arbitrary, B : Arbitrary ... @@ -156,8 +157,8 @@ func isPrime(n : Int) -> Bool { ``` -We would like to test whether our sieve works properly, so we run it through SwiftCheck -with the following property: +We would like to test whether our sieve works properly, so we run it through +SwiftCheck with the following property: ```swift import SwiftCheck @@ -206,10 +207,6 @@ public struct ArbitraryFoo { let x : Int let y : Int - public static func create(x : Int) -> Int -> ArbitraryFoo { - return { y in ArbitraryFoo(x: x, y: y) } - } - public var description : String { return "Arbitrary Foo!" } @@ -217,7 +214,7 @@ public struct ArbitraryFoo { extension ArbitraryFoo : Arbitrary { public static var arbitrary : Gen { - return ArbitraryFoo.create <^> Int.arbitrary <*> Int.arbitrary + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) } } @@ -230,6 +227,49 @@ class SimpleSpec : XCTestCase { } ``` +There's also a `Gen.compose` method which allows you to procedurally compose +values from multiple generators to construct instances of a type: + +``` swift +public static var arbitrary : Gen { + return Gen.compose { c in + return MyClass( + // Use the nullary method to get an `arbitrary` value. + a: c.generate(), + + // or pass a custom generator + b: c.generate(Bool.suchThat { $0 == false }), + + // .. and so on, for as many values and types as you need. + c: c.generate(), ... + ) + } +} +``` + +`Gen.compose` can also be used with types that can only be customized with setters: + +``` swift +public struct ArbitraryMutableFoo : Arbitrary { + var a: Int8 + var b: Int16 + + public init() { + a = 0 + b = 0 + } + + public static var arbitrary: Gen { + return Gen.compose { c in + var foo = ArbitraryMutableFoo() + foo.a = c.generate() + foo.b = c.generate() + return foo + } + } +} +``` + For everything else, SwiftCheck defines a number of combinators to make working with custom generators as simple as possible: @@ -244,11 +284,11 @@ let uppers : Gen= Gen.fromElementsIn("A"..."Z") let lowers : Gen = Gen.fromElementsIn("a"..."z") let numbers : Gen = Gen.fromElementsIn("0"..."9") -/// This generator will generate `.None` 1/4 of the time and an arbitrary -/// `.Some` 3/4 of the time +/// This generator will generate `.none` 1/4 of the time and an arbitrary +/// `.some` 3/4 of the time let weightedOptionals = Gen.frequency([ (1, Gen.pure(nil)), - (3, Optional.Some <^> Int.arbitrary) + (3, Int.arbitrary.map(Optional.some)) ]) ``` diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 98cbe6e..703573e 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -8,48 +8,48 @@ /// A type that implements random generation and shrinking of values. /// -/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times -/// (usually 100 if the default settings are used). During that time, the -/// receiver has an opportunity to call through to any data or sources of +/// While testing, SwiftCheck will invoke `arbitrary` a given amount of times +/// (usually 100 if the default settings are used). During that time, the +/// receiver has an opportunity to call through to any data or sources of /// randomness it needs to return what it deems an "Arbitrary" value. /// -/// Shrinking is reduction in the complexity of a tested value to remove noise -/// and present a minimal counterexample when a property fails. A shrink -/// necessitates returning a list of all possible "smaller" values for +/// Shrinking is reduction in the complexity of a tested value to remove noise +/// and present a minimal counterexample when a property fails. A shrink +/// necessitates returning a list of all possible "smaller" values for /// SwiftCheck to run through. As long as each individual value in the returned -/// list is less than or equal to the size of the input value, and is not a -/// duplicate of the input value, a minimal case should be reached fairly -/// efficiently. Shrinking is an optional extension of normal testing. If no -/// implementation of `shrink` is provided, SwiftCheck will default to an empty +/// list is less than or equal to the size of the input value, and is not a +/// duplicate of the input value, a minimal case should be reached fairly +/// efficiently. Shrinking is an optional extension of normal testing. If no +/// implementation of `shrink` is provided, SwiftCheck will default to an empty /// one - that is, no shrinking will occur. /// /// As an example, take the `ArrayOf` implementation of shrink: /// /// Arbitrary.shrink(ArrayOf([1, 2, 3])) -/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] +/// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// /// SwiftCheck will search each case forward, one-by-one, and continue shrinking /// until it has reached a case it deems minimal enough to present. /// -/// SwiftCheck implements a number of generators for common Swift Standard +/// SwiftCheck implements a number of generators for common Swift Standard /// Library types for convenience. If more fine-grained testing is required see -/// `Modifiers.swift` for an example of how to define a "Modifier" type to +/// `Modifiers.swift` for an example of how to define a "Modifier" type to /// implement it. public protocol Arbitrary { /// The generator for this particular type. /// - /// This function should call out to any sources of randomness or state - /// necessary to generate values. It should not, however, be written as a - /// deterministic function. If such a generator is needed, combinators are + /// This function should call out to any sources of randomness or state + /// necessary to generate values. It should not, however, be written as a + /// deterministic function. If such a generator is needed, combinators are /// provided in `Gen.swift`. static var arbitrary : Gen { get } - /// An optional shrinking function. If this function goes unimplemented, it + /// An optional shrinking function. If this function goes unimplemented, it /// is the same as returning the empty list. /// - /// Shrunken values must be less than or equal to the "size" of the original - /// type but never the same as the value provided to this function (or a loop - /// will form in the shrinker). It is recommended that they be presented + /// Shrunken values must be less than or equal to the "size" of the original + /// type but never the same as the value provided to this function (or a loop + /// will form in the shrinker). It is recommended that they be presented /// smallest to largest to speed up the overall shrinking process. static func shrink(_ : Self) -> [Self] } @@ -61,24 +61,23 @@ extension Arbitrary { } } -extension IntegerType { +extension Integer { /// Shrinks any `IntegerType`. public var shrinkIntegral : [Self] { return unfoldr({ i in if i <= 0 { - return .None + return .none } let n = i / 2 - return .Some((n, n)) + return .some((n, n)) }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) } } -extension RawRepresentable where RawValue: Arbitrary { - /// Default implementation, maps arbitrary values of its `RawValue` type - /// until a valid representation is obtained. Naturally, you should strive - /// to override this with a more efficient version. - public static var arbitrary: Gen { +extension RawRepresentable where RawValue : Arbitrary & Integer { + /// Uses the default generator for `Integer` values to search for a value + /// that can construct an instance of the reciever's type. + public static var arbitrary : Gen { return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } } } @@ -90,7 +89,7 @@ extension Bool : Arbitrary { } /// The default shrinking function for `Bool`ean values. - public static func shrink(x : Bool) -> [Bool] { + public static func shrink(_ x : Bool) -> [Bool] { if x { return [false] } @@ -107,7 +106,7 @@ extension Int : Arbitrary { } /// The default shrinking function for `Int` values. - public static func shrink(x : Int) -> [Int] { + public static func shrink(_ x : Int) -> [Int] { return x.shrinkIntegral } } @@ -121,7 +120,7 @@ extension Int8 : Arbitrary { } /// The default shrinking function for `Int8` values. - public static func shrink(x : Int8) -> [Int8] { + public static func shrink(_ x : Int8) -> [Int8] { return x.shrinkIntegral } } @@ -135,7 +134,7 @@ extension Int16 : Arbitrary { } /// The default shrinking function for `Int16` values. - public static func shrink(x : Int16) -> [Int16] { + public static func shrink(_ x : Int16) -> [Int16] { return x.shrinkIntegral } } @@ -149,7 +148,7 @@ extension Int32 : Arbitrary { } /// The default shrinking function for `Int32` values. - public static func shrink(x : Int32) -> [Int32] { + public static func shrink(_ x : Int32) -> [Int32] { return x.shrinkIntegral } } @@ -163,7 +162,7 @@ extension Int64 : Arbitrary { } /// The default shrinking function for `Int64` values. - public static func shrink(x : Int64) -> [Int64] { + public static func shrink(_ x : Int64) -> [Int64] { return x.shrinkIntegral } } @@ -175,7 +174,7 @@ extension UInt : Arbitrary { } /// The default shrinking function for `UInt` values. - public static func shrink(x : UInt) -> [UInt] { + public static func shrink(_ x : UInt) -> [UInt] { return x.shrinkIntegral } } @@ -189,7 +188,7 @@ extension UInt8 : Arbitrary { } /// The default shrinking function for `UInt8` values. - public static func shrink(x : UInt8) -> [UInt8] { + public static func shrink(_ x : UInt8) -> [UInt8] { return x.shrinkIntegral } } @@ -201,7 +200,7 @@ extension UInt16 : Arbitrary { } /// The default shrinking function for `UInt16` values. - public static func shrink(x : UInt16) -> [UInt16] { + public static func shrink(_ x : UInt16) -> [UInt16] { return x.shrinkIntegral } } @@ -213,7 +212,7 @@ extension UInt32 : Arbitrary { } /// The default shrinking function for `UInt32` values. - public static func shrink(x : UInt32) -> [UInt32] { + public static func shrink(_ x : UInt32) -> [UInt32] { return x.shrinkIntegral } } @@ -225,7 +224,7 @@ extension UInt64 : Arbitrary { } /// The default shrinking function for `UInt64` values. - public static func shrink(x : UInt64) -> [UInt64] { + public static func shrink(_ x : UInt64) -> [UInt64] { return x.shrinkIntegral } } @@ -243,20 +242,20 @@ extension Float : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Float(a) / Float(b)) } } + return numerator.flatMap { a in + return denominator.flatMap { b in Gen.pure(Float(a) / Float(b)) } + } } } /// The default shrinking function for `Float` values. - public static func shrink(x : Float) -> [Float] { + public static func shrink(_ x : Float) -> [Float] { return unfoldr({ i in if i == 0.0 { - return .None + return .none } let n = i / 2.0 - return .Some((n, n)) + return .some((n, n)) }, initial: x) } } @@ -274,20 +273,21 @@ extension Double : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return numerator - >>- { a in denominator - >>- { b in Gen.pure(Double(a) / Double(b)) } } + return numerator.flatMap { a in + return denominator.flatMap { b in Gen.pure(Double(a) / Double(b)) + } + } } } /// The default shrinking function for `Double` values. - public static func shrink(x : Double) -> [Double] { + public static func shrink(_ x : Double) -> [Double] { return unfoldr({ i in if i == 0.0 { - return .None + return .none } let n = i / 2.0 - return .Some((n, n)) + return .some((n, n)) }, initial: x) } } @@ -295,12 +295,12 @@ extension Double : Arbitrary { extension UnicodeScalar : Arbitrary { /// Returns a generator of `UnicodeScalar` values. public static var arbitrary : Gen { - return UInt32.arbitrary.flatMap(Gen.pure • UnicodeScalar.init) + return UInt32.arbitrary.flatMap { Gen.pure(UnicodeScalar($0)!) } } /// The default shrinking function for `UnicodeScalar` values. - public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { - let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value)))) + public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { + let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } } } @@ -309,11 +309,11 @@ extension String : Arbitrary { /// Returns a generator of `String` values. public static var arbitrary : Gen { let chars = Gen.sized(Character.arbitrary.proliferateSized) - return chars >>- { Gen.pure(String($0)) } + return chars.flatMap { Gen.pure(String($0)) } } /// The default shrinking function for `String` values. - public static func shrink(s : String) -> [String] { + public static func shrink(_ s : String) -> [String] { return [Character].shrink([Character](s.characters)).map { String($0) } } } @@ -321,27 +321,20 @@ extension String : Arbitrary { extension Character : Arbitrary { /// Returns a generator of `Character` values. public static var arbitrary : Gen { - return Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) + return Gen.choose((32, 255)).flatMap(comp(Gen.pure, comp(Character.init, UnicodeScalar.init))) } /// The default shrinking function for `Character` values. - public static func shrink(x : Character) -> [Character] { + public static func shrink(_ x : Character) -> [Character] { let ss = String(x).unicodeScalars return UnicodeScalar.shrink(ss[ss.startIndex]).map(Character.init) } } -extension AnyForwardIndex : Arbitrary { +extension AnyIndex : Arbitrary { /// Returns a generator of `AnyForwardIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyForwardIndex.init) - } -} - -extension AnyRandomAccessIndex : Arbitrary { - /// Returns a generator of `AnyRandomAccessIndex` values. - public static var arbitrary : Gen { - return Gen.choose((1, Int64.max)).flatMap(Gen.pure • AnyRandomAccessIndex.init) + public static var arbitrary : Gen { + return Gen.choose((1, Int64.max)).flatMap(comp(Gen.pure, AnyIndex.init)) } } @@ -349,18 +342,18 @@ extension Mirror : Arbitrary { /// Returns a generator of `Mirror` values. public static var arbitrary : Gen { let genAny : Gen = Gen.oneOf([ - Bool.arbitrary.map(asAny), - Int.arbitrary.map(asAny), - UInt.arbitrary.map(asAny), - Float.arbitrary.map(asAny), - Double.arbitrary.map(asAny), - Character.arbitrary.map(asAny), + Bool.arbitrary.map { x in x as Any }, + Int.arbitrary.map { x in x as Any }, + UInt.arbitrary.map { x in x as Any }, + Float.arbitrary.map { x in x as Any }, + Double.arbitrary.map { x in x as Any }, + Character.arbitrary.map { x in x as Any }, ]) let genAnyWitnessed : Gen = Gen.oneOf([ - Optional.arbitrary.map(asAny), - Array.arbitrary.map(asAny), - Set.arbitrary.map(asAny), + Optional.arbitrary.map { x in x as Any }, + Array.arbitrary.map { x in x as Any }, + Set.arbitrary.map { x in x as Any }, ]) return Gen.oneOf([ @@ -373,21 +366,17 @@ extension Mirror : Arbitrary { // MARK: - Implementation Details Follow -private func asAny(x : T) -> Any { - return x -} - extension Array where Element : Hashable { - private var nub : [Element] { + fileprivate var nub : [Element] { return [Element](Set(self)) } } -private func unfoldr(f : B -> Optional<(A, B)>, initial : B) -> [A] { +private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { var acc = [A]() var ini = initial while let next = f(ini) { - acc.insert(next.0, atIndex: 0) + acc.insert(next.0, at: 0) ini = next.1 } return acc diff --git a/Sources/Cartesian.swift.gyb b/Sources/Cartesian.swift.gyb index a7fdd63..1e0f883 100644 --- a/Sources/Cartesian.swift.gyb +++ b/Sources/Cartesian.swift.gyb @@ -7,59 +7,65 @@ // %{ -max_arity = 22 +MAX_ARITY = 22 }% extension Gen /*: Cartesian*/ { /// Zips together two generators and returns a generator of tuples. - public static func zip(ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { + public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { return Gen<(A1, A2)> { r, n in let (r1, r2) = r.split return (ga1.unGen(r1, n), ga2.unGen(r2, n)) } } - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(ga1 : Gen, _ ga2 : Gen, transform: (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } -% for arity in range(3, max_arity + 1): - +% for arity in range(3, MAX_ARITY + 1): %{ # Zip definition template type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) -parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(2, arity + 1)]) +parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) # Zip body template previous_parameter_range = range(1, arity) -previous_zip_type_arguments = ', '.join(['A{0}'.format(n) for n in previous_parameter_range]) previous_zip_arguments = ', '.join(['ga{0}'.format(n) for n in previous_parameter_range]) expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_parameter_range]) - -# Map body template -map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) - }% + /// Zips together ${arity} generators generator of tuples. - public static func zip<${type_parameter_list}>(ga1 : Gen, ${parameter_list}) -> Gen<(${type_parameter_list})> { - return Gen<(${previous_zip_type_arguments}, A${arity})> + public static func zip<${type_parameter_list}>(${parameter_list}) -> Gen<(${type_parameter_list})> { + return Gen .zip( .zip(${previous_zip_arguments}), ga${arity} ).map { - ( - ${expanded_previous_tuple}, - $$1 - ) + (${expanded_previous_tuple}, $$1) } } +% end + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } + +% for arity in range(3, MAX_ARITY + 1): +%{ + +# Map definition template +type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) +parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) + +# Map body template +map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) + +}% /// Returns a new generator that applies a given function to any outputs the /// two receivers create. - public static func map<${type_parameter_list}, R>(ga1 : Gen, ${parameter_list}, transform: (${type_parameter_list}) -> R) -> Gen { + public static func map<${type_parameter_list}, R>(${parameter_list}, transform: @escaping (${type_parameter_list}) -> R) -> Gen { return zip(${map_zip_argument_list}).map(transform) } % end diff --git a/Sources/TestOperators.swift b/Sources/Check.swift similarity index 73% rename from Sources/TestOperators.swift rename to Sources/Check.swift index 5275624..455ae07 100644 --- a/Sources/TestOperators.swift +++ b/Sources/Check.swift @@ -1,24 +1,24 @@ // -// Operators.swift +// Check.swift // SwiftCheck // // Created by Robert Widmann on 5/4/15. // Copyright (c) 2015 TypeLift. All rights reserved. // -/// The main interface for the SwiftCheck testing mechanism. `property` -/// notation is used to define a property that SwiftCheck can generate test -/// cases for and a human-readable label for debugging output. A simple +/// The main interface for the SwiftCheck testing mechanism. `property` +/// notation is used to define a property that SwiftCheck can generate test +/// cases for and a human-readable label for debugging output. A simple /// property test might look like the following: /// /// property("reflexitivity") <- forAll { (i : Int8) in -/// return i == i +/// return i == i /// } /// -/// SwiftCheck will report all failures through the XCTest mechanism like a +/// SwiftCheck will report all failures through the XCTest mechanism like a /// normal testing assert, but with the minimal failing case reported as well. /// -/// If necessary, arguments can be provided to this function to change the +/// If necessary, arguments can be provided to this function to change the /// behavior of the testing mechanism: /// /// let args = CheckerArguments @@ -29,24 +29,23 @@ /// ) /// /// property("reflexitivity", arguments: args) <- forAll { (i : Int8) in -/// return i == i +/// return i == i /// } /// /// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func property(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { +public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that uses XCTest to assert all testing failures and /// display them in both the testing log and Xcode. public struct AssertiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line @@ -56,20 +55,19 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. -@warn_unused_result(message="Did you forget to bind this property to a quantifier?") -public func reportProperty(msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { +public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) } /// Describes a checker that only reports failures to the testing log but does /// not assert when a property fails. public struct ReportiveQuickCheck { - private let msg : String - private let file : StaticString - private let line : UInt - private let args : CheckerArguments - - private init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { + fileprivate let msg : String + fileprivate let file : StaticString + fileprivate let line : UInt + fileprivate let args : CheckerArguments + + fileprivate init(msg : String, file : StaticString, line : UInt, args : CheckerArguments) { self.msg = msg self.file = file self.line = line @@ -77,7 +75,7 @@ public struct ReportiveQuickCheck { } } -/// Represents the arguments the test driver will use while performing testing, +/// Represents the arguments the test driver will use while performing testing, /// shrinking, and printing results. public struct CheckerArguments { /// Provides a way of re-doing a test at the given size with a new generator. @@ -86,7 +84,7 @@ public struct CheckerArguments { /// passes. /// /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` + /// this amount, but less is rare. If you need a value of 1 use `.once` /// on the property instead. let maxAllowableSuccessfulTests : Int /// The maximum number of tests cases that can be discarded before testing gives up on the @@ -102,9 +100,9 @@ public struct CheckerArguments { /// size, are necessary then increase this value, else keep it relatively near the default. If /// it becomes too small the samples present in the test case will lose diversity. let maxTestCaseSize : Int - + internal let silence : Bool - + public init(replay : Optional<(StdGen, Int)> = nil , maxAllowableSuccessfulTests : Int = 100 , maxAllowableDiscardedTests : Int = 500 @@ -118,7 +116,7 @@ public struct CheckerArguments { , name: "" ) } - + internal init(replay : Optional<(StdGen, Int)> = nil , maxAllowableSuccessfulTests : Int = 100 , maxAllowableDiscardedTests : Int = 500 @@ -127,7 +125,7 @@ public struct CheckerArguments { , silence : Bool = false ) { - + self.replay = replay self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests self.maxAllowableDiscardedTests = maxAllowableDiscardedTests @@ -135,20 +133,20 @@ public struct CheckerArguments { self.name = name self.silence = silence } - + internal var name : String } -infix operator <- {} +infix operator <- /// Binds a Testable value to a property. -public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { +public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, _, seed, sz, reason, _, _): + case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .NoExpectedFailure(_, seed, sz, _, _): + case let .noExpectedFailure(_, seed, sz, _, _): XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .InsufficientCoverage(_, seed, sz, _, _): + case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return @@ -158,11 +156,11 @@ public func <- (checker : AssertiveQuickCheck, @autoclosure(escaping) test : () /// Binds a Testable value to a property. public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { switch quickCheckWithResult(checker.args, test()) { - case let .Failure(_, _, seed, sz, reason, _, _): + case let .failure(_, _, seed, sz, reason, _, _): XCTFail(reason + "; Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .NoExpectedFailure(_, seed, sz, _, _): + case let .noExpectedFailure(_, seed, sz, _, _): XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - case let .InsufficientCoverage(_, seed, sz, _, _): + case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) default: return @@ -171,23 +169,25 @@ public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { /// Binds a Testable value to a property. public func <- (checker : ReportiveQuickCheck, test : () -> Testable) { - quickCheckWithResult(checker.args, test()) + _ = quickCheckWithResult(checker.args, test()) } /// Binds a Testable value to a property. -public func <- (checker : ReportiveQuickCheck, @autoclosure(escaping) test : () -> Testable) { - quickCheckWithResult(checker.args, test()) +public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () -> Testable) { + _ = quickCheckWithResult(checker.args, test()) } -infix operator ==> { - associativity right - precedence 100 +precedencegroup SwiftCheckImplicationPrecedence { + associativity: right + lowerThan: ComparisonPrecedence } +infix operator ==> : SwiftCheckImplicationPrecedence + /// Models implication for properties. That is, the property holds if the first -/// argument is false (in which case the test case is discarded), or if the +/// argument is false (in which case the test case is discarded), or if the /// given property holds. -public func ==> (b : Bool, @autoclosure p : () -> Testable) -> Property { +public func ==> (b : Bool, p : @autoclosure() -> Testable) -> Property { if b { return p().property } @@ -195,7 +195,7 @@ public func ==> (b : Bool, @autoclosure p : () -> Testable) -> Property { } /// Models implication for properties. That is, the property holds if the first -/// argument is false (in which case the test case is discarded), or if the +/// argument is false (in which case the test case is discarded), or if the /// given property holds. public func ==> (b : Bool, p : () -> Testable) -> Property { if b { @@ -204,56 +204,57 @@ public func ==> (b : Bool, p : () -> Testable) -> Property { return Discard().property } -infix operator ==== { - precedence 140 -} +infix operator ==== : ComparisonPrecedence /// Like equality but prints a verbose description when it fails. -public func ==== (x : A, y : A) -> Property { - return (x == y).counterexample(String(x) + " /= " + String(y)) +public func ==== (x : A, y : A) -> Property + where A : Equatable +{ + return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) } - -infix operator { - associativity left - precedence 200 +precedencegroup SwiftCheckLabelPrecedence { + associativity: right + higherThan: BitwiseShiftPrecedence } +infix operator : SwiftCheckLabelPrecedence + /// Attaches a label to a property. /// -/// Labelled properties aid in testing conjunctions and disjunctions, or any -/// other cases where test cases need to be distinct from one another. In -/// addition to shrunken test cases, upon failure SwiftCheck will print a -/// distribution map for the property that shows a percentage success rate for +/// Labelled properties aid in testing conjunctions and disjunctions, or any +/// other cases where test cases need to be distinct from one another. In +/// addition to shrunken test cases, upon failure SwiftCheck will print a +/// distribution map for the property that shows a percentage success rate for /// the property. public func (p : Testable, s : String) -> Property { return p.label(s) } -infix operator ^&&^ { - associativity right - precedence 110 +precedencegroup SwiftCheckLogicalPrecedence { + associativity: left + higherThan: LogicalConjunctionPrecedence + lowerThan: ComparisonPrecedence } -/// Takes the conjunction of two properties and treats them as a single large +infix operator ^&&^ : SwiftCheckLogicalPrecedence + +/// Takes the conjunction of two properties and treats them as a single large /// property. /// -/// Conjoined properties succeed only when both sub-properties succeed and fail +/// Conjoined properties succeed only when both sub-properties succeed and fail /// when one or more sub-properties fail. public func ^&&^ (p1 : Testable, p2 : Testable) -> Property { return conjoin(p1.property, p2.property) } -infix operator ^||^ { - associativity right - precedence 110 -} +infix operator ^||^ : SwiftCheckLogicalPrecedence -/// Takes the disjunction of two properties and treats them as a single large +/// Takes the disjunction of two properties and treats them as a single large /// property. /// -/// Disjoined properties succeed only when one or more sub-properties succeed +/// Disjoined properties succeed only when one or more sub-properties succeed /// and fail when both sub-properties fail. public func ^||^ (p1 : Testable, p2 : Testable) -> Property { return disjoin(p1.property, p2.property) diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index c238d5b..e0a3089 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -6,39 +6,39 @@ // Copyright © 2016 Typelift. All rights reserved. // -/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` -/// allows generating random values, `CoArbitrary` allows observance of random -/// values passing through as input to random functions. A `CoArbitrary` type +/// `CoArbitrary is the dual to the `Arbitrary` protocol. Where `Arbitrary` +/// allows generating random values, `CoArbitrary` allows observance of random +/// values passing through as input to random functions. A `CoArbitrary` type /// is thus able to influence the flow of values in the function. /// -/// `CoArbitrary` types must take an arbitrary value of their type and yield a +/// `CoArbitrary` types must take an arbitrary value of their type and yield a /// function that transforms a given generator by returning a new generator that -/// depends on the input value. Put simply, the function should perturb the -/// given generator (more than likely using `Gen.variant()`) based on the value +/// depends on the input value. Put simply, the function should perturb the +/// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a + /// Uses an instance of the receiver to return a function that perturbs a /// generator. - static func coarbitrary(x : Self) -> (Gen -> Gen) + static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } -extension IntegerType { +extension Integer { /// A coarbitrary implementation for any IntegerType - public func coarbitraryIntegral() -> Gen -> Gen { + public func coarbitraryIntegral() -> (Gen) -> Gen { return { $0.variant(self) } } } -/// A coarbitrary implementation for any Printable type. Avoid using this +/// A coarbitrary implementation for any Printable type. Avoid using this /// function if you can, it can be quite an expensive operation given a detailed /// enough description. -public func coarbitraryPrintable(x : A) -> Gen -> Gen { - return String.coarbitrary(String(x)) +public func coarbitraryPrintable(_ x : A) -> (Gen) -> Gen { + return String.coarbitrary(String(describing: x)) } extension Bool : CoArbitrary { - /// The default coarbitrary implementation for `Bool` values. - public static func coarbitrary(x : Bool) -> Gen -> Gen { + /// The default coarbitrary implementation for `Bool` values. + public static func coarbitrary(_ x : Bool) -> (Gen) -> Gen { return { g in if x { return g.variant(1) @@ -49,128 +49,131 @@ extension Bool : CoArbitrary { } extension UnicodeScalar : CoArbitrary { - /// The default coarbitrary implementation for `UnicodeScalar` values. - public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { + /// The default coarbitrary implementation for `UnicodeScalar` values. + public static func coarbitrary(_ x : UnicodeScalar) -> (Gen) -> Gen { return UInt32.coarbitrary(x.value) } } extension Character : CoArbitrary { - /// The default coarbitrary implementation for `Character` values. - public static func coarbitrary(x : Character) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `Character` values. + public static func coarbitrary(_ x : Character) -> ((Gen) -> Gen) { let ss = String(x).unicodeScalars return UnicodeScalar.coarbitrary(ss[ss.startIndex]) } } extension String : CoArbitrary { - /// The default coarbitrary implementation for `String` values. - public static func coarbitrary(x : String) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `String` values. + public static func coarbitrary(_ x : String) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } - return Character.coarbitrary(x[x.startIndex]) • String.coarbitrary(x[x.startIndex.successor()..(x : Int) -> Gen -> Gen { + /// The default coarbitrary implementation for `Int` values. + public static func coarbitrary(_ x : Int) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { - /// The default coarbitrary implementation for `Int8` values. - public static func coarbitrary(x : Int8) -> Gen -> Gen { + /// The default coarbitrary implementation for `Int8` values. + public static func coarbitrary(_ x : Int8) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { - /// The default coarbitrary implementation for `Int16` values. - public static func coarbitrary(x : Int16) -> Gen -> Gen { + /// The default coarbitrary implementation for `Int16` values. + public static func coarbitrary(_ x : Int16) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { - /// The default coarbitrary implementation for `Int32` values. - public static func coarbitrary(x : Int32) -> Gen -> Gen { + /// The default coarbitrary implementation for `Int32` values. + public static func coarbitrary(_ x : Int32) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { - /// The default coarbitrary implementation for `Int64` values. - public static func coarbitrary(x : Int64) -> Gen -> Gen { + /// The default coarbitrary implementation for `Int64` values. + public static func coarbitrary(_ x : Int64) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { - /// The default coarbitrary implementation for `UInt` values. - public static func coarbitrary(x : UInt) -> Gen -> Gen { + /// The default coarbitrary implementation for `UInt` values. + public static func coarbitrary(_ x : UInt) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { - /// The default coarbitrary implementation for `UInt8` values. - public static func coarbitrary(x : UInt8) -> Gen -> Gen { + /// The default coarbitrary implementation for `UInt8` values. + public static func coarbitrary(_ x : UInt8) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { - /// The default coarbitrary implementation for `UInt16` values. - public static func coarbitrary(x : UInt16) -> Gen -> Gen { + /// The default coarbitrary implementation for `UInt16` values. + public static func coarbitrary(_ x : UInt16) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { - /// The default coarbitrary implementation for `UInt32` values. - public static func coarbitrary(x : UInt32) -> Gen -> Gen { + /// The default coarbitrary implementation for `UInt32` values. + public static func coarbitrary(_ x : UInt32) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { - /// The default coarbitrary implementation for `UInt64` values. - public static func coarbitrary(x : UInt64) -> Gen -> Gen { + /// The default coarbitrary implementation for `UInt64` values. + public static func coarbitrary(_ x : UInt64) -> (Gen) -> Gen { return x.coarbitraryIntegral() } } // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { - /// The default coarbitrary implementation for `Float` values. - public static func coarbitrary(x : Float) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `Float` values. + public static func coarbitrary(_ x : Float) -> ((Gen) -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { - /// The default coarbitrary implementation for `Double` values. - public static func coarbitrary(x : Double) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `Double` values. + public static func coarbitrary(_ x : Double) -> ((Gen) -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Array : CoArbitrary { - /// The default coarbitrary implementation for an `Array` of values. - public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { + /// The default coarbitrary implementation for an `Array` of values. + public static func coarbitrary(_ a : [Element]) -> ((Gen) -> Gen) { if a.isEmpty { return { $0.variant(0) } } - return { $0.variant(1) } • [Element].coarbitrary([Element](a[1..(x : Dictionary) -> (Gen -> Gen) { + /// The default coarbitrary implementation for a `Dictionary` of values. + public static func coarbitrary(_ x : Dictionary) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } @@ -179,8 +182,8 @@ extension Dictionary : CoArbitrary { } extension Optional : CoArbitrary { - /// The default coarbitrary implementation for `Optional` values. - public static func coarbitrary(x : Optional) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `Optional` values. + public static func coarbitrary(_ x : Optional) -> ((Gen) -> Gen) { if let _ = x { return { $0.variant(0) } } @@ -189,8 +192,8 @@ extension Optional : CoArbitrary { } extension Set : CoArbitrary { - /// The default coarbitrary implementation for `Set`s of values. - public static func coarbitrary(x : Set) -> (Gen -> Gen) { + /// The default coarbitrary implementation for `Set`s of values. + public static func coarbitrary(_ x : Set) -> ((Gen) -> Gen) { if x.isEmpty { return { $0.variant(0) } } diff --git a/Sources/Compose.swift b/Sources/Compose.swift new file mode 100644 index 0000000..dc6b80d --- /dev/null +++ b/Sources/Compose.swift @@ -0,0 +1,89 @@ +// +// Compose.swift +// SwiftCheck +// +// Created by Robert Widmann on 8/25/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +extension Gen { + /// Construct a `Gen`erator suitable for initializing an aggregate value. + /// + /// When using SwiftCheck with most classes and structures that contain more + /// than one field that conforms to `Arbitrary`, the monadic and applicative + /// syntax can be unwieldy. `Gen.compose` simplifies the construction of + /// these values by exposing a simple, natural, and imperative interface to + /// instance generation. For example: + /// + /// public static var arbitrary : Gen { + /// return Gen.compose { c in + /// return MyClass( + /// // Use the nullary method to get an `arbitrary` value. + /// a: c.generate(), + /// + /// // or pass a custom generator + /// b: c.generate(Bool.suchThat { $0 == false }), + /// + /// // .. and so on, for as many values & types as you need + /// c: c.generate(), ... + /// ) + /// } + /// } + /// + /// - parameter build: A closure with a `GenComposer` that uses an + /// underlying `Gen`erator to construct arbitrary values. + /// + /// - returns: A generator which uses the `build` function to build + /// instances of `A`. + public static func compose(build: @escaping (GenComposer) -> A) -> Gen { + return Gen(unGen: { (stdgen, size) -> A in + let composer = GenComposer(stdgen, size) + return build(composer) + }) + } +} + +/// `GenComposer` presents an imperative interface over top of `Gen`. +/// +/// Instances of this class may not be constructed manually. +/// Use `Gen.compose` instead. +/// +/// - seealso: Gen.compose +public final class GenComposer { + private var stdgen: StdGen + private var size: Int + + fileprivate init(_ stdgen : StdGen, _ size : Int) { + self.stdgen = stdgen + self.size = size + } + + + /// Generate a new `T` with a specific generator. + /// + /// - parameter gen: The generator used to create a random value. + /// + /// - returns: A random value of type `T` using the given `Gen`erator + /// for that type. + public func generate(using gen : Gen) -> T { + return gen.unGen(self.split, size) + } + + /// Generate a new value of type `T` with the default `Gen`erator + /// for that type. + /// + /// - returns: An arbitrary value of type `T`. + /// + /// - seealso: generate\(gen:) + public func generate() -> T + where T: Arbitrary + { + return generate(using: T.arbitrary) + } + + private var split : StdGen { + let old = stdgen + stdgen = old.split.0 + return old + } +} diff --git a/Sources/Gen.swift b/Sources/Gen.swift index dc87665..63085e2 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -8,9 +8,9 @@ /// `Gen` represents a generator for random arbitrary values of type `A`. /// -/// `Gen` wraps a function that, when given a random number generator and a -/// size, can be used to control the distribution of resultant values. A -/// generator relies on its size to help control aspects like the length of +/// `Gen` wraps a function that, when given a random number generator and a +/// size, can be used to control the distribution of resultant values. A +/// generator relies on its size to help control aspects like the length of /// generated arrays and the magnitude of integral values. public struct Gen { /// The function underlying the receiver. @@ -23,8 +23,8 @@ public struct Gen { /// Generates a value. /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the /// replay functionality and the robustness of tests in general. public var generate : A { let r = newStdGen() @@ -33,110 +33,130 @@ public struct Gen { /// Generates some example values. /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the + /// This property exists as a convenience mostly to test generators. In + /// practice, you should never use this property because it hinders the /// replay functionality and the robustness of tests in general. public var sample : [A] { return sequence((2...20).map(self.resize)).generate } - /// Constructs a Generator that selects a random value from the given + /// Constructs a Generator that selects a random value from the given /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf>(xs : S) -> Gen { - return Gen.fromElementsIn(xs.startIndex...xs.endIndex.advancedBy(-1)).map { i in + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : Comparable & RandomType + { + return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } } - /// Constructs a Generator that selects a random value from the given + /// Constructs a Generator that selects a random value from the given /// interval and produces only that value. /// /// The input interval is required to be non-empty. - public static func fromElementsIn(xs : S) -> Gen { + public static func fromElementsIn(_ xs : ClosedRange) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") - return choose((xs.start, xs.end)) + return choose((xs.lowerBound, xs.upperBound)) } /// Constructs a Generator that uses a given array to produce smaller arrays - /// composed of its initial segments. The size of each initial segment + /// composed of its initial segments. The size of each initial segment /// increases with the receiver's size parameter. /// /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(xs : [S]) -> Gen<[S]> { + public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") return Gen<[S]>.sized { n in - let ss = xs[xs.startIndex...pure([S](ss)) } } /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(xs : [S]) -> Gen<[S]> { + public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sort({ l, r in l.0 < r.0 }).map { $0.1 }) + return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) } } /// Constructs a generator that depends on a size parameter. - public static func sized(f : Int -> Gen) -> Gen { + public static func sized(_ f : @escaping (Int) -> Gen) -> Gen { return Gen(unGen: { r, n in return f(n).unGen(r, n) }) } - /// Constructs a random element in the range of two `RandomType`s. + /// Constructs a random element in the inclusive range of two `RandomType`s. /// - /// When using this function, it is necessary to explicitly specialize the + /// When using this function, it is necessary to explicitly specialize the /// generic parameter `A`. For example: /// - /// Gen.choose((32, 255)) >>- (Gen.pure • Character.init • UnicodeScalar.init) - public static func choose(rng : (A, A)) -> Gen { + /// Gen.choose((32, 255)).flatMap(Gen.pure • Character.init • UnicodeScalar.init) + public static func choose(_ rng : (A, A)) -> Gen { return Gen(unGen: { s, _ in return A.randomInRange(rng, gen: s).0 }) } + + /// Constructs a random element in the range of a bounded `RandomType`. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.chooseAny().flatMap(Gen.pure • Character.init • UnicodeScalar.init) + public static func chooseAny() -> Gen { + return Gen(unGen: { (s, _) in + return randomBound(s).0 + }) + } - /// Constructs a Generator that randomly selects and uses a particular + /// Constructs a Generator that randomly selects and uses a particular /// generator from the given sequence of Generators. /// - /// If control over the distribution of generators is needed, see + /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf, S.Index : protocol>(gs : S) -> Gen { + public static func oneOf(_ gs : S) -> Gen + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable + { assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.indices.startIndex, gs.indices.endIndex.predecessor())) >>- { x in + return choose((gs.startIndex, gs.index(before: gs.endIndex))).flatMap { x in return gs[x] } } - /// Given a sequence of Generators and weights associated with them, this + /// Given a sequence of Generators and weights associated with them, this /// function randomly selects and uses a Generator. /// - /// Only use this function when you need to assign uneven "weights" to each - /// generator. If all generators need to have an equal chance of being + /// Only use this function when you need to assign uneven "weights" to each + /// generator. If all generators need to have an equal chance of being /// selected, use `Gen.oneOf`. - public static func frequency)>(xs : S) -> Gen { + public static func frequency(_ xs : S) -> Gen + where S.Iterator.Element == (Int, Gen) + { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") - return choose((1, xs.map({ $0.0 }).reduce(0, combine: +))).flatMap { l in + return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in return pick(l, xs) } } - /// Given a list of values and weights associated with them, this function + /// Given a list of values and weights associated with them, this function /// randomly selects and uses a Generator wrapping one of the values. /// - /// This function operates in exactly the same manner as `Gen.frequency`, - /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather - /// than only Generators. It can help in cases where your `Gen.from*` call - /// contains only `Gen.pure` calls by allowing you to remove every + /// This function operates in exactly the same manner as `Gen.frequency`, + /// `Gen.fromElementsOf`, and `Gen.fromElementsIn` but for any type rather + /// than only Generators. It can help in cases where your `Gen.from*` call + /// contains only `Gen.pure` calls by allowing you to remove every /// `Gen.pure` in favor of a direct list of values. - public static func weighted(xs : S) -> Gen { + public static func weighted(_ xs : S) -> Gen + where S.Iterator.Element == (Int, A) + { return frequency(xs.map { ($0, Gen.pure($1)) }) } } @@ -145,14 +165,14 @@ public struct Gen { extension Gen { /// Shakes up the receiver's internal Random Number Generator with a seed. - public func variant(seed : S) -> Gen { + public func variant(_ seed : S) -> Gen { return Gen(unGen: { rng, n in return self.unGen(vary(seed, rng), n) }) } /// Modifies a Generator to always use a given size. - public func resize(n : Int) -> Gen { + public func resize(_ n : Int) -> Gen { return Gen(unGen: { r, _ in return self.unGen(r, n) }) @@ -160,62 +180,62 @@ extension Gen { /// Modifiers a Generator's size parameter by transforming it with the given /// function. - public func scale(f : Int -> Int) -> Gen { + public func scale(_ f : @escaping (Int) -> Int) -> Gen { return Gen.sized { n in return self.resize(f(n)) } } - /// Modifies a Generator such that it only returns values that satisfy a - /// predicate. When the predicate fails the test case is treated as though + /// Modifies a Generator such that it only returns values that satisfy a + /// predicate. When the predicate fails the test case is treated as though /// it never occured. /// - /// Because the Generator will spin until it reaches a non-failing case, - /// executing a condition that fails more often than it succeeds may result - /// in a space leak. At that point, it is better to use `suchThatOptional` + /// Because the Generator will spin until it reaches a non-failing case, + /// executing a condition that fails more often than it succeeds may result + /// in a space leak. At that point, it is better to use `suchThatOptional` /// or `.invert` the test case. - public func suchThat(p : A -> Bool) -> Gen { + public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { return self.suchThatOptional(p).flatMap { mx in switch mx { - case .Some(let x): + case .some(let x): return Gen.pure(x) - case .None: + case .none: return Gen.sized { n in - return self.suchThat(p).resize(n.successor()) + return self.suchThat(p).resize((n + 1)) } } } } - /// Modifies a Generator such that it attempts to generate values that - /// satisfy a predicate. All attempts are encoded in the form of an - /// `Optional` where values satisfying the predicate are wrapped in `.Some` + /// Modifies a Generator such that it attempts to generate values that + /// satisfy a predicate. All attempts are encoded in the form of an + /// `Optional` where values satisfying the predicate are wrapped in `.Some` /// and failing values are `.None`. - public func suchThatOptional(p : A -> Bool) -> Gen> { + public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { return Gen>.sized { n in return attemptBoundedTry(self, 0, max(n, 1), p) } } - /// Modifies a Generator such that it produces arrays with a length + /// Modifies a Generator such that it produces arrays with a length /// determined by the receiver's size parameter. public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((0, n)) >>- self.proliferateSized + return Gen.choose((0, n)).flatMap(self.proliferateSized) } } - /// Modifies a Generator such that it produces non-empty arrays with a + /// Modifies a Generator such that it produces non-empty arrays with a /// length determined by the receiver's size parameter. public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))) >>- self.proliferateSized + return Gen.choose((1, max(1, n))).flatMap(self.proliferateSized) } } /// Modifies a Generator such that it only produces arrays of a given length. - public func proliferateSized(k : Int) -> Gen<[A]> { - return sequence(Array>(count: k, repeatedValue: self)) + public func proliferateSized(_ k : Int) -> Gen<[A]> { + return sequence(Array>(repeating: self, count: k)) } } @@ -224,98 +244,62 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the /// receiver creates. - public func map(f : A -> B) -> Gen { - return f <^> self + /// + /// This function is most useful for converting between generators of inter- + /// related types. For example, you might have a Generator of `Character` + /// values that you then `.proliferate` into an `Array` of `Character`s. You + /// can then use `fmap` to convert that generator of `Array`s to a generator of + /// `String`s. + public func map(_ f : @escaping (A) -> B) -> Gen { + return Gen(unGen: { r, n in + return f(self.unGen(r, n)) + }) } } -/// Fmap | Returns a new generator that applies a given function to any outputs -/// the given generator creates. -/// -/// This function is most useful for converting between generators of inter- -/// related types. For example, you might have a Generator of `Character` -/// values that you then `.proliferate` into an `Array` of `Character`s. You -/// can then use `fmap` to convert that generator of `Array`s to a generator of -/// `String`s. -public func <^> (f : A -> B, g : Gen) -> Gen { - return Gen(unGen: { r, n in - return f(g.unGen(r, n)) - }) -} - extension Gen /*: Applicative*/ { /// Lifts a value into a generator that will only generate that value. - public static func pure(a : A) -> Gen { + public static func pure(_ a : A) -> Gen { return Gen(unGen: { _ in return a }) } - /// Given a generator of functions, applies any generated function to any + /// Given a generator of functions, applies any generated function to any /// outputs the receiver creates. - public func ap(fn : Gen B>) -> Gen { - return fn <*> self + public func ap(_ fn : Gen<(A) -> B>) -> Gen { + return Gen(unGen: { r, n in + let (r1, r2) = r.split + return fn.unGen(r1, n)(self.unGen(r2, n)) + }) } } -/// Ap | Returns a Generator that uses the first given Generator to produce -/// functions and the second given Generator to produce values that it applies -/// to those functions. It can be used in conjunction with <^> to simplify the -/// application of "combining" functions to a large amount of sub-generators. -/// For example: -/// -/// struct Foo { let b : Int; let c : Int; let d : Int } -/// -/// let genFoo = curry(Foo.init) <^> Int.arbitrary <*> Int.arbitrary <*> Int.arbitrary -/// -/// This combinator acts like `zip`, but instead of creating pairs it creates -/// values after applying the zipped function to the zipped value. -/// -/// Promotes function application to a Generator of functions applied to a -/// Generator of values. -public func <*> (fn : Gen B>, g : Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - return fn.unGen(r1, n)(g.unGen(r2, n)) - }) -} - extension Gen /*: Monad*/ { - /// Applies the function to any generated values to yield a new generator. + /// Applies the function to any generated values to yield a new generator. /// This generator is then given a new random seed and returned. /// /// `flatMap` allows for the creation of Generators that depend on other - /// generators. One might, for example, use a Generator of integers to - /// control the length of a Generator of strings, or use it to choose a + /// generators. One might, for example, use a Generator of integers to + /// control the length of a Generator of strings, or use it to choose a /// random index into a Generator of arrays. - public func flatMap(fn : A -> Gen) -> Gen { - return self >>- fn + public func flatMap(_ fn : @escaping (A) -> Gen) -> Gen { + return Gen(unGen: { r, n in + let (r1, r2) = r.split + let m2 = fn(self.unGen(r1, n)) + return m2.unGen(r2, n) + }) } } -/// Flat Map | Applies the function to any generated values to yield a new -/// generator. This generator is then given a new random seed and returned. -/// -/// `flatMap` allows for the creation of Generators that depend on other -/// generators. One might, for example, use a Generator of integers to control -/// the length of a Generator of strings, or use it to choose a random index -/// into a Generator of arrays. -public func >>- (m : Gen, fn : A -> Gen) -> Gen { - return Gen(unGen: { r, n in - let (r1, r2) = r.split - let m2 = fn(m.unGen(r1, n)) - return m2.unGen(r2, n) - }) -} - -/// Creates and returns a Generator of arrays of values drawn from each +/// Creates and returns a Generator of arrays of values drawn from each /// generator in the given array. /// -/// The array that is created is guaranteed to use each of the given Generators -/// in the order they were given to the function exactly once. Thus all arrays +/// The array that is created is guaranteed to use each of the given Generators +/// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. -public func sequence(ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), combine: { n, m in +public func sequence(_ ms : [Gen]) -> Gen<[A]> { + return ms.reduce(Gen<[A]>.pure([]), { n, m in return m.flatMap { x in return n.flatMap { xs in return Gen<[A]>.pure(xs + [x]) @@ -325,7 +309,7 @@ public func sequence(ms : [Gen]) -> Gen<[A]> { } /// Flattens a generator of generators by one level. -public func join(rs : Gen>) -> Gen { +public func join(_ rs : Gen>) -> Gen { return rs.flatMap { x in return x } @@ -333,29 +317,29 @@ public func join(rs : Gen>) -> Gen { /// Lifts a function from some A to some R to a function from generators of A to /// generators of R. -public func liftM(f : A -> R, _ m1 : Gen) -> Gen { +public func liftM(_ f : @escaping (A) -> R, _ m1 : Gen) -> Gen { return m1.flatMap{ x1 in return Gen.pure(f(x1)) } } /// Promotes a rose of generators to a generator of rose values. -public func promote(x : Rose>) -> Gen> { +public func promote(_ x : Rose>) -> Gen> { return delay().flatMap { eval in return Gen>.pure(liftM(eval, x)) } } /// Promotes a function returning generators to a generator of functions. -public func promote(m : A -> Gen) -> Gen B> { +public func promote(_ m : @escaping (A) -> Gen) -> Gen<(A) -> B> { return delay().flatMap { eval in - return Gen B>.pure(eval • m) + return Gen<(A) -> B>.pure(comp(eval, m)) } } // MARK: - Implementation Details -private func delay() -> Gen -> A> { +private func delay() -> Gen<(Gen) -> A> { return Gen(unGen: { r, n in return { g in return g.unGen(r, n) @@ -363,40 +347,38 @@ private func delay() -> Gen -> A> { }) } -private func vary(k : S, _ rng : StdGen) -> StdGen { +private func vary(_ k : S, _ rng : StdGen) -> StdGen { let s = rng.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(gen: Gen, _ k : Int, _ bound : Int, _ pred : A -> Bool) -> Gen> { +private func attemptBoundedTry(_ gen : Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { if bound == 0 { - return Gen.pure(.None) + return Gen.pure(.none) } return gen.resize(2 * k + bound).flatMap { x in if pred(x) { - return Gen.pure(.Some(x)) + return Gen.pure(.some(x)) } - return attemptBoundedTry(gen, k.successor(), bound - 1, pred) + return attemptBoundedTry(gen, (k + 1), bound - 1, pred) } } -private func size(k : S, _ m : Int) -> Int { +private func size(_ k : S, _ m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) } -private func selectOne(xs : [A]) -> [(A, [A])] { - if xs.isEmpty { - return [] - } - let y = xs.first! +private func selectOne(_ xs : [A]) -> [(A, [A])] { + guard let y = xs.first else { return [] } + let ys = Array(xs[1..)] = selectOne(ys).map({ t in (t.0, [y] + t.1) }) return [(y, ys)] + rec } -private func pick(n : Int, _ lst : [(Int, Gen)]) -> Gen { +private func pick(_ n : Int, _ lst : [(Int, Gen)]) -> Gen { let (k, x) = lst[0] let tl = Array<(Int, Gen)>(lst[1..) in /// return x.description == "(*)" /// } /// -/// For an example of the latter see the `ArrowOf` modifier. Because Swift's +/// For an example of the latter see the `ArrowOf` modifier. Because Swift's /// type system treats arrows (`->`) as an opaque entity that you can't interact -/// with or extend, SwiftCheck provides `ArrowOf` to enable the generation of -/// functions between 2 types. That's right, we can generate arbitrary +/// with or extend, SwiftCheck provides `ArrowOf` to enable the generation of +/// functions between 2 types. That's right, we can generate arbitrary /// functions! /// /// property("map accepts SwiftCheck arrows") <- forAll { (xs : [Int]) in /// return forAll { (f : ArrowOf) in -/// /// Just to prove it really is a function (that is, every input -/// /// always maps to the same output), and not just a trick, we +/// /// Just to prove it really is a function (that is, every input +/// /// always maps to the same output), and not just a trick, we /// /// map twice and should get equal arrays. -/// return xs.map(f.getArrow) == xs.map(f.getArrow) +/// return xs.map(f.getArrow) == xs.map(f.getArrow) /// } /// } /// /// Finally, modifiers nest to allow the generation of intricate structures that -/// would not otherwise be possible due to the limitations above. For example, -/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a -/// type that normally looks like `Array>>`), +/// would not otherwise be possible due to the limitations above. For example, +/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a +/// type that normally looks like `Array>>`), /// would look like this: /// /// property("Generating monstrous data types is possible") <- forAll { (xs : ArrayOf>>) in /// /// We're gonna need a bigger boat. /// } -/// For types that either do not have a `CustomStringConvertible` instance or -/// that wish to have no description to print, Blind will create a default +/// For types that either do not have a `CustomStringConvertible` instance or +/// that wish to have no description to print, Blind will create a default /// description for them. public struct Blind : Arbitrary, CustomStringConvertible { /// Retrieves the underlying value. @@ -68,18 +68,18 @@ public struct Blind : Arbitrary, CustomStringConvertible { /// Returns a generator of `Blind` values. public static var arbitrary : Gen> { - return Blind.init <^> A.arbitrary + return A.arbitrary.map(Blind.init) } /// The default shrinking function for `Blind` values. - public static func shrink(bl : Blind) -> [Blind] { + public static func shrink(_ bl : Blind) -> [Blind] { return A.shrink(bl.getBlind).map(Blind.init) } } extension Blind : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Blind) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } @@ -100,13 +100,13 @@ public struct Static : Arbitrary, CustomStringConvertible { /// Returns a generator of `Static` values. public static var arbitrary : Gen> { - return Static.init <^> A.arbitrary + return A.arbitrary.map(Static.init) } } extension Static : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Static) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } @@ -115,7 +115,7 @@ extension Static : CoArbitrary { public struct ArrayOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying array of values. public let getArray : [A] - + /// Retrieves the underlying array of values as a contiguous array. public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getArray) @@ -132,38 +132,38 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { /// Returns a generator of `ArrayOf` values. public static var arbitrary : Gen> { - return ArrayOf.init <^> Array.arbitrary + return Array.arbitrary.map(ArrayOf.init) } /// The default shrinking function for an `ArrayOf` values. - public static func shrink(bl : ArrayOf) -> [ArrayOf] { + public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { return Array.shrink(bl.getArray).map(ArrayOf.init) } } extension ArrayOf : CoArbitrary { - public static func coarbitrary(x : ArrayOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { let a = x.getArray if a.isEmpty { return { $0.variant(0) } } - return { $0.variant(1) } • ArrayOf.coarbitrary(ArrayOf([A](a[1..> : Arbitrary, CustomStringConvertible { +public struct OrderedArrayOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying sorted array of values. public let getOrderedArray : [A] - - /// Retrieves the underlying sorted array of values as a contiguous + + /// Retrieves the underlying sorted array of values as a contiguous /// array. public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getOrderedArray) } public init(_ array : [A]) { - self.getOrderedArray = array.sort() + self.getOrderedArray = array.sorted() } /// A textual representation of `self`. @@ -173,18 +173,18 @@ public struct OrderedArrayOf> : Arbitrary, C /// Returns a generator for an `OrderedArrayOf` values. public static var arbitrary : Gen> { - return OrderedArrayOf.init <^> Array.arbitrary + return Array.arbitrary.map(OrderedArrayOf.init) } /// The default shrinking function for an `OrderedArrayOf` values. - public static func shrink(bl : OrderedArrayOf) -> [OrderedArrayOf] { - return Array.shrink(bl.getOrderedArray).filter({ $0.sort() == $0 }).map(OrderedArrayOf.init) + public static func shrink(_ bl : OrderedArrayOf) -> [OrderedArrayOf] { + return Array.shrink(bl.getOrderedArray).filter({ $0.sorted() == $0 }).map(OrderedArrayOf.init) } } /// Generates an dictionary of arbitrary keys and values. -public struct DictionaryOf, V : Arbitrary> : Arbitrary, CustomStringConvertible { +public struct DictionaryOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying dictionary of values. public let getDictionary : Dictionary @@ -199,17 +199,17 @@ public struct DictionaryOf, V : Arbitrary> : A /// Returns a generator for a `DictionaryOf` values. public static var arbitrary : Gen> { - return DictionaryOf.init <^> Dictionary.arbitrary + return Dictionary.arbitrary.map(DictionaryOf.init) } /// The default shrinking function for a `DictionaryOf` values. - public static func shrink(d : DictionaryOf) -> [DictionaryOf] { + public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) } } extension DictionaryOf : CoArbitrary { - public static func coarbitrary(x : DictionaryOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { return Dictionary.coarbitrary(x.getDictionary) } } @@ -230,17 +230,17 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { /// Returns a generator for `OptionalOf` values. public static var arbitrary : Gen> { - return OptionalOf.init <^> Optional.arbitrary + return Optional.arbitrary.map(OptionalOf.init) } /// The default shrinking function for `OptionalOf` values. - public static func shrink(bl : OptionalOf) -> [OptionalOf] { + public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { return Optional.shrink(bl.getOptional).map(OptionalOf.init) } } extension OptionalOf : CoArbitrary { - public static func coarbitrary(x : OptionalOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { if let _ = x.getOptional { return { $0.variant(0) } } @@ -249,7 +249,7 @@ extension OptionalOf : CoArbitrary { } /// Generates a set of arbitrary values of type A. -public struct SetOf> : Arbitrary, CustomStringConvertible { +public struct SetOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying set of values. public let getSet : Set @@ -270,19 +270,19 @@ public struct SetOf> : Arbitrary, CustomString return Gen.pure(SetOf(Set([]))) } - return (SetOf.init • Set.init) <^> sequence(Array((0...k)).map { _ in A.arbitrary }) + return sequence(Array((0...k)).map { _ in A.arbitrary }).map(comp(SetOf.init, Set.init)) } } } /// The default shrinking function for a `SetOf` values. - public static func shrink(s : SetOf) -> [SetOf] { + public static func shrink(_ s : SetOf) -> [SetOf] { return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) } } extension SetOf : CoArbitrary { - public static func coarbitrary(x : SetOf) -> (Gen -> Gen) { + public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { if x.getSet.isEmpty { return { $0.variant(0) } } @@ -292,11 +292,11 @@ extension SetOf : CoArbitrary { /// Generates pointers of varying size of random values of type T. public struct PointerOf : Arbitrary, CustomStringConvertible { - private let _impl : PointerOfImpl + fileprivate let _impl : PointerOfImpl /// Retrieves the underlying pointer value. public var getPointer : UnsafePointer { - return UnsafePointer(self._impl.ptr) + return UnsafePointer(self._impl.ptr!) } public var size : Int { @@ -315,14 +315,14 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { } /// Generates a Swift function from T to U. -public struct ArrowOf, U : Arbitrary> : Arbitrary, CustomStringConvertible { - private let _impl : ArrowOfImpl +public struct ArrowOf : Arbitrary, CustomStringConvertible { + fileprivate let _impl : ArrowOfImpl /// Retrieves the underlying function value, `T -> U`. - public var getArrow : T -> U { + public var getArrow : (T) -> U { return self._impl.arr } - + /// A textual representation of `self`. public var description : String { return self._impl.description @@ -335,7 +335,7 @@ public struct ArrowOf, U : Arbitrary> : Arbi } extension ArrowOf : CustomReflectable { - public func customMirror() -> Mirror { + public var customMirror : Mirror { return Mirror(self, children: [ "types": "\(T.self) -> \(U.self)", "currentMap": self._impl.table, @@ -344,16 +344,16 @@ extension ArrowOf : CustomReflectable { } /// Generates two isomorphic Swift functions from `T` to `U` and back again. -public struct IsoOf, U : protocol> : Arbitrary, CustomStringConvertible { - private let _impl : IsoOfImpl +public struct IsoOf : Arbitrary, CustomStringConvertible { + fileprivate let _impl : IsoOfImpl /// Retrieves the underlying embedding function, `T -> U`. - public var getTo : T -> U { + public var getTo : (T) -> U { return self._impl.embed } /// Retrieves the underlying projecting function, `U -> T`. - public var getFrom : U -> T { + public var getFrom : (U) -> T { return self._impl.project } @@ -369,7 +369,7 @@ public struct IsoOf, U : protocol } extension IsoOf : CustomReflectable { - public func customMirror() -> Mirror { + public var customMirror : Mirror { return Mirror(self, children: [ "embed": "\(T.self) -> \(U.self)", "project": "\(U.self) -> \(T.self)", @@ -378,9 +378,9 @@ extension IsoOf : CustomReflectable { } } -/// By default, SwiftCheck generates values drawn from a small range. `Large` +/// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. -public struct Large> : Arbitrary { +public struct Large : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A @@ -399,13 +399,13 @@ public struct Large> : Arbitr } /// The default shrinking function for `Large` values. - public static func shrink(bl : Large) -> [Large] { + public static func shrink(_ bl : Large) -> [Large] { return bl.getLarge.shrinkIntegral.map(Large.init) } } /// Guarantees that every generated integer is greater than 0. -public struct Positive> : Arbitrary, CustomStringConvertible { +public struct Positive : Arbitrary, CustomStringConvertible { /// Retrieves the underlying positive value. public let getPositive : A @@ -420,24 +420,24 @@ public struct Positive> : Arbitrary, C /// Returns a generator of `Positive` values. public static var arbitrary : Gen> { - return A.arbitrary.map(Positive.init • abs).suchThat { $0.getPositive > 0 } + return A.arbitrary.map(comp(Positive.init, abs)).suchThat { $0.getPositive > 0 } } /// The default shrinking function for `Positive` values. - public static func shrink(bl : Positive) -> [Positive] { + public static func shrink(_ bl : Positive) -> [Positive] { return A.shrink(bl.getPositive).filter({ $0 > 0 }).map(Positive.init) } } extension Positive : CoArbitrary { // Take the lazy way out. - public static func coarbitrary(x : Positive) -> (Gen -> Gen) { + public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { return coarbitraryPrintable(x) } } /// Guarantees that every generated integer is never 0. -public struct NonZero> : Arbitrary, CustomStringConvertible { +public struct NonZero : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-zero value. public let getNonZero : A @@ -452,23 +452,23 @@ public struct NonZero> : Arbitrary, CustomS /// Returns a generator of `NonZero` values. public static var arbitrary : Gen> { - return NonZero.init <^> A.arbitrary.suchThat { $0 != 0 } + return A.arbitrary.suchThat({ $0 != 0 }).map(NonZero.init) } /// The default shrinking function for `NonZero` values. - public static func shrink(bl : NonZero) -> [NonZero] { + public static func shrink(_ bl : NonZero) -> [NonZero] { return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map(NonZero.init) } } extension NonZero : CoArbitrary { - public static func coarbitrary(x : NonZero) -> (Gen -> Gen) { + public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { return x.getNonZero.coarbitraryIntegral() } } /// Guarantees that every generated integer is greater than or equal to 0. -public struct NonNegative> : Arbitrary, CustomStringConvertible { +public struct NonNegative : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-negative value. public let getNonNegative : A @@ -483,17 +483,17 @@ public struct NonNegative> : Arbitrary, Cus /// Returns a generator of `NonNegative` values. public static var arbitrary : Gen> { - return NonNegative.init <^> A.arbitrary.suchThat { $0 >= 0 } + return A.arbitrary.suchThat({ $0 >= 0 }).map(NonNegative.init) } /// The default shrinking function for `NonNegative` values. - public static func shrink(bl : NonNegative) -> [NonNegative] { + public static func shrink(_ bl : NonNegative) -> [NonNegative] { return A.shrink(bl.getNonNegative).filter({ $0 >= 0 }).map(NonNegative.init) } } extension NonNegative : CoArbitrary { - public static func coarbitrary(x : NonNegative) -> (Gen -> Gen) { + public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { return x.getNonNegative.coarbitraryIntegral() } } @@ -506,16 +506,16 @@ private func undefined() -> A { fatalError("") } -private final class ArrowOfImpl, U : Arbitrary> : Arbitrary, CustomStringConvertible { - private var table : Dictionary - private var arr : T -> U +fileprivate final class ArrowOfImpl : Arbitrary, CustomStringConvertible { + fileprivate var table : Dictionary + fileprivate var arr : (T) -> U - init (_ table : Dictionary, _ arr : (T -> U)) { + init (_ table : Dictionary, _ arr : @escaping (T) -> U) { self.table = table self.arr = arr } - convenience init(_ arr : (T -> U)) { + convenience init(_ arr : @escaping (T) -> U) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }) self.arr = { [unowned self] x in @@ -533,12 +533,12 @@ private final class ArrowOfImpl, U : Arbitra } static var arbitrary : Gen> { - return ArrowOfImpl.init <^> promote { a in + return promote({ a in return T.coarbitrary(a)(U.arbitrary) - } + }).map(ArrowOfImpl.init) } - static func shrink(f : ArrowOfImpl) -> [ArrowOfImpl] { + static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { return f.table.flatMap { (x, y) in return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in return ArrowOfImpl({ (z : T) -> U in @@ -552,18 +552,18 @@ private final class ArrowOfImpl, U : Arbitra } } -private final class IsoOfImpl, U : protocol> : Arbitrary, CustomStringConvertible { - var table : Dictionary - var embed : T -> U - var project : U -> T +fileprivate final class IsoOfImpl : Arbitrary, CustomStringConvertible { + fileprivate var table : Dictionary + fileprivate var embed : (T) -> U + fileprivate var project : (U) -> T - init (_ table : Dictionary, _ embed : (T -> U), _ project : (U -> T)) { + init (_ table : Dictionary, _ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) { self.table = table self.embed = embed self.project = project } - convenience init(_ embed : (T -> U), _ project : (U -> T)) { + convenience init(_ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) { self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) self.embed = { [unowned self] t in @@ -577,7 +577,7 @@ private final class IsoOfImpl, U self.project = { [unowned self] u in let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, _ = self.table[k] { + if let k = ts.first, let _ = self.table[k] { return k } let y = project(u) @@ -591,22 +591,22 @@ private final class IsoOfImpl, U } static var arbitrary : Gen> { - return Gen<(T -> U, U -> T)>.zip(promote({ a in + return Gen<((T) -> U, (U) -> T)>.zip(promote({ a in return T.coarbitrary(a)(U.arbitrary) }), promote({ a in return U.coarbitrary(a)(T.arbitrary) })).map(IsoOfImpl.init) } - static func shrink(f : IsoOfImpl) -> [IsoOfImpl] { + static func shrink(_ f : IsoOfImpl) -> [IsoOfImpl] { return f.table.flatMap { (x, y) in - return Zip2Sequence(T.shrink(x), U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in return IsoOfImpl({ (z : T) -> U in if x == z { return y2 } return f.embed(z) - }, { (z : U) -> T in + }, { (z : U) -> T in if y == z { return y1 } @@ -618,7 +618,7 @@ private final class IsoOfImpl, U } private final class PointerOfImpl : Arbitrary { - var ptr : UnsafeMutablePointer + var ptr : UnsafeMutablePointer? let size : Int var description : String { @@ -632,7 +632,7 @@ private final class PointerOfImpl : Arbitrary { deinit { if self.size > 0 && self.ptr != nil { - self.ptr.dealloc(self.size) + self.ptr?.deallocate(capacity: self.size) self.ptr = nil } } @@ -640,12 +640,12 @@ private final class PointerOfImpl : Arbitrary { static var arbitrary : Gen> { return Gen.sized { n in if n <= 0 { - return Gen.pure(PointerOfImpl(nil, 0)) + let size = 1 + return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) } - let pt = UnsafeMutablePointer.alloc(n) - let gt = pt.initializeFrom <^> sequence(Array((0...allocate(capacity: n) + let gt = sequence(Array((0.. { - associativity left - precedence 95 -} - -/// On | Given a "combining" function and a function that converts arguments to the target of the -/// combiner, returns a function that applies the right hand side to two arguments, then runs both -/// results through the combiner. -infix operator |*| { - associativity left - precedence 100 -} - - -// MARK: Control.* - -/// Fmap | Maps a function over the value encapsulated by a functor. -infix operator <^> { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 130 -} - -/// Replace | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator <^ { - associativity left - precedence 140 -} - -/// Replace Backwards | Maps all the values encapsulated by a functor to a user-specified constant. -infix operator ^> { - associativity left - precedence 140 -} - - -/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. -infix operator <*> { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 130 -} - -/// Sequence Right | Disregards the Functor on the Left. -/// -/// Default definition: -/// `const(id) <^> a <*> b` -infix operator *> { - associativity left - precedence 140 -} - -/// Sequence Left | Disregards the Functor on the Right. -/// -/// Default definition: -/// `const <^> a <*> b` -infix operator <* { - associativity left - precedence 140 -} - -/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the -/// left to a function on the right yielding a new monad. -infix operator >>- { - associativity left - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 100 -} - -/// Bind Backwards | Composes two monadic actions by passing the value inside the monad on the -/// right to the funciton on the left. -infix operator -<< { - associativity right - // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift - precedence 100 -} - -/// Left-to-Right Kleisli | Composition for monads. -infix operator >>->> { - associativity right - precedence 110 -} - -/// Right-to-Left Kleisli | Composition for monads. -infix operator <<-<< { - associativity right - precedence 110 -} - -/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the -/// original context. -infix operator ->> { - associativity left - precedence 110 -} - -/// Imap | Maps covariantly over the index of a right-leaning bifunctor. -infix operator <^^> { - associativity left - precedence 140 -} - -/// Contramap | Contravariantly maps a function over the value encapsulated by a functor. -infix operator { - associativity left - precedence 140 -} - -// MARK: Data.Result - -/// From | Creates a Result given a function that can possibly fail with an error. -infix operator !! { - associativity none - precedence 120 -} - -// MARK: Data.Monoid - -/// Append | Alias for a Semigroup's operation. -infix operator <> { - associativity right - precedence 160 -} - -// MARK: Control.Category - -/// Right-to-Left Composition | Composes two categories to form a new category with the source of -/// the second category and the target of the first category. -/// -/// This function is literally `•`, but for Categories. -infix operator <<< { - associativity right - precedence 110 -} - -/// Left-to-Right Composition | Composes two categories to form a new category with the source of -/// the first category and the target of the second category. -/// -/// Function composition with the arguments flipped. -infix operator >>> { - associativity right - precedence 110 -} - -// MARK: Control.Arrow - -/// Split | Splits two computations and combines the result into one Arrow yielding a tuple of -/// the result of each side. -infix operator *** { - associativity right - precedence 130 -} - -/// Fanout | Given two functions with the same source but different targets, this function -/// splits the computation and combines the result of each Arrow into a tuple of the result of -/// each side. -infix operator &&& { - associativity right - precedence 130 -} - -// MARK: Control.Arrow.Choice - -/// Splat | Splits two computations and combines the results into Eithers on the left and right. -infix operator +++ { - associativity right - precedence 120 -} - -/// Fanin | Given two functions with the same target but different sources, this function splits -/// the input between the two and merges the output. -infix operator ||| { - associativity right - precedence 120 -} - -// MARK: Control.Arrow.Plus - -/// Op | Combines two ArrowZero monoids. -infix operator <+> { - associativity right - precedence 150 -} - -// MARK: Data.JSON - -/// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. -/// -/// If the given keypath is not present or the retrieved value is not of the appropriate type, this -/// function returns `.None`. -infix operator Property { +/// +/// - parameter ps: A variadic list of properties to be conjoined. +/// +/// - returns: A `Property` that evaluates to the result of conjoining each +/// of the given `Testable` expressions. +public func conjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in return Gen.pure(Prop(unProp: conj(id, xs: roses))) - })) + })).again } -/// Takes the disjunction of multiple properties and reports all successes and +/// Takes the disjunction of multiple properties and reports all successes and /// failures of each sub-property distinctly. That is, this property holds when /// any one of its sub-properties holds and fails when all of its sub-properties /// fail simultaneously. /// -/// Disjoined properties, when used in conjunction with labelling, cause +/// Disjoined properties, when used in conjunction with labelling, cause /// SwiftCheck to print a distribution map of the success rate of each sub- /// property. /// /// When disjoining properties all calls to `expectFailure` will fail. You can, /// however, `invert` the property. -public func disjoin(ps : Testable...) -> Property { +/// +/// - parameter ps: A variadic list of properties to be disjoined. +/// +/// - returns: A `Property` that evaluates to the result of disjoining each +/// of the given `Testable` expressions. +public func disjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in - return Gen.pure(Prop(unProp: roses.reduce(.MkRose({ TestResult.failed() }, { [] }), combine: disj))) - })) + return Gen.pure(Prop(unProp: roses.reduce(.mkRose({ TestResult.failed() }, { [] }), disj))) + })).again } -/// Takes the nondeterministic conjunction of multiple properties and treats +/// Takes the nondeterministic conjunction of multiple properties and treats /// them as a single large property. /// -/// The resulting property makes 100 random choices to test any of the given -/// properties. Thus, running multiple test cases will result in distinct +/// The resulting property makes 100 random choices to test any of the given +/// properties. Thus, running multiple test cases will result in distinct /// arbitrary sequences of each property being tested. -public func conjamb(ps : () -> Testable...) -> Property { +/// +/// - parameter ps: A variadic list of properties to be randomly conjoined. +/// +/// - returns: A `Property` that evaluates to the result of randomly conjoining +/// any of the given `Testable` expressions. +public func conjamb(_ ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } - return Property(Gen.oneOf(ls)) + return Property(Gen.oneOf(ls)).again } extension Testable { @@ -59,98 +74,138 @@ extension Testable { public var noShrinking : Property { return self.mapRoseResult { rs in return rs.onRose { res, _ in - return .MkRose({ res }, { [] }) + return .mkRose({ res }, { [] }) } } } - /// Inverts the result of a test. That is, test cases that would pass now + /// Inverts the result of a test. That is, test cases that would pass now /// fail and vice versa. /// /// Discarded tests remain discarded under inversion. public var invert : Property { return self.mapResult { res in - return TestResult(ok: res.ok.map(!) - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok.map(!), + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } /// Modifies a property so that it only will be tested once. + /// + /// Undoes the effect of `.again`. public var once : Property { return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: true - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: true, + quantifier: res.quantifier + ) + } + } + + /// Modifies a property so that it will be tested many times. + /// + /// Undoes the effect of `.once`. + public var again : Property { + return self.mapResult { res in + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: false, + quantifier: res.quantifier + ) } } /// Attaches a callback to a test case. - public func withCallback(cb : Callback) -> Property { + public func withCallback(_ cb : Callback) -> Property { return self.mapResult { (res) in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: [cb] + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: [cb] + res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } /// Adds the given string to the counterexamples of a failing property. - public func counterexample(s : String) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .Counterexample) { _ in - return print(s) + /// + /// - parameter example: A string describing a counteraxmple that causes + /// this property to fail. + /// + /// - returns: A `Property` that prints the counterexample value on failure. + public func counterexample(_ example : String) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in + return print(example) }) } /// Executes an action after the last failure of the property. - public func whenFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { _ in - return m() + /// + /// - parameter callback: A callback block to be executed after all failures + /// have been processed. + /// + /// - returns: A `Property` that executes the given callback block on failure. + public func whenFail(_ callback : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in + return callback() }) } /// Executes an action after the every failure of the property. /// - /// Because the action is executed after every failing test it can be used + /// Because the action is executed after every failing test it can be used /// to track the list of failures generated by the shrinking mechanism. - public func whenEachFail(m : () -> ()) -> Property { - return self.withCallback(Callback.AfterFinalFailure(kind: .NotCounterexample) { (st, res) in - if res.ok == .Some(false) { - m() + /// + /// - parameter callback: A callback block to be executed after each + /// failing case of the property has been processed. + public func whenEachFail(_ callback : @escaping () -> ()) -> Property { + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (st, res) in + if res.ok == .some(false) { + callback() } }) } - /// Modifies a property so it prints out every generated test case and the + /// Modifies a property so it prints out every generated test case and the /// result of the property every time it is tested. /// - /// This function maps AfterFinalFailure callbacks that have the + /// This function maps AfterFinalFailure callbacks that have the /// `.Counterexample` kind to `.AfterTest` callbacks. public var verbose : Property { - func chattyCallbacks(cbs : [Callback]) -> [Callback] { - let c = Callback.AfterTest(kind: .Counterexample) { (st, res) in + func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { + let c = Callback.afterTest(kind: .counterexample) { (st, res) in switch res.ok { - case .Some(true): + case .some(true): print("\nPassed: ", terminator: "") printLabels(res) - case .Some(false): + case .some(false): print("\nFailed: ", terminator: "") printLabels(res) print("Pass the seed values \(st.randomSeedGenerator) to replay the test.", terminator: "\n\n") @@ -162,8 +217,8 @@ extension Testable { return [c] + cbs.map { (c : Callback) -> Callback in switch c { - case let .AfterFinalFailure(.Counterexample, f): - return .AfterTest(kind: .Counterexample, f: f) + case let .afterFinalFailure(.counterexample, f): + return .afterTest(kind: .counterexample, f) default: return c } @@ -171,15 +226,17 @@ extension Testable { } return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks + chattyCallbacks(res.callbacks) - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks + chattyCallbacks(res.callbacks), + abort: res.abort, + quantifier: res.quantifier + ) } } @@ -188,56 +245,84 @@ extension Testable { /// If the property does not fail, SwiftCheck will report an error. public var expectFailure : Property { return self.mapTotalResult { res in - return TestResult(ok: res.ok - , expect: false - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: false, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } /// Attaches a label to a property. /// /// Labelled properties aid in testing conjunctions and disjunctions, or any - /// other cases where test cases need to be distinct from one another. In - /// addition to shrunken test cases, upon failure SwiftCheck will print a - /// distribution map for the property that shows a percentage success rate + /// other cases where test cases need to be distinct from one another. In + /// addition to shrunken test cases, upon failure SwiftCheck will print a + /// distribution map for the property that shows a percentage success rate /// for the property. - public func label(s : String) -> Property { - return self.classify(true, label: s) + /// + /// - parameter label: The label to apply to the property. + /// + /// - returns: A `Property` with the given label attached. + public func label(_ label : String) -> Property { + return self.classify(true, label: label) } /// Labels a property with a printable value. - public func collect(x : A) -> Property { - return self.label(String(x)) + /// + /// - parameter value: The value whose reflected representation will label + /// the property. + /// + /// - returns: A `Property` labelled with the reflected representation of + /// the given value. + public func collect(_ value : A) -> Property { + return self.label(String(describing: value)) } /// Conditionally labels a property with a value. - public func classify(b : Bool, label : String) -> Property { - return self.cover(b, percentage: 0, label: label) + /// + /// - parameter condition: The condition to evaluate. + /// - parameter label: The label to apply to the property if the given + /// condition evaluates to true. + /// + /// - returns: A property that carries a label dependent upon the condition. + public func classify(_ condition : Bool, label : String) -> Property { + return self.cover(condition, percentage: 0, label: label) } - /// Checks that at least the given proportion of successful test cases + /// Checks that at least the given proportion of successful test cases /// belong to the given class. /// - /// Discarded tests (i.e. ones with a false precondition) do not affect + /// Discarded tests (i.e. ones with a false precondition) do not affect /// coverage. - public func cover(b : Bool, percentage : Int, label : String) -> Property { - if b { + /// + /// - parameter condition: The condition to evaluate. + /// - parameter percentage: A value from 0-100 inclusive that describes + /// the expected percentage the given condition will evaluate to true. + /// - parameter label: The label to apply to the property if the given + /// condition evaluates to true. + /// + /// - returns: A property that carries a label dependent upon the condition. + public func cover(_ condition : Bool, percentage : Int, label : String) -> Property { + if condition { return self.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: insertWith(max, k: label, v: percentage, m: res.labels) - , stamp: res.stamp.union([label]) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: insertWith(max, k: label, v: percentage, m: res.labels), + stamp: res.stamp.union([label]), + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } return self.property @@ -248,46 +333,80 @@ extension Testable { /// This function can be used to completely change the evaluation schema of /// generated test cases by replacing the test's rose tree with a custom /// one. - public func mapProp(f : Prop -> Prop) -> Property { - return Property(f <^> self.property.unProperty) + /// + /// - parameter transform: The transformation function to apply to the + /// `Prop`s of this `Property`. + /// + /// - returns: A `Property` that applies the given transformation upon evaluation. + public func mapProp(_ transform : @escaping (Prop) -> Prop) -> Property { + return Property(self.property.unProperty.map(transform)) } /// Applies a function that modifies the test case generator's size. - public func mapSize(f : Int -> Int) -> Property { + /// + /// - parameter transform: The transformation function to apply to the size + /// of the generators underlying this `Property`. + /// + /// - returns: A `Property` that applies the given transformation upon evaluation. + public func mapSize(_ transform : @escaping (Int) -> Int) -> Property { return Property(Gen.sized { n in - return self.property.unProperty.resize(f(n)) + return self.property.unProperty.resize(transform(n)) }) } /// Applies a function that modifies the result of a test case. - public func mapTotalResult(f : TestResult -> TestResult) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// result of executing this `Property`. + /// + /// - returns: A `Property` that modifies its final result by executing the + /// given transformation block. + public func mapTotalResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return protectResults(f <^> rs) + return protectResults(rs.map(transform)) } } /// Applies a function that modifies the result of a test case. - public func mapResult(f : TestResult -> TestResult) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// result of executing this `Property`. + /// + /// - returns: A `Property` that modifies its final result by executing the + /// given transformation block. + public func mapResult(_ transform : @escaping (TestResult) -> TestResult) -> Property { return self.mapRoseResult { rs in - return f <^> rs + return rs.map(transform) } } - /// Applies a function that modifies the underlying Rose Tree that a test + /// Applies a function that modifies the underlying Rose Tree that a test /// case has generated. - public func mapRoseResult(f : Rose -> Rose) -> Property { + /// + /// - parameter transform: The transformation function to apply to the + /// rose tree used to execute this `Property`. + /// + /// - returns: A `Property` that modifies its evaluation strategy by + /// executing the given transformation block. + public func mapRoseResult(_ transform : @escaping (Rose) -> Rose) -> Property { return self.mapProp { t in - return Prop(unProp: f(t.unProp)) + return Prop(unProp: transform(t.unProp)) } } } -/// Using a shrinking function, shrinks a given argument to a property if it +/// Using a shrinking function, shrinks a given argument to a property if it /// fails. /// /// Shrinking is handled automatically by SwiftCheck. Invoking this function is /// only necessary when you must override the default behavior. -public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) -> Property { +/// +/// - parameter shrinker: The custom shrinking function to use for this type. +/// - parameter initial: The initial value that kicks off the shrinking process. +/// - parameter prop: The property to be tested. +/// +/// - returns: A `Property` that shrinks its arguments with the given function. +public func shrinking(_ shrinker : @escaping (A) -> [A], initial : A, prop : @escaping (A) -> Testable) -> Property { return Property(promote(props(shrinker, original: initial, pf: prop)).map { rs in return Prop(unProp: joinRose(rs.map { x in return x.unProp @@ -295,93 +414,95 @@ public func shrinking(shrinker : A -> [A], initial : A, prop : A -> Testable) }) } -/// A `Callback` is a block of code that can be run after a test case has -/// finished. They consist of a kind and the callback block itself, which is +/// A `Callback` is a block of code that can be run after a test case has +/// finished. They consist of a kind and the callback block itself, which is /// given the state SwiftCheck ran the test case with and the result of the test /// to do with as it sees fit. public enum Callback { /// A callback that is posted after a test case has completed. - case AfterTest(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterTest(kind : CallbackKind, (CheckerState, TestResult) -> ()) /// The callback is posted after all cases in the test have failed. - case AfterFinalFailure(kind : CallbackKind, f : (CheckerState, TestResult) -> ()) + case afterFinalFailure(kind : CallbackKind, (CheckerState, TestResult) -> ()) } /// The type of callbacks SwiftCheck can dispatch. public enum CallbackKind { /// Affected by the verbose combinator. - case Counterexample + case counterexample /// Not affected by the verbose combinator - case NotCounterexample + case notCounterexample } /// The types of quantification SwiftCheck can perform. public enum Quantification { /// Universal Quantification ("for all"). - case Universal + case universal /// Existential Quanfication ("there exists"). - case Existential + case existential /// Uniqueness Quantification ("there exists one and only one") -// case Uniqueness + // case Uniqueness /// Counting Quantification ("there exist exactly k") -// case Counting + // case Counting } /// A `TestResult` represents the result of performing a single test. public struct TestResult { - /// The result of executing the test case. For Discarded test cases the + /// The result of executing the test case. For Discarded test cases the /// value of this property is `.None`. - let ok : Optional + let ok : Optional /// Indicates what the expected result of the property is. - let expect : Bool + let expect : Bool /// A message indicating the reason a test case failed. - let reason : String + let reason : String /// The exception that was thrown if one occured during testing. - let theException : Optional + let theException : Optional /// All the labels used during the test case. - let labels : Dictionary + let labels : Dictionary /// The collected values for the test case. - let stamp : Set + let stamp : Set /// Callbacks attached to the test case. - let callbacks : [Callback] + let callbacks : [Callback] /// Indicates that any further testing of the property should cease. - let abort : Bool + let abort : Bool /// The quantifier being applied to this test case. - let quantifier : Quantification + let quantifier : Quantification - /// Provides a pattern-match-friendly view of the current state of a test + /// Provides a pattern-match-friendly view of the current state of a test /// result. public enum TestResultMatcher { - /// A case-able view of the current state of a test result. - case MatchResult( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : Array - , abort : Bool - , quantifier : Quantification + /// A case-able view of the current state of a test result. + case matchResult( + ok : Optional, + expect : Bool, + reason : String, + theException : Optional, + labels : Dictionary, + stamp : Set, + callbacks : Array, + abort : Bool, + quantifier : Quantification ) } - - /// Destructures a test case into a matcher that can be used in switch + + /// Destructures a test case into a matcher that can be used in switch /// statement. public var match : TestResultMatcher { - return .MatchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) + return .matchResult(ok: ok, expect: expect, reason: reason, theException: theException, labels: labels, stamp: stamp, callbacks: callbacks, abort: abort, quantifier: quantifier) } /// Creates and returns a new test result initialized with the given /// parameters. - public init( ok : Optional - , expect : Bool - , reason : String - , theException : Optional - , labels : Dictionary - , stamp : Set - , callbacks : [Callback] - , abort : Bool - , quantifier : Quantification) - { + public init( + ok : Optional, + expect : Bool, + reason : String, + theException : Optional, + labels : Dictionary, + stamp : Set, + callbacks : [Callback], + abort : Bool, + quantifier : Quantification + ) { self.ok = ok self.expect = expect self.reason = reason @@ -395,67 +516,68 @@ public struct TestResult { /// Convenience constructor for a passing `TestResult`. public static var succeeded : TestResult { - return result(Optional.Some(true)) + return result(Optional.some(true)) } /// Convenience constructor for a failing `TestResult`. - public static func failed(reason : String = "") -> TestResult { - return result(Optional.Some(false), reason: reason) + public static func failed(_ reason : String = "") -> TestResult { + return result(Optional.some(false), reason: reason) } /// Convenience constructor for a discarded `TestResult`. public static var rejected : TestResult { - return result(Optional.None) + return result(Optional.none) } - /// Lifts a `Bool`ean value to a TestResult by mapping true to + /// Lifts a `Bool`ean value to a TestResult by mapping true to /// `TestResult.suceeded` and false to `TestResult.failed`. - public static func liftBool(b : Bool) -> TestResult { + public static func liftBool(_ b : Bool) -> TestResult { if b { return TestResult.succeeded } - return result(Optional.Some(false), reason: "Falsifiable") + return result(Optional.some(false), reason: "Falsifiable") + } + + private static func result(_ ok : Bool?, reason : String = "") -> TestResult { + return TestResult( + ok: ok, + expect: true, + reason: reason, + theException: .none, + labels: [:], + stamp: Set(), + callbacks: [], + abort: false, + quantifier: .universal + ) } } // MARK: - Implementation Details -private func exception(msg : String) -> ErrorType -> TestResult { - return { e in TestResult.failed(String(e)) } +private func exception(_ msg : String) -> (Error) -> TestResult { + return { e in TestResult.failed(String(describing: e)) } } -private func props(shrinker : A -> [A], original : A, pf : A -> Testable) -> Rose> { - return .MkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in +private func props(_ shrinker : @escaping (A) -> [A], original : A, pf : @escaping (A) -> Testable) -> Rose> { + return .mkRose({ pf(original).property.unProperty }, { shrinker(original).map { x1 in return props(shrinker, original: x1, pf: pf) }}) } -private func result(ok : Bool?, reason : String = "") -> TestResult { - return TestResult( ok: ok - , expect: true - , reason: reason - , theException: .None - , labels: [:] - , stamp: Set() - , callbacks: [] - , abort: false - , quantifier: .Universal - ) -} - -private func protectResults(rs : Rose) -> Rose { +private func protectResults(_ rs : Rose) -> Rose { return rs.onRose { x, rs in - return .IORose({ - return .MkRose(protectResult({ x }), { rs.map(protectResults) }) + return .ioRose({ + return .mkRose(protectResult({ x }), { rs.map(protectResults) }) }) } } //internal func protectRose(f : () throws -> Rose) -> (() -> Rose) { -// return { protect(Rose.pure • exception("Exception"), x: f) } +// return { protect(Rose.pure • exception("Exception"), x: f) } //} -internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { +internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { do { return try x() } catch let e { @@ -463,19 +585,19 @@ internal func protect(f : ErrorType -> A, x : () throws -> A) -> A { } } -internal func id(x : A) -> A { +internal func id(_ x : A) -> A { return x } -internal func • (f : B -> C, g : A -> B) -> A -> C { +internal func comp(_ f : @escaping (B) -> C, _ g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } -private func protectResult(r : () throws -> TestResult) -> (() -> TestResult) { +private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> TestResult) { return { protect(exception("Exception"), x: r) } } -internal func unionWith(f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { +internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l r.forEach { (k, v) in if let val = map.updateValue(v, forKey: k) { @@ -485,7 +607,7 @@ internal func unionWith(f : (V, V) -> V, l : Dictionary, return map } -private func insertWith(f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { +private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { var res = m let oldV = res[k] if let existV = oldV { @@ -496,20 +618,9 @@ private func insertWith(f : (V, V) -> V, k : K, v : V, m : Dict return res } -private func sep(l : String, r : String) -> String { - if l.isEmpty { - return r - } - - if r.isEmpty { - return l - } - return l + ", " + r -} - -private func mplus(l : Optional, r : Optional) -> Optional { - if let ls = l, rs = r { - return .Some(ls + rs) +private func mplus(_ l : Optional, r : Optional) -> Optional { + if let ls = l, let rs = r { + return .some(ls + rs) } if l == nil { @@ -519,35 +630,39 @@ private func mplus(l : Optional, r : Optional) -> Optional TestResult -> TestResult { +private func addCallbacks(_ result : TestResult) -> (TestResult) -> TestResult { return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: result.callbacks + res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: result.callbacks + res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } -private func addLabels(result : TestResult) -> TestResult -> TestResult { +private func addLabels(_ result : TestResult) -> (TestResult) -> TestResult { return { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: unionWith(max, l: res.labels, r: result.labels) - , stamp: res.stamp.union(result.stamp) - , callbacks: res.callbacks - , abort: res.abort - , quantifier: res.quantifier) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: unionWith(max, l: res.labels, r: result.labels), + stamp: res.stamp.union(result.stamp), + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } } -private func printLabels(st : TestResult) { +private func printLabels(_ st : TestResult) { if st.labels.isEmpty { print("(.)") } else if st.labels.count == 1, let pt = st.labels.first { @@ -555,38 +670,38 @@ private func printLabels(st : TestResult) { } else { let gAllLabels = st.labels.map({ (l, _) in return l + ", " - }).reduce("", combine: +) - print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { +private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose]) -> Rose { if xs.isEmpty { - return Rose.MkRose({ k(TestResult.succeeded) }, { [] }) + return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) } else if let p = xs.first { - return .IORose(/*protectRose*/({ + return .ioRose(/*protectRose*/({ let rose = p.reduce switch rose { - case .MkRose(let result, _): + case .mkRose(let result, _): if !result().expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) } switch result().ok { - case .Some(true): - return conj(addLabels(result()) • addCallbacks(result()) • k, xs: [Rose](xs[1..](xs[1..](xs[1..](xs[1.. TestResult, xs : [Rose]) -> Rose fatalError("Non-exhaustive if-else statement reached") } -private func disj(p : Rose, q : Rose) -> Rose { +private func disj(_ p : Rose, q : Rose) -> Rose { return p.flatMap { result1 in if !result1.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result1.ok { - case .Some(true): + case .some(true): return Rose.pure(result1) - case .Some(false): + case .some(false): return q.flatMap { (result2 : TestResult) in if !result2.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { - case .Some(true): + case .some(true): return Rose.pure(result2) - case .Some(false): - let callbacks : [Callback] = [.AfterFinalFailure(kind: .Counterexample, - f: { _ in - return print("") - })] - return Rose.pure(TestResult(ok: .Some(false), - expect: true, - reason: sep(result1.reason, r: result2.reason), - theException: mplus(result1.theException, r: result2.theException), - labels: [:], - stamp: Set(), - callbacks: result1.callbacks + callbacks + result2.callbacks, - abort: false, - quantifier: .Universal)) - case .None: + case .some(false): + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { _ in return print("") })] + return Rose.pure(TestResult( + ok: .some(false), + expect: true, + reason: [result1.reason, result2.reason].joined(separator: ", "), + theException: mplus(result1.theException, r: result2.theException), + labels: [:], + stamp: Set(), + callbacks: result1.callbacks + callbacks + result2.callbacks, + abort: false, + quantifier: .universal + )) + case .none: return Rose.pure(result2) } } - case .None: + case .none: return q.flatMap { (result2 : TestResult) in if !result2.expect { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { - case .Some(true): + case .some(true): return Rose.pure(result2) default: return Rose.pure(result1) diff --git a/Sources/Random.swift b/Sources/Random.swift index 04bf379..5fd3a12 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -7,14 +7,14 @@ // /// Provides a standard interface to an underlying Random Value Generator of any -/// type. It is analogous to `GeneratorType`, but rather than consume a +/// type. It is analogous to `GeneratorType`, but rather than consume a /// sequence it uses sources of randomness to generate values indefinitely. public protocol RandomGeneneratorType { - /// The next operation returns an Int that is uniformly distributed in the - /// range returned by `genRange` (including both end points), and a new + /// The next operation returns an Int that is uniformly distributed in the + /// range returned by `genRange` (including both end points), and a new /// generator. var next : (Int, Self) { get } - /// The genRange operation yields the range of values returned by the + /// The genRange operation yields the range of values returned by the /// generator. /// /// This property must return integers in ascending order. @@ -23,16 +23,16 @@ public protocol RandomGeneneratorType { var split : (Self, Self) { get } } -/// `StdGen` represents a pseudo-random number generator. The library makes it -/// possible to generate repeatable results, by starting with a specified +/// `StdGen` represents a pseudo-random number generator. The library makes it +/// possible to generate repeatable results, by starting with a specified /// initial random number generator, or to get different results on each run by -/// using the system-initialised generator or by supplying a seed from some +/// using the system-initialised generator or by supplying a seed from some /// other source. public struct StdGen : RandomGeneneratorType { let seed1 : Int let seed2 : Int - /// Creates a `StdGen` initialized at the given seeds that is suitable for + /// Creates a `StdGen` initialized at the given seeds that is suitable for /// replaying of tests. public init(_ replaySeed1 : Int, _ replaySeed2 : Int) { self.seed1 = replaySeed1 @@ -41,7 +41,7 @@ public struct StdGen : RandomGeneneratorType { /// Convenience to create a `StdGen` from a given integer. public init(_ o : Int) { - func mkStdGen32(sMaybeNegative : Int) -> StdGen { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 @@ -107,23 +107,23 @@ public func newStdGen() -> StdGen { /// Types that can generate random versions of themselves. public protocol RandomType { /// Takes a range `(lo, hi)` and a random number generator `G`, and returns - /// a random value uniformly distributed in the closed interval `[lo,hi]`, - /// together with a new generator. It is unspecified what happens if lo>hi. + /// a random value uniformly distributed in the closed interval `[lo,hi]`, + /// together with a new generator. It is unspecified what happens if lo>hi. /// - /// For continuous types there is no requirement that the values `lo` and + /// For continuous types there is no requirement that the values `lo` and /// `hi` are ever produced, but they may be, depending on the implementation /// and the interval. - static func randomInRange(range : (Self, Self), gen : G) -> (Self, G) + static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) } /// Generates a random value from a LatticeType random type. -public func randomBound, G : RandomGeneneratorType>(gen : G) -> (A, G) { +public func randomBound(_ gen : G) -> (A, G) { return A.randomInRange((A.min, A.max), gen: gen) } extension Bool : RandomType { /// Returns a random `Bool`ean value using the given range and generator. - public static func randomInRange(range : (Bool, Bool), gen: G) -> (Bool, G) { + public static func randomInRange(_ range : (Bool, Bool), gen: G) -> (Bool, G) { let (x, gg) = Int.randomInRange((range.0 ? 1 : 0, range.1 ? 1 : 0), gen: gen) return (x == 1, gg) } @@ -131,7 +131,7 @@ extension Bool : RandomType { extension Character : RandomType { /// Returns a random `Character` value using the given range and generator. - public static func randomInRange(range : (Character, Character), gen : G) -> (Character, G) { + public static func randomInRange(_ range : (Character, Character), gen : G) -> (Character, G) { let (min, max) = range let minc = String(min).unicodeScalars.first! let maxc = String(max).unicodeScalars.first! @@ -143,15 +143,15 @@ extension Character : RandomType { extension UnicodeScalar : RandomType { /// Returns a random `UnicodeScalar` value using the given range and generator. - public static func randomInRange(range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { + public static func randomInRange(_ range : (UnicodeScalar, UnicodeScalar), gen : G) -> (UnicodeScalar, G) { let (val, gg) = UInt32.randomInRange((range.0.value, range.1.value), gen: gen) - return (UnicodeScalar(val), gg) + return (UnicodeScalar(val)!, gg) } } extension Int : RandomType { /// Returns a random `Int` value using the given range and generator. - public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { + public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int(truncatingBitPattern: bb), gg) @@ -160,7 +160,7 @@ extension Int : RandomType { extension Int8 : RandomType { /// Returns a random `Int8` value using the given range and generator. - public static func randomInRange(range : (Int8, Int8), gen : G) -> (Int8, G) { + public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int8(truncatingBitPattern: bb), gg) @@ -169,7 +169,7 @@ extension Int8 : RandomType { extension Int16 : RandomType { /// Returns a random `Int16` value using the given range and generator. - public static func randomInRange(range : (Int16, Int16), gen : G) -> (Int16, G) { + public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int16(truncatingBitPattern: bb), gg) @@ -178,7 +178,7 @@ extension Int16 : RandomType { extension Int32 : RandomType { /// Returns a random `Int32` value using the given range and generator. - public static func randomInRange(range : (Int32, Int32), gen : G) -> (Int32, G) { + public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) return (Int32(truncatingBitPattern: bb), gg) @@ -187,7 +187,7 @@ extension Int32 : RandomType { extension Int64 : RandomType { /// Returns a random `Int64` value using the given range and generator. - public static func randomInRange(range : (Int64, Int64), gen : G) -> (Int64, G) { + public static func randomInRange(_ range : (Int64, Int64), gen : G) -> (Int64, G) { let (l, h) = range if l > h { return Int64.randomInRange((h, l), gen: gen) @@ -197,8 +197,8 @@ extension Int64 : RandomType { let q : Double = 1000 let k = Double(h) - Double(l) + 1 let magtgt = k * q - - func entropize(mag : Double, _ v : Double, _ g : G) -> (Double, G) { + + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { if mag >= magtgt { return (v, g) } else { @@ -207,61 +207,81 @@ extension Int64 : RandomType { return entropize(mag * b, v_, g_) } } - + let (v, rng_) = entropize(1, 0, gen) - return (Int64(Double(l) + (v % k)), rng_) + return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) } } } extension UInt : RandomType { /// Returns a random `UInt` value using the given range and generator. - public static func randomInRange(range : (UInt, UInt), gen : G) -> (UInt, G) { + public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(Int(bitPattern: minl)), Int64(Int(bitPattern: maxl))), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt(truncatingBitPattern: bb), gg) } } extension UInt8 : RandomType { /// Returns a random `UInt8` value using the given range and generator. - public static func randomInRange(range : (UInt8, UInt8), gen : G) -> (UInt8, G) { + public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt8(truncatingBitPattern: bb), gg) } } extension UInt16 : RandomType { /// Returns a random `UInt16` value using the given range and generator. - public static func randomInRange(range : (UInt16, UInt16), gen : G) -> (UInt16, G) { + public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt16(truncatingBitPattern: bb), gg) } } extension UInt32 : RandomType { /// Returns a random `UInt32` value using the given range and generator. - public static func randomInRange(range : (UInt32, UInt32), gen : G) -> (UInt32, G) { + public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) + let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) return (UInt32(truncatingBitPattern: bb), gg) } } extension UInt64 : RandomType { /// Returns a random `UInt64` value using the given range and generator. - public static func randomInRange(range : (UInt64, UInt64), gen : G) -> (UInt64, G) { - let (minl, maxl) = range - let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (UInt64(bb), gg) + public static func randomInRange(_ range : (UInt64, UInt64), gen : G) -> (UInt64, G) { + let (l, h) = range + if l > h { + return UInt64.randomInRange((h, l), gen: gen) + } else { + let (genlo, genhi) : (Int64, Int64) = (1, 2147483562) + let b = Double(genhi - genlo + 1) + let q : Double = 1000 + let k = Double(h) - Double(l) + 1 + let magtgt = k * q + + func entropize(_ mag : Double, _ v : Double, _ g : G) -> (Double, G) { + if mag >= magtgt { + return (v, g) + } else { + let (x, g_) = g.next + let v_ = (v * b + (Double(x) - Double(genlo))) + return entropize(mag * b, v_, g_) + } + } + + let (v, rng_) = entropize(1, 0, gen) + return (UInt64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) + } } } extension Float : RandomType { /// Produces a random `Float` value in the range `[Float.min, Float.max]`. - public static func random(rng : G) -> (Float, G) { + public static func random(_ rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) let twoto24 = Int32(2) ^ Int32(24) let mask24 = twoto24 - 1 @@ -270,7 +290,7 @@ extension Float : RandomType { } /// Returns a random `Float` value using the given range and generator. - public static func randomInRange(range : (Float, Float), gen : G) -> (Float, G) { + public static func randomInRange(_ range : (Float, Float), gen : G) -> (Float, G) { let (l, h) = range if l > h { return Float.randomInRange((h , l), gen: gen) @@ -283,7 +303,7 @@ extension Float : RandomType { extension Double : RandomType { /// Produces a random `Float` value in the range `[Double.min, Double.max]`. - public static func random(rng : G) -> (Double, G) { + public static func random(_ rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) let twoto53 = Int64(2) ^ Int64(53) let mask53 = twoto53 - 1 @@ -292,7 +312,7 @@ extension Double : RandomType { } /// Returns a random `Double` value using the given range and generator. - public static func randomInRange(range : (Double, Double), gen : G) -> (Double, G) { + public static func randomInRange(_ range : (Double, Double), gen : G) -> (Double, G) { let (l, h) = range if l > h { return Double.randomInRange((h , l), gen: gen) @@ -304,9 +324,13 @@ extension Double : RandomType { } /// Implementation Details Follow +private enum ClockTimeResult { + case success + case failure(Int) +} -private func mkStdRNG(o : Int) -> StdGen { - func mkStdGen32(sMaybeNegative : Int) -> StdGen { +private func mkStdRNG(_ o : Int) -> StdGen { + func mkStdGen32(_ sMaybeNegative : Int) -> StdGen { let s = sMaybeNegative & Int.max let (q, s1) = (s / 2147483562, s % 2147483562) let s2 = q % 2147483398 @@ -315,22 +339,28 @@ private func mkStdRNG(o : Int) -> StdGen { let ct = Int(clock()) var tt = timespec() - clock_gettime(0, &tt) + switch clock_gettime(0, &tt) { + case .success: + break + case let .failure(error): + fatalError("call to `clock_gettime` failed. error: \(error)") + } + let (sec, psec) = (tt.tv_sec, tt.tv_nsec) let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) } -private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> Int { +private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> ClockTimeResult { var now : timeval = timeval() let rv = gettimeofday(&now, nil) if rv != 0 { - return Int(rv) + return .failure(Int(rv)) } - t.memory.tv_sec = now.tv_sec - t.memory.tv_nsec = Int(now.tv_usec) * 1000 + t.pointee.tv_sec = now.tv_sec + t.pointee.tv_nsec = Int(now.tv_usec) * 1000 - return 0 + return .success } #if os(Linux) diff --git a/Sources/Rose.swift b/Sources/Rose.swift index 6cc9544..c47bfae 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -6,28 +6,28 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the -/// steps necessary for testing a property. The first case, .MkRose, consists -/// of a value and a list of trees. The second, case, .IORose, is a suspended -/// IO action SwiftCheck must execute in order to produce another Rose tree. +/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the +/// steps necessary for testing a property. The first case, .MkRose, consists +/// of a value and a list of trees. The second, case, .IORose, is a suspended +/// IO action SwiftCheck must execute in order to produce another Rose tree. /// All values in a `Rose` are lazy. /// -/// In practice SwiftCheck will minimize the side-effects performed in a given +/// In practice SwiftCheck will minimize the side-effects performed in a given /// `IORose` to printing values to the console and executing callbacks. public enum Rose { /// A normal branch in the Rose Tree. - case MkRose(() -> A, () -> [Rose]) + case mkRose(() -> A, () -> [Rose]) /// An IO branch in the Rose Tree. That is, a branch that must execute /// side effects before revealing further structure. - case IORose(() -> Rose) + case ioRose(() -> Rose) /// Case analysis for a Rose Tree. - public func onRose(f : (A, [Rose]) -> Rose) -> Rose { + public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { switch self { - case .MkRose(let x, let rs): + case .mkRose(let x, let rs): return f(x(), rs()) - case .IORose(let m): - return .IORose({ m().onRose(f) }) + case .ioRose(let m): + return .ioRose({ m().onRose(f) }) } } @@ -35,9 +35,9 @@ public enum Rose { /// `.MkRose` branch is encountered. That branch is then returned. public var reduce : Rose { switch self { - case .MkRose(_, _): + case .mkRose(_, _): return self - case .IORose(let m): + case .ioRose(let m): return m().reduce } } @@ -46,69 +46,52 @@ public enum Rose { extension Rose /*: Functor*/ { /// Maps a function over all the nodes of a Rose Tree. /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` branches + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` branches /// the map is suspended. - public func map(f : A -> B) -> Rose { - return f <^> self - } -} - -/// Fmap | Maps a function over all the nodes of a Rose Tree. -public func <^> (f : A -> B, g : Rose) -> Rose { - switch g { - case .MkRose(let root, let children): - return .MkRose({ f(root()) }, { children().map() { $0.map(f) } }) - case .IORose(let rs): - return .IORose({ rs().map(f) }) + public func map(_ f : @escaping (A) -> B) -> Rose { + switch self { + case .mkRose(let root, let children): + return .mkRose({ f(root()) }, { children().map() { $0.map(f) } }) + case .ioRose(let rs): + return .ioRose({ rs().map(f) }) + } } } extension Rose /*: Applicative*/ { /// Lifts a value into a Rose Tree. - public static func pure(a : A) -> Rose { - return .MkRose({ a }, { [] }) + public static func pure(_ a : A) -> Rose { + return .mkRose({ a }, { [] }) } - /// Applies a Rose Tree of functions to the receiver to yield a new Rose + /// Applies a Rose Tree of functions to the receiver to yield a new Rose /// Tree of values. /// - /// For `.MkRose` branches the computation is applied to the node's value - /// then application recurses into the sub-trees. For `.IORose` the branch - /// is reduced to a `.MkRose` and applied, executing all side-effects along + /// For `.MkRose` branches the computation is applied to the node's value + /// then application recurses into the sub-trees. For `.IORose` the branch + /// is reduced to a `.MkRose` and applied, executing all side-effects along /// the way. - public func ap(fn : Rose B>) -> Rose { - return fn <*> self - } -} - -/// Ap | Applies a Rose Tree of functions to the receiver to yield a new Rose -/// Tree of values. -public func <*> (fn : Rose B>, g : Rose) -> Rose { - switch fn { - case .MkRose(let f, _): - return g.map(f()) - case .IORose(let rs): - return g.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + public func ap(_ fn : Rose<(A) -> B>) -> Rose { + switch fn { + case .mkRose(let f, _): + return self.map(f()) + case .ioRose(let rs): + return self.ap(rs()) ///EEWW, EW, EW, EW, EW, EW + } } } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all + /// Maps the values in the receiver to Rose Trees and joins them all /// together. - public func flatMap(fn : A -> Rose) -> Rose { - return self >>- fn + public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { + return joinRose(self.map(fn)) } } -/// Flat Map | Maps the values in the receiver to Rose Trees and joins them all -/// together. -public func >>- (m : Rose, fn : A -> Rose) -> Rose { - return joinRose(m.map(fn)) -} - /// Lifts functions to functions over Rose Trees. -public func liftM(f : A -> R, _ m1 : Rose) -> Rose { +public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { return m1.flatMap { x1 in return Rose.pure(f(x1)) } @@ -116,28 +99,28 @@ public func liftM(f : A -> R, _ m1 : Rose) -> Rose { /// Flattens a Rose Tree of Rose Trees by a single level. /// -/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the -/// kind of subtree at the node dictates the behavior of the join. For -/// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the +/// For `.IORose` branches the join is suspended. For `.MkRose` branches, the +/// kind of subtree at the node dictates the behavior of the join. For +/// `.IORose` sub-trees The join is suspended. For `.MkRose` the result is the /// value at the sub-tree node and a recursive call to join the branch's tree to /// its sub-trees. -public func joinRose(rs : Rose>) -> Rose { +public func joinRose(_ rs : Rose>) -> Rose { switch rs { - case .IORose(let rs): - return .IORose({ joinRose(rs()) }) - case .MkRose(let bx , let rs): - switch bx() { - case .IORose(let rm): - return .IORose({ joinRose(.MkRose(rm, rs)) }) - case .MkRose(let x, let ts): - return .MkRose(x, { rs().map(joinRose) + ts() }) - } + case .ioRose(let rs): + return .ioRose({ joinRose(rs()) }) + case .mkRose(let bx , let rs): + switch bx() { + case .ioRose(let rm): + return .ioRose({ joinRose(.mkRose(rm, rs)) }) + case .mkRose(let x, let ts): + return .mkRose(x, { rs().map(joinRose) + ts() }) + } } } /// Sequences an array of Rose Trees into a Rose Tree of an array. -public func sequence(ms : [Rose]) -> Rose<[A]> { - return ms.reduce(Rose<[A]>.pure([]), combine: { n, m in +public func sequence(_ ms : [Rose]) -> Rose<[A]> { + return ms.reduce(Rose<[A]>.pure([]), { n, m in return m.flatMap { x in return n.flatMap { xs in return Rose<[A]>.pure(xs + [x]) @@ -148,6 +131,6 @@ public func sequence(ms : [Rose]) -> Rose<[A]> { /// Sequences the result of mapping values to Rose trees into a single rose tree /// of an array of values. -public func mapM(f : A -> Rose, xs : [A]) -> Rose<[B]> { +public func mapM(_ f : (A) -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) } diff --git a/Sources/State.swift b/Sources/State.swift index 847ca3c..314a275 100644 --- a/Sources/State.swift +++ b/Sources/State.swift @@ -9,69 +9,70 @@ /// The internal state of the testing system. public struct CheckerState { /// The name bound to the current property (not labels). - let name : String - /// The maximum number of successful tests before SwiftCheck gives up. + let name : String + /// The maximum number of successful tests before SwiftCheck gives up. /// Defaults to 100. - let maxAllowableSuccessfulTests : Int + let maxAllowableSuccessfulTests : Int /// The maximum number of discarded tests before SwiftCheck gives up. - let maxAllowableDiscardedTests : Int - /// The function that generates the sizes fed to the generators for each + let maxAllowableDiscardedTests : Int + /// The function that generates the sizes fed to the generators for each /// test case. - let computeSize : (Int, Int) -> Int + let computeSize : (Int, Int) -> Int /// The count of the number of successful test cases seen so far. - let successfulTestCount : Int + let successfulTestCount : Int /// The count of the number of discarded test cases seen so far. - let discardedTestCount : Int - /// A dictionary of labels collected inside the test case. Each maps to an - /// integer describing the number of passed tests. It is used in - /// conjunction with the number of successful tests to print a coverage + let discardedTestCount : Int + /// A dictionary of labels collected inside the test case. Each maps to an + /// integer describing the number of passed tests. It is used in + /// conjunction with the number of successful tests to print a coverage /// percentage. - let labels : Dictionary + let labels : Dictionary /// A uniqued collection of all the labels collected during the test case. - let collected : [Set] - /// Returns whether the test case has fulfilled its expected failure - /// outcome. If the test case fails and it was expected this property - /// returns true. If the test case doesn't fail and it was not expected to + let collected : [Set] + /// Returns whether the test case has fulfilled its expected failure + /// outcome. If the test case fails and it was expected this property + /// returns true. If the test case doesn't fail and it was not expected to /// fail this property returns true. Only when the test case's outcome and - /// its failure fulfillment expectation do not match does this property + /// its failure fulfillment expectation do not match does this property /// return false. - let hasFulfilledExpectedFailure : Bool + let hasFulfilledExpectedFailure : Bool /// The Random Number Generator backing the testing session. - let randomSeedGenerator : StdGen + let randomSeedGenerator : StdGen /// Returns the number of successful shrinking steps performed so far. - let successfulShrinkCount : Int - /// Returns the number of failed shrinking steps since the last successful + let successfulShrinkCount : Int + /// Returns the number of failed shrinking steps since the last successful /// shrink. - let failedShrinkStepDistance : Int + let failedShrinkStepDistance : Int /// Returns the number of failed shrink steps. - let failedShrinkStepCount : Int + let failedShrinkStepCount : Int /// Returns whether the testing system should cease testing altogether. - let shouldAbort : Bool + let shouldAbort : Bool /// The quantifier being applied to this test case. - let quantifier : Quantification + let quantifier : Quantification /// The arguments currently being applied to the testing driver. - let arguments : CheckerArguments + let arguments : CheckerArguments - let silence : Bool + let silence : Bool - public init( name : String - , maxAllowableSuccessfulTests : Int - , maxAllowableDiscardedTests : Int - , computeSize : (Int, Int) -> Int - , successfulTestCount : Int - , discardedTestCount : Int - , labels : Dictionary - , collected : [Set] - , hasFulfilledExpectedFailure : Bool - , randomSeedGenerator : StdGen - , successfulShrinkCount : Int - , failedShrinkStepDistance : Int - , failedShrinkStepCount : Int - , shouldAbort : Bool - , quantifier : Quantification - , arguments : CheckerArguments - , silence : Bool) - { + public init( + name : String, + maxAllowableSuccessfulTests : Int, + maxAllowableDiscardedTests : Int, + computeSize : @escaping (Int, Int) -> Int, + successfulTestCount : Int, + discardedTestCount : Int, + labels : Dictionary, + collected : [Set], + hasFulfilledExpectedFailure : Bool, + randomSeedGenerator : StdGen, + successfulShrinkCount : Int, + failedShrinkStepDistance : Int, + failedShrinkStepCount : Int, + shouldAbort : Bool, + quantifier : Quantification, + arguments : CheckerArguments, + silence : Bool + ) { self.name = name self.maxAllowableSuccessfulTests = maxAllowableSuccessfulTests self.maxAllowableDiscardedTests = maxAllowableDiscardedTests diff --git a/Sources/SwiftCheck.h b/Sources/SwiftCheck.h index 1c17d82..a6bd494 100644 --- a/Sources/SwiftCheck.h +++ b/Sources/SwiftCheck.h @@ -6,4 +6,3 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -// In this header, you should import all the public headers of your framework using statements like #import diff --git a/Sources/Test.swift b/Sources/Test.swift index c51f0d7..bb38892 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -8,24 +8,24 @@ // MARK: - Property Testing with SwiftCheck -/// Property Testing is a more static and expressive form of Test-Driven -/// Development that emphasizes the testability of program properties - A -/// statement or invariant that can be proven to hold when fed any number of +/// Property Testing is a more static and expressive form of Test-Driven +/// Development that emphasizes the testability of program properties - A +/// statement or invariant that can be proven to hold when fed any number of /// arguments of a particular kind. It is akin to Fuzz Testing but is made /// significantly more powerful by the primitives in this framework. /// -/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a -/// value that is capable of producing a framework type called `Prop`, which -/// models individual test cases that themselves are capable of passing or +/// A `Property` in SwiftCheck is more than just `true` and `false`, it is a +/// value that is capable of producing a framework type called `Prop`, which +/// models individual test cases that themselves are capable of passing or /// failing "in the small" with a `TestResult`. For those familiar with /// Protocol-Oriented Programming, lying at the heart of all of these types is a -/// protocol called `Testable` that provides any type a means of converting -/// itself to a `Property`. SwiftCheck uses `Testable` early and often in -/// functions and operators to enable a high level of nesting of framework -/// primitives and an even higher level of genericity in the interface. By -/// default SwiftCheck provides `Testable` instances for `Bool`, `Property`, +/// protocol called `Testable` that provides any type a means of converting +/// itself to a `Property`. SwiftCheck uses `Testable` early and often in +/// functions and operators to enable a high level of nesting of framework +/// primitives and an even higher level of genericity in the interface. By +/// default SwiftCheck provides `Testable` instances for `Bool`, `Property`, /// `Prop`, and several other internal framework types. Practically, this means -/// any assertions you could make in `XCTest` will work immediately with the +/// any assertions you could make in `XCTest` will work immediately with the /// framework. // MARK: - Going Further @@ -41,11 +41,11 @@ /// v /// property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in /// -/// /// This part of the property uses `==>`, or the "implication" -/// /// combinator. Implication only executes the following block if -/// /// the preceding expression returns true. It can be used to +/// /// This part of the property uses `==>`, or the "implication" +/// /// combinator. Implication only executes the following block if +/// /// the preceding expression returns true. It can be used to /// /// discard test cases that contain data you don't want to test with. -/// return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { +/// return (!s.getSet.isEmpty && s.getSet != [0]) ==> { /// /// /// N.B. `shrinkArbitrary` is a internal method call that invokes the shrinker. /// let ls = self.shrinkArbitrary(s).map { $0.getSet } @@ -59,22 +59,22 @@ /// | +--- The property will print EVERY generated test case to the console. /// + --- We expect this property not to hold. /// -/// Testing is not limited to just these listed functions. New users should -/// check out our test suite and the files `Gen.swift`, `Property.swift`, -/// `Modifiers.swift`, and the top half of this very file to learn more about +/// Testing is not limited to just these listed functions. New users should +/// check out our test suite and the files `Gen.swift`, `Property.swift`, +/// `Modifiers.swift`, and the top half of this very file to learn more about /// the various parts of the SwiftCheck testing mechanism. // MARK: - Quantifiers -/// Below is the method all SwiftCheck properties are based on, `forAll`. It -/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a +/// Below is the method all SwiftCheck properties are based on, `forAll`. It +/// acts as a "Quantifier", i.e. a contract that serves as a guarantee that a /// property holds when the given testing block returns `true` or truthy values, -/// and fails when the testing block returns `false` or falsy values. The +/// and fails when the testing block returns `false` or falsy values. The /// testing block is usually used with Swift's abbreviated block syntax and -/// requires type annotations for all value positions being requested. For +/// requires type annotations for all value positions being requested. For /// example: /// -/// + This is "Property Notation". It allows you to give your properties a +/// + This is "Property Notation". It allows you to give your properties a /// | name and instructs SwiftCheck to test it. /// | /// | This backwards arrow binds a property name and a property + @@ -82,128 +82,244 @@ /// | | /// v v /// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in -/// return -/// (xs.reverse().reverse() == xs) "Reverse on the left" -/// ^&&^ -/// (xs == xs.reverse().reverse()) "Reverse on the right" +/// return +/// (xs.reverse().reverse() == xs) "Reverse on the left" +/// ^&&^ +/// (xs == xs.reverse().reverse()) "Reverse on the right" /// } /// -/// Why require types? For one, Swift cannot infer the types of local variables -/// because SwiftCheck uses highly polymorphic testing primitives. But, more -/// importantly, types are required because SwiftCheck uses them to select the -/// appropriate `Gen`erators and shrinkers for each data type automagically by -/// default. Those `Gen`erators and shrinkers are then used to create 100 +/// Why require types? For one, Swift cannot infer the types of local variables +/// because SwiftCheck uses highly polymorphic testing primitives. But, more +/// importantly, types are required because SwiftCheck uses them to select the +/// appropriate `Gen`erators and shrinkers for each data type automagically by +/// default. Those `Gen`erators and shrinkers are then used to create 100 /// random test cases that are evaluated lazily to produce a final result. /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A throws -> Testable)) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A) throws -> Testable) -> Property + where A : Arbitrary +{ return forAllShrink(A.arbitrary, shrinker: A.shrink, f: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary +{ return forAll { t in forAll { b in try pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary +{ return forAll { t in forAll { b, c in try pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary +{ return forAll { t in forAll { b, c, d in try pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary +{ return forAll { t in forAll { b, c, d, e in try pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f in try pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary, H : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) } } } /// Given an explicit generator, converts a function to a universally quantified /// property using the default shrinker for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { +/// +/// - parameter gen: A generator for values of type `A`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property + where A : Arbitrary +{ return forAllShrink(gen, shrinker: A.shrink, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property using the default shrinkers for those 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter genH: A generator for values of type `H`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property + where A : Arbitrary, B : Arbitrary, C : Arbitrary, D : Arbitrary, E : Arbitrary, F : Arbitrary, G : Arbitrary, H : Arbitrary +{ return forAll(genA, pf: { t in forAll(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } @@ -212,247 +328,331 @@ public func forAll(gen : Gen, pf : (A throws -> Testable)) -> Property { +/// +/// - parameter gen: A generator for values of type `A`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllShrink(gen, shrinker: { _ in [A]() }, f: pf) } /// Given 2 explicit generators, converts a function to a universally quantified /// property for those 2 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, pf : (A, B) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, pf : @escaping (A, B) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, pf: { b in try pf(t, b) }) }) } /// Given 3 explicit generators, converts a function to a universally quantified /// property for those 3 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, pf : (A, B, C) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, pf : @escaping (A, B, C) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, pf: { b, c in try pf(t, b, c) }) }) } /// Given 4 explicit generators, converts a function to a universally quantified /// property for those 4 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : (A, B, C, D) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, pf : @escaping (A, B, C, D) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, pf: { b, c, d in try pf(t, b, c, d) }) }) } /// Given 5 explicit generators, converts a function to a universally quantified /// property for those 5 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : (A, B, C, D, E) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, pf : @escaping (A, B, C, D, E) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, pf: { b, c, d, e in try pf(t, b, c, d, e) }) }) } /// Given 6 explicit generators, converts a function to a universally quantified /// property for those 6 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : (A, B, C, D, E, F) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, pf : @escaping (A, B, C, D, E, F) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, pf: { b, c, d, e, f in try pf(t, b, c, d, e, f) }) }) } /// Given 7 explicit generators, converts a function to a universally quantified /// property for those 7 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : (A, B, C, D, E, F, G) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, pf : @escaping (A, B, C, D, E, F, G) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, pf: { b, c, d, e, f, g in try pf(t, b, c, d, e, f, g) }) }) } /// Given 8 explicit generators, converts a function to a universally quantified /// property for those 8 types. /// -/// This variant of `forAll` does not shrink its argument but allows generators +/// This variant of `forAll` does not shrink its argument but allows generators /// of any type, not just those that conform to `Arbitrary`. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllNoShrink(genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { +/// +/// - parameter genA: A generator for values of type `A`. +/// - parameter genB: A generator for values of type `B`. +/// - parameter genC: A generator for values of type `C`. +/// - parameter genD: A generator for values of type `D`. +/// - parameter genE: A generator for values of type `E`. +/// - parameter genF: A generator for values of type `F`. +/// - parameter genG: A generator for values of type `G`. +/// - parameter genH: A generator for values of type `H`. +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAllNoShrink(_ genA : Gen, _ genB : Gen, _ genC : Gen, _ genD : Gen, _ genE : Gen, _ genF : Gen, _ genG : Gen, _ genH : Gen, pf : @escaping (A, B, C, D, E, F, G, H) throws -> Testable) -> Property { return forAllNoShrink(genA, pf: { t in forAllNoShrink(genB, genC, genD, genE, genF, genG, genH, pf: { b, c, d, e, f, g, h in try pf(t, b, c, d, e, f, g, h) }) }) } -/// Given an explicit generator and shrinker, converts a function to a +/// Given an explicit generator and shrinker, converts a function to a /// universally quantified property. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAllShrink(gen : Gen, shrinker : A -> [A], f : A throws -> Testable) -> Property { +/// +/// - parameter gen: A generator for values of type `A`. +/// - parameter shrinker: The shrinking function. +/// - parameter f: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block against values +/// generated with the given generator and shrunk on failure by the given +/// shrinking function. +public func forAllShrink(_ gen : Gen, shrinker : @escaping (A) -> [A], f : @escaping (A) throws -> Testable) -> Property { return Property(gen.flatMap { x in return shrinking(shrinker, initial: x, prop: { xs in do { - return (try f(xs)).counterexample(String(xs)) + return (try f(xs)).counterexample(String(describing: xs)) } catch let e { - return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(xs)) + return TestResult.failed("Test case threw an exception: \"\(e)\"").counterexample(String(describing: xs)) } }).unProperty - }) + }).again } -/// Converts a function into an existentially quantified property using the -/// default shrinker and generator for that type to search for a passing case. +/// Converts a function into an existentially quantified property using the +/// default shrinker and generator for that type to search for a passing case. /// SwiftCheck only runs a limited number of trials before giving up and failing. /// -/// The nature of Existential Quantification means SwiftCheck would have to +/// The nature of Existential Quantification means SwiftCheck would have to /// enumerate over the entire domain of the type `A` in order to return a proper -/// value. Because such a traversal is both impractical and leads to -/// computationally questionable behavior (infinite loops and the like), -/// SwiftCheck instead interprets `exists` as a finite search over arbitrarily +/// value. Because such a traversal is both impractical and leads to +/// computationally questionable behavior (infinite loops and the like), +/// SwiftCheck instead interprets `exists` as a finite search over arbitrarily /// many values (around 500). No shrinking is performed during the search. /// /// Existential Quantification should rarely be used, and in practice is usually /// used for *negative* statements "there does not exist `foo` such that `bar`". -/// It is recommended that you avoid `exists` and instead reduce your property -/// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). -/// `SNF` involves turning every `exists` into a function returning the -/// existential value, taking any other parameters being quantified over as +/// It is recommended that you avoid `exists` and instead reduce your property +/// to [Skolem Normal Form](https://en.wikipedia.org/wiki/Skolem_normal_form). +/// `SNF` involves turning every `exists` into a function returning the +/// existential value, taking any other parameters being quantified over as /// needed. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func exists(pf : A throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func exists(_ pf : @escaping (A) throws -> Testable) -> Property { return exists(A.arbitrary, pf: pf) } -/// Given an explicit generator, converts a function to an existentially +/// Given an explicit generator, converts a function to an existentially /// quantified property using the default shrinker for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func exists(gen : Gen, pf : A throws -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func exists(_ gen : Gen, pf : @escaping (A) throws -> Testable) -> Property { return forAllNoShrink(A.arbitrary, pf: { try pf($0).invert }).invert.mapResult { res in - return TestResult(ok: res.ok - , expect: res.expect - , reason: res.reason - , theException: res.theException - , labels: res.labels - , stamp: res.stamp - , callbacks: res.callbacks - , abort: res.abort - , quantifier: .Existential) + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: res.labels, + stamp: res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: .existential + ) } } /// Tests a property and prints the results to stdout. -public func quickCheck(prop : Testable, name : String = "") { - quickCheckWithResult(CheckerArguments(name: name), prop) +/// +/// - parameter prop: The property to be tested. +/// - parameter name: The name of the property being tested. +public func quickCheck(_ prop : Testable, name : String = "") { + _ = quickCheckWithResult(CheckerArguments(name: name), prop) } // MARK: - Implementation Details internal enum Result { - case Success(numTests : Int - , labels : [(String, Int)] - , output : String + case success( + numTests : Int, + labels : [(String, Int)], + output : String ) - case GaveUp(numTests : Int - , labels : [(String,Int)] - , output : String + case gaveUp( + numTests : Int, + labels : [(String,Int)], + output : String ) - case Failure(numTests : Int - , numShrinks : Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String + case failure( + numTests : Int, + numShrinks : Int, + usedSeed : StdGen, + usedSize : Int, + reason : String, + labels : [(String,Int)], + output : String ) - case ExistentialFailure(numTests: Int - , usedSeed : StdGen - , usedSize : Int - , reason : String - , labels : [(String,Int)] - , output : String - , lastResult : TestResult + case existentialFailure( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + reason : String, + labels : [(String,Int)], + output : String, + lastResult : TestResult ) - case NoExpectedFailure(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String + case noExpectedFailure( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + labels : [(String,Int)], + output : String ) - case InsufficientCoverage(numTests : Int - , usedSeed : StdGen - , usedSize : Int - , labels : [(String,Int)] - , output : String + case insufficientCoverage( + numTests : Int, + usedSeed : StdGen, + usedSize : Int, + labels : [(String,Int)], + output : String ) } private indirect enum Either { - case Left(L) - case Right(R) -} - -internal func quickCheckWithResult(args : CheckerArguments, _ p : Testable) -> Result { - let istate = CheckerState(name: args.name - , maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: args.maxAllowableDiscardedTests - , computeSize: { computeSize(args, vals: $0) } - , successfulTestCount: 0 - , discardedTestCount: 0 - , labels: [:] - , collected: [] - , hasFulfilledExpectedFailure: false - , randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen() - , successfulShrinkCount: 0 - , failedShrinkStepDistance: 0 - , failedShrinkStepCount: 0 - , shouldAbort: false - , quantifier: .Universal - , arguments: args - , silence: args.silence) - let modP : Property = (p.exhaustive ? p.property.once : p.property) - return test(istate, caseGen: modP.unProperty.unGen) + case left(L) + case right(R) +} + +internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { + let istate = CheckerState( + name: args.name, + maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: args.maxAllowableDiscardedTests, + computeSize: { computeSize(args, vals: $0) }, + successfulTestCount: 0, + discardedTestCount: 0, + labels: [:], + collected: [], + hasFulfilledExpectedFailure: false, + randomSeedGenerator: args.replay.map({ $0.0 }) ?? newStdGen(), + successfulShrinkCount: 0, + failedShrinkStepDistance: 0, + failedShrinkStepCount: 0, + shouldAbort: false, + quantifier: .universal, + arguments: args, + silence: args.silence + ) + return test(istate, caseGen: p.property.unProperty.unGen) } // Main Testing Loop: // -// Given an initial state and the inner function that runs the property begins -// turning a runloop that starts firing off individual test cases. Only 3 +// Given an initial state and the inner function that runs the property begins +// turning a runloop that starts firing off individual test cases. Only 3 // functions get dispatched from this loop: // -// - runATest: Does what it says; .Left indicates failure, .Right indicates +// - runATest: Does what it says; .Left indicates failure, .Right indicates // continuation. -// - doneTesting: Invoked when testing the property fails or succeeds once and +// - doneTesting: Invoked when testing the property fails or succeeds once and // for all. -// - giveUp: When the number of discarded tests exceeds the number given in the +// - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. -private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { +private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { var state = st while true { switch runATest(state, caseGen: caseGen) { - case let .Left(fail): + case let .left(fail): switch (fail.0, doneTesting(fail.1)) { - case (.Success(_, _, _), _): + case (.success(_, _, _), _): return fail.0 - case let (_, .NoExpectedFailure(numTests, seed, sz, labels, output)): - return .NoExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) - // Existential Failures need explicit propagation. Existentials increment the - // discard count so we check if it has been surpassed. If it has with any kind - // of success we're done. If no successes are found we've failed checking the + case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): + return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) + // Existential Failures need explicit propagation. Existentials increment the + // discard count so we check if it has been surpassed. If it has with any kind + // of success we're done. If no successes are found we've failed checking the // existential and report it as such. Otherwise turn the testing loop. - case (.ExistentialFailure(_, _, _, _, _, _, _), _): + case (.existentialFailure(_, _, _, _, _, _, _), _): if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { return reportExistentialFailure(fail.1, res: fail.0) } else { state = fail.1 - break } default: return fail.0 } - case let .Right(lsta): + case let .right(lsta): if lsta.successfulTestCount >= lsta.maxAllowableSuccessfulTests || lsta.shouldAbort { return doneTesting(lsta) } @@ -464,66 +664,70 @@ private func test(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result } } -// Executes a single test of the property given an initial state and the +// Executes a single test of the property given an initial state and the // generator function. // // On success the next state is returned. On failure the final result and state // are returned. -private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { +private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split // Execute the Rose Tree for the test and reduce to .MkRose. switch caseGen(rnd1, size).unProp.reduce { - case .MkRose(let resC, let ts): + case .mkRose(let resC, let ts): let res = resC() // Force the result only once. dispatchAfterTestCallbacks(st, res: res) // Then invoke the post-test callbacks switch res.match { - // Success - case .MatchResult(.Some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount.successor() - , discardedTestCount: st.discardedTestCount - , labels: unionWith(max, l: st.labels, r: labels) - , collected: [stamp] + st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .Right(nstate) - // Discard - case .MatchResult(.None, let expect, _, _, let labels, _, _, let abort, let quantifier): - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() - , labels: unionWith(max, l: st.labels, r: labels) - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .Right(nstate) - // Fail - case .MatchResult(.Some(false), let expect, _, _, _, _, _, let abort, let quantifier): - if quantifier == .Existential { -// print("") + // Success + case .matchResult(.some(true), let expect, _, _, let labels, let stamp, _, let abort, let quantifier): + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: (st.successfulTestCount + 1), + discardedTestCount: st.discardedTestCount, + labels: unionWith(max, l: st.labels, r: labels), + collected: [stamp] + st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) + return .right(nstate) + // Discard + case .matchResult(.none, let expect, _, _, let labels, _, _, let abort, let quantifier): + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: unionWith(max, l: st.labels, r: labels), + collected: st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) + return .right(nstate) + // Fail + case .matchResult(.some(false), let expect, _, _, _, _, _, let abort, let quantifier): + if quantifier == .existential { + // print("") } else if !expect { printCond(st.silence, "+++ OK, failed as expected. ", terminator: "") } else { @@ -532,127 +736,138 @@ private func runATest(st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Eit // Failure of an existential is not necessarily failure of the whole // test case, so treat this like a discard. - if quantifier == .Existential { - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) + if quantifier == .existential { + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.ExistentialFailure(numTests: st.successfulTestCount.successor() - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: "Could not satisfy existential" - , labels: summary(st) - , output: "*** Failed! " - , lastResult: res) - return .Left((resul, nstate)) + let resul = Result.existentialFailure( + numTests: (st.successfulTestCount + 1), + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + reason: "Could not satisfy existential", + labels: summary(st), + output: "*** Failed! ", + lastResult: res + ) + return .left((resul, nstate)) } - return .Right(nstate) + return .right(nstate) } // Attempt a shrink. let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) if !expect { - let s = Result.Success(numTests: st.successfulTestCount.successor(), labels: summary(st), output: "+++ OK, failed as expected. ") - return .Left((s, st)) + let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") + return .left((s, st)) } - let stat = Result.Failure(numTests: st.successfulTestCount.successor() - , numShrinks: numShrinks - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , reason: res.reason - , labels: summary(st) - , output: "*** Failed! ") - - let nstate = CheckerState(name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount.successor() - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: res.expect - , randomSeedGenerator: rnd2 - , successfulShrinkCount: st.successfulShrinkCount - , failedShrinkStepDistance: st.failedShrinkStepDistance - , failedShrinkStepCount: st.failedShrinkStepCount - , shouldAbort: abort - , quantifier: quantifier - , arguments: st.arguments - , silence: st.silence) - return .Left((stat, nstate)) + let stat = Result.failure( + numTests: (st.successfulTestCount + 1), + numShrinks: numShrinks, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + reason: res.reason, + labels: summary(st), + output: "*** Failed! " + ) + + let nstate = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: (st.discardedTestCount + 1), + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: res.expect, + randomSeedGenerator: rnd2, + successfulShrinkCount: st.successfulShrinkCount, + failedShrinkStepDistance: st.failedShrinkStepDistance, + failedShrinkStepCount: st.failedShrinkStepCount, + shouldAbort: abort, + quantifier: quantifier, + arguments: st.arguments, + silence: st.silence + ) + return .left((stat, nstate)) } default: fatalError("Pattern Match Failed: Rose should have been reduced to MkRose, not IORose.") - break } } -private func doneTesting(st : CheckerState) -> Result { +private func doneTesting(_ st : CheckerState) -> Result { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { printCond(st.silence, "+++ OK, failed as expected. ") - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) - return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } - + printDistributionGraph(st) - return .NoExpectedFailure(numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") + return .noExpectedFailure( + numTests: st.successfulTestCount, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + labels: summary(st), + output: "" + ) } else if insufficientCoverage(st) { - printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Insufficient coverage after " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) - return .InsufficientCoverage( numTests: st.successfulTestCount - , usedSeed: st.randomSeedGenerator - , usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount) - , labels: summary(st) - , output: "") + return .insufficientCoverage( + numTests: st.successfulTestCount, + usedSeed: st.randomSeedGenerator, + usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), + labels: summary(st), + output: "" + ) } else { - printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", i: st.successfulTestCount)) + printCond(st.silence, "*** Passed " + "\(st.successfulTestCount)" + pluralize(" test", st.successfulTestCount)) printDistributionGraph(st) - return .Success(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .success(numTests: st.successfulTestCount, labels: summary(st), output: "") } } -private func giveUp(st: CheckerState) -> Result { +private func giveUp(_ st : CheckerState) -> Result { printDistributionGraph(st) - return .GaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") + return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } // Interface to shrinking loop. Returns (number of shrinks performed, number of // failed shrinks, total number of shrinks performed). // -// This ridiculously stateful looping nonsense is due to limitations of the -// Swift unroller and, more importantly, ARC. This has been written with -// recursion in the past, and it was fabulous and beautiful, but it generated -// useless objects that ARC couldn't release on the order of Gigabytes for -// complex shrinks (much like `split` in the Swift Standard Library), and was +// This ridiculously stateful looping nonsense is due to limitations of the +// Swift unroller and, more importantly, ARC. This has been written with +// recursion in the past, and it was fabulous and beautiful, but it generated +// useless objects that ARC couldn't release on the order of Gigabytes for +// complex shrinks (much like `split` in the Swift Standard Library), and was // slow as hell. This way we stay in one stack frame no matter what and give ARC // a chance to cleanup after us. Plus we get to stay within a reasonable ~50-100 // megabytes for truly horrendous tests that used to eat 8 gigs. -private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { +private func findMinimalFailingTestCase(_ st : CheckerState, res : TestResult, ts : [Rose]) -> (Int, Int, Int) { if let e = res.theException { fatalError("Test failed due to exception: \(e)") } @@ -660,12 +875,12 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts var lastResult = res var branches = ts var successfulShrinkCount = st.successfulShrinkCount - var failedShrinkStepDistance = st.failedShrinkStepDistance.successor() + var failedShrinkStepDistance = (st.failedShrinkStepDistance + 1) var failedShrinkStepCount = st.failedShrinkStepCount // cont is a sanity check so we don't fall into an infinite loop. It is set - // to false at each new iteration and true when we select a new set of - // branches to test. If the branch selection doesn't change then we have + // to false at each new iteration and true when we select a new set of + // branches to test. If the branch selection doesn't change then we have // exhausted our possibilities and so must have reached a minimal case. var cont = true while cont { @@ -678,71 +893,73 @@ private func findMinimalFailingTestCase(st : CheckerState, res : TestResult, ts failedShrinkStepDistance = 0 // Try all possible courses of action in this Rose Tree - branches.forEach { r in + for r in branches { switch r.reduce { - case .MkRose(let resC, let ts1): + case .mkRose(let resC, let ts1): let res1 = resC() dispatchAfterTestCallbacks(st, res: res1) // Did we fail? Good! Failure is healthy. // Try the next set of branches. - if res1.ok == .Some(false) { + if res1.ok == .some(false) { lastResult = res1 branches = ts1() cont = true break } - // Otherwise increment the tried shrink counter and the failed + // Otherwise increment the tried shrink counter and the failed // shrink counter. - failedShrinkStepDistance = failedShrinkStepDistance.successor() - failedShrinkStepCount = failedShrinkStepCount.successor() + failedShrinkStepDistance = (failedShrinkStepDistance + 1) + failedShrinkStepCount = (failedShrinkStepCount + 1) default: fatalError("Rose should not have reduced to IO") } } - successfulShrinkCount = successfulShrinkCount.successor() + successfulShrinkCount = (successfulShrinkCount + 1) } - let state = CheckerState( name: st.name - , maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests - , maxAllowableDiscardedTests: st.maxAllowableDiscardedTests - , computeSize: st.computeSize - , successfulTestCount: st.successfulTestCount - , discardedTestCount: st.discardedTestCount - , labels: st.labels - , collected: st.collected - , hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure - , randomSeedGenerator: st.randomSeedGenerator - , successfulShrinkCount: successfulShrinkCount - , failedShrinkStepDistance: failedShrinkStepDistance - , failedShrinkStepCount: failedShrinkStepCount - , shouldAbort: st.shouldAbort - , quantifier: st.quantifier - , arguments: st.arguments - , silence: st.silence) + let state = CheckerState( + name: st.name, + maxAllowableSuccessfulTests: st.maxAllowableSuccessfulTests, + maxAllowableDiscardedTests: st.maxAllowableDiscardedTests, + computeSize: st.computeSize, + successfulTestCount: st.successfulTestCount, + discardedTestCount: st.discardedTestCount, + labels: st.labels, + collected: st.collected, + hasFulfilledExpectedFailure: st.hasFulfilledExpectedFailure, + randomSeedGenerator: st.randomSeedGenerator, + successfulShrinkCount: successfulShrinkCount, + failedShrinkStepDistance: failedShrinkStepDistance, + failedShrinkStepCount: failedShrinkStepCount, + shouldAbort: st.shouldAbort, + quantifier: st.quantifier, + arguments: st.arguments, + silence: st.silence + ) return reportMinimumCaseFound(state, res: lastResult) } -private func reportMinimumCaseFound(st : CheckerState, res : TestResult) -> (Int, Int, Int) { - let testMsg = " (after \(st.successfulTestCount.successor()) test" +private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (Int, Int, Int) { + let testMsg = " (after \((st.successfulTestCount + 1)) test" let shrinkMsg = st.successfulShrinkCount > 1 ? (" and \(st.successfulShrinkCount) shrink") : "" printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, res.reason + pluralize(testMsg, i: st.successfulTestCount.successor()) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, i: st.successfulShrinkCount) : "") + "):") + printCond(st.silence, res.reason + pluralize(testMsg, (st.successfulTestCount + 1)) + (st.successfulShrinkCount > 1 ? pluralize(shrinkMsg, st.successfulShrinkCount) : "") + "):") dispatchAfterFinalFailureCallbacks(st, res: res) return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } -private func reportExistentialFailure(st : CheckerState, res : Result) -> Result { +private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result { switch res { - case let .ExistentialFailure(_, _, _, reason, _, _, lastTest): + case let .existentialFailure(_, _, _, reason, _, _, lastTest): let testMsg = " (after \(st.discardedTestCount) test" printCond(st.silence, "*** Failed! ", terminator: "") printCond(st.silence, "Proposition: " + st.name) - printCond(st.silence, reason + pluralize(testMsg, i: st.discardedTestCount) + "):") + printCond(st.silence, reason + pluralize(testMsg, st.discardedTestCount) + "):") dispatchAfterFinalFailureCallbacks(st, res: lastTest) return res default: @@ -750,14 +967,14 @@ private func reportExistentialFailure(st : CheckerState, res : Result) -> Result } } -private func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterTestCallbacks(_ st : CheckerState, res : TestResult) { guard !st.silence else { return } - + res.callbacks.forEach { c in switch c { - case let .AfterTest(_, f): + case let .afterTest(_, f): f(st, res) default: break @@ -765,14 +982,14 @@ private func dispatchAfterTestCallbacks(st : CheckerState, res : TestResult) { } } -private func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestResult) { +private func dispatchAfterFinalFailureCallbacks(_ st : CheckerState, res : TestResult) { guard !st.silence else { return } res.callbacks.forEach { c in switch c { - case let .AfterFinalFailure(_, f): + case let .afterFinalFailure(_, f): f(st, res) default: break @@ -780,28 +997,28 @@ private func dispatchAfterFinalFailureCallbacks(st : CheckerState, res : TestRes } } -private func summary(s : CheckerState) -> [(String, Int)] { +private func summary(_ s : CheckerState) -> [(String, Int)] { let lff : [String] = s.collected.flatMap({ l in l.map({ s in "," + s }).filter({ xs in !xs.isEmpty }) }) - let l : [[String]] = lff.sort().groupBy(==) + let l : [[String]] = lff.sorted().groupBy(==) return l.map { ss in (ss.first!, ss.count * 100 / s.successfulTestCount) } } -private func labelPercentage(l : String, st : CheckerState) -> Int { +private func labelPercentage(_ l : String, st : CheckerState) -> Int { let occur = st.collected.flatMap(Array.init).filter { $0 == l } return (100 * occur.count) / st.maxAllowableSuccessfulTests } -private func printDistributionGraph(st : CheckerState) { - func showP(n : Int) -> String { +private func printDistributionGraph(_ st : CheckerState) { + func showP(_ n : Int) -> String { return (n < 10 ? " " : "") + "\(n)" + "%" } - + let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .Some(0) }).reduce("", combine: { (l : String, r : String) in l + ", " + r }) + return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) }) - let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sort().groupBy(==) + let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) - let allLabels : [String] = Array(gPrint.sort().reverse()) + let allLabels : [String] = Array(gPrint.sorted().reversed()) var covers = [String]() st.labels.forEach { (l, reqP) in @@ -824,27 +1041,27 @@ private func printDistributionGraph(st : CheckerState) { } } -private func pluralize(s : String, i : Int) -> String { +private func pluralize(_ s : String, _ i : Int) -> String { if i == 1 { return s } return s + "s" } -private func insufficientCoverage(st : CheckerState) -> Bool { +private func insufficientCoverage(_ st : CheckerState) -> Bool { return st.labels - .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) - .reduce(false, combine: { $0 || $1 }) + .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) + .reduce(false, { $0 || $1 }) } -private func printCond(cond : Bool, _ str : String, terminator : String = "\n") { +private func printCond(_ cond : Bool, _ str : String, terminator : String = "\n") { if !cond { print(str, terminator: terminator) } } extension Array { - private func groupBy(p : (Element , Element) -> Bool) -> [[Element]] { + fileprivate func groupBy(_ p : (Element , Element) -> Bool) -> [[Element]] { var result = [[Element]]() var accumulator = [Element]() self.forEach { current in @@ -868,12 +1085,12 @@ extension Array { /// Testing loop stuff -private func computeSize(args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { - func computeSize_(successes : Int, _ discards : Int) -> Int { - func roundTo(n : Int, _ m : Int) -> Int { +private func computeSize(_ args : CheckerArguments, vals : (successes : Int, discards : Int)) -> Int { + func computeSize_(_ successes : Int, _ discards : Int) -> Int { + func roundTo(_ n : Int, _ m : Int) -> Int { return (n / m) * m } - + if roundTo(successes, args.maxTestCaseSize) + args.maxTestCaseSize <= args.maxAllowableSuccessfulTests { return min(successes % args.maxTestCaseSize + (discards / 10), args.maxTestCaseSize) } else if successes >= args.maxAllowableSuccessfulTests { @@ -885,7 +1102,7 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca } } - func initialSizeForTest(defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { + func initialSizeForTest(default defaultSize : Int, successes : Int, discards : Int, computeSize : (Int, Int) -> Int) -> Int { if successes == 0 && discards == 0 { return defaultSize } else { @@ -893,13 +1110,14 @@ private func computeSize(args : CheckerArguments, vals : (successes : Int, disca } } - + if let (_, argSize) = args.replay { - return initialSizeForTest( argSize - , successes: vals.successes - , discards: vals.discards - , computeSize: computeSize_ - ) + return initialSizeForTest( + default: argSize, + successes: vals.successes, + discards: vals.discards, + computeSize: computeSize_ + ) } return computeSize_(vals.successes, vals.discards) } diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 46acad1..1e35fe2 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -7,33 +7,20 @@ // -/// The type of things that can be tested. Consequently, the type of things +/// The type of things that can be tested. Consequently, the type of things /// that can be returned from a `forAll` block. /// -/// `Testable` values must be able to produce a `Rose`, that is a -/// rose tree of test cases that terminates in a passing or failing -/// `TestResult`. SwiftCheck provides instances for `Bool`, `Discard`, `Prop`, -/// and `Property`. The last of these enables `forAll`s to return further +/// `Testable` values must be able to produce a `Rose`, that is a +/// rose tree of test cases that terminates in a passing or failing +/// `TestResult`. SwiftCheck provides instances for `Bool`, `Discard`, `Prop`, +/// and `Property`. The last of these enables `forAll`s to return further /// `forAll`s that can depend on previously generated values. public protocol Testable { - /// Returns true iff a single test case is exhaustive i.e. adequately covers - /// the search space. - /// - /// If true, the property will only be tested once. Defaults to false. - var exhaustive : Bool { get } - - /// Returns a `Property`, which SwiftCheck uses to perform test case + /// Returns a `Property`, which SwiftCheck uses to perform test case /// generation. var property : Property { get } } -extension Testable { - /// By default, all `Testable` types are non-exhaustive. - public var exhaustive : Bool { - return false - } -} - /// A property is anything that generates `Prop`s. public struct Property : Testable { let unProperty : Gen @@ -48,33 +35,26 @@ public struct Property : Testable { } } -/// A `Prop` describes a strategy for evaluating a test case to a final -/// `TestResult`. It holds a Rose Tree of branches that evaluate the test and -/// any modifiers and mappings that may have been applied to a particular +/// A `Prop` describes a strategy for evaluating a test case to a final +/// `TestResult`. It holds a Rose Tree of branches that evaluate the test and +/// any modifiers and mappings that may have been applied to a particular /// testing tree. /// -/// As a testable value, it creates a Property that generates only its testing +/// As a testable value, it creates a Property that generates only its testing /// tree. public struct Prop : Testable { var unProp : Rose - /// `Prop` tests are exhaustive because they unwrap to reveal non-exhaustive - /// property tests. - public var exhaustive : Bool { return true } - - /// Returns a property that tests the receiver. + /// Returns a property that tests the receiver. public var property : Property { -// return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) - return Property(Gen.pure(Prop(unProp: .IORose({ self.unProp })))) + // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) + return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) } } /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { - /// `Discard`s are trivially exhaustive. - public var exhaustive : Bool { return true } - - /// Create a `Discard` suitable for + /// Create a `Discard` suitable for public init() { } /// Returns a property that always rejects whatever result occurs. @@ -84,9 +64,6 @@ public struct Discard : Testable { } extension TestResult : Testable { - /// `TestResult`s are trivially exhaustive. - public var exhaustive : Bool { return true } - /// Returns a property that tests the receiver. public var property : Property { return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) @@ -94,9 +71,6 @@ extension TestResult : Testable { } extension Bool : Testable { - /// `Bool`ean values are trivially exhaustive. - public var exhaustive : Bool { return true } - /// Returns a property that evaluates to a test success if the receiver is /// `true`, else returns a property that evaluates to a test failure. public var property : Property { @@ -106,6 +80,6 @@ extension Bool : Testable { extension Gen /*: Testable*/ where A : Testable { public var property : Property { - return Property(self >>- { $0.property.unProperty }) + return Property(self.flatMap { $0.property.unProperty }) } } diff --git a/Sources/Witness.swift b/Sources/Witness.swift index bb54ac0..29c750d 100644 --- a/Sources/Witness.swift +++ b/Sources/Witness.swift @@ -13,14 +13,14 @@ /// say, the `Element`s underlying an `Array` are all `Arbitrary`, we /// instead ask the conformee to hand over information about the type parameter /// it wishes to guarantee is `Arbitrary` then SwiftCheck will synthesize a -/// function to act as a Witness that the parameter is in fact `Arbitrary`. -/// SwiftCheck presents a stronger but less general version of `forAll` that +/// function to act as a Witness that the parameter is in fact `Arbitrary`. +/// SwiftCheck presents a stronger but less general version of `forAll` that /// must be implemented by the conformee to guarantee a type-safe interface with /// the rest of the framework. /// -/// Implementating the `WitnessedArbitrary` protocol functions much like +/// Implementating the `WitnessedArbitrary` protocol functions much like /// implementing the `Arbitrary` protocol, but with a little extra baggage. For -/// example, to implement the protocol for `Array`, we declare the usual +/// example, to implement the protocol for `Array`, we declare the usual /// `arbitrary` and `shrink`: /// /// extension Array where Element : Arbitrary { @@ -30,12 +30,12 @@ /// if k == 0 { /// return Gen.pure([]) /// } -/// +/// /// return sequence((0...k).map { _ in Element.arbitrary }) /// } /// } /// } -/// +/// /// public static func shrink(bl : Array) -> [[Element]] { /// let rec : [[Element]] = shrinkOne(bl) /// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec @@ -48,7 +48,7 @@ /// /// extension Array : WitnessedArbitrary { /// public typealias Param = Element -/// +/// /// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { /// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in /// return pf(bl.map(wit)) @@ -59,63 +59,103 @@ public protocol WitnessedArbitrary { /// The witnessing type parameter. associatedtype Param - /// A property test that relies on a witness that the given type parameter + /// A property test that relies on a witness that the given type parameter /// is actually `Arbitrary`. - static func forAllWitnessed(wit : A -> Param, pf : (Self -> Testable)) -> Property + static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : @escaping (Self) -> Testable) -> Property } /// Converts a function into a universally quantified property using the default /// shrinker and generator for that type. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A -> Testable)) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A) -> Testable) -> Property + where A.Param : Arbitrary +{ return A.forAllWitnessed(id, pf: pf) } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 2 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary +{ return forAll { t in forAll { b in pf(t, b) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 3 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary +{ return forAll { t in forAll { b, c in pf(t, b, c) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 4 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary +{ return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 5 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 6 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 7 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } } /// Converts a function into a universally quantified property using the default /// shrinker and generator for 8 types. -@warn_unused_result(message="Did you forget to bind this quantifier to a property?") -public func forAll(pf : (A, B, C, D, E, F, G, H) -> Testable) -> Property { +/// +/// - parameter pf: A block that carries the property or invariant to be tested. +/// +/// - returns: A `Property` that executes the given testing block. +public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property + where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary +{ return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 6f9d82a..f99b1fa 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -9,21 +9,13 @@ extension Array where Element : Arbitrary { /// Returns a generator of `Array`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure([]) - } - - return sequence((0...k).map { _ in Element.arbitrary }) - } - } + return Element.arbitrary.proliferate } /// The default shrinking function for `Array`s of arbitrary `Element`s. - public static func shrink(bl : Array) -> [[Element]] { + public static func shrink(_ bl : Array) -> [[Element]] { let rec : [[Element]] = shrinkOne(bl) - return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec + return Int.shrink(bl.count).reversed().flatMap({ k in removes((k + 1), n: bl.count, xs: bl) }) + rec } } @@ -32,7 +24,7 @@ extension Array : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Array`s. - public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping ([Element]) -> Testable) -> Property { return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in return pf(bl.map(wit)) }) @@ -42,11 +34,11 @@ extension Array : WitnessedArbitrary { extension AnyBidirectionalCollection where Element : Arbitrary { /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return AnyBidirectionalCollection.init <^> [Element].arbitrary + return [Element].arbitrary.map(AnyBidirectionalCollection.init) } /// The default shrinking function for `AnyBidirectionalCollection`s of arbitrary `Element`s. - public static func shrink(bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { + public static func shrink(_ bl : AnyBidirectionalCollection) -> [AnyBidirectionalCollection] { return [Element].shrink([Element](bl)).map(AnyBidirectionalCollection.init) } } @@ -56,7 +48,7 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(wit : A -> Element, pf : (AnyBidirectionalCollection -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnyBidirectionalCollection) -> Testable) -> Property { return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in return pf(AnyBidirectionalCollection(bl.map(wit))) }) @@ -66,11 +58,11 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { extension AnySequence where Element : Arbitrary { /// Returns a generator of `AnySequence`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return AnySequence.init <^> [Element].arbitrary + return [Element].arbitrary.map(AnySequence.init) } /// The default shrinking function for `AnySequence`s of arbitrary `Element`s. - public static func shrink(bl : AnySequence) -> [AnySequence] { + public static func shrink(_ bl : AnySequence) -> [AnySequence] { return [Element].shrink([Element](bl)).map(AnySequence.init) } } @@ -80,7 +72,7 @@ extension AnySequence : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnySequence`s. - public static func forAllWitnessed(wit : A -> Element, pf : (AnySequence -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnySequence) -> Testable) -> Property { return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in return pf(AnySequence(bl.map(wit))) }) @@ -90,11 +82,11 @@ extension AnySequence : WitnessedArbitrary { extension ArraySlice where Element : Arbitrary { /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return ArraySlice.init <^> [Element].arbitrary + return [Element].arbitrary.map(ArraySlice.init) } /// The default shrinking function for `ArraySlice`s of arbitrary `Element`s. - public static func shrink(bl : ArraySlice) -> [ArraySlice] { + public static func shrink(_ bl : ArraySlice) -> [ArraySlice] { return [Element].shrink([Element](bl)).map(ArraySlice.init) } } @@ -104,7 +96,7 @@ extension ArraySlice : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(wit : A -> Element, pf : (ArraySlice -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ArraySlice) -> Testable) -> Property { return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in return pf(ArraySlice(bl.map(wit))) }) @@ -114,7 +106,7 @@ extension ArraySlice : WitnessedArbitrary { extension CollectionOfOne where Element : Arbitrary { /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return CollectionOfOne.init <^> Element.arbitrary + return Element.arbitrary.map(CollectionOfOne.init) } } @@ -123,9 +115,9 @@ extension CollectionOfOne : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(wit : A -> Element, pf : (CollectionOfOne -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (CollectionOfOne) -> Testable) -> Property { return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in - return pf(CollectionOfOne(wit(bl[.Zero]))) + return pf(CollectionOfOne(wit(bl[bl.startIndex]))) }) } } @@ -135,16 +127,16 @@ extension Optional where Wrapped : Arbitrary { /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. public static var arbitrary : Gen> { return Gen>.frequency([ - (1, Gen>.pure(.None)), - (3, liftM(Optional.Some, Wrapped.arbitrary)), + (1, Gen>.pure(.none)), + (3, liftM(Optional.some, Wrapped.arbitrary)), ]) } /// The default shrinking function for `Optional`s of arbitrary `Wrapped`s. - public static func shrink(bl : Optional) -> [Optional] { + public static func shrink(_ bl : Optional) -> [Optional] { if let x = bl { - let rec : [Optional] = Wrapped.shrink(x).map(Optional.Some) - return [.None] + rec + let rec : [Optional] = Wrapped.shrink(x).map(Optional.some) + return [.none] + rec } return [] } @@ -155,7 +147,7 @@ extension Optional : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Optional`s. - public static func forAllWitnessed(wit : A -> Wrapped, pf : (Optional -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : @escaping (Optional) -> Testable) -> Property { return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in return pf(bl.map(wit)) }) @@ -165,11 +157,11 @@ extension Optional : WitnessedArbitrary { extension ContiguousArray where Element : Arbitrary { /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. public static var arbitrary : Gen> { - return ContiguousArray.init <^> [Element].arbitrary + return [Element].arbitrary.map(ContiguousArray.init) } /// The default shrinking function for `ContiguousArray`s of arbitrary `Element`s. - public static func shrink(bl : ContiguousArray) -> [ContiguousArray] { + public static func shrink(_ bl : ContiguousArray) -> [ContiguousArray] { return [Element].shrink([Element](bl)).map(ContiguousArray.init) } } @@ -179,7 +171,7 @@ extension ContiguousArray : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(wit : A -> Element, pf : (ContiguousArray -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ContiguousArray) -> Testable) -> Property { return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in return pf(ContiguousArray(bl.map(wit))) }) @@ -190,17 +182,19 @@ extension ContiguousArray : WitnessedArbitrary { extension Dictionary where Key : Arbitrary, Value : Arbitrary { /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. public static var arbitrary : Gen> { - return [Key].arbitrary.flatMap { k in - return [Value].arbitrary.flatMap { v in - return Gen.pure(Dictionary(Zip2Sequence(k, v))) + return [Key].arbitrary.flatMap { (k : [Key]) in + return [Value].arbitrary.flatMap { (v : [Value]) in + return Gen.pure(Dictionary(zip(k, v))) } } } /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and /// `Value`s. - public static func shrink(d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(Zip2Sequence(Key.shrink($0), Value.shrink($1))) } + public static func shrink(_ d : Dictionary) -> [Dictionary] { + return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in + (key: k, value: v) + })) } } } @@ -211,73 +205,61 @@ extension EmptyCollection : Arbitrary { } } -extension HalfOpenInterval where Bound : protocol { +extension Range where Bound : Comparable & Arbitrary { /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. - public static var arbitrary : Gen> { + public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in return Bound.arbitrary.flatMap { r in - return Gen.pure(HalfOpenInterval(min(l, r), max(l, r))) + return Gen.pure((min(l, r) ..< max(l, r))) } } } /// The default shrinking function for `HalfOpenInterval`s of arbitrary `Bound`s. - public static func shrink(bl : HalfOpenInterval) -> [HalfOpenInterval] { - return zip(Bound.shrink(bl.start), Bound.shrink(bl.end)).map(HalfOpenInterval.init) + public static func shrink(_ bl : Range) -> [Range] { + return zip(Bound.shrink(bl.lowerBound), Bound.shrink(bl.upperBound)).map(Range.init) } } -extension LazyCollection where Base : protocol, Base.Index : ForwardIndexType { +extension LazyCollection where Base : Collection & Arbitrary, Base.Index : Comparable { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } -extension LazySequence where Base : protocol { +extension LazySequence where Base : Sequence & Arbitrary { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary } } -extension Range where Element : protocol { - /// Returns a generator of `Range`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Element.arbitrary.flatMap { l in - return Element.arbitrary.flatMap { r in - return Gen.pure(min(l, r)..> { + let constructor: (Element, Int) -> Repeated = { (element, count) in + return repeatElement(element , count: count) } - } - - /// The default shrinking function for `Range`s of arbitrary `Element`s. - public static func shrink(bl : Range) -> [Range] { - return Zip2Sequence(Element.shrink(bl.startIndex), Element.shrink(bl.endIndex)).map(..<) - } -} -extension Repeat where Element : Arbitrary { - /// Returns a generator of `Repeat`s of arbitrary `Element`s. - public static var arbitrary : Gen> { - return Repeat.init <^> Gen.zip(Int.arbitrary, Element.arbitrary) + return Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary).map(constructor) } } -extension Repeat : WitnessedArbitrary { +extension Repeated : WitnessedArbitrary { public typealias Param = Element /// Given a witness and a function to test, converts them into a universally /// quantified property over `Repeat`s. - public static func forAllWitnessed(wit : A -> Element, pf : (Repeat -> Testable)) -> Property { - return forAllShrink(Repeat.arbitrary, shrinker: { _ in [] }, f: { bl in + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Repeated) -> Testable) -> Property { + return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in let xs = bl.map(wit) - return pf(Repeat(count: xs.count, repeatedValue: xs.first!)) + return pf(repeatElement(xs.first!, count: xs.count)) }) } } -extension Set where Element : protocol { +extension Set where Element : Arbitrary & Hashable { /// Returns a generator of `Set`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in @@ -286,13 +268,13 @@ extension Set where Element : protocol { return Gen.pure(Set([])) } - return Set.init <^> sequence(Array((0...k)).map { _ in Element.arbitrary }) + return sequence(Array((0...k)).map { _ in Element.arbitrary }).map(Set.init) } } } /// The default shrinking function for `Set`s of arbitrary `Element`s. - public static func shrink(s : Set) -> [Set] { + public static func shrink(_ s : Set) -> [Set] { return [Element].shrink([Element](s)).map(Set.init) } } @@ -302,7 +284,7 @@ extension Set : WitnessedArbitrary { /// Given a witness and a function to test, converts them into a universally /// quantified property over `Set`s. - public static func forAllWitnessed(wit : A -> Element, pf : (Set -> Testable)) -> Property { + public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Set) -> Testable) -> Property { return forAll { (xs : [A]) in return pf(Set(xs.map(wit))) } @@ -311,38 +293,20 @@ extension Set : WitnessedArbitrary { // MARK: - Implementation Details Follow -private func bits(n : N) -> Int { - if n / 2 == 0 { - return 0 - } - return 1 + bits(n / 2) -} - -private func removes(k : Int, n : Int, xs : [A]) -> [[A]] { - let xs1 : [A] = take(k, xs: xs) - let xs2 : [A] = drop(k, xs: xs) - +private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { + let xs2 : [A] = Array(xs.suffix(max(0, xs.count - k))) if k > n { return [] } else if xs2.isEmpty { return [[]] } else { + let xs1 : [A] = Array(xs.prefix(k)) let rec : [[A]] = removes(k, n: n - k, xs: xs2).map({ xs1 + $0 }) return [xs2] + rec } } -private func take(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[0..(num : Int, xs : [T]) -> [T] { - let n = (num < xs.count) ? num : xs.count - return [T](xs[n..(xs : [A]) -> [[A]] { +private func shrinkOne(_ xs : [A]) -> [[A]] { if xs.isEmpty { return [[A]]() } else if let x : A = xs.first { @@ -355,9 +319,11 @@ private func shrinkOne(xs : [A]) -> [[A]] { } extension Dictionary { - private init(_ pairs : S) { + fileprivate init(_ pairs : S) + where S.Iterator.Element == (Key, Value) + { self.init() - var g = pairs.generate() + var g = pairs.makeIterator() while let (k, v): (Key, Value) = g.next() { self[k] = v } diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index d12c0ff..dfdce2e 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.6.1" + s.version = "0.6.2" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 52e47d0..54f2de3 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,11 +7,53 @@ objects = { /* Begin PBXBuildFile section */ - 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; - 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; - 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; + 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; + 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; + 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; + 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; + 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; + 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; + 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; + 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; + 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; + 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; + 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; + 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; + 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; + 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; + 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; + 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; @@ -27,9 +69,6 @@ 826D816A1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; 826D816B1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; 826D816C1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816D1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; - 826D816E1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; - 826D816F1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; 826D81701C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; 826D81711C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; 826D81721C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; @@ -51,62 +90,27 @@ 826D81821C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; 826D81831C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; 826D81841C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81851C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; - 826D81861C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; - 826D81871C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; + 826D81851C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; + 826D81861C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; + 826D81871C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; 826D81881C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; 826D81891C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; 826D818A1C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; - 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; - 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; - 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; - 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; - 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; - 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; - 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; - 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; - 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; - 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; - 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; - 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; - 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; - 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; - 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; + 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; + 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; + 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - FA3AD5371CE53BB30098B92B /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */; }; - FA7865841CE581810077CD7C /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7865831CE581810077CD7C /* Cartesian.swift */; }; + FAAB9E811D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; + FAAB9E821D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; + FAAB9E831D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; + FAAB9E851D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; + FAAB9E861D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; + FAAB9E871D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -157,16 +161,30 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 825C9AC81D8EE445003313E1 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = SOURCE_ROOT; }; + 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/SwiftCheckTests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/SwiftCheckTests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/SwiftCheckTests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/SwiftCheckTests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD41D8EE86E003313E1 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/SwiftCheckTests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/SwiftCheckTests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD71D8EE86E003313E1 /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/SwiftCheckTests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/SwiftCheckTests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/SwiftCheckTests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/SwiftCheckTests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/SwiftCheckTests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/SwiftCheckTests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; + 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; 826D814B1C953D070022266C /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lattice.swift; path = Sources/Lattice.swift; sourceTree = SOURCE_ROOT; }; 826D814C1C953D070022266C /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = Sources/Modifiers.swift; sourceTree = SOURCE_ROOT; }; - 826D814D1C953D070022266C /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/Operators.swift; sourceTree = SOURCE_ROOT; }; 826D814E1C953D070022266C /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = SOURCE_ROOT; }; 826D814F1C953D070022266C /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Random.swift; path = Sources/Random.swift; sourceTree = SOURCE_ROOT; }; 826D81501C953D070022266C /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Rose.swift; path = Sources/Rose.swift; sourceTree = SOURCE_ROOT; }; @@ -174,30 +192,19 @@ 826D81521C953D070022266C /* SwiftCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = Sources/SwiftCheck.h; sourceTree = SOURCE_ROOT; }; 826D81531C953D070022266C /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Test.swift; path = Sources/Test.swift; sourceTree = SOURCE_ROOT; }; 826D81541C953D070022266C /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Testable.swift; path = Sources/Testable.swift; sourceTree = SOURCE_ROOT; }; - 826D81551C953D070022266C /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestOperators.swift; path = Sources/TestOperators.swift; sourceTree = SOURCE_ROOT; }; + 826D81551C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D818F1C953D2D0022266C /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81901C953D2D0022266C /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81911C953D2D0022266C /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81921C953D2D0022266C /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81931C953D2D0022266C /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81941C953D2D0022266C /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81951C953D2D0022266C /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81961C953D2D0022266C /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81971C953D2D0022266C /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81981C953D2D0022266C /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81991C953D2D0022266C /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D819A1C953D2D0022266C /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D819B1C953D2D0022266C /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cartesian.swift.gyb; path = Sources/Cartesian.swift.gyb; sourceTree = SOURCE_ROOT; }; - FA7865831CE581810077CD7C /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = "Sources/Generated Files/Cartesian.swift"; sourceTree = SOURCE_ROOT; }; + FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; + FAAB9E7A1D91B96C0097AC78 /* compile.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = compile.sh; sourceTree = ""; }; + FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cartesian.swift.gyb; path = Sources/Cartesian.swift.gyb; sourceTree = SOURCE_ROOT; }; + FAAB9E841D91C1670097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cartesian.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -255,6 +262,7 @@ 826D81521C953D070022266C /* SwiftCheck.h */, 844FCC8F198B320500EB242A /* SwiftCheck */, 844FCC9C198B320500EB242A /* SwiftCheckTests */, + FAAB9E781D91B96C0097AC78 /* Templates */, 844FCC8E198B320500EB242A /* Products */, ); sourceTree = ""; @@ -275,21 +283,21 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( - FA7865821CE580960077CD7C /* Generated Files */, - FA3AD5361CE53BB30098B92B /* Cartesian.swift.gyb */, + FAAB9E7F1D91C12E0097AC78 /* Generated Files */, 826D81461C953D070022266C /* Arbitrary.swift */, + FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */, + 826D81551C953D070022266C /* Check.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, + 82BA08CE1D6FFBD20068D32F /* Compose.swift */, 826D81491C953D070022266C /* Gen.swift */, 826D814B1C953D070022266C /* Lattice.swift */, 826D814C1C953D070022266C /* Modifiers.swift */, - 826D814D1C953D070022266C /* Operators.swift */, 826D814E1C953D070022266C /* Property.swift */, 826D814F1C953D070022266C /* Random.swift */, 826D81501C953D070022266C /* Rose.swift */, 826D81511C953D070022266C /* State.swift */, 826D81531C953D070022266C /* Test.swift */, 826D81541C953D070022266C /* Testable.swift */, - 826D81551C953D070022266C /* TestOperators.swift */, 826D81561C953D070022266C /* Witness.swift */, 826D81571C953D070022266C /* WitnessedArbitrary.swift */, 844FCC90198B320500EB242A /* Supporting Files */, @@ -308,21 +316,22 @@ 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { isa = PBXGroup; children = ( - 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */, - 826D818F1C953D2D0022266C /* ComplexSpec.swift */, - 826D81901C953D2D0022266C /* DiscardSpec.swift */, - 826D81911C953D2D0022266C /* FailureSpec.swift */, - 826D81921C953D2D0022266C /* GenSpec.swift */, - 826D81931C953D2D0022266C /* LambdaSpec.swift */, - 826D81941C953D2D0022266C /* ModifierSpec.swift */, - 826D81951C953D2D0022266C /* PathSpec.swift */, - 826D81961C953D2D0022266C /* PropertySpec.swift */, - 080BE02A1CDAEA330043ACDE /* RawRepresentableSpec.swift */, - 826D81971C953D2D0022266C /* ReplaySpec.swift */, - 826D81981C953D2D0022266C /* RoseSpec.swift */, - 826D81991C953D2D0022266C /* ShrinkSpec.swift */, - 826D819A1C953D2D0022266C /* SimpleSpec.swift */, - 826D819B1C953D2D0022266C /* TestSpec.swift */, + 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, + 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, + 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, + 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, + 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, + 825C9AD41D8EE86E003313E1 /* GenSpec.swift */, + 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */, + 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, + 825C9AD71D8EE86E003313E1 /* PathSpec.swift */, + 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */, + 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */, + 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */, + 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */, + 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */, + 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */, + 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); path = SwiftCheckTests; @@ -336,14 +345,23 @@ name = "Supporting Files"; sourceTree = ""; }; - FA7865821CE580960077CD7C /* Generated Files */ = { + FAAB9E781D91B96C0097AC78 /* Templates */ = { isa = PBXGroup; children = ( - FA7865831CE581810077CD7C /* Cartesian.swift */, + FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */, + FAAB9E7A1D91B96C0097AC78 /* compile.sh */, + ); + path = Templates; + sourceTree = SOURCE_ROOT; + }; + FAAB9E7F1D91C12E0097AC78 /* Generated Files */ = { + isa = PBXGroup; + children = ( + FAAB9E841D91C1670097AC78 /* Cartesian.swift */, ); name = "Generated Files"; path = "Sources/Generated Files"; - sourceTree = ""; + sourceTree = SOURCE_ROOT; }; /* End PBXGroup section */ @@ -493,7 +511,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -504,16 +522,20 @@ }; 844FCC8C198B320500EB242A = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; }; 844FCC97198B320500EB242A = { CreatedOnToolsVersion = 6.0; + LastSwiftMigration = 0800; TestTargetID = 844FCC8C198B320500EB242A; }; 84DF75F71B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; 84DF76011B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; + LastSwiftMigration = 0800; }; }; }; @@ -544,6 +566,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + FAAB9E831D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -558,7 +581,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FA3AD5371CE53BB30098B92B /* Cartesian.swift.gyb in Resources */, + FAAB9E811D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -573,6 +596,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + FAAB9E821D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -597,7 +621,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "./Utils/gyb -o ./Sources/Generated\\ Files/Cartesian.swift Sources/Cartesian.swift.gyb\n"; + shellScript = "./Utils/gyb -o Sources/Generated\\ Files/Cartesian.swift Sources/Cartesian.swift.gyb"; }; /* End PBXShellScriptBuildPhase section */ @@ -610,16 +634,17 @@ 826D81691C953D070022266C /* Lattice.swift in Sources */, 826D81751C953D070022266C /* Random.swift in Sources */, 826D81841C953D070022266C /* Testable.swift in Sources */, - 826D816F1C953D070022266C /* Operators.swift in Sources */, + FAAB9E871D91C1670097AC78 /* Cartesian.swift in Sources */, 826D818A1C953D070022266C /* Witness.swift in Sources */, 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, 826D816C1C953D070022266C /* Modifiers.swift in Sources */, 826D81811C953D070022266C /* Test.swift in Sources */, - 826D81871C953D070022266C /* TestOperators.swift in Sources */, + 826D81871C953D070022266C /* Check.swift in Sources */, 826D81781C953D070022266C /* Rose.swift in Sources */, 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, 826D81631C953D070022266C /* Gen.swift in Sources */, 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */, 826D817B1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -628,21 +653,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02D1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -654,17 +679,17 @@ 826D81671C953D070022266C /* Lattice.swift in Sources */, 826D81731C953D070022266C /* Random.swift in Sources */, 826D81821C953D070022266C /* Testable.swift in Sources */, - 826D816D1C953D070022266C /* Operators.swift in Sources */, + FAAB9E851D91C1670097AC78 /* Cartesian.swift in Sources */, 826D81881C953D070022266C /* Witness.swift in Sources */, 826D81581C953D070022266C /* Arbitrary.swift in Sources */, 826D816A1C953D070022266C /* Modifiers.swift in Sources */, 826D817F1C953D070022266C /* Test.swift in Sources */, - 826D81851C953D070022266C /* TestOperators.swift in Sources */, + 826D81851C953D070022266C /* Check.swift in Sources */, 826D81761C953D070022266C /* Rose.swift in Sources */, 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, - FA7865841CE581810077CD7C /* Cartesian.swift in Sources */, 826D81611C953D070022266C /* Gen.swift in Sources */, 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */, 826D81791C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -673,21 +698,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02B1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -699,16 +724,17 @@ 826D81681C953D070022266C /* Lattice.swift in Sources */, 826D81741C953D070022266C /* Random.swift in Sources */, 826D81831C953D070022266C /* Testable.swift in Sources */, - 826D816E1C953D070022266C /* Operators.swift in Sources */, + FAAB9E861D91C1670097AC78 /* Cartesian.swift in Sources */, 826D81891C953D070022266C /* Witness.swift in Sources */, 826D81591C953D070022266C /* Arbitrary.swift in Sources */, 826D816B1C953D070022266C /* Modifiers.swift in Sources */, 826D81801C953D070022266C /* Test.swift in Sources */, - 826D81861C953D070022266C /* TestOperators.swift in Sources */, + 826D81861C953D070022266C /* Check.swift in Sources */, 826D81771C953D070022266C /* Rose.swift in Sources */, 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, 826D81621C953D070022266C /* Gen.swift in Sources */, 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */, 826D817A1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -717,21 +743,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, - 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */, - 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */, - 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */, - 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */, - 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */, - 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */, - 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */, - 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */, - 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */, - 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */, - 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */, - 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */, - 080BE02C1CDAEA330043ACDE /* RawRepresentableSpec.swift in Sources */, - 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */, + 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, + 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, + 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */, + 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */, + 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, + 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */, + 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */, + 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */, + 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, + 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, + 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */, + 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -781,6 +807,7 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -812,6 +839,8 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -831,6 +860,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -846,6 +876,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -874,6 +906,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -919,6 +952,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -963,6 +997,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -995,6 +1030,8 @@ SKIP_INSTALL = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1016,6 +1053,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1034,6 +1072,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -1046,6 +1085,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", @@ -1067,6 +1107,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1082,6 +1123,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", @@ -1099,6 +1141,8 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1126,6 +1170,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -1144,6 +1189,8 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index e559f2e..81d7615 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -52,11 +52,11 @@ .oneOf([ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init) + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init) + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) let args = CheckerArguments(maxTestCaseSize: 10) - + property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in return e.characters.filter({ $0 == "@" }).count == 1 }.once } func testIPv6Properties() { + + let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } + let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } + let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } + let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } + let ipHexDigits = Gen.oneOf([ - hexDigits.proliferateSized(1).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(2).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(3).map{ String.init($0) + ":" }, - hexDigits.proliferateSized(4).map{ String.init($0) + ":" }, + gen1, + gen2, + gen3, + gen4 ]) - let ipGen = { $0.initial } <^> glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]) + let ipGen = glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]).map { $0.initial } property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in return e.characters.filter({ $0 == ":" }).count == 3 } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testEmailAddressProperties", testEmailAddressProperties), + ("testIPv6Properties", testIPv6Properties), + ]) + #endif } // MARK: String Conveniences -func glue(parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", combine: +) } +func glue(_ parts : [Gen]) -> Gen { + return sequence(parts).map { $0.reduce("", +) } } extension String { - private var initial : String { - return self[self.startIndex...choose((mn, mx))) { n in + return mn <= n && n <= mx + } + } + + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int.min <= x && x <= Int.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int8.min <= x && x <= Int8.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int16.min <= x && x <= Int16.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int32.min <= x && x <= Int32.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int64.min <= x && x <= Int64.max } + + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt.min <= x && x <= UInt.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt8.min <= x && x <= UInt8.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt16.min <= x && x <= UInt16.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt32.min <= x && x <= UInt32.max } + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt64.min <= x && x <= UInt64.max } + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.frequency(Array(count: n, repeatedValue: (1, Gen.pure(0))))) { $0 == 0 } + return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } } - + property("Gen.weighted behaves") <- { let g = Gen.weighted([ (10, 0), @@ -38,7 +58,7 @@ class GenSpec : XCTestCase { } property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.weighted(Array(count: n, repeatedValue: (1, 0)))) { $0 == 0 } + return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } } property("The only value Gen.pure generates is the given value") <- { @@ -68,14 +88,14 @@ class GenSpec : XCTestCase { property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in return !xs.isEmpty ==> { return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in - return xs.startsWith(ys) + return xs.starts(with: ys) } } } property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in - return (xs.count == ys.count) ^&&^ (xs.sort() == ys.sort()) + return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) } } @@ -94,11 +114,11 @@ class GenSpec : XCTestCase { } property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = ArrayOf.init <^> Int.arbitrary.proliferateSized(n) + let g = Int.arbitrary.proliferateSized(n).map(ArrayOf.init) return forAll(g) { $0.getArray.count == n } } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(ArrayOf.init <^> Int.arbitrary.proliferateSized(0)) { + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferateSized(0).map(ArrayOf.init)) { return $0.getArray.isEmpty } @@ -123,32 +143,32 @@ class GenSpec : XCTestCase { } property("Gen.suchThat in series obeys both predicates") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in - return !(str.isEmpty || str.rangeOfString(",") != nil) + return !(str.isEmpty || str.range(of: ",") != nil) } } property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in return !str.isEmpty } } property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.rangeOfString(",") == nil }) + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) return forAll(g) { str in - return str.rangeOfString(",") == nil + return str.range(of: ",") == nil } } - + property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in return ss == xs } } - + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) return forAllNoShrink(g) { (x1, y1) in @@ -165,7 +185,7 @@ class GenSpec : XCTestCase { property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in let fx = Gen.pure(x) let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<(Int -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } } property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in @@ -182,28 +202,28 @@ class GenSpec : XCTestCase { return (x1, y1, z1) == (x, y, z) } } - + property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) return forAllNoShrink(g) { (x1, y1, z1, w1) in return (x1, y1, z1, w1) == (x, y, z, w) } } - + property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in return (x1, y1, z1, w1, a1) == (x, y, z, w, a) } } - + property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) } } - + property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in @@ -211,7 +231,7 @@ class GenSpec : XCTestCase { && c1 == c } } - + property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in @@ -219,14 +239,14 @@ class GenSpec : XCTestCase { && (c1, d1) == (c, d) } } - + property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in return forAll { (e : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) && (c1, d1, e1) == (c, d, e) - } + } } } @@ -236,7 +256,7 @@ class GenSpec : XCTestCase { return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) && (c1, d1, e1, f1) == (c, d, e, f) - } + } } } } @@ -252,54 +272,63 @@ class GenSpec : XCTestCase { property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in return forAllNoShrink(lawfulGen) { (x : Gen) in - return ((f.getArrow • g.getArrow) <^> x) == (x.map(g.getArrow).map(f.getArrow)) + return (x.map(f.getArrow • g.getArrow)) == (x.map(g.getArrow).map(f.getArrow)) } } property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (Gen.pure(id) <*> x) == x + return (x.ap(Gen.pure(id))) == x } property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in let f = fl.map({ $0.getArrow }) let g = gl.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x) == (f <*> (g <*> x)) + return x.ap(g.ap(f.map(curry(•)))) == x.ap(g).ap(f) } property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in let f = fl.map({ $0.getArrow }) let g = gl.map({ $0.getArrow }) - return (Gen.pure(curry(•)) <*> f <*> g <*> x) == (f <*> (g <*> x)) + return x.ap(g.ap(f.ap(Gen.pure(curry(•))))) == x.ap(g).ap(f) } property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in - let f : Int -> Gen = Gen.pure • fa.getArrow - return (Gen.pure(a) >>- f) == f(a) + let f : (Int) -> Gen = Gen.pure • fa.getArrow + return Gen.pure(a).flatMap(f) == f(a) } property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in - return (m >>- Gen.pure) == m + return (m.flatMap(Gen.pure)) == m } property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in - let f : Int -> Gen = Gen.pure • fa.getArrow - let g : Int -> Gen = Gen.pure • ga.getArrow + let f : (Int) -> Gen = Gen.pure • fa.getArrow + let g : (Int) -> Gen = Gen.pure • ga.getArrow return forAllNoShrink(lawfulGen) { (m : Gen) in - return ((m >>- f) >>- g) == (m >>- { x in f(x) >>- g }) + return m.flatMap(f).flatMap(g) == m.flatMap({ x in f(x).flatMap(g) }) } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testLaws", testLaws), + ]) + #endif } -internal func curry(f : (A, B) -> C) -> A -> B -> C { +internal func curry(_ f : @escaping (A, B) -> C) -> (A) -> (B) -> C { return { a in { b in f(a, b) } } } -internal func id(x : A) -> A { +internal func id(_ x : A) -> A { return x } -internal func • (f : B -> C, g : A -> B) -> A -> C { +infix operator • : NilCoalescingPrecedence + +internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } @@ -314,14 +343,14 @@ private func ==(l : Gen, r : Gen) -> Bool { private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> Bool { let normalizedL = lhs.map { ($0, $1.0, $1.1) } let normalizedR = rhs.map { ($0.0, $0.1, $1) } - + let sampleSize = 10 let sampleL = normalizedL.proliferateSized(sampleSize).generate let sampleR = normalizedR.proliferateSized(sampleSize).generate - + for (tupleL, tupleR) in zip(sampleL, sampleR) { guard tupleL == tupleR else { return false } } - + return true } diff --git a/Tests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift similarity index 61% rename from Tests/LambdaSpec.swift rename to Tests/SwiftCheckTests/LambdaSpec.swift index ca3a210..f38692b 100644 --- a/Tests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -30,7 +30,7 @@ func == (l : Name, r : Name) -> Bool { return l.unName == r.unName } -private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { +private func liftM2(_ f : @escaping (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { return m1.flatMap { x1 in return m2.flatMap { x2 in return Gen.pure(f(x1, x2)) @@ -39,18 +39,18 @@ private func liftM2(f : (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> G } indirect enum Exp : Equatable { - case Lam(Name, Exp) - case App(Exp, Exp) - case Var(Name) + case lam(Name, Exp) + case app(Exp, Exp) + case `var`(Name) } func == (l : Exp, r : Exp) -> Bool { switch (l, r) { - case let (.Lam(ln, le), .Lam(rn, re)): + case let (.lam(ln, le), .lam(rn, re)): return ln == rn && le == re - case let (.App(ln, le), .App(rn, re)): + case let (.app(ln, le), .app(rn, re)): return ln == rn && le == re - case let (.Var(n1), .Var(n2)): + case let (.var(n1), .var(n2)): return n1 == n2 default: return false @@ -58,66 +58,66 @@ func == (l : Exp, r : Exp) -> Bool { } extension Exp : Arbitrary { - private static func arbExpr(n : Int) -> Gen { + private static func arbExpr(_ n : Int) -> Gen { return Gen.frequency([ - (2, liftM(Exp.Var, Name.arbitrary)), - ] + ((n <= 0) ? [] : [ - (5, liftM2(Exp.Lam, Name.arbitrary, arbExpr(n.predecessor()))), - (5, liftM2(Exp.App, arbExpr(n/2), arbExpr(n/2))), - ])) + (2, liftM(Exp.var, Name.arbitrary)), + ] + ((n <= 0) ? [] : [ + (5, liftM2(Exp.lam, Name.arbitrary, arbExpr((n - 1)))), + (5, liftM2(Exp.app, arbExpr(n/2), arbExpr(n/2))), + ])) } static var arbitrary : Gen { return Gen.sized(self.arbExpr) } - static func shrink(e : Exp) -> [Exp] { + static func shrink(_ e : Exp) -> [Exp] { switch e { - case .Var(_): + case .var(_): return [] - case let .Lam(x, a): - return [a] + Exp.shrink(a).map { .Lam(x, $0) } - case let .App(a, b): + case let .lam(x, a): + return [a] + Exp.shrink(a).map { .lam(x, $0) } + case let .app(a, b): let part1 : [Exp] = [a, b] + [a].flatMap({ (expr : Exp) -> Exp? in - if case let .Lam(x, a) = expr { + if case let .lam(x, a) = expr { return a.subst(x, b) } return nil }) - let part2 : [Exp] = Exp.shrink(a).map { App($0, b) } - + Exp.shrink(b).map { App(a, $0) } + let part2 : [Exp] = Exp.shrink(a).map { app($0, b) } + + Exp.shrink(b).map { app(a, $0) } return part1 + part2 } } var free : Set { switch self { - case let .Var(x): + case let .var(x): return Set([x]) - case let .Lam(x, a): - return a.free.subtract([x]) - case let .App(a, b): + case let .lam(x, a): + return a.free.subtracting([x]) + case let .app(a, b): return a.free.union(b.free) } } - func rename(x : Name, _ y : Name) -> Exp { + func rename(_ x : Name, _ y : Name) -> Exp { if x == y { return self } - return self.subst(x, .Var(y)) + return self.subst(x, .var(y)) } - func subst(x : Name, _ c : Exp) -> Exp { + func subst(_ x : Name, _ c : Exp) -> Exp { switch self { - case let .Var(y) where x == y : + case let .var(y) where x == y : return c - case let .Lam(y, a) where x != y: - return .Lam(y, a.subst(x, c)) - case let .App(a, b): - return .App(a.subst(x, c), b.subst(x, c)) + case let .lam(y, a) where x != y: + return .lam(y, a.subst(x, c)) + case let .app(a, b): + return .app(a.subst(x, c), b.subst(x, c)) default: return self } @@ -125,14 +125,14 @@ extension Exp : Arbitrary { var eval : Exp { switch self { - case .Var(_): + case .var(_): fatalError("Cannot evaluate free variable!") - case let .App(a, b): + case let .app(a, b): switch a.eval { - case let .Lam(x, aPrime): + case let .lam(x, aPrime): return aPrime.subst(x, b) default: - return .App(a.eval, b.eval) + return .app(a.eval, b.eval) } default: return self @@ -143,24 +143,24 @@ extension Exp : Arbitrary { extension Exp : CustomStringConvertible { var description : String { switch self { - case let .Var(x): + case let .var(x): return "$" + x.description - case let .Lam(x, t): + case let .lam(x, t): return "(λ $\(x.description).\(t.description))" - case let .App(a, b): + case let .app(a, b): return "(\(a.description) \(b.description))" } } } extension Name { - func fresh(ys : Set) -> Name { + func fresh(_ ys : Set) -> Name { let zz = "abcdefghijklmnopqrstuvwxyz".unicodeScalars.map { Name(unName: String($0)) } - return Set(zz).subtract(ys).first ?? self + return Set(zz).subtracting(ys).first ?? self } } -private func showResult(x : A, f : A -> Testable) -> Property { +private func showResult(_ x : A, f : (A) -> Testable) -> Property { return f(x).whenFail { print("Result: \(x)") } @@ -173,9 +173,9 @@ class LambdaSpec : XCTestCase { property("Free variable capture occurs", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in return showResult(a.subst(x, b)) { subst_x_b_a in return a.free.contains(x) - ==> subst_x_b_a.free == a.free.subtract([x]).union(b.free) + ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) } - }.expectFailure + }.expectFailure property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in return showResult(a.subst(x, b)) { subst_x_b_a in @@ -189,4 +189,11 @@ class LambdaSpec : XCTestCase { } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } + diff --git a/Tests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift similarity index 78% rename from Tests/ModifierSpec.swift rename to Tests/SwiftCheckTests/ModifierSpec.swift index a01cfd7..fb9dd4e 100644 --- a/Tests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -20,7 +20,7 @@ class ModifierSpec : XCTestCase { } property("Pointers behave") <- forAll { (x : PointerOf) in - return x.getPointer == nil || x.size != 0 + return x.size != 0 } property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in @@ -40,10 +40,9 @@ class ModifierSpec : XCTestCase { } property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in - return - (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" + return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" ^&&^ - (xs.getArray == xs.getArray.reverse().reverse()) "Right identity" + (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" } property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in @@ -51,15 +50,20 @@ class ModifierSpec : XCTestCase { } property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in - return - iso.getFrom(iso.getTo(x)) == x + return iso.getFrom(iso.getTo(x)) == x ^&&^ iso.getTo(iso.getFrom(y)) == y } property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) + return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testModifiers", testModifiers), + ]) + #endif } diff --git a/Tests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift similarity index 59% rename from Tests/PathSpec.swift rename to Tests/SwiftCheckTests/PathSpec.swift index c98986f..f49fc9b 100644 --- a/Tests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -11,91 +11,97 @@ import XCTest struct Path : Arbitrary { let unPath : [A] - - private static func pathFrom(x : A) -> Gen<[A]> { + + private static func pathFrom(_ x : A) -> Gen<[A]> { return Gen.sized { n in return Gen<[A]>.oneOf( [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } ).map { [x] + $0 } } } - + static var arbitrary : Gen> { - return A.arbitrary >>- { x in + return A.arbitrary.flatMap { x in return pathFrom(x).map(Path.init) } } } -func path(p : A -> Bool, _ pth : Path) -> Bool { - return pth.unPath.reduce(true, combine: { $0 && p($1) }) +func path(_ p : (A) -> Bool, _ pth : Path) -> Bool { + return pth.unPath.reduce(true, { $0 && p($1) }) } -func somePath(p : A -> Bool, _ pth : Path) -> Property { +func somePath(_ p : (A) -> Bool, _ pth : Path) -> Property { return path({ !p($0) }, pth).expectFailure } -struct Extremal> : Arbitrary { +struct Extremal : Arbitrary { let getExtremal : A - + static var arbitrary : Gen> { - return Gen.frequency([ - (1, Gen.pure(A.min)), - (1, Gen.pure(A.max)), - (8, A.arbitrary) - ]).map(Extremal.init) + return Gen.frequency([ + (1, Gen.pure(A.min)), + (1, Gen.pure(A.max)), + (8, A.arbitrary) + ]).map(Extremal.init) } - - static func shrink(x : Extremal) -> [Extremal] { + + static func shrink(_ x : Extremal) -> [Extremal] { return A.shrink(x.getExtremal).map(Extremal.init) } } class PathSpec : XCTestCase { - private static func smallProp>(pth : Path) -> Bool { - return path({ x in + private static func smallProp(_ pth : Path) -> Bool { + return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 }, pth) } - - private static func largeProp>(pth : Path) -> Property { - return somePath({ x in + + private static func largeProp(_ pth : Path) -> Property { + return somePath({ x in return (x < -1000000 || x > 1000000) }, pth) } - + func testAll() { property("Int") <- forAll { (x : Path) in - return somePath({ x in + return somePath({ x in return (x < 1000000 || x > -1000000) - }, x) + }, x) } - + property("Int32") <- forAll { (x : Path) in - return path({ x in + return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 - }, x) + }, x) } - + property("UInt") <- forAll { (x : Path) in - return somePath({ x in + return somePath({ x in return (x < 1000000 || x > 0) - }, x) + }, x) } - + property("UInt32") <- forAll { (x : Path) in - return path({ x in + return path({ x in return (x >= 0 || -100 >= 0) && x <= 100 - }, x) + }, x) } - + property("Large Int") <- forAll { (x : Path>) in return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) } - + property("Large UInt") <- forAll { (x : Path>) in return PathSpec.largeProp(Path(unPath: x.unPath.map { $0.getLarge })) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift similarity index 76% rename from Tests/PropertySpec.swift rename to Tests/SwiftCheckTests/PropertySpec.swift index c151a03..f0acdfd 100644 --- a/Tests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -14,17 +14,17 @@ func ==(l : Property, r : Property) -> Bool { let res2 = quickCheckWithResult(CheckerArguments(name: "", silence: true), r) switch (res1, res2) { - case (.Success(_, _, _), .Success(_, _, _)): + case (.success(_, _, _), .success(_, _, _)): return true - case (.GaveUp(_, _, _), .GaveUp(_, _, _)): + case (.gaveUp(_, _, _), .gaveUp(_, _, _)): return true - case (.Failure(_, _, _, _, _, _, _), .Failure(_, _, _, _, _, _, _)): + case (.failure(_, _, _, _, _, _, _), .failure(_, _, _, _, _, _, _)): return true - case (.ExistentialFailure(_, _, _, _, _, _, _), .ExistentialFailure(_, _, _, _, _, _, _)): + case (.existentialFailure(_, _, _, _, _, _, _), .existentialFailure(_, _, _, _, _, _, _)): return true - case (.NoExpectedFailure(_, _, _, _, _), .NoExpectedFailure(_, _, _, _, _)): + case (.noExpectedFailure(_, _, _, _, _), .noExpectedFailure(_, _, _, _, _)): return true - case (.InsufficientCoverage(_, _, _, _, _), .InsufficientCoverage(_, _, _, _, _)): + case (.insufficientCoverage(_, _, _, _, _), .insufficientCoverage(_, _, _, _, _)): return true default: return false @@ -34,7 +34,7 @@ func ==(l : Property, r : Property) -> Bool { func ==(l : Property, r : Bool) -> Bool { let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) switch res1 { - case .Success(_, _, _): + case .success(_, _, _): return r == true default: return r == false @@ -44,7 +44,7 @@ func ==(l : Property, r : Bool) -> Bool { class PropertySpec : XCTestCase { func testProperties() { property("Once really only tests a property once") <- forAll { (n : Int) in - var bomb : Optional = .Some(n) + var bomb : Optional = .some(n) return forAll { (_ : Int) in let b = bomb! // Will explode if we test more than once bomb = nil @@ -52,31 +52,49 @@ class PropertySpec : XCTestCase { }.once } + property("Again undoes once") <- forAll { (n : Int) in + var counter : Int = 0 + quickCheck(forAll { (_ : Int) in + counter += 1 + return true + }.once.again) + return counter > 1 + } + + property("Once undoes again") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.again.once + } + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in return conjamb({ return true "picked 1" - }, { - return true "picked 2" - }, { - return true "picked 3" + }, { + return true "picked 2" + }, { + return true "picked 3" }) } property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in return n == n - }.invert.expectFailure + }.invert.expectFailure property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in return n != n - }.invert + }.invert property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in - throw SwiftCheckError.Bogus - }.invert + throw SwiftCheckError.bogus + }.invert property("Invert does not affect discards") <- forAll { (n : Int) in return Discard() - }.invert + }.invert property("Existential Quantification works") <- exists { (x : Int) in return true @@ -84,7 +102,7 @@ class PropertySpec : XCTestCase { property("Cover reports failures properly") <- forAll { (s : Set) in return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") - }.expectFailure + }.expectFailure property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in let p = p2 ==> p1 @@ -92,7 +110,7 @@ class PropertySpec : XCTestCase { } property("==> Short Circuits") <- forAll { (n : Int) in - func isPositive(n : Int) -> Bool { + func isPositive(_ n : Int) -> Bool { if n > 0 { return true } else if (n & 1) == 0 { @@ -150,4 +168,10 @@ class PropertySpec : XCTestCase { return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testProperties", testProperties), + ]) + #endif } diff --git a/Tests/SwiftCheckTests/RawRepresentableSpec.swift b/Tests/SwiftCheckTests/RawRepresentableSpec.swift new file mode 100644 index 0000000..bef8bdf --- /dev/null +++ b/Tests/SwiftCheckTests/RawRepresentableSpec.swift @@ -0,0 +1,42 @@ +// +// RawRepresentable+ArbitrarySpec.swift +// SwiftCheck +// +// Created by Brian Gerstle on 5/4/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +import XCTest +import SwiftCheck + +enum ImplicitRawValues : Int { + case foo + case bar + case baz +} + +extension ImplicitRawValues : Arbitrary {} + +enum ExplicitRawIntValues : Int { + case zero = 0 + case one = 1 + case two = 2 +} + +class RawRepresentableSpec : XCTestCase { + func testAll() { + property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in + return [.foo, .bar, .baz].contains(e) + } + + property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawIntValues.arbitrary) { e in + return [.zero, .one, .two].contains(e) + } + } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif +} diff --git a/Tests/ReplaySpec.swift b/Tests/SwiftCheckTests/ReplaySpec.swift similarity index 77% rename from Tests/ReplaySpec.swift rename to Tests/SwiftCheckTests/ReplaySpec.swift index f9cd608..7d02134 100644 --- a/Tests/ReplaySpec.swift +++ b/Tests/SwiftCheckTests/ReplaySpec.swift @@ -10,9 +10,9 @@ import SwiftCheck import XCTest class ReplaySpec : XCTestCase { - func testProperties() { + func testAll() { property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .Some(StdGen(seedl, seedr), size)) + let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) var foundArgs : [Int] = [] property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in foundArgs.append(x) @@ -28,4 +28,10 @@ class ReplaySpec : XCTestCase { return foundArgs == foundArgs2 } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift similarity index 69% rename from Tests/RoseSpec.swift rename to Tests/SwiftCheckTests/RoseSpec.swift index f411260..6885e01 100644 --- a/Tests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -10,82 +10,88 @@ import SwiftCheck import XCTest class RoseSpec : XCTestCase { - private static func intRoseTree(v : Int) -> Rose { - return .MkRose({ v }, { Int.shrink(v).map(intRoseTree) }) + private static func intRoseTree(_ v : Int) -> Rose { + return .mkRose({ v }, { Int.shrink(v).map(intRoseTree) }) } - - private static func depthOneChildren(rose : Rose) -> [A] { + + private static func depthOneChildren(_ rose : Rose) -> [A] { return rose.children.map { $0.root } } - - private static func depthOneAndTwoChildren(rose : Rose) -> [A] { + + private static func depthOneAndTwoChildren(_ rose : Rose) -> [A] { let topChildren = rose.children let vs = topChildren.map { $0.root } let cs = topChildren.flatMap({ $0.children }).map({ $0.root }) return vs + cs } - + func testAll() { property("Collapse brings up one level of rose tree depth") <- forAll { (i : Int) in let tree = RoseSpec.intRoseTree(i) return RoseSpec.depthOneChildren(tree.collapse) == RoseSpec.depthOneAndTwoChildren(tree) } } - + func testLaws() { let smallArgs = CheckerArguments(maxTestCaseSize: 5) property("Rose obeys the Functor identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in return (x.getRose.map(id)) == id(x.getRose) } - + property("Rose obeys the Functor composition law", arguments: smallArgs) <- forAll { (f : ArrowOf, g : ArrowOf) in return forAll { (x : RoseTreeOf) in - return ((f.getArrow • g.getArrow) <^> x.getRose) == (x.getRose.map(g.getArrow).map(f.getArrow)) + return x.getRose.map(f.getArrow • g.getArrow) == x.getRose.map(g.getArrow).map(f.getArrow) } } - + property("Rose obeys the Applicative identity law", arguments: smallArgs) <- forAll { (x : RoseTreeOf) in - return (Rose.pure(id) <*> x.getRose) == x.getRose + return x.getRose.ap(Rose.pure(id)) == x.getRose } - + property("Rose obeys the first Applicative composition law", arguments: smallArgs) <- forAll{ (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in let f = fl.getRose.map({ $0.getArrow }) let g = gl.getRose.map({ $0.getArrow }) - return (curry(•) <^> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + return x.getRose.ap(g.ap(f.map(curry(•)))) == x.getRose.ap(g).ap(f) } - + property("Rose obeys the second Applicative composition law", arguments: smallArgs) <- forAll { (fl : RoseTreeOf>, gl : RoseTreeOf>, x : RoseTreeOf) in let f = fl.getRose.map({ $0.getArrow }) let g = gl.getRose.map({ $0.getArrow }) - return (Rose.pure(curry(•)) <*> f <*> g <*> x.getRose) == (f <*> (g <*> x.getRose)) + return x.getRose.ap(g.ap(f.ap(Rose.pure(curry(•))))) == x.getRose.ap(g).ap(f) } - + property("Rose obeys the Monad left identity law", arguments: smallArgs) <- forAll { (a : Int, f : ArrowOf>) in - return (Rose.pure(a) >>- { f.getArrow($0).getRose }) == f.getArrow(a).getRose + return (Rose.pure(a).flatMap { f.getArrow($0).getRose }) == f.getArrow(a).getRose } - + property("Rose obeys the Monad right identity law", arguments: smallArgs) <- forAll { (m : RoseTreeOf) in - return (m.getRose >>- Rose.pure) == m.getRose + return m.getRose.flatMap(Rose.pure) == m.getRose } - + property("Rose obeys the Monad associativity law", arguments: smallArgs) <- forAll { (f : ArrowOf>, g : ArrowOf>) in return forAll { (m : RoseTreeOf) in - return - ((m.getRose >>- { f.getArrow($0).getRose }) >>- { g.getArrow($0).getRose }) - == - (m.getRose >>- { x in f.getArrow(x).getRose >>- { g.getArrow($0).getRose } }) + return m.getRose.flatMap({ f.getArrow($0).getRose }).flatMap({ g.getArrow($0).getRose }) + == + m.getRose.flatMap({ x in f.getArrow(x).getRose.flatMap({ g.getArrow($0).getRose }) }) } } } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testLaws", testLaws), + ]) + #endif } struct RoseTreeOf : Arbitrary { let getRose : Rose - + init(_ rose : Rose) { self.getRose = rose } - + static var arbitrary : Gen> { return Gen.sized { n in return arbTree(n) @@ -93,23 +99,23 @@ struct RoseTreeOf : Arbitrary { } } -private func arbTree(n : Int) -> Gen> { +private func arbTree(_ n : Int) -> Gen> { if n == 0 { - return A.arbitrary >>- { Gen.pure(RoseTreeOf(Rose.pure($0))) } + return A.arbitrary.flatMap { Gen.pure(RoseTreeOf(Rose.pure($0))) } } return Positive.arbitrary.flatMap { m in let n2 = n / (m.getPositive + 1) return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in - return Gen.pure(RoseTreeOf(.MkRose({ a }, { f.map { $0.getRose } }))) + return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) } } } private func == (l : Rose, r : Rose) -> Bool { switch (l, r) { - case let (.MkRose(l1, r1), .MkRose(l2, r2)): + case let (.mkRose(l1, r1), .mkRose(l2, r2)): return l1() == l2() && zip(r1(), r2()).reduce(true) { (a, t) in a && (t.0 == t.1) } - case (.IORose(_), .IORose(_)): + case (.ioRose(_), .ioRose(_)): return true default: return false @@ -119,28 +125,28 @@ private func == (l : Rose, r : Rose) -> Bool { extension Rose { var root : A { switch self.reduce { - case let .MkRose(root, _): + case let .mkRose(root, _): return root() default: fatalError("Rose should not have reduced to .IORose") } } - + var children : [Rose] { switch self.reduce { - case let .MkRose(_, children): + case let .mkRose(_, children): return children() default: fatalError("Rose should not have reduced to .IORose") } } - + var collapse : Rose { let children = self.children - + let vs = children.map { $0.collapse } let cs = children.flatMap({ $0.children }).map { $0.collapse } - - return .MkRose({ self.root }, { vs + cs }) + + return .mkRose({ self.root }, { vs + cs }) } } diff --git a/Tests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift similarity index 66% rename from Tests/ShrinkSpec.swift rename to Tests/SwiftCheckTests/ShrinkSpec.swift index 58e29ba..6df6452 100644 --- a/Tests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -10,7 +10,7 @@ import SwiftCheck import XCTest class ShrinkSpec : XCTestCase { - func shrinkArbitrary(x : A) -> [A] { + func shrinkArbitrary(_ x : A) -> [A] { let xs = A.shrink(x) if let x = xs.first { return xs + [x].flatMap(self.shrinkArbitrary) @@ -37,14 +37,11 @@ class ShrinkSpec : XCTestCase { return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) } } - - // This should not hold because eventually you'll get to [0, 0] which gets shrunk from - // [0] to [[]] which doesn't shrink so you're out of luck. We'll ExpectFailure here. - property("Shrunken sets of integers don't always contain [] or [0]") <- forAll { (s : SetOf) in - return (!s.getSet.isEmpty && s.getSet != Set([0])) ==> { - let ls = self.shrinkArbitrary(s).map { $0.getSet } - return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) - } - }.expectFailure } + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif } diff --git a/Tests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift similarity index 57% rename from Tests/SimpleSpec.swift rename to Tests/SwiftCheckTests/SimpleSpec.swift index 692e444..145c1eb 100644 --- a/Tests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -24,6 +24,31 @@ extension ArbitraryFoo : Arbitrary { } } +public struct ArbitraryMutableFoo : Arbitrary { + var a: Int8 + var b: Int16 + + public init() { + a = 0 + b = 0 + } + + public static var arbitrary: Gen { + return Gen.compose { c in + var foo = ArbitraryMutableFoo() + foo.a = c.generate() + foo.b = c.generate() + return foo + } + } +} + +extension ArbitraryMutableFoo: Equatable {} + +public func == (lhs: ArbitraryMutableFoo, rhs: ArbitraryMutableFoo) -> Bool { + return lhs.a == rhs.a && lhs.b == rhs.b +} + public struct ArbitraryLargeFoo { let a : Int8 let b : Int16 @@ -41,6 +66,26 @@ public struct ArbitraryLargeFoo { let n : (Bool, Bool, Bool, Bool) } +extension ArbitraryLargeFoo: Equatable {} + +public func ==(i: ArbitraryLargeFoo, j: ArbitraryLargeFoo) -> Bool { + return + i.a == j.a + && i.b == j.b + && i.c == j.c + && i.d == j.d + && i.e == j.e + && i.f == j.f + && i.g == j.g + && i.h == j.h + && i.i == j.i + && i.j == j.j + && i.k == j.k + && i.l == j.l + && i.m == j.m + && i.n == j.n +} + extension ArbitraryLargeFoo : Arbitrary { public static var arbitrary : Gen { return Gen<(Int8, Int16, Int32, Int64 @@ -63,6 +108,26 @@ extension ArbitraryLargeFoo : Arbitrary { } } +let composedArbitraryLargeFoo = Gen.compose { c in + let evenInt16 = Int16.arbitrary.suchThat { $0 % 2 == 0 } + return ArbitraryLargeFoo( + a: c.generate(), + b: c.generate(using: evenInt16), + c: c.generate(), + d: c.generate(), + e: c.generate(), + f: c.generate(), + g: c.generate(), + h: c.generate(), + i: c.generate(), + j: c.generate(), + k: c.generate(), + l: (c.generate(), c.generate()), + m: (c.generate(), c.generate(), c.generate()), + n: (c.generate(), c.generate(), c.generate(), c.generate()) + ) +} + class SimpleSpec : XCTestCase { func testAll() { property("Integer Equality is Reflexive") <- forAll { (i : Int8) in @@ -112,11 +177,14 @@ class SimpleSpec : XCTestCase { || (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) } - + + let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) + let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) + let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ - ((>), (<=)), - ((<), (>=)), - ((==), (!=)), + greaterThan_lessThanEqualTo, + lessThan_greaterThanEqualTo, + equalTo_notEqualTo, ]) property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in @@ -124,6 +192,25 @@ class SimpleSpec : XCTestCase { return op(x, y) ==== !iop(x, y) } } + + property("composition generates high-entropy, arbitrary values") + <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in + return a != b + } + } + + func testComposeWithMutableType() { + property("composition allows setting values on mutable types") + <- (forAll { (a: ArbitraryMutableFoo, b: ArbitraryMutableFoo) in + return a != b + // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size + }.mapSize { $0 + 100 }) } -} + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ("testComposeWithMutableType", testComposeWithMutableType), + ]) + #endif +} diff --git a/Tests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift similarity index 60% rename from Tests/TestSpec.swift rename to Tests/SwiftCheckTests/TestSpec.swift index bb9200a..f1c78ce 100644 --- a/Tests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -9,20 +9,9 @@ import SwiftCheck import XCTest -extension Dictionary { - init(_ pairs : S) { - self.init() - var g = pairs.generate() - while let (k, v) : (Key, Value) = g.next() { - self[k] = v - } - } -} - - class TestSpec : XCTestCase { func testAll() { - let dictionaryGen = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map(Dictionary.init) + let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in return true @@ -37,18 +26,16 @@ class TestSpec : XCTestCase { } property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in - return - (xs.reverse().reverse() == xs) "Left identity" + return (xs.reversed().reversed() == xs) "Left identity" ^&&^ - (xs == xs.reverse().reverse()) "Right identity" + (xs == xs.reversed().reversed()) "Right identity" } property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in - return - (xs.sort().sort() == xs.sort()).verbose "Sort Left" + return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" ^&&^ - ((xs.sort() != xs.sort().sort()).verbose "Bad Sort Right") - }.expectFailure + ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") + }.expectFailure property("map behaves") <- forAll { (xs : Array) in return forAll { (f : ArrowOf) in @@ -59,9 +46,14 @@ class TestSpec : XCTestCase { property("filter behaves") <- forAll { (xs : Array) in return forAll { (pred : ArrowOf) in let f = pred.getArrow - return (xs.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) as Bool) + return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) } } } -} + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAll", testAll), + ]) + #endif +} diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 37c057a..c4f014e 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -1,6 +1,7 @@ //: Playground - noun: a place where people can play import SwiftCheck +import Foundation.NSDate //: # Prerequisites @@ -129,7 +130,7 @@ pairsOfNumbers.generate // This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. let weightedGen = Gen.weighted([ (1, nil), - (3, .Some(5)), + (3, .some(5)), ]) weightedGen.generate @@ -196,28 +197,6 @@ generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate generatorBoundedSizeArrays.generate - -//: Because SwiftCheck is based on the functional concepts in our other library -//: [Swiftz](https://github.com/typelift/Swiftz), each of these functions has an operator alias: -//: -//: * `<^>` is an alias for `map` -//: * `<*>` is an alias for `ap` -//: * `>>-` is an alias for `flatMap` - -let fromTwoToSix_ = { $0 + 1 } <^> fromOnetoFive - -fromTwoToSix_.generate -fromTwoToSix_.generate -fromTwoToSix_.generate - -let generatorBoundedSizeArrays_ = fromOnetoFive >>- { len in - return characterArray.suchThat { xs in xs.count <= len } -} - -generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate -generatorBoundedSizeArrays_.generate - //: # Practical Generators //: For our purposes, we will say that an email address consists of 3 parts: A local part, a @@ -245,8 +224,8 @@ let allowedLocalCharacters : Gen = Gen.oneOf([ let localEmail = allowedLocalCharacters .proliferateNonEmpty // Make a non-empty array of characters - .suchThat({ $0[$0.endIndex.predecessor()] != "." }) // Such that the last character isn't a dot. - .map(String.init) // Then make a string. + .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) // Such that the last character isn't a dot. + .map { String($0) } // Then make a string. //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine them all into one big generator. @@ -255,21 +234,21 @@ let hostname = Gen.oneOf([ lowerCaseLetters, numeric, Gen.pure("-"), -]).proliferateNonEmpty.map(String.init) +]).proliferateNonEmpty.map { String($0) } //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. let tld = lowerCaseLetters .proliferateNonEmpty .suchThat({ $0.count > 1 }) - .map(String.init) + .map { String($0) } //: So now that we've got all the pieces, so how do we put them together to make the final generator? Well, how //: about some glue? // Concatenates an array of `String` `Gen`erators together in order. -func glue(parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", combine: +) } +func glue(_ parts : [Gen]) -> Gen { + return sequence(parts).map { $0.reduce("", +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) @@ -281,7 +260,6 @@ emailGen.generate emailGen.generate emailGen.generate - //: Complex cases like the above are rare in practice. Most of the time you won't even need to use //: generators at all! This brings us to one of the most important parts of SwiftCheck: @@ -309,56 +287,12 @@ emailGen.generate //: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance //: for `Int` calls `arc4random_uniform`. //: -//: We'll take this opportunity here to show you how to use Arbitrary for any types you might happen -//: to write yourself. But before that, let's try to write an `Arbitrary` instance for `NSDate`. - -import class Foundation.NSDate -import typealias Foundation.NSTimeInterval - -//: Here's the obvious way to do it -// -// extension NSDate : Arbitrary { -// public static var arbitrary : Gen { -// return Gen.oneOf([ -// Gen.pure(NSDate()), -// Gen.pure(NSDate.distantFuture()), -// Gen.pure(NSDate.distantPast()), -// NSDate.init <^> NSTimeInterval.arbitrary, -// ]) -// } -// } -// -//: But this doesn't work! Swift won't let us extend `NSDate` directly because we use `Gen` -//: in the wrong position. What to do? -//: -//: Let's write a wrapper! - -struct ArbitraryDate : Arbitrary { - let getDate : NSDate - - init(date : NSDate) { self.getDate = date } - - static var arbitrary : Gen { - return Gen.oneOf([ - Gen.pure(NSDate()), - Gen.pure(NSDate.distantFuture()), - Gen.pure(NSDate.distantPast()), - NSDate.init <^> NSTimeInterval.arbitrary, - ]).map(ArbitraryDate.init) - } -} - -ArbitraryDate.arbitrary.generate.getDate -ArbitraryDate.arbitrary.generate.getDate - -//: What we've just written is called a `Modifier Type`; a wrapper around one type that we can't -//: generate with another that we can. -//: -//: SwiftCheck uses this strategy for a few of the more "difficult" types in the Swift STL, but +//: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't +//: generate with another that we can–for a few of the more "difficult" types in the Swift STL, but //: we also use them in more benign ways too. For example, we can write a modifier type that only //: generates positive numbers: -public struct ArbitraryPositive> : Arbitrary { +public struct ArbitraryPositive : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -395,7 +329,7 @@ ArbitraryPositive.arbitrary.generate.getPositive // | | // v v property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in - return xs.reverse().reverse() == xs + return xs.reversed().reversed() == xs } // From now on, all of our examples will take the form above. @@ -408,7 +342,7 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, combine: { $0.0 && f($0.1) }) + return xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) // ^ This property says that if we filter an array then apply the predicate // to all its elements, then they should all respond with `true`. } @@ -499,7 +433,7 @@ struct ArbitraryEmail : Arbitrary { // Let's be wrong for the sake of example property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in - return !email.getEmail.containsString(".") + return !email.getEmail.contains(".") }.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail // and live up to your expectations, SwiftCheck treats that as a failure of the test case. @@ -531,7 +465,7 @@ func sieve(n : Int) -> [Int] { marked[1] = true for p in 2.. [Int] { // // Short and sweet check if a number is prime by enumerating from 2...⌈√(x)⌉ and checking // for a nonzero modulus. -func isPrime(n : Int) -> Bool { +func isPrime(_ n : Int) -> Bool { if n == 0 || n == 1 { return false } else if n == 2 { @@ -569,7 +503,7 @@ func isPrime(n : Int) -> Bool { //: following property: reportProperty("All Prime") <- forAll { (n : Positive) in - let primes = sieve(n.getPositive) + let primes = sieve(n: n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElementsOf(primes) return forAll(primeNumberGen) { (p : Int) in @@ -624,7 +558,7 @@ reportProperty("All Prime") <- forAll { (n : Positive) in // //: Looks like we used `to:` when we meant `through:`. Let's try again: -func sieveProperly(n : Int) -> [Int] { +func sieveProperly(_ n : Int) -> [Int] { if n <= 1 { return [] } @@ -634,7 +568,8 @@ func sieveProperly(n : Int) -> [Int] { marked[1] = true for p in 2..) in return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } -//; # One More Thing +//: # One More Thing //: When working with failing tests, it's often tough to be able to replicate the exact conditions //: that cause a failure or a bug. With SwiftCheck, that is now a thing of the past. The framework From 4365e340938f610cc4a7b0cbc3a6264553694090 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Tue, 20 Sep 2016 12:30:26 -0700 Subject: [PATCH 361/460] Change GYB template structure. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to play nice with spm, I’m moving the templates and the build script to a Template folder, that then outputs the generated file into Sources. --- Sources/Cartesian.swift | 366 +++++++++++++++++++++ SwiftCheck.xcodeproj/project.pbxproj | 35 +- {Sources => Templates}/Cartesian.swift.gyb | 0 Templates/compile.sh | 11 + 4 files changed, 386 insertions(+), 26 deletions(-) create mode 100644 Sources/Cartesian.swift rename {Sources => Templates}/Cartesian.swift.gyb (100%) create mode 100755 Templates/compile.sh diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift new file mode 100644 index 0000000..9675439 --- /dev/null +++ b/Sources/Cartesian.swift @@ -0,0 +1,366 @@ +// +// Cartesian.swift.gyb +// SwiftCheck +// +// Created by Adam Kuipers on 5/10/16. +// Copyright © 2016 Typelift. All rights reserved. +// + + +extension Gen /*: Cartesian*/ { + /// Zips together two generators and returns a generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { + return Gen<(A1, A2)> { r, n in + let (r1, r2) = r.split + return (ga1.unGen(r1, n), ga2.unGen(r2, n)) + } + } + + + /// Zips together 3 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> { + return Gen + .zip( + .zip(ga1, ga2), + ga3 + ).map { + ($0.0, $0.1, $1) + } + } + + /// Zips together 4 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { + return Gen + .zip( + .zip(ga1, ga2, ga3), + ga4 + ).map { + ($0.0, $0.1, $0.2, $1) + } + } + + /// Zips together 5 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4), + ga5 + ).map { + ($0.0, $0.1, $0.2, $0.3, $1) + } + } + + /// Zips together 6 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5), + ga6 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $1) + } + } + + /// Zips together 7 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6), + ga7 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $1) + } + } + + /// Zips together 8 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7), + ga8 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $1) + } + } + + /// Zips together 9 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8), + ga9 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $1) + } + } + + /// Zips together 10 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9), + ga10 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $1) + } + } + + /// Zips together 11 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10), + ga11 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $1) + } + } + + /// Zips together 12 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11), + ga12 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $1) + } + } + + /// Zips together 13 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12), + ga13 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $1) + } + } + + /// Zips together 14 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13), + ga14 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $1) + } + } + + /// Zips together 15 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14), + ga15 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $1) + } + } + + /// Zips together 16 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15), + ga16 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $1) + } + } + + /// Zips together 17 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16), + ga17 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $1) + } + } + + /// Zips together 18 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17), + ga18 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $1) + } + } + + /// Zips together 19 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18), + ga19 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $1) + } + } + + /// Zips together 20 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19), + ga20 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $1) + } + } + + /// Zips together 21 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20), + ga21 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $0.19, $1) + } + } + + /// Zips together 22 generators generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { + return Gen + .zip( + .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21), + ga22 + ).map { + ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $0.19, $0.20, $1) + } + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } + + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { + return zip(ga1, ga2, ga3).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map(transform) + } +} diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 54f2de3..778204c 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -105,12 +105,9 @@ 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - FAAB9E811D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; - FAAB9E821D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; - FAAB9E831D91C1400097AC78 /* Cartesian.swift.gyb in Resources */ = {isa = PBXBuildFile; fileRef = FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */; }; - FAAB9E851D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; - FAAB9E861D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; - FAAB9E871D91C1670097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E841D91C1670097AC78 /* Cartesian.swift */; }; + FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; + FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; + FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -203,8 +200,7 @@ 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; FAAB9E7A1D91B96C0097AC78 /* compile.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = compile.sh; sourceTree = ""; }; - FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Cartesian.swift.gyb; path = Sources/Cartesian.swift.gyb; sourceTree = SOURCE_ROOT; }; - FAAB9E841D91C1670097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cartesian.swift; sourceTree = ""; }; + FAAB9E881D91C28F0097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = Sources/Cartesian.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -283,9 +279,8 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( - FAAB9E7F1D91C12E0097AC78 /* Generated Files */, 826D81461C953D070022266C /* Arbitrary.swift */, - FAAB9E801D91C1400097AC78 /* Cartesian.swift.gyb */, + FAAB9E881D91C28F0097AC78 /* Cartesian.swift */, 826D81551C953D070022266C /* Check.swift */, 826D81481C953D070022266C /* CoArbitrary.swift */, 82BA08CE1D6FFBD20068D32F /* Compose.swift */, @@ -354,15 +349,6 @@ path = Templates; sourceTree = SOURCE_ROOT; }; - FAAB9E7F1D91C12E0097AC78 /* Generated Files */ = { - isa = PBXGroup; - children = ( - FAAB9E841D91C1670097AC78 /* Cartesian.swift */, - ); - name = "Generated Files"; - path = "Sources/Generated Files"; - sourceTree = SOURCE_ROOT; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -566,7 +552,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FAAB9E831D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -581,7 +566,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FAAB9E811D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -596,7 +580,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FAAB9E821D91C1400097AC78 /* Cartesian.swift.gyb in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -621,7 +604,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "./Utils/gyb -o Sources/Generated\\ Files/Cartesian.swift Sources/Cartesian.swift.gyb"; + shellScript = "pushd Templates\n./compile.sh\npopd\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -634,7 +617,7 @@ 826D81691C953D070022266C /* Lattice.swift in Sources */, 826D81751C953D070022266C /* Random.swift in Sources */, 826D81841C953D070022266C /* Testable.swift in Sources */, - FAAB9E871D91C1670097AC78 /* Cartesian.swift in Sources */, + FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */, 826D818A1C953D070022266C /* Witness.swift in Sources */, 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, 826D816C1C953D070022266C /* Modifiers.swift in Sources */, @@ -679,7 +662,7 @@ 826D81671C953D070022266C /* Lattice.swift in Sources */, 826D81731C953D070022266C /* Random.swift in Sources */, 826D81821C953D070022266C /* Testable.swift in Sources */, - FAAB9E851D91C1670097AC78 /* Cartesian.swift in Sources */, + FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */, 826D81881C953D070022266C /* Witness.swift in Sources */, 826D81581C953D070022266C /* Arbitrary.swift in Sources */, 826D816A1C953D070022266C /* Modifiers.swift in Sources */, @@ -724,7 +707,7 @@ 826D81681C953D070022266C /* Lattice.swift in Sources */, 826D81741C953D070022266C /* Random.swift in Sources */, 826D81831C953D070022266C /* Testable.swift in Sources */, - FAAB9E861D91C1670097AC78 /* Cartesian.swift in Sources */, + FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */, 826D81891C953D070022266C /* Witness.swift in Sources */, 826D81591C953D070022266C /* Arbitrary.swift in Sources */, 826D816B1C953D070022266C /* Modifiers.swift in Sources */, diff --git a/Sources/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb similarity index 100% rename from Sources/Cartesian.swift.gyb rename to Templates/Cartesian.swift.gyb diff --git a/Templates/compile.sh b/Templates/compile.sh new file mode 100755 index 0000000..7e4a4c5 --- /dev/null +++ b/Templates/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +wget https://github.com/apple/swift/raw/master/utils/gyb +wget https://github.com/apple/swift/raw/master/utils/gyb.py +chmod +x gyb + +./gyb --line-directive '' -o ../Sources/Cartesian.swift Cartesian.swift.gyb + +rm gyb +rm gyb.py +rm gyb.pyc From fc8a3aa907cf64a39568c484301f6b6e99f1d859 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Tue, 20 Sep 2016 12:47:23 -0700 Subject: [PATCH 362/460] Add GYB compilation step to travis. --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 995d71a..fcca87a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,11 @@ matrix: osx_image: xcode8 before_install: - git submodule update --init --recursive + - pushd Templates + - ./compile.sh + - popd script: - # Restore pod build before shipping for 3.0 + # Restore pod build before shipping for 3.0 # - pod lib lint - carthage build --no-skip-current - os: osx @@ -17,6 +20,9 @@ matrix: osx_image: xcode8 before_install: - git submodule update --init --recursive + - pushd Templates + - ./compile.sh + - popd script: - set -o pipefail - xcodebuild test -scheme SwiftCheck | xcpretty -c @@ -44,6 +50,9 @@ matrix: - wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz - tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz - export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - pushd Templates + - ./compile.sh + - popd script: - swift test notifications: From f1c096aa7d3551c690bcaee5d21ddd3632101f7a Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Tue, 20 Sep 2016 12:59:08 -0700 Subject: [PATCH 363/460] Remove utils. --- Utils/gyb | 4 - Utils/gyb.py | 1128 -------------------------------------------------- 2 files changed, 1132 deletions(-) delete mode 100755 Utils/gyb delete mode 100644 Utils/gyb.py diff --git a/Utils/gyb b/Utils/gyb deleted file mode 100755 index 7db0fcb..0000000 --- a/Utils/gyb +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python2.7 -import gyb -gyb.main() - diff --git a/Utils/gyb.py b/Utils/gyb.py deleted file mode 100644 index 7a03d57..0000000 --- a/Utils/gyb.py +++ /dev/null @@ -1,1128 +0,0 @@ -#!/usr/bin/env python -# GYB: Generate Your Boilerplate (improved names welcome; at least -# this one's short). See -h output for instructions - -from __future__ import print_function - -import os -import re -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO -import textwrap -import tokenize - -from bisect import bisect - - -def get_line_starts(s): - """Return a list containing the start index of each line in s. - - The list also contains a sentinel index for the end of the string, - so there will be one more element in the list than there are lines - in the string - """ - starts = [0] - - for line in s.split('\n'): - starts.append(starts[-1] + len(line) + 1) - - starts[-1] -= 1 - return starts - - -def strip_trailing_nl(s): - """If s ends with a newline, drop it; else return s intact""" - return s[:-1] if s.endswith('\n') else s - - -def split_lines(s): - """Split s into a list of lines, each of which has a trailing newline - - If the lines are later concatenated, the result is s, possibly - with a single appended newline. - """ - return [l + '\n' for l in s.split('\n')] - -# text on a line up to the first '$$', '${', or '%%' -literalText = r'(?: [^$\n%] | \$(?![${]) | %(?!%) )*' - -# The part of an '%end' line that follows the '%' sign -linesClose = r'[\ \t]* end [\ \t]* (?: \# .* )? $' - -# Note: Where "# Absorb" appears below, the regexp attempts to eat up -# through the end of ${...} and %{...}% constructs. In reality we -# handle this with the Python tokenizer, which avoids mis-detections -# due to nesting, comments and strings. This extra absorption in the -# regexp facilitates testing the regexp on its own, by preventing the -# interior of some of these constructs from being treated as literal -# text. -tokenize_re = re.compile( - r''' -# %-lines and %{...}-blocks - # \n? # absorb one preceding newline - ^ - (?: - (?P - (?P<_indent> [\ \t]* % (?! [{%] ) [\ \t]* ) (?! [\ \t] | ''' + linesClose + r''' ) .* - ( \n (?P=_indent) (?! ''' + linesClose + r''' ) .* ) * - ) - | (?P [\ \t]* % [ \t]* ''' + linesClose + r''' ) - | [\ \t]* (?P %\{ ) - (?: [^}]| \} (?!%) )* \}% # Absorb - ) - \n? # absorb one trailing newline - -# Substitutions -| (?P \$\{ ) - [^}]* \} # Absorb - -# %% and $$ are literal % and $ respectively -| (?P[$%]) (?P=symbol) - -# Literal text -| (?P ''' + literalText + r''' - (?: - # newline that doesn't precede space+% - (?: \n (?! [\ \t]* %[^%] ) ) - ''' + literalText + r''' - )* - \n? - ) -''', re.VERBOSE | re.MULTILINE) - -gyb_block_close = re.compile('\}%[ \t]*\n?') - - -def token_pos_to_index(token_pos, start, line_starts): - """Translate a tokenize (line, column) pair into an absolute - position in source text given the position where we started - tokenizing and a list that maps lines onto their starting - character indexes. - """ - relative_token_line_plus1, token_col = token_pos - - # line number where we started tokenizing - start_line_num = bisect(line_starts, start) - 1 - - # line number of the token in the whole text - abs_token_line = relative_token_line_plus1 - 1 + start_line_num - - # if found in the first line, adjust the end column to account - # for the extra text - if relative_token_line_plus1 == 1: - token_col += start - line_starts[start_line_num] - - # Sometimes tokenizer errors report a line beyond the last one - if abs_token_line >= len(line_starts): - return line_starts[-1] - - return line_starts[abs_token_line] + token_col - - -def tokenize_python_to_unmatched_close_curly(source_text, start, line_starts): - """Apply Python's tokenize to source_text starting at index start - while matching open and close curly braces. When an unmatched - close curly brace is found, return its index. If not found, - return len(source_text). If there's a tokenization error, return - the position of the error. - """ - stream = StringIO(source_text) - stream.seek(start) - nesting = 0 - - try: - for kind, text, token_start, token_end, line_text \ - in tokenize.generate_tokens(stream.readline): - - if text == '{': - nesting += 1 - elif text == '}': - nesting -= 1 - if nesting < 0: - return token_pos_to_index(token_start, start, line_starts) - - except tokenize.TokenError as error: - (message, error_pos) = error.args - return token_pos_to_index(error_pos, start, line_starts) - - return len(source_text) - - -def tokenize_template(template_text): - r"""Given the text of a template, returns an iterator over - (tokenType, token, match) tuples. - - **Note**: this is template syntax tokenization, not Python - tokenization. - - When a non-literal token is matched, a client may call - iter.send(pos) on the iterator to reset the position in - template_text at which scanning will resume. - - This function provides a base level of tokenization which is - then refined by ParseContext.token_generator. - - >>> from pprint import * - >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( - ... '%for x in range(10):\n% print x\n%end\njuicebox'))) - [('gybLines', '%for x in range(10):\n% print x'), - ('gybLinesClose', '%end'), - ('literal', 'juicebox')] - - >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( - ... '''Nothing - ... % if x: - ... % for i in range(3): - ... ${i} - ... % end - ... % else: - ... THIS SHOULD NOT APPEAR IN THE OUTPUT - ... '''))) - [('literal', 'Nothing\n'), - ('gybLines', '% if x:\n% for i in range(3):'), - ('substitutionOpen', '${'), - ('literal', '\n'), - ('gybLinesClose', '% end'), - ('gybLines', '% else:'), - ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n')] - - >>> for kind, text, _ in tokenize_template(''' - ... This is $some$ literal stuff containing a ${substitution} - ... followed by a %{...} block: - ... %{ - ... # Python code - ... }% - ... and here $${are} some %-lines: - ... % x = 1 - ... % y = 2 - ... % if z == 3: - ... % print '${hello}' - ... % end - ... % for x in zz: - ... % print x - ... % # different indentation - ... % twice - ... and some lines that literally start with a %% token - ... %% first line - ... %% second line - ... '''): - ... print (kind, text.strip().split('\n',1)[0]) - ('literal', 'This is $some$ literal stuff containing a') - ('substitutionOpen', '${') - ('literal', 'followed by a %{...} block:') - ('gybBlockOpen', '%{') - ('literal', 'and here ${are} some %-lines:') - ('gybLines', '% x = 1') - ('gybLinesClose', '% end') - ('gybLines', '% for x in zz:') - ('gybLines', '% # different indentation') - ('gybLines', '% twice') - ('literal', 'and some lines that literally start with a % token') - """ - pos = 0 - end = len(template_text) - - saved_literal = [] - literal_first_match = None - - while pos < end: - m = tokenize_re.match(template_text, pos, end) - - # pull out the one matched key (ignoring internal patterns starting - # with _) - ((kind, text), ) = ( - (kind, text) for (kind, text) in m.groupdict().items() - if text is not None and kind[0] != '_') - - if kind in ('literal', 'symbol'): - if len(saved_literal) == 0: - literal_first_match = m - # literals and symbols get batched together - saved_literal.append(text) - pos = None - else: - # found a non-literal. First yield any literal we've accumulated - if saved_literal != []: - yield 'literal', ''.join(saved_literal), literal_first_match - saved_literal = [] - - # Then yield the thing we found. If we get a reply, it's - # the place to resume tokenizing - pos = yield kind, text, m - - # If we were not sent a new position by our client, resume - # tokenizing at the end of this match. - if pos is None: - pos = m.end(0) - else: - # Client is not yet ready to process next token - yield - - if saved_literal != []: - yield 'literal', ''.join(saved_literal), literal_first_match - - -def split_gyb_lines(source_lines): - r"""Return a list of lines at which to split the incoming source - - These positions represent the beginnings of python line groups that - will require a matching %end construct if they are to be closed. - - >>> src = split_lines('''\ - ... if x: - ... print x - ... if y: # trailing comment - ... print z - ... if z: # another comment\ - ... ''') - >>> s = split_gyb_lines(src) - >>> len(s) - 2 - >>> src[s[0]] - ' print z\n' - >>> s[1] - len(src) - 0 - - >>> src = split_lines('''\ - ... if x: - ... if y: print 1 - ... if z: - ... print 2 - ... pass\ - ... ''') - >>> s = split_gyb_lines(src) - >>> len(s) - 1 - >>> src[s[0]] - ' if y: print 1\n' - - >>> src = split_lines('''\ - ... if x: - ... if y: - ... print 1 - ... print 2 - ... ''') - >>> s = split_gyb_lines(src) - >>> len(s) - 2 - >>> src[s[0]] - ' if y:\n' - >>> src[s[1]] - ' print 1\n' - """ - last_token_text, last_token_kind = None, None - unmatched_indents = [] - - dedents = 0 - try: - for token_kind, token_text, token_start, \ - (token_end_line, token_end_col), line_text \ - in tokenize.generate_tokens(lambda i=iter(source_lines): - next(i)): - - if token_kind in (tokenize.COMMENT, tokenize.ENDMARKER): - continue - - if token_text == '\n' and last_token_text == ':': - unmatched_indents.append(token_end_line) - - # The tokenizer appends dedents at EOF; don't consider - # those as matching indentations. Instead just save them - # up... - if last_token_kind == tokenize.DEDENT: - dedents += 1 - # And count them later, when we see something real. - if token_kind != tokenize.DEDENT and dedents > 0: - unmatched_indents = unmatched_indents[:-dedents] - dedents = 0 - - last_token_text, last_token_kind = token_text, token_kind - - except tokenize.TokenError: - # Let the later compile() call report the error - return [] - - if last_token_text == ':': - unmatched_indents.append(len(source_lines)) - - return unmatched_indents - - -def code_starts_with_dedent_keyword(source_lines): - r"""Return True iff the incoming Python source_lines begin with "else", - "elif", "except", or "finally". - - Initial comments and whitespace are ignored. - - >>> code_starts_with_dedent_keyword(split_lines('if x in y: pass')) - False - >>> code_starts_with_dedent_keyword(split_lines('except ifSomethingElse:')) - True - >>> code_starts_with_dedent_keyword( - split_lines('\n# comment\nelse: # yes')) - True - """ - token_text = None - for token_kind, token_text, _, _, _ \ - in tokenize.generate_tokens(lambda i=iter(source_lines): next(i)): - - if token_kind != tokenize.COMMENT and token_text.strip() != '': - break - - return token_text in ('else', 'elif', 'except', 'finally') - - -class ParseContext(object): - """State carried through a parse of a template""" - - filename = '' - template = '' - line_starts = [] - code_start_line = -1 - code_text = None - tokens = None # The rest of the tokens - close_lines = False - - def __init__(self, filename, template=None): - self.filename = os.path.abspath(filename) - if template is None: - with open(filename) as f: - self.template = f.read() - else: - self.template = template - self.line_starts = get_line_starts(self.template) - self.tokens = self.token_generator(tokenize_template(self.template)) - self.next_token() - - def pos_to_line(self, pos): - return bisect(self.line_starts, pos) - 1 - - def token_generator(self, base_tokens): - r"""Given an iterator over (kind, text, match) triples (see - tokenize_template above), return a refined iterator over - token_kinds. - - Among other adjustments to the elements found by base_tokens, - this refined iterator tokenizes python code embedded in - template text to help determine its true extent. The - expression "base_tokens.send(pos)" is used to reset the index at - which base_tokens resumes scanning the underlying text. - - >>> ctx = ParseContext('dummy', ''' - ... %for x in y: - ... % print x - ... % end - ... literally - ... ''') - >>> while ctx.token_kind: - ... print (ctx.token_kind, ctx.code_text or ctx.token_text) - ... ignored = ctx.next_token() - ('literal', '\n') - ('gybLinesOpen', 'for x in y:\n') - ('gybLines', ' print x\n') - ('gybLinesClose', '% end') - ('literal', 'literally\n') - - >>> ctx = ParseContext('dummy', - ... '''Nothing - ... % if x: - ... % for i in range(3): - ... ${i} - ... % end - ... % else: - ... THIS SHOULD NOT APPEAR IN THE OUTPUT - ... ''') - >>> while ctx.token_kind: - ... print (ctx.token_kind, ctx.code_text or ctx.token_text) - ... ignored = ctx.next_token() - ('literal', 'Nothing\n') - ('gybLinesOpen', 'if x:\n') - ('gybLinesOpen', ' for i in range(3):\n') - ('substitutionOpen', 'i') - ('literal', '\n') - ('gybLinesClose', '% end') - ('gybLinesOpen', 'else:\n') - ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n') - - >>> ctx = ParseContext('dummy', - ... '''% for x in [1, 2, 3]: - ... % if x == 1: - ... literal1 - ... % elif x > 1: # add an output line after this line to fix bug - ... % if x == 2: - ... literal2 - ... % end - ... % end - ... % end - ... ''') - >>> while ctx.token_kind: - ... print (ctx.token_kind, ctx.code_text or ctx.token_text) - ... ignored = ctx.next_token() - ('gybLinesOpen', 'for x in [1, 2, 3]:\n') - ('gybLinesOpen', ' if x == 1:\n') - ('literal', 'literal1\n') - ('gybLinesOpen', 'elif x > 1: # add output line here to fix bug\n') - ('gybLinesOpen', ' if x == 2:\n') - ('literal', 'literal2\n') - ('gybLinesClose', '% end') - ('gybLinesClose', '% end') - ('gybLinesClose', '% end') - """ - for self.token_kind, self.token_text, self.token_match in base_tokens: - kind = self.token_kind - self.code_text = None - - # Do we need to close the current lines? - self.close_lines = kind == 'gybLinesClose' - - # %{...}% and ${...} constructs - if kind.endswith('Open'): - - # Tokenize text that follows as Python up to an unmatched '}' - code_start = self.token_match.end(kind) - self.code_start_line = self.pos_to_line(code_start) - - close_pos = tokenize_python_to_unmatched_close_curly( - self.template, code_start, self.line_starts) - self.code_text = self.template[code_start:close_pos] - yield kind - - if (kind == 'gybBlockOpen'): - # Absorb any '}% \n' - m2 = gyb_block_close.match(self.template, close_pos) - if not m2: - raise ValueError("Invalid block closure") - next_pos = m2.end(0) - else: - assert kind == 'substitutionOpen' - # skip past the closing '}' - next_pos = close_pos + 1 - - # Resume tokenizing after the end of the code. - base_tokens.send(next_pos) - - elif kind == 'gybLines': - - self.code_start_line = self.pos_to_line( - self.token_match.start('gybLines')) - indentation = self.token_match.group('_indent') - - # Strip off the leading indentation and %-sign - source_lines = re.split( - '^' + re.escape(indentation), - self.token_match.group('gybLines') + '\n', - flags=re.MULTILINE)[1:] - - if code_starts_with_dedent_keyword(source_lines): - self.close_lines = True - - last_split = 0 - for line in split_gyb_lines(source_lines): - self.token_kind = 'gybLinesOpen' - self.code_text = ''.join(source_lines[last_split:line]) - yield self.token_kind - last_split = line - self.code_start_line += line - last_split - self.close_lines = False - - self.code_text = ''.join(source_lines[last_split:]) - if self.code_text: - self.token_kind = 'gybLines' - yield self.token_kind - else: - yield self.token_kind - - def next_token(self): - """Move to the next token""" - for kind in self.tokens: - return self.token_kind - - self.token_kind = None - - -class ExecutionContext(object): - """State we pass around during execution of a template""" - - def __init__(self, line_directive='// ###sourceLocation', - **local_bindings): - self.local_bindings = local_bindings - self.line_directive = line_directive - self.local_bindings['__context__'] = self - self.result_text = [] - self.last_file_line = None - - def append_text(self, text, file, line): - # see if we need to inject a line marker - if self.line_directive: - if (file, line) != self.last_file_line: - # We can only insert the line directive at a line break - if len(self.result_text) == 0 \ - or self.result_text[-1].endswith('\n'): - self.result_text.append('%s(file: "%s", line: %d)\n' % ( - self.line_directive, file, line + 1)) - # But if the new text contains any line breaks, we can create - # one - elif '\n' in text: - i = text.find('\n') - self.result_text.append(text[:i + 1]) - self.last_file_line = ( - self.last_file_line[0], self.last_file_line[1] + 1) - # and try again - self.append_text(text[i + 1:], file, line) - return - - self.result_text.append(text) - self.last_file_line = (file, line + text.count('\n')) - - -class ASTNode(object): - """Abstract base class for template AST nodes""" - - def __init__(self): - raise NotImplementedError("ASTNode.__init__ is not implemented.") - - def execute(self, context): - raise NotImplementedError("ASTNode.execute is not implemented.") - - def __str__(self, indent=''): - raise NotImplementedError("ASTNode.__str__ is not implemented.") - - def format_children(self, indent): - if not self.children: - return ' []' - - return '\n'.join( - ['', indent + '['] + - [x.__str__(indent + 4 * ' ') for x in self.children] + - [indent + ']']) - - -class Block(ASTNode): - """A sequence of other AST nodes, to be executed in order""" - - children = [] - - def __init__(self, context): - self.children = [] - - while context.token_kind and not context.close_lines: - if context.token_kind == 'literal': - node = Literal - else: - node = Code - self.children.append(node(context)) - - def execute(self, context): - for x in self.children: - x.execute(context) - - def __str__(self, indent=''): - return indent + 'Block:' + self.format_children(indent) - - -class Literal(ASTNode): - """An AST node that generates literal text""" - - def __init__(self, context): - self.text = context.token_text - start_position = context.token_match.start(context.token_kind) - self.start_line_number = context.pos_to_line(start_position) - self.filename = context.filename - context.next_token() - - def execute(self, context): - context.append_text(self.text, self.filename, self.start_line_number) - - def __str__(self, indent=''): - return '\n'.join( - [indent + x for x in ['Literal:'] + - strip_trailing_nl(self.text).split('\n')]) - - -class Code(ASTNode): - """An AST node that is evaluated as Python""" - - code = None - children = () - kind = None - - def __init__(self, context): - - source = '' - source_line_count = 0 - - def accumulate_code(): - s = source + (context.code_start_line - source_line_count) * '\n' \ - + textwrap.dedent(context.code_text) - line_count = context.code_start_line + \ - context.code_text.count('\n') - context.next_token() - return s, line_count - - eval_exec = 'exec' - if context.token_kind.startswith('substitution'): - eval_exec = 'eval' - source, source_line_count = accumulate_code() - source = '(' + source.strip() + ')' - - else: - while context.token_kind == 'gybLinesOpen': - source, source_line_count = accumulate_code() - source += ' __children__[%d].execute(__context__)\n' % len( - self.children) - source_line_count += 1 - - self.children += (Block(context),) - - if context.token_kind == 'gybLinesClose': - context.next_token() - - if context.token_kind == 'gybLines': - source, source_line_count = accumulate_code() - - # Only handle a substitution as part of this code block if - # we don't already have some %-lines. - elif context.token_kind == 'gybBlockOpen': - - # Opening ${...} and %{...}% constructs - source, source_line_count = accumulate_code() - - self.filename = context.filename - self.start_line_number = context.code_start_line - self.code = compile(source, context.filename, eval_exec) - self.source = source - - def execute(self, context): - # Save __children__ from the local bindings - save_children = context.local_bindings.get('__children__') - # Execute the code with our __children__ in scope - context.local_bindings['__children__'] = self.children - result = eval(self.code, context.local_bindings) - - if context.local_bindings['__children__'] is not self.children: - raise ValueError("The code is not allowed to mutate __children__") - # Restore the bindings - context.local_bindings['__children__'] = save_children - - # If we got a result, the code was an expression, so append - # its value - if result is not None and result != '': - context.append_text( - str(result), self.filename, self.start_line_number) - - def __str__(self, indent=''): - source_lines = re.sub(r'^\n', '', strip_trailing_nl( - self.source), flags=re.MULTILINE).split('\n') - if len(source_lines) == 1: - s = indent + 'Code: {' + source_lines[0] + '}' - else: - s = indent + 'Code:\n' + indent + '{\n' + '\n'.join( - indent + 4 * ' ' + l for l in source_lines - ) + '\n' + indent + '}' - return s + self.format_children(indent) - - -def parse_template(filename, text=None): - r"""Return an AST corresponding to the given template file. - - If text is supplied, it is assumed to be the contents of the file, - as a string. - - >>> print parse_template('dummy.file', text= - ... '''% for x in [1, 2, 3]: - ... % if x == 1: - ... literal1 - ... % elif x > 1: # add an output line after this line to fix the bug - ... % if x == 2: - ... literal2 - ... % end - ... % end - ... % end - ... ''') - Block: - [ - Code: - { - for x in [1, 2, 3]: - __children__[0].execute(__context__) - } - [ - Block: - [ - Code: - { - if x == 1: - __children__[0].execute(__context__) - elif x > 1: # add output line after this line to fix bug - __children__[1].execute(__context__) - } - [ - Block: - [ - Literal: - literal1 - ] - Block: - [ - Code: - { - if x == 2: - __children__[0].execute(__context__) - } - [ - Block: - [ - Literal: - literal2 - ] - ] - ] - ] - ] - ] - ] - - >>> print parse_template( - >>> 'dummy.file', text='%for x in range(10):\n% print x\n%end\njuicebox') - Block: - [ - Code: - { - for x in range(10): - __children__[0].execute(__context__) - } - [ - Block: - [ - Code: {print x} [] - ] - ] - Literal: - juicebox - ] - - >>> print parse_template('/dummy.file', text= - ... '''Nothing - ... % if x: - ... % for i in range(3): - ... ${i} - ... % end - ... % else: - ... THIS SHOULD NOT APPEAR IN THE OUTPUT - ... ''') - Block: - [ - Literal: - Nothing - Code: - { - if x: - __children__[0].execute(__context__) - else: - __children__[1].execute(__context__) - } - [ - Block: - [ - Code: - { - for i in range(3): - __children__[0].execute(__context__) - } - [ - Block: - [ - Code: {(i)} [] - Literal: - - ] - ] - ] - Block: - [ - Literal: - THIS SHOULD NOT APPEAR IN THE OUTPUT - ] - ] - ] - - >>> print parse_template('dummy.file', text='''% - ... %for x in y: - ... % print y - ... ''') - Block: - [ - Code: - { - for x in y: - __children__[0].execute(__context__) - } - [ - Block: - [ - Code: {print y} [] - ] - ] - ] - - >>> print parse_template('dummy.file', text='''% - ... %if x: - ... % print y - ... AAAA - ... %else: - ... BBBB - ... ''') - Block: - [ - Code: - { - if x: - __children__[0].execute(__context__) - else: - __children__[1].execute(__context__) - } - [ - Block: - [ - Code: {print y} [] - Literal: - AAAA - ] - Block: - [ - Literal: - BBBB - ] - ] - ] - - >>> print parse_template('dummy.file', text='''% - ... %if x: - ... % print y - ... AAAA - ... %# This is a comment - ... %else: - ... BBBB - ... ''') - Block: - [ - Code: - { - if x: - __children__[0].execute(__context__) - # This is a comment - else: - __children__[1].execute(__context__) - } - [ - Block: - [ - Code: {print y} [] - Literal: - AAAA - ] - Block: - [ - Literal: - BBBB - ] - ] - ] - - >>> print parse_template('dummy.file', text='''\ - ... %for x in y: - ... AAAA - ... %if x: - ... BBBB - ... %end - ... CCCC - ... ''') - Block: - [ - Code: - { - for x in y: - __children__[0].execute(__context__) - } - [ - Block: - [ - Literal: - AAAA - Code: - { - if x: - __children__[0].execute(__context__) - } - [ - Block: - [ - Literal: - BBBB - ] - ] - Literal: - CCCC - ] - ] - ] - """ - return Block(ParseContext(filename, text)) - - -def execute_template(ast, line_directive='', **local_bindings): - r"""Return the text generated by executing the given template AST. - - Keyword arguments become local variable bindings in the execution context - - >>> ast = parse_template('/dummy.file', text= - ... '''Nothing - ... % if x: - ... % for i in range(3): - ... ${i} - ... % end - ... % else: - ... THIS SHOULD NOT APPEAR IN THE OUTPUT - ... ''') - >>> print execute_template(ast, line_directive='//#sourceLocation', x=1), - //#sourceLocation(file: "/dummy.file", line: 1) - Nothing - //#sourceLocation(file: "/dummy.file", line: 4) - 0 - //#sourceLocation(file: "/dummy.file", line: 4) - 1 - //#sourceLocation(file: "/dummy.file", line: 4) - 2 - - >>> ast = parse_template('/dummy.file', text= - ... '''Nothing - ... % a = [] - ... % for x in range(3): - ... % a.append(x) - ... % end - ... ${a} - ... ''') - >>> print execute_template(ast, line_directive='//#sourceLocation', x=1), - //#sourceLocation(file: "/dummy.file", line: 1) - Nothing - //#sourceLocation(file: "/dummy.file", line: 6) - [0, 1, 2] - """ - execution_context = ExecutionContext( - line_directive=line_directive, **local_bindings) - ast.execute(execution_context) - return ''.join(execution_context.result_text) - - -def main(): - import argparse - import sys - - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description='Generate Your Boilerplate!', epilog=''' - A GYB template consists of the following elements: - - - Literal text which is inserted directly into the output - - - %% or $$ in literal text, which insert literal '%' and '$' - symbols respectively. - - - Substitutions of the form ${}. The Python - expression is converted to a string and the result is inserted - into the output. - - - Python code delimited by %{...}%. Typically used to inject - definitions (functions, classes, variable bindings) into the - evaluation context of the template. Common indentation is - stripped, so you can add as much indentation to the beginning - of this code as you like - - - Lines beginning with optional whitespace followed by a single - '%' and Python code. %-lines allow you to nest other - constructs inside them. To close a level of nesting, use the - "%end" construct. - - - Lines beginning with optional whitespace and followed by a - single '%' and the token "end", which close open constructs in - %-lines. - - Example template: - - - Hello - - %{ - x = 42 - def succ(a): - return a+1 - }% - - I can assure you that ${x} < ${succ(x)} - - % if int(y) > 7: - % for i in range(3): - y is greater than seven! - % end - % else: - y is less than or equal to seven - % end - - - The End. - - - When run with "gyb -Dy=9", the output is - - - Hello - - - I can assure you that 42 < 43 - - y is greater than seven! - y is greater than seven! - y is greater than seven! - - - The End. - -''' - ) - parser.add_argument( - '-D', action='http://github.com/append', dest='defines', metavar='NAME=VALUE', - default=[], - help='''Bindings to be set in the template's execution context''') - - parser.add_argument( - 'file', type=argparse.FileType(), - help='Path to GYB template file (defaults to stdin)', nargs='?', - default=sys.stdin) - parser.add_argument( - '-o', dest='target', type=argparse.FileType('w'), - help='Output file (defaults to stdout)', default=sys.stdout) - parser.add_argument( - '--test', action='http://github.com/store_true', - default=False, help='Run a self-test') - parser.add_argument( - '--verbose-test', action='http://github.com/store_true', - default=False, help='Run a verbose self-test') - parser.add_argument( - '--dump', action='http://github.com/store_true', - default=False, help='Dump the parsed template to stdout') - parser.add_argument( - '--line-directive', default='// ###sourceLocation', - help='Line directive prefix; empty => no line markers') - - args = parser.parse_args(sys.argv[1:]) - - if args.test or args.verbose_test: - import doctest - if doctest.testmod(verbose=args.verbose_test).failed: - sys.exit(1) - - bindings = dict(x.split('=', 1) for x in args.defines) - ast = parse_template(args.file.name, args.file.read()) - if args.dump: - print(ast) - # Allow the template to import .py files from its own directory - sys.path = [os.path.split(args.file.name)[0] or '.'] + sys.path - - args.target.write(execute_template(ast, args.line_directive, **bindings)) - -if __name__ == '__main__': - main() From a90a39f5f4fd8db5b2d70c71c0bd0fe05a89ffed Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Tue, 20 Sep 2016 13:01:43 -0700 Subject: [PATCH 364/460] Clean out unneeded gitignore entries. --- .gitignore | 7 - SwiftCheck.xcodeproj/project.pbxproj.orig | 1262 --------------------- 2 files changed, 1269 deletions(-) delete mode 100644 SwiftCheck.xcodeproj/project.pbxproj.orig diff --git a/.gitignore b/.gitignore index 4bb4329..70f99d1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,10 +23,3 @@ DerivedData Carthage/Build Carthage/Checkouts build/ - -# Python bytecode -*.pyc - -# Generated Files -Sources/Generated\ Files/ - diff --git a/SwiftCheck.xcodeproj/project.pbxproj.orig b/SwiftCheck.xcodeproj/project.pbxproj.orig deleted file mode 100644 index cbf0ec7..0000000 --- a/SwiftCheck.xcodeproj/project.pbxproj.orig +++ /dev/null @@ -1,1262 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; - 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; - 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; - 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; - 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D81601C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D81611C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81621C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81631C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81671C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D81681C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D81691C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D816A1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816B1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816C1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D81701C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81711C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81721C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81731C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81741C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81751C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81761C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81771C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81781C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81791C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817A1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817B1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817C1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817D1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817E1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817F1C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81801C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81811C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81821C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81831C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81841C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81851C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81861C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81871C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81881C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D81891C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D818A1C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; - 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; - FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; - FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 8240CCBC1C3A123700EF4D29 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 844FCC84198B320500EB242A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 8240CCB01C3A123600EF4D29; - remoteInfo = "SwiftCheck-tvOS"; - }; - 844FCC9A198B320500EB242A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 844FCC84198B320500EB242A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 844FCC8C198B320500EB242A; - remoteInfo = SwiftCheck; - }; - 84DF76041B0BD54600C912B0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 844FCC84198B320500EB242A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 84DF75F71B0BD54600C912B0; - remoteInfo = "SwiftCheck-iOS"; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 8240CCDA1C3A126100EF4D29 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 841408BA1B1A859B00BA2B6C /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 825C9AC81D8EE445003313E1 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = SOURCE_ROOT; }; - 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/SwiftCheckTests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/SwiftCheckTests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/SwiftCheckTests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/SwiftCheckTests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD41D8EE86E003313E1 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/SwiftCheckTests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/SwiftCheckTests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD71D8EE86E003313E1 /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/SwiftCheckTests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/SwiftCheckTests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/SwiftCheckTests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/SwiftCheckTests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/SwiftCheckTests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/SwiftCheckTests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; - 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; - 826D814B1C953D070022266C /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lattice.swift; path = Sources/Lattice.swift; sourceTree = SOURCE_ROOT; }; - 826D814C1C953D070022266C /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = Sources/Modifiers.swift; sourceTree = SOURCE_ROOT; }; - 826D814E1C953D070022266C /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = SOURCE_ROOT; }; - 826D814F1C953D070022266C /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Random.swift; path = Sources/Random.swift; sourceTree = SOURCE_ROOT; }; - 826D81501C953D070022266C /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Rose.swift; path = Sources/Rose.swift; sourceTree = SOURCE_ROOT; }; - 826D81511C953D070022266C /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = State.swift; path = Sources/State.swift; sourceTree = SOURCE_ROOT; }; - 826D81521C953D070022266C /* SwiftCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = Sources/SwiftCheck.h; sourceTree = SOURCE_ROOT; }; - 826D81531C953D070022266C /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Test.swift; path = Sources/Test.swift; sourceTree = SOURCE_ROOT; }; - 826D81541C953D070022266C /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Testable.swift; path = Sources/Testable.swift; sourceTree = SOURCE_ROOT; }; - 826D81551C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; - 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; - 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; - 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; - 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; - FAAB9E7A1D91B96C0097AC78 /* compile.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = compile.sh; sourceTree = ""; }; - FAAB9E881D91C28F0097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = Sources/Cartesian.swift; sourceTree = SOURCE_ROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 8240CCAD1C3A123600EF4D29 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 8240CCB71C3A123700EF4D29 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC89198B320500EB242A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC95198B320500EB242A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75F41B0BD54600C912B0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75FF1B0BD54600C912B0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 844FCC83198B320500EB242A = { - isa = PBXGroup; - children = ( - 826D81521C953D070022266C /* SwiftCheck.h */, - 844FCC8F198B320500EB242A /* SwiftCheck */, - 844FCC9C198B320500EB242A /* SwiftCheckTests */, - FAAB9E781D91B96C0097AC78 /* Templates */, - 844FCC8E198B320500EB242A /* Products */, - ); - sourceTree = ""; - }; - 844FCC8E198B320500EB242A /* Products */ = { - isa = PBXGroup; - children = ( - 844FCC8D198B320500EB242A /* SwiftCheck.framework */, - 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */, - 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */, - 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */, - 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */, - 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 844FCC8F198B320500EB242A /* SwiftCheck */ = { - isa = PBXGroup; - children = ( - 826D81461C953D070022266C /* Arbitrary.swift */, -<<<<<<< HEAD - FAAB9E881D91C28F0097AC78 /* Cartesian.swift */, -======= ->>>>>>> master - 826D81551C953D070022266C /* Check.swift */, - 826D81481C953D070022266C /* CoArbitrary.swift */, - 82BA08CE1D6FFBD20068D32F /* Compose.swift */, - 826D81491C953D070022266C /* Gen.swift */, - 826D814B1C953D070022266C /* Lattice.swift */, - 826D814C1C953D070022266C /* Modifiers.swift */, - 826D814E1C953D070022266C /* Property.swift */, - 826D814F1C953D070022266C /* Random.swift */, - 826D81501C953D070022266C /* Rose.swift */, - 826D81511C953D070022266C /* State.swift */, - 826D81531C953D070022266C /* Test.swift */, - 826D81541C953D070022266C /* Testable.swift */, - 826D81561C953D070022266C /* Witness.swift */, - 826D81571C953D070022266C /* WitnessedArbitrary.swift */, - 844FCC90198B320500EB242A /* Supporting Files */, - ); - path = SwiftCheck; - sourceTree = ""; - }; - 844FCC90198B320500EB242A /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 826D814A1C953D070022266C /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { - isa = PBXGroup; - children = ( - 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, - 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, - 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, - 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, - 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, - 825C9AD41D8EE86E003313E1 /* GenSpec.swift */, - 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */, - 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, - 825C9AD71D8EE86E003313E1 /* PathSpec.swift */, - 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */, - 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */, - 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */, - 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */, - 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */, - 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */, - 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */, - 844FCC9D198B320500EB242A /* Supporting Files */, - ); - path = SwiftCheckTests; - sourceTree = ""; - }; - 844FCC9D198B320500EB242A /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 826D81C61C953D350022266C /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - FAAB9E781D91B96C0097AC78 /* Templates */ = { - isa = PBXGroup; - children = ( - FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */, - FAAB9E7A1D91B96C0097AC78 /* compile.sh */, - ); - path = Templates; - sourceTree = SOURCE_ROOT; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 8240CCAE1C3A123600EF4D29 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D817E1C953D070022266C /* SwiftCheck.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC8A198B320500EB242A /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D817C1C953D070022266C /* SwiftCheck.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75F51B0BD54600C912B0 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D817D1C953D070022266C /* SwiftCheck.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 8240CCC61C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOS" */; - buildPhases = ( - 8240CCAC1C3A123600EF4D29 /* Sources */, - 8240CCAD1C3A123600EF4D29 /* Frameworks */, - 8240CCAE1C3A123600EF4D29 /* Headers */, - 8240CCAF1C3A123600EF4D29 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SwiftCheck-tvOS"; - productName = "SwiftCheck-tvOS"; - productReference = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; - productType = "com.apple.product-type.framework"; - }; - 8240CCB91C3A123700EF4D29 /* SwiftCheck-tvOSTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 8240CCC71C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOSTests" */; - buildPhases = ( - 8240CCB61C3A123700EF4D29 /* Sources */, - 8240CCB71C3A123700EF4D29 /* Frameworks */, - 8240CCB81C3A123700EF4D29 /* Resources */, - 8240CCDA1C3A126100EF4D29 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - 8240CCBD1C3A123700EF4D29 /* PBXTargetDependency */, - ); - name = "SwiftCheck-tvOSTests"; - productName = "SwiftCheck-tvOSTests"; - productReference = 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 844FCC8C198B320500EB242A /* SwiftCheck */ = { - isa = PBXNativeTarget; - buildConfigurationList = 844FCCA3198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheck" */; - buildPhases = ( - FA7865811CE57F430077CD7C /* ShellScript */, - 844FCC88198B320500EB242A /* Sources */, - 844FCC89198B320500EB242A /* Frameworks */, - 844FCC8A198B320500EB242A /* Headers */, - 844FCC8B198B320500EB242A /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SwiftCheck; - productName = SwiftCheck; - productReference = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; - productType = "com.apple.product-type.framework"; - }; - 844FCC97198B320500EB242A /* SwiftCheckTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 844FCCA6198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheckTests" */; - buildPhases = ( - 844FCC94198B320500EB242A /* Sources */, - 844FCC95198B320500EB242A /* Frameworks */, - 844FCC96198B320500EB242A /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 844FCC9B198B320500EB242A /* PBXTargetDependency */, - ); - name = SwiftCheckTests; - productName = SwiftCheckTests; - productReference = 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 84DF75F71B0BD54600C912B0 /* SwiftCheck-iOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 84DF760B1B0BD54600C912B0 /* Build configuration list for PBXNativeTarget "SwiftCheck-iOS" */; - buildPhases = ( - 84DF75F31B0BD54600C912B0 /* Sources */, - 84DF75F41B0BD54600C912B0 /* Frameworks */, - 84DF75F51B0BD54600C912B0 /* Headers */, - 84DF75F61B0BD54600C912B0 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "SwiftCheck-iOS"; - productName = "SwiftCheck-iOS"; - productReference = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; - productType = "com.apple.product-type.framework"; - }; - 84DF76011B0BD54600C912B0 /* SwiftCheck-iOSTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 84DF760E1B0BD54600C912B0 /* Build configuration list for PBXNativeTarget "SwiftCheck-iOSTests" */; - buildPhases = ( - 84DF75FE1B0BD54600C912B0 /* Sources */, - 84DF75FF1B0BD54600C912B0 /* Frameworks */, - 84DF76001B0BD54600C912B0 /* Resources */, - 841408BA1B1A859B00BA2B6C /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - 84DF76051B0BD54600C912B0 /* PBXTargetDependency */, - ); - name = "SwiftCheck-iOSTests"; - productName = "SwiftCheck-iOSTests"; - productReference = 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 844FCC84198B320500EB242A /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; - ORGANIZATIONNAME = Typelift; - TargetAttributes = { - 8240CCB01C3A123600EF4D29 = { - CreatedOnToolsVersion = 7.2; - }; - 8240CCB91C3A123700EF4D29 = { - CreatedOnToolsVersion = 7.2; - }; - 844FCC8C198B320500EB242A = { - CreatedOnToolsVersion = 6.0; - LastSwiftMigration = 0800; - }; - 844FCC97198B320500EB242A = { - CreatedOnToolsVersion = 6.0; - LastSwiftMigration = 0800; - TestTargetID = 844FCC8C198B320500EB242A; - }; - 84DF75F71B0BD54600C912B0 = { - CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; - }; - 84DF76011B0BD54600C912B0 = { - CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; - }; - }; - }; - buildConfigurationList = 844FCC87198B320500EB242A /* Build configuration list for PBXProject "SwiftCheck" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 844FCC83198B320500EB242A; - productRefGroup = 844FCC8E198B320500EB242A /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 844FCC8C198B320500EB242A /* SwiftCheck */, - 844FCC97198B320500EB242A /* SwiftCheckTests */, - 84DF75F71B0BD54600C912B0 /* SwiftCheck-iOS */, - 84DF76011B0BD54600C912B0 /* SwiftCheck-iOSTests */, - 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */, - 8240CCB91C3A123700EF4D29 /* SwiftCheck-tvOSTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 8240CCAF1C3A123600EF4D29 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 8240CCB81C3A123700EF4D29 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC8B198B320500EB242A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC96198B320500EB242A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75F61B0BD54600C912B0 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF76001B0BD54600C912B0 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - FA7865811CE57F430077CD7C /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "pushd Templates\n./compile.sh\npopd\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 8240CCAC1C3A123600EF4D29 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D81721C953D070022266C /* Property.swift in Sources */, - 826D81691C953D070022266C /* Lattice.swift in Sources */, - 826D81751C953D070022266C /* Random.swift in Sources */, - 826D81841C953D070022266C /* Testable.swift in Sources */, -<<<<<<< HEAD - FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */, -======= ->>>>>>> master - 826D818A1C953D070022266C /* Witness.swift in Sources */, - 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, - 826D816C1C953D070022266C /* Modifiers.swift in Sources */, - 826D81811C953D070022266C /* Test.swift in Sources */, - 826D81871C953D070022266C /* Check.swift in Sources */, - 826D81781C953D070022266C /* Rose.swift in Sources */, - 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81631C953D070022266C /* Gen.swift in Sources */, - 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */, - 826D817B1C953D070022266C /* State.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 8240CCB61C3A123700EF4D29 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, - 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC88198B320500EB242A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D81701C953D070022266C /* Property.swift in Sources */, - 826D81671C953D070022266C /* Lattice.swift in Sources */, - 826D81731C953D070022266C /* Random.swift in Sources */, - 826D81821C953D070022266C /* Testable.swift in Sources */, -<<<<<<< HEAD - FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */, -======= ->>>>>>> master - 826D81881C953D070022266C /* Witness.swift in Sources */, - 826D81581C953D070022266C /* Arbitrary.swift in Sources */, - 826D816A1C953D070022266C /* Modifiers.swift in Sources */, - 826D817F1C953D070022266C /* Test.swift in Sources */, - 826D81851C953D070022266C /* Check.swift in Sources */, - 826D81761C953D070022266C /* Rose.swift in Sources */, - 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81611C953D070022266C /* Gen.swift in Sources */, - 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */, - 826D81791C953D070022266C /* State.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 844FCC94198B320500EB242A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, - 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75F31B0BD54600C912B0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 826D81711C953D070022266C /* Property.swift in Sources */, - 826D81681C953D070022266C /* Lattice.swift in Sources */, - 826D81741C953D070022266C /* Random.swift in Sources */, - 826D81831C953D070022266C /* Testable.swift in Sources */, -<<<<<<< HEAD - FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */, -======= ->>>>>>> master - 826D81891C953D070022266C /* Witness.swift in Sources */, - 826D81591C953D070022266C /* Arbitrary.swift in Sources */, - 826D816B1C953D070022266C /* Modifiers.swift in Sources */, - 826D81801C953D070022266C /* Test.swift in Sources */, - 826D81861C953D070022266C /* Check.swift in Sources */, - 826D81771C953D070022266C /* Rose.swift in Sources */, - 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81621C953D070022266C /* Gen.swift in Sources */, - 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */, - 826D817A1C953D070022266C /* State.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 84DF75FE1B0BD54600C912B0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, - 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 8240CCBD1C3A123700EF4D29 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 8240CCB01C3A123600EF4D29 /* SwiftCheck-tvOS */; - targetProxy = 8240CCBC1C3A123700EF4D29 /* PBXContainerItemProxy */; - }; - 844FCC9B198B320500EB242A /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 844FCC8C198B320500EB242A /* SwiftCheck */; - targetProxy = 844FCC9A198B320500EB242A /* PBXContainerItemProxy */; - }; - 84DF76051B0BD54600C912B0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 84DF75F71B0BD54600C912B0 /* SwiftCheck-iOS */; - targetProxy = 84DF76041B0BD54600C912B0 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 8240CCC21C3A123700EF4D29 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; - DEBUG_INFORMATION_FORMAT = dwarf; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; - PRODUCT_NAME = SwiftCheck; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 8240CCC31C3A123700EF4D29 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; - COPY_PHASE_STRIP = NO; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; - PRODUCT_NAME = SwiftCheck; - SDKROOT = appletvos; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; - VALIDATE_PRODUCT = YES; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 8240CCC41C3A123700EF4D29 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - }; - name = Debug; - }; - 8240CCC51C3A123700EF4D29 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - COPY_PHASE_STRIP = NO; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = appletvos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 844FCCA1198B320500EB242A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 844FCCA2198B320500EB242A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 844FCCA4198B320500EB242A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_DEBUG_INFORMATION_LEVEL = default; - CLANG_ENABLE_MODULES = YES; - COMBINE_HIDPI_IMAGES = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - OTHER_LDFLAGS = ( - "-framework", - XCTest, - ); - OTHER_SWIFT_FLAGS = ""; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - 844FCCA5198B320500EB242A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_DEBUG_INFORMATION_LEVEL = default; - CLANG_ENABLE_MODULES = YES; - COMBINE_HIDPI_IMAGES = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - OTHER_LDFLAGS = ( - "-framework", - XCTest, - ); - OTHER_SWIFT_FLAGS = ""; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - }; - name = Release; - }; - 844FCCA7198B320500EB242A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - 844FCCA8198B320500EB242A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - COMBINE_HIDPI_IMAGES = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - GCC_OPTIMIZATION_LEVEL = s; - INFOPLIST_FILE = Tests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - }; - name = Release; - }; - 84DF760C1B0BD54600C912B0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = ""; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = SwiftCheck; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 9.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 84DF760D1B0BD54600C912B0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(PLATFORM_DIR)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Sources/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = ""; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = SwiftCheck; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 9.0; - VALIDATE_PRODUCT = YES; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 84DF760F1B0BD54600C912B0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; - }; - name = Debug; - }; - 84DF76101B0BD54600C912B0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = Tests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 8240CCC61C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8240CCC21C3A123700EF4D29 /* Debug */, - 8240CCC31C3A123700EF4D29 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 8240CCC71C3A123700EF4D29 /* Build configuration list for PBXNativeTarget "SwiftCheck-tvOSTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8240CCC41C3A123700EF4D29 /* Debug */, - 8240CCC51C3A123700EF4D29 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 844FCC87198B320500EB242A /* Build configuration list for PBXProject "SwiftCheck" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 844FCCA1198B320500EB242A /* Debug */, - 844FCCA2198B320500EB242A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 844FCCA3198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheck" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 844FCCA4198B320500EB242A /* Debug */, - 844FCCA5198B320500EB242A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 844FCCA6198B320500EB242A /* Build configuration list for PBXNativeTarget "SwiftCheckTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 844FCCA7198B320500EB242A /* Debug */, - 844FCCA8198B320500EB242A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 84DF760B1B0BD54600C912B0 /* Build configuration list for PBXNativeTarget "SwiftCheck-iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 84DF760C1B0BD54600C912B0 /* Debug */, - 84DF760D1B0BD54600C912B0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 84DF760E1B0BD54600C912B0 /* Build configuration list for PBXNativeTarget "SwiftCheck-iOSTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 84DF760F1B0BD54600C912B0 /* Debug */, - 84DF76101B0BD54600C912B0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 844FCC84198B320500EB242A /* Project object */; -} From 26b67da314290724e5eb89be19e892571673fad3 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Wed, 21 Sep 2016 10:52:40 -0700 Subject: [PATCH 365/460] Move primitive Cartesian methods to main Gen file Moves primitive zip and map methods to Gen.swift. If any edits are made to zip and map based methods, most likely one will only have to edit the primitives. --- Sources/Cartesian.swift | 223 +++++++++++++++------------------- Sources/Gen.swift | 18 +++ Templates/Cartesian.swift.gyb | 33 +---- 3 files changed, 118 insertions(+), 156 deletions(-) diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift index 9675439..dbbece1 100644 --- a/Sources/Cartesian.swift +++ b/Sources/Cartesian.swift @@ -8,13 +8,6 @@ extension Gen /*: Cartesian*/ { - /// Zips together two generators and returns a generator of tuples. - public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { - return Gen<(A1, A2)> { r, n in - let (r1, r2) = r.split - return (ga1.unGen(r1, n), ga2.unGen(r2, n)) - } - } /// Zips together 3 generators generator of tuples. @@ -28,6 +21,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { + return zip(ga1, ga2, ga3).map(transform) + } /// Zips together 4 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { return Gen @@ -39,6 +37,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4).map(transform) + } /// Zips together 5 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { return Gen @@ -50,6 +53,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + } /// Zips together 6 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { return Gen @@ -61,6 +69,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + } /// Zips together 7 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { return Gen @@ -72,6 +85,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + } /// Zips together 8 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { return Gen @@ -83,6 +101,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + } /// Zips together 9 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { return Gen @@ -94,6 +117,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + } /// Zips together 10 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { return Gen @@ -105,6 +133,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + } /// Zips together 11 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { return Gen @@ -116,6 +149,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) + } /// Zips together 12 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { return Gen @@ -127,6 +165,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) + } /// Zips together 13 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { return Gen @@ -138,6 +181,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) + } /// Zips together 14 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { return Gen @@ -149,6 +197,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) + } /// Zips together 15 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { return Gen @@ -160,6 +213,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) + } /// Zips together 16 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { return Gen @@ -171,6 +229,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) + } /// Zips together 17 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { return Gen @@ -182,6 +245,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) + } /// Zips together 18 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { return Gen @@ -193,6 +261,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) + } /// Zips together 19 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { return Gen @@ -204,6 +277,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) + } /// Zips together 20 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { return Gen @@ -215,6 +293,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) + } /// Zips together 21 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { return Gen @@ -226,6 +309,11 @@ extension Gen /*: Cartesian*/ { } } + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) + } /// Zips together 22 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { return Gen @@ -237,127 +325,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } - - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) - } - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) - } - /// Returns a new generator that applies a given function to any outputs the /// two receivers create. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 63085e2..f227028 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -161,6 +161,24 @@ public struct Gen { } } +// MARK: Monoidal Functor methods. + +extension Gen { + /// Zips together two generators and returns a generator of tuples. + public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { + return Gen<(A1, A2)> { r, n in + let (r1, r2) = r.split + return (ga1.unGen(r1, n), ga2.unGen(r2, n)) + } + } + + /// Returns a new generator that applies a given function to any outputs the + /// two receivers create. + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { + return zip(ga1, ga2).map(transform) + } +} + // MARK: Generator Modifiers extension Gen { diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 1e0f883..7d16b1d 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -11,18 +11,10 @@ MAX_ARITY = 22 }% extension Gen /*: Cartesian*/ { - /// Zips together two generators and returns a generator of tuples. - public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { - return Gen<(A1, A2)> { r, n in - let (r1, r2) = r.split - return (ga1.unGen(r1, n), ga2.unGen(r2, n)) - } - } % for arity in range(3, MAX_ARITY + 1): %{ - -# Zip definition template +# Function definition template type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) @@ -31,6 +23,10 @@ previous_parameter_range = range(1, arity) previous_zip_arguments = ', '.join(['ga{0}'.format(n) for n in previous_parameter_range]) expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_parameter_range]) + + +# Map body template +map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) }% /// Zips together ${arity} generators generator of tuples. @@ -43,25 +39,6 @@ expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_pa (${expanded_previous_tuple}, $$1) } } -% end - - /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) - } - -% for arity in range(3, MAX_ARITY + 1): -%{ - -# Map definition template -type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) -parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) - -# Map body template -map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) - -}% /// Returns a new generator that applies a given function to any outputs the /// two receivers create. From 33df6afd203bfdcc30e2b4c12b0288a3b827d14e Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Wed, 21 Sep 2016 10:53:59 -0700 Subject: [PATCH 366/460] Make obvious that Cartesian.swift is a generated file Adds line directives to generated source to show where in the template the source is defined. Also adds documentation explaining the the source is generated. --- Sources/Cartesian.swift | 46 +++++++++++++++++++++++++++++++++++ Templates/Cartesian.swift.gyb | 4 +++ Templates/compile.sh | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift index dbbece1..224554b 100644 --- a/Sources/Cartesian.swift +++ b/Sources/Cartesian.swift @@ -1,3 +1,4 @@ +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 1) // // Cartesian.swift.gyb // SwiftCheck @@ -6,9 +7,15 @@ // Copyright © 2016 Typelift. All rights reserved. // +// This is a GYB generated file; any changes will be overwritten +// during the build phase. Edit the template instead, +// found in Templates/Cartesian.swift.gyb + +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 16) extension Gen /*: Cartesian*/ { +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 3 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> { @@ -26,6 +33,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { return zip(ga1, ga2, ga3).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 4 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { return Gen @@ -42,6 +51,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 5 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { return Gen @@ -58,6 +69,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 6 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { return Gen @@ -74,6 +87,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 7 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { return Gen @@ -90,6 +105,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 8 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { return Gen @@ -106,6 +123,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 9 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { return Gen @@ -122,6 +141,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 10 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { return Gen @@ -138,6 +159,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 11 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { return Gen @@ -154,6 +177,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 12 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { return Gen @@ -170,6 +195,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 13 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { return Gen @@ -186,6 +213,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 14 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { return Gen @@ -202,6 +231,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 15 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { return Gen @@ -218,6 +249,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 16 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { return Gen @@ -234,6 +267,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 17 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { return Gen @@ -250,6 +285,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 18 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { return Gen @@ -266,6 +303,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 19 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { return Gen @@ -282,6 +321,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 20 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { return Gen @@ -298,6 +339,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 21 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { return Gen @@ -314,6 +357,8 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) + /// Zips together 22 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { return Gen @@ -330,4 +375,5 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map(transform) } +// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 53) } diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 7d16b1d..8ef03a9 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -6,6 +6,10 @@ // Copyright © 2016 Typelift. All rights reserved. // +// This is a GYB generated file; any changes will be overwritten +// during the build phase. Edit the template instead, +// found in Templates/Cartesian.swift.gyb + %{ MAX_ARITY = 22 }% diff --git a/Templates/compile.sh b/Templates/compile.sh index 7e4a4c5..72df1ee 100755 --- a/Templates/compile.sh +++ b/Templates/compile.sh @@ -4,7 +4,7 @@ wget https://github.com/apple/swift/raw/master/utils/gyb wget https://github.com/apple/swift/raw/master/utils/gyb.py chmod +x gyb -./gyb --line-directive '' -o ../Sources/Cartesian.swift Cartesian.swift.gyb +./gyb -o ../Sources/Cartesian.swift Cartesian.swift.gyb rm gyb rm gyb.py From e4a28c53634641302cf7872f5ebcb2e09983bb16 Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Wed, 21 Sep 2016 11:51:38 -0700 Subject: [PATCH 367/460] Add generated tests for templated code. --- Sources/Cartesian.swift | 23 --- SwiftCheck.xcodeproj/project.pbxproj | 10 + Templates/CartesianSpec.swift.gyb | 54 ++++++ Templates/compile.sh | 3 +- Tests/SwiftCheckTests/CartesianSpec.swift | 224 ++++++++++++++++++++++ Tests/SwiftCheckTests/GenSpec.swift | 6 +- 6 files changed, 292 insertions(+), 28 deletions(-) create mode 100644 Templates/CartesianSpec.swift.gyb create mode 100644 Tests/SwiftCheckTests/CartesianSpec.swift diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift index 224554b..858c95c 100644 --- a/Sources/Cartesian.swift +++ b/Sources/Cartesian.swift @@ -1,4 +1,3 @@ -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 1) // // Cartesian.swift.gyb // SwiftCheck @@ -11,11 +10,9 @@ // during the build phase. Edit the template instead, // found in Templates/Cartesian.swift.gyb -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 16) extension Gen /*: Cartesian*/ { -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 3 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> { @@ -33,7 +30,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { return zip(ga1, ga2, ga3).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 4 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { @@ -51,7 +47,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 5 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { @@ -69,7 +64,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 6 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { @@ -87,7 +81,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 7 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { @@ -105,7 +98,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 8 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { @@ -123,7 +115,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 9 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { @@ -141,7 +132,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 10 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { @@ -159,7 +149,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 11 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { @@ -177,7 +166,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 12 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { @@ -195,7 +183,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 13 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { @@ -213,7 +200,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 14 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { @@ -231,7 +217,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 15 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { @@ -249,7 +234,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 16 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { @@ -267,7 +251,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 17 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { @@ -285,7 +268,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 18 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { @@ -303,7 +285,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 19 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { @@ -321,7 +302,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 20 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { @@ -339,7 +319,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 21 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { @@ -357,7 +336,6 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 35) /// Zips together 22 generators generator of tuples. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { @@ -375,5 +353,4 @@ extension Gen /*: Cartesian*/ { public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map(transform) } -// ###sourceLocation(file: "/Users/adamkuipers/development/SwiftCheck/Templates/Cartesian.swift.gyb", line: 53) } diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 778204c..06c0cf0 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -105,6 +105,9 @@ 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; + FA3C185B1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; + FA3C185C1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; + FA3C185D1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; @@ -198,6 +201,8 @@ 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CartesianSpec.swift.gyb; sourceTree = ""; }; + FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CartesianSpec.swift; path = Tests/SwiftCheckTests/CartesianSpec.swift; sourceTree = SOURCE_ROOT; }; FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; FAAB9E7A1D91B96C0097AC78 /* compile.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = compile.sh; sourceTree = ""; }; FAAB9E881D91C28F0097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = Sources/Cartesian.swift; sourceTree = SOURCE_ROOT; }; @@ -313,6 +318,7 @@ children = ( 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, + FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */, 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, @@ -344,6 +350,7 @@ isa = PBXGroup; children = ( FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */, + FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */, FAAB9E7A1D91B96C0097AC78 /* compile.sh */, ); path = Templates; @@ -639,6 +646,7 @@ 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + FA3C185D1D93056D003DEB10 /* CartesianSpec.swift in Sources */, 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */, 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */, 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, @@ -684,6 +692,7 @@ 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + FA3C185B1D93056D003DEB10 /* CartesianSpec.swift in Sources */, 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */, 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */, 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, @@ -729,6 +738,7 @@ 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, + FA3C185C1D93056D003DEB10 /* CartesianSpec.swift in Sources */, 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */, 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */, 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, diff --git a/Templates/CartesianSpec.swift.gyb b/Templates/CartesianSpec.swift.gyb new file mode 100644 index 0000000..0697ae1 --- /dev/null +++ b/Templates/CartesianSpec.swift.gyb @@ -0,0 +1,54 @@ +// +// CartesianSpec.swift +// SwiftCheck +// +// Created by Adam Kuipers on 9/21/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +// This is a GYB generated file; any changes will be overwritten +// during the build phase. Edit the template instead, +// found in Templates/CartesianSpec.swift.gyb + +%{ +MAX_ARITY = 22 +}% + +import SwiftCheck +import XCTest +import Foundation + +final class CartesianSpec : XCTestCase { + func testGeneratedZips() { +% for arity in range(3, MAX_ARITY + 1): +%{ +gen_type_argument_list = ', '.join(['Int' for _ in range(1, arity + 1)]) +zip_argument_list = ', '.join(['Gen.pure({0})'.format(n) for n in range(1, arity + 1)]) +tupled_parameters = ', '.join(['x{0}'.format(n) for n in range(1, arity + 1)]) +}% + + let g${arity} = Gen<(${gen_type_argument_list})>.zip(${zip_argument_list}) + + property("Gen.zip${arity} behaves") <- forAllNoShrink(g${arity}) { (tuple : (${gen_type_argument_list})) -> Bool in + tuple.0 == 1 && tuple.${arity - 1} == ${arity} + } +% end + } + + func testGeneratedMaps() { +% for arity in range(3, MAX_ARITY + 1): +%{ +gen_type_argument_list = ', '.join(['Int' for _ in range(1, arity + 1)]) +map_argument_list = ', '.join(['Gen.pure({0})'.format(n) for n in range(1, arity + 1)]) +tupled_parameters = ', '.join(['x{0}'.format(n) for n in range(1, arity + 1)]) +max_argument_list = ', '.join(['${0}'.format(n) for n in range(0, arity)]) +}% + + let g${arity} = Gen<(${gen_type_argument_list})>.map(${map_argument_list}) { max(${max_argument_list}) } + + property("Gen.zip${arity} behaves") <- forAllNoShrink(g${arity}) { maxInt in + maxInt == ${arity} + } +% end + } +} diff --git a/Templates/compile.sh b/Templates/compile.sh index 72df1ee..db7f911 100755 --- a/Templates/compile.sh +++ b/Templates/compile.sh @@ -4,7 +4,8 @@ wget https://github.com/apple/swift/raw/master/utils/gyb wget https://github.com/apple/swift/raw/master/utils/gyb.py chmod +x gyb -./gyb -o ../Sources/Cartesian.swift Cartesian.swift.gyb +./gyb --line-directive '' -o ../Sources/Cartesian.swift Cartesian.swift.gyb +./gyb --line-directive '' -o ../Tests/SwiftCheckTests/CartesianSpec.swift CartesianSpec.swift.gyb rm gyb rm gyb.py diff --git a/Tests/SwiftCheckTests/CartesianSpec.swift b/Tests/SwiftCheckTests/CartesianSpec.swift new file mode 100644 index 0000000..3d1bc63 --- /dev/null +++ b/Tests/SwiftCheckTests/CartesianSpec.swift @@ -0,0 +1,224 @@ +// +// CartesianSpec.swift +// SwiftCheck +// +// Created by Adam Kuipers on 9/21/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +// This is a GYB generated file; any changes will be overwritten +// during the build phase. Edit the template instead, +// found in Templates/CartesianSpec.swift.gyb + + +import SwiftCheck +import XCTest +import Foundation + +final class CartesianSpec : XCTestCase { + func testGeneratedZips() { + let g3 = Gen<(Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3)) + + property("Gen.zip3 behaves") <- forAllNoShrink(g3) { (tuple : (Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.2 == 3 + } + let g4 = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) + + property("Gen.zip4 behaves") <- forAllNoShrink(g4) { (tuple : (Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.3 == 4 + } + let g5 = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) + + property("Gen.zip5 behaves") <- forAllNoShrink(g5) { (tuple : (Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.4 == 5 + } + let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) + + property("Gen.zip6 behaves") <- forAllNoShrink(g6) { (tuple : (Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.5 == 6 + } + let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) + + property("Gen.zip7 behaves") <- forAllNoShrink(g7) { (tuple : (Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.6 == 7 + } + let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) + + property("Gen.zip8 behaves") <- forAllNoShrink(g8) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.7 == 8 + } + let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) + + property("Gen.zip9 behaves") <- forAllNoShrink(g9) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.8 == 9 + } + let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) + + property("Gen.zip10 behaves") <- forAllNoShrink(g10) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.9 == 10 + } + let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) + + property("Gen.zip11 behaves") <- forAllNoShrink(g11) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.10 == 11 + } + let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) + + property("Gen.zip12 behaves") <- forAllNoShrink(g12) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.11 == 12 + } + let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) + + property("Gen.zip13 behaves") <- forAllNoShrink(g13) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.12 == 13 + } + let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) + + property("Gen.zip14 behaves") <- forAllNoShrink(g14) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.13 == 14 + } + let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) + + property("Gen.zip15 behaves") <- forAllNoShrink(g15) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.14 == 15 + } + let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) + + property("Gen.zip16 behaves") <- forAllNoShrink(g16) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.15 == 16 + } + let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) + + property("Gen.zip17 behaves") <- forAllNoShrink(g17) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.16 == 17 + } + let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) + + property("Gen.zip18 behaves") <- forAllNoShrink(g18) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.17 == 18 + } + let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) + + property("Gen.zip19 behaves") <- forAllNoShrink(g19) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.18 == 19 + } + let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) + + property("Gen.zip20 behaves") <- forAllNoShrink(g20) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.19 == 20 + } + let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) + + property("Gen.zip21 behaves") <- forAllNoShrink(g21) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.20 == 21 + } + let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) + + property("Gen.zip22 behaves") <- forAllNoShrink(g22) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in + tuple.0 == 1 && tuple.21 == 22 + } + } + + func testGeneratedMaps() { +let g3 = Gen<(Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3)) { max($0, $1, $2) } + + property("Gen.zip3 behaves") <- forAllNoShrink(g3) { maxInt in + maxInt == 3 + } +let g4 = Gen<(Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) { max($0, $1, $2, $3) } + + property("Gen.zip4 behaves") <- forAllNoShrink(g4) { maxInt in + maxInt == 4 + } +let g5 = Gen<(Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) { max($0, $1, $2, $3, $4) } + + property("Gen.zip5 behaves") <- forAllNoShrink(g5) { maxInt in + maxInt == 5 + } +let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) { max($0, $1, $2, $3, $4, $5) } + + property("Gen.zip6 behaves") <- forAllNoShrink(g6) { maxInt in + maxInt == 6 + } +let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) { max($0, $1, $2, $3, $4, $5, $6) } + + property("Gen.zip7 behaves") <- forAllNoShrink(g7) { maxInt in + maxInt == 7 + } +let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) { max($0, $1, $2, $3, $4, $5, $6, $7) } + + property("Gen.zip8 behaves") <- forAllNoShrink(g8) { maxInt in + maxInt == 8 + } +let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8) } + + property("Gen.zip9 behaves") <- forAllNoShrink(g9) { maxInt in + maxInt == 9 + } +let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) } + + property("Gen.zip10 behaves") <- forAllNoShrink(g10) { maxInt in + maxInt == 10 + } +let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } + + property("Gen.zip11 behaves") <- forAllNoShrink(g11) { maxInt in + maxInt == 11 + } +let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } + + property("Gen.zip12 behaves") <- forAllNoShrink(g12) { maxInt in + maxInt == 12 + } +let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) } + + property("Gen.zip13 behaves") <- forAllNoShrink(g13) { maxInt in + maxInt == 13 + } +let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) } + + property("Gen.zip14 behaves") <- forAllNoShrink(g14) { maxInt in + maxInt == 14 + } +let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) } + + property("Gen.zip15 behaves") <- forAllNoShrink(g15) { maxInt in + maxInt == 15 + } +let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) } + + property("Gen.zip16 behaves") <- forAllNoShrink(g16) { maxInt in + maxInt == 16 + } +let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) } + + property("Gen.zip17 behaves") <- forAllNoShrink(g17) { maxInt in + maxInt == 17 + } +let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) } + + property("Gen.zip18 behaves") <- forAllNoShrink(g18) { maxInt in + maxInt == 18 + } +let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) } + + property("Gen.zip19 behaves") <- forAllNoShrink(g19) { maxInt in + maxInt == 19 + } +let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) } + + property("Gen.zip20 behaves") <- forAllNoShrink(g20) { maxInt in + maxInt == 20 + } +let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) } + + property("Gen.zip21 behaves") <- forAllNoShrink(g21) { maxInt in + maxInt == 21 + } +let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) } + + property("Gen.zip22 behaves") <- forAllNoShrink(g22) { maxInt in + maxInt == 22 + } + } +} diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index c3f57ed..c4148dc 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -169,11 +169,9 @@ class GenSpec : XCTestCase { } } - property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) in + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) -> Property in let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) - return forAllNoShrink(g) { (x1, y1) in - return (x1, y1) == (x, y) - } + return forAllNoShrink(g) { $0 == (x, y) } } property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in From 1d71204e82bbd1427d2bdbe072018505922e9c5d Mon Sep 17 00:00:00 2001 From: Adam Kuipers Date: Wed, 21 Sep 2016 11:58:35 -0700 Subject: [PATCH 368/460] Move scripts and gyb to Utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of fetching gyb for each build we’re storing it in Utilities. --- .gitignore | 3 + .travis.yml | 6 +- SwiftCheck.xcodeproj/project.pbxproj | 4 +- Templates/compile.sh | 12 - Tests/SwiftCheckTests/CartesianSpec.swift | 80 +- Utilities/compile.sh | 4 + Utilities/gyb | 3 + Utilities/gyb.py | 1146 +++++++++++++++++++++ 8 files changed, 1220 insertions(+), 38 deletions(-) delete mode 100755 Templates/compile.sh create mode 100755 Utilities/compile.sh create mode 100755 Utilities/gyb create mode 100644 Utilities/gyb.py diff --git a/.gitignore b/.gitignore index 70f99d1..f69cd72 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ DerivedData Carthage/Build Carthage/Checkouts build/ + +# Python +*.pyc diff --git a/.travis.yml b/.travis.yml index fcca87a..9919594 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ matrix: osx_image: xcode8 before_install: - git submodule update --init --recursive - - pushd Templates + - pushd Utilities - ./compile.sh - popd script: @@ -20,7 +20,7 @@ matrix: osx_image: xcode8 before_install: - git submodule update --init --recursive - - pushd Templates + - pushd Utilities - ./compile.sh - popd script: @@ -50,7 +50,7 @@ matrix: - wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz - tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz - export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - - pushd Templates + - pushd Utilities - ./compile.sh - popd script: diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 06c0cf0..104b16c 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -204,7 +204,6 @@ FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CartesianSpec.swift.gyb; sourceTree = ""; }; FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CartesianSpec.swift; path = Tests/SwiftCheckTests/CartesianSpec.swift; sourceTree = SOURCE_ROOT; }; FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; - FAAB9E7A1D91B96C0097AC78 /* compile.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = compile.sh; sourceTree = ""; }; FAAB9E881D91C28F0097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = Sources/Cartesian.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -351,7 +350,6 @@ children = ( FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */, FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */, - FAAB9E7A1D91B96C0097AC78 /* compile.sh */, ); path = Templates; sourceTree = SOURCE_ROOT; @@ -611,7 +609,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "pushd Templates\n./compile.sh\npopd\n"; + shellScript = "pushd Utilities\n./compile.sh\npopd\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/Templates/compile.sh b/Templates/compile.sh deleted file mode 100755 index db7f911..0000000 --- a/Templates/compile.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -wget https://github.com/apple/swift/raw/master/utils/gyb -wget https://github.com/apple/swift/raw/master/utils/gyb.py -chmod +x gyb - -./gyb --line-directive '' -o ../Sources/Cartesian.swift Cartesian.swift.gyb -./gyb --line-directive '' -o ../Tests/SwiftCheckTests/CartesianSpec.swift CartesianSpec.swift.gyb - -rm gyb -rm gyb.py -rm gyb.pyc diff --git a/Tests/SwiftCheckTests/CartesianSpec.swift b/Tests/SwiftCheckTests/CartesianSpec.swift index 3d1bc63..3619bb3 100644 --- a/Tests/SwiftCheckTests/CartesianSpec.swift +++ b/Tests/SwiftCheckTests/CartesianSpec.swift @@ -17,101 +17,121 @@ import Foundation final class CartesianSpec : XCTestCase { func testGeneratedZips() { + let g3 = Gen<(Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3)) property("Gen.zip3 behaves") <- forAllNoShrink(g3) { (tuple : (Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.2 == 3 } + let g4 = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) property("Gen.zip4 behaves") <- forAllNoShrink(g4) { (tuple : (Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.3 == 4 } + let g5 = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) property("Gen.zip5 behaves") <- forAllNoShrink(g5) { (tuple : (Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.4 == 5 } + let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) property("Gen.zip6 behaves") <- forAllNoShrink(g6) { (tuple : (Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.5 == 6 } + let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) property("Gen.zip7 behaves") <- forAllNoShrink(g7) { (tuple : (Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.6 == 7 } + let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) property("Gen.zip8 behaves") <- forAllNoShrink(g8) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.7 == 8 } + let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) property("Gen.zip9 behaves") <- forAllNoShrink(g9) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.8 == 9 } + let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) property("Gen.zip10 behaves") <- forAllNoShrink(g10) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.9 == 10 } + let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) property("Gen.zip11 behaves") <- forAllNoShrink(g11) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.10 == 11 } + let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) property("Gen.zip12 behaves") <- forAllNoShrink(g12) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.11 == 12 } + let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) property("Gen.zip13 behaves") <- forAllNoShrink(g13) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.12 == 13 } + let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) property("Gen.zip14 behaves") <- forAllNoShrink(g14) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.13 == 14 } + let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) property("Gen.zip15 behaves") <- forAllNoShrink(g15) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.14 == 15 } + let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) property("Gen.zip16 behaves") <- forAllNoShrink(g16) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.15 == 16 } + let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) property("Gen.zip17 behaves") <- forAllNoShrink(g17) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.16 == 17 } + let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) property("Gen.zip18 behaves") <- forAllNoShrink(g18) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.17 == 18 } + let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) property("Gen.zip19 behaves") <- forAllNoShrink(g19) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.18 == 19 } + let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) property("Gen.zip20 behaves") <- forAllNoShrink(g20) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.19 == 20 } + let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) property("Gen.zip21 behaves") <- forAllNoShrink(g21) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in tuple.0 == 1 && tuple.20 == 21 } + let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) property("Gen.zip22 behaves") <- forAllNoShrink(g22) { (tuple : (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)) -> Bool in @@ -120,102 +140,122 @@ final class CartesianSpec : XCTestCase { } func testGeneratedMaps() { -let g3 = Gen<(Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3)) { max($0, $1, $2) } + + let g3 = Gen<(Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3)) { max($0, $1, $2) } property("Gen.zip3 behaves") <- forAllNoShrink(g3) { maxInt in maxInt == 3 } -let g4 = Gen<(Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) { max($0, $1, $2, $3) } + + let g4 = Gen<(Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) { max($0, $1, $2, $3) } property("Gen.zip4 behaves") <- forAllNoShrink(g4) { maxInt in maxInt == 4 } -let g5 = Gen<(Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) { max($0, $1, $2, $3, $4) } + + let g5 = Gen<(Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) { max($0, $1, $2, $3, $4) } property("Gen.zip5 behaves") <- forAllNoShrink(g5) { maxInt in maxInt == 5 } -let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) { max($0, $1, $2, $3, $4, $5) } + + let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) { max($0, $1, $2, $3, $4, $5) } property("Gen.zip6 behaves") <- forAllNoShrink(g6) { maxInt in maxInt == 6 } -let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) { max($0, $1, $2, $3, $4, $5, $6) } + + let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) { max($0, $1, $2, $3, $4, $5, $6) } property("Gen.zip7 behaves") <- forAllNoShrink(g7) { maxInt in maxInt == 7 } -let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) { max($0, $1, $2, $3, $4, $5, $6, $7) } + + let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) { max($0, $1, $2, $3, $4, $5, $6, $7) } property("Gen.zip8 behaves") <- forAllNoShrink(g8) { maxInt in maxInt == 8 } -let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8) } + + let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8) } property("Gen.zip9 behaves") <- forAllNoShrink(g9) { maxInt in maxInt == 9 } -let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) } + + let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) } property("Gen.zip10 behaves") <- forAllNoShrink(g10) { maxInt in maxInt == 10 } -let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } + + let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } property("Gen.zip11 behaves") <- forAllNoShrink(g11) { maxInt in maxInt == 11 } -let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } + + let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } property("Gen.zip12 behaves") <- forAllNoShrink(g12) { maxInt in maxInt == 12 } -let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) } + + let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) } property("Gen.zip13 behaves") <- forAllNoShrink(g13) { maxInt in maxInt == 13 } -let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) } + + let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) } property("Gen.zip14 behaves") <- forAllNoShrink(g14) { maxInt in maxInt == 14 } -let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) } + + let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) } property("Gen.zip15 behaves") <- forAllNoShrink(g15) { maxInt in maxInt == 15 } -let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) } + + let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) } property("Gen.zip16 behaves") <- forAllNoShrink(g16) { maxInt in maxInt == 16 } -let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) } + + let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) } property("Gen.zip17 behaves") <- forAllNoShrink(g17) { maxInt in maxInt == 17 } -let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) } + + let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) } property("Gen.zip18 behaves") <- forAllNoShrink(g18) { maxInt in maxInt == 18 } -let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) } + + let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) } property("Gen.zip19 behaves") <- forAllNoShrink(g19) { maxInt in maxInt == 19 } -let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) } + + let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) } property("Gen.zip20 behaves") <- forAllNoShrink(g20) { maxInt in maxInt == 20 } -let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) } + + let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) } property("Gen.zip21 behaves") <- forAllNoShrink(g21) { maxInt in maxInt == 21 } -let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) } + + let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) } property("Gen.zip22 behaves") <- forAllNoShrink(g22) { maxInt in maxInt == 22 diff --git a/Utilities/compile.sh b/Utilities/compile.sh new file mode 100755 index 0000000..cb9d933 --- /dev/null +++ b/Utilities/compile.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +./gyb --line-directive '' -o ../Sources/Cartesian.swift ../Templates/Cartesian.swift.gyb +./gyb --line-directive '' -o ../Tests/SwiftCheckTests/CartesianSpec.swift ../Templates/CartesianSpec.swift.gyb diff --git a/Utilities/gyb b/Utilities/gyb new file mode 100755 index 0000000..dece788 --- /dev/null +++ b/Utilities/gyb @@ -0,0 +1,3 @@ +#!/usr/bin/env python2.7 +import gyb +gyb.main() diff --git a/Utilities/gyb.py b/Utilities/gyb.py new file mode 100644 index 0000000..e7bbf89 --- /dev/null +++ b/Utilities/gyb.py @@ -0,0 +1,1146 @@ +#!/usr/bin/env python +# GYB: Generate Your Boilerplate (improved names welcome; at least +# this one's short). See -h output for instructions + +from __future__ import print_function + +import os +import re +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +import textwrap +import tokenize + +from bisect import bisect + + +def get_line_starts(s): + """Return a list containing the start index of each line in s. + + The list also contains a sentinel index for the end of the string, + so there will be one more element in the list than there are lines + in the string + """ + starts = [0] + + for line in s.split('\n'): + starts.append(starts[-1] + len(line) + 1) + + starts[-1] -= 1 + return starts + + +def strip_trailing_nl(s): + """If s ends with a newline, drop it; else return s intact""" + return s[:-1] if s.endswith('\n') else s + + +def split_lines(s): + """Split s into a list of lines, each of which has a trailing newline + + If the lines are later concatenated, the result is s, possibly + with a single appended newline. + """ + return [l + '\n' for l in s.split('\n')] + +# text on a line up to the first '$$', '${', or '%%' +literalText = r'(?: [^$\n%] | \$(?![${]) | %(?!%) )*' + +# The part of an '%end' line that follows the '%' sign +linesClose = r'[\ \t]* end [\ \t]* (?: \# .* )? $' + +# Note: Where "# Absorb" appears below, the regexp attempts to eat up +# through the end of ${...} and %{...}% constructs. In reality we +# handle this with the Python tokenizer, which avoids mis-detections +# due to nesting, comments and strings. This extra absorption in the +# regexp facilitates testing the regexp on its own, by preventing the +# interior of some of these constructs from being treated as literal +# text. +tokenize_re = re.compile( + r''' +# %-lines and %{...}-blocks + # \n? # absorb one preceding newline + ^ + (?: + (?P + (?P<_indent> [\ \t]* % (?! [{%] ) [\ \t]* ) (?! [\ \t] | ''' + + linesClose + r''' ) .* + ( \n (?P=_indent) (?! ''' + linesClose + r''' ) .* ) * + ) + | (?P [\ \t]* % [ \t]* ''' + linesClose + r''' ) + | [\ \t]* (?P %\{ ) + (?: [^}]| \} (?!%) )* \}% # Absorb + ) + \n? # absorb one trailing newline + +# Substitutions +| (?P \$\{ ) + [^}]* \} # Absorb + +# %% and $$ are literal % and $ respectively +| (?P[$%]) (?P=symbol) + +# Literal text +| (?P ''' + literalText + r''' + (?: + # newline that doesn't precede space+% + (?: \n (?! [\ \t]* %[^%] ) ) + ''' + literalText + r''' + )* + \n? + ) +''', re.VERBOSE | re.MULTILINE) + +gyb_block_close = re.compile('\}%[ \t]*\n?') + + +def token_pos_to_index(token_pos, start, line_starts): + """Translate a tokenize (line, column) pair into an absolute + position in source text given the position where we started + tokenizing and a list that maps lines onto their starting + character indexes. + """ + relative_token_line_plus1, token_col = token_pos + + # line number where we started tokenizing + start_line_num = bisect(line_starts, start) - 1 + + # line number of the token in the whole text + abs_token_line = relative_token_line_plus1 - 1 + start_line_num + + # if found in the first line, adjust the end column to account + # for the extra text + if relative_token_line_plus1 == 1: + token_col += start - line_starts[start_line_num] + + # Sometimes tokenizer errors report a line beyond the last one + if abs_token_line >= len(line_starts): + return line_starts[-1] + + return line_starts[abs_token_line] + token_col + + +def tokenize_python_to_unmatched_close_curly(source_text, start, line_starts): + """Apply Python's tokenize to source_text starting at index start + while matching open and close curly braces. When an unmatched + close curly brace is found, return its index. If not found, + return len(source_text). If there's a tokenization error, return + the position of the error. + """ + stream = StringIO(source_text) + stream.seek(start) + nesting = 0 + + try: + for kind, text, token_start, token_end, line_text \ + in tokenize.generate_tokens(stream.readline): + + if text == '{': + nesting += 1 + elif text == '}': + nesting -= 1 + if nesting < 0: + return token_pos_to_index(token_start, start, line_starts) + + except tokenize.TokenError as error: + (message, error_pos) = error.args + return token_pos_to_index(error_pos, start, line_starts) + + return len(source_text) + + +def tokenize_template(template_text): + r"""Given the text of a template, returns an iterator over + (tokenType, token, match) tuples. + + **Note**: this is template syntax tokenization, not Python + tokenization. + + When a non-literal token is matched, a client may call + iter.send(pos) on the iterator to reset the position in + template_text at which scanning will resume. + + This function provides a base level of tokenization which is + then refined by ParseContext.token_generator. + + >>> from pprint import * + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '%for x in range(10):\n% print x\n%end\njuicebox'))) + [('gybLines', '%for x in range(10):\n% print x'), + ('gybLinesClose', '%end'), + ('literal', 'juicebox')] + + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... '''))) + [('literal', 'Nothing\n'), + ('gybLines', '% if x:\n% for i in range(3):'), + ('substitutionOpen', '${'), + ('literal', '\n'), + ('gybLinesClose', '% end'), + ('gybLines', '% else:'), + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n')] + + >>> for kind, text, _ in tokenize_template(''' + ... This is $some$ literal stuff containing a ${substitution} + ... followed by a %{...} block: + ... %{ + ... # Python code + ... }% + ... and here $${are} some %-lines: + ... % x = 1 + ... % y = 2 + ... % if z == 3: + ... % print '${hello}' + ... % end + ... % for x in zz: + ... % print x + ... % # different indentation + ... % twice + ... and some lines that literally start with a %% token + ... %% first line + ... %% second line + ... '''): + ... print((kind, text.strip().split('\n',1)[0])) + ('literal', 'This is $some$ literal stuff containing a') + ('substitutionOpen', '${') + ('literal', 'followed by a %{...} block:') + ('gybBlockOpen', '%{') + ('literal', 'and here ${are} some %-lines:') + ('gybLines', '% x = 1') + ('gybLinesClose', '% end') + ('gybLines', '% for x in zz:') + ('gybLines', '% # different indentation') + ('gybLines', '% twice') + ('literal', 'and some lines that literally start with a % token') + """ + pos = 0 + end = len(template_text) + + saved_literal = [] + literal_first_match = None + + while pos < end: + m = tokenize_re.match(template_text, pos, end) + + # pull out the one matched key (ignoring internal patterns starting + # with _) + ((kind, text), ) = ( + (kind, text) for (kind, text) in m.groupdict().items() + if text is not None and kind[0] != '_') + + if kind in ('literal', 'symbol'): + if len(saved_literal) == 0: + literal_first_match = m + # literals and symbols get batched together + saved_literal.append(text) + pos = None + else: + # found a non-literal. First yield any literal we've accumulated + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + saved_literal = [] + + # Then yield the thing we found. If we get a reply, it's + # the place to resume tokenizing + pos = yield kind, text, m + + # If we were not sent a new position by our client, resume + # tokenizing at the end of this match. + if pos is None: + pos = m.end(0) + else: + # Client is not yet ready to process next token + yield + + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + + +def split_gyb_lines(source_lines): + r"""Return a list of lines at which to split the incoming source + + These positions represent the beginnings of python line groups that + will require a matching %end construct if they are to be closed. + + >>> src = split_lines('''\ + ... if x: + ... print x + ... if y: # trailing comment + ... print z + ... if z: # another comment\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' print z\n' + >>> s[1] - len(src) + 0 + + >>> src = split_lines('''\ + ... if x: + ... if y: print 1 + ... if z: + ... print 2 + ... pass\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 1 + >>> src[s[0]] + ' if y: print 1\n' + + >>> src = split_lines('''\ + ... if x: + ... if y: + ... print 1 + ... print 2 + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' if y:\n' + >>> src[s[1]] + ' print 1\n' + """ + last_token_text, last_token_kind = None, None + unmatched_indents = [] + + dedents = 0 + try: + for token_kind, token_text, token_start, \ + (token_end_line, token_end_col), line_text \ + in tokenize.generate_tokens(lambda i=iter(source_lines): + next(i)): + + if token_kind in (tokenize.COMMENT, tokenize.ENDMARKER): + continue + + if token_text == '\n' and last_token_text == ':': + unmatched_indents.append(token_end_line) + + # The tokenizer appends dedents at EOF; don't consider + # those as matching indentations. Instead just save them + # up... + if last_token_kind == tokenize.DEDENT: + dedents += 1 + # And count them later, when we see something real. + if token_kind != tokenize.DEDENT and dedents > 0: + unmatched_indents = unmatched_indents[:-dedents] + dedents = 0 + + last_token_text, last_token_kind = token_text, token_kind + + except tokenize.TokenError: + # Let the later compile() call report the error + return [] + + if last_token_text == ':': + unmatched_indents.append(len(source_lines)) + + return unmatched_indents + + +def code_starts_with_dedent_keyword(source_lines): + r"""Return True iff the incoming Python source_lines begin with "else", + "elif", "except", or "finally". + + Initial comments and whitespace are ignored. + + >>> code_starts_with_dedent_keyword(split_lines('if x in y: pass')) + False + >>> code_starts_with_dedent_keyword(split_lines('except ifSomethingElse:')) + True + >>> code_starts_with_dedent_keyword( + ... split_lines('\n# comment\nelse: # yes')) + True + """ + token_text = None + for token_kind, token_text, _, _, _ \ + in tokenize.generate_tokens(lambda i=iter(source_lines): next(i)): + + if token_kind != tokenize.COMMENT and token_text.strip() != '': + break + + return token_text in ('else', 'elif', 'except', 'finally') + + +class ParseContext(object): + + """State carried through a parse of a template""" + + filename = '' + template = '' + line_starts = [] + code_start_line = -1 + code_text = None + tokens = None # The rest of the tokens + close_lines = False + + def __init__(self, filename, template=None): + self.filename = os.path.abspath(filename) + if template is None: + with open(filename) as f: + self.template = f.read() + else: + self.template = template + self.line_starts = get_line_starts(self.template) + self.tokens = self.token_generator(tokenize_template(self.template)) + self.next_token() + + def pos_to_line(self, pos): + return bisect(self.line_starts, pos) - 1 + + def token_generator(self, base_tokens): + r"""Given an iterator over (kind, text, match) triples (see + tokenize_template above), return a refined iterator over + token_kinds. + + Among other adjustments to the elements found by base_tokens, + this refined iterator tokenizes python code embedded in + template text to help determine its true extent. The + expression "base_tokens.send(pos)" is used to reset the index at + which base_tokens resumes scanning the underlying text. + + >>> ctx = ParseContext('dummy', ''' + ... %for x in y: + ... % print x + ... % end + ... literally + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('literal', '\n') + ('gybLinesOpen', 'for x in y:\n') + ('gybLines', ' print x\n') + ('gybLinesClose', '% end') + ('literal', 'literally\n') + + >>> ctx = ParseContext('dummy', + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('literal', 'Nothing\n') + ('gybLinesOpen', 'if x:\n') + ('gybLinesOpen', ' for i in range(3):\n') + ('substitutionOpen', 'i') + ('literal', '\n') + ('gybLinesClose', '% end') + ('gybLinesOpen', 'else:\n') + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n') + + >>> ctx = ParseContext('dummy', + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add output line here to fix bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('gybLinesOpen', 'for x in [1, 2, 3]:\n') + ('gybLinesOpen', ' if x == 1:\n') + ('literal', 'literal1\n') + ('gybLinesOpen', 'elif x > 1: # add output line here to fix bug\n') + ('gybLinesOpen', ' if x == 2:\n') + ('literal', 'literal2\n') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + """ + for self.token_kind, self.token_text, self.token_match in base_tokens: + kind = self.token_kind + self.code_text = None + + # Do we need to close the current lines? + self.close_lines = kind == 'gybLinesClose' + + # %{...}% and ${...} constructs + if kind.endswith('Open'): + + # Tokenize text that follows as Python up to an unmatched '}' + code_start = self.token_match.end(kind) + self.code_start_line = self.pos_to_line(code_start) + + close_pos = tokenize_python_to_unmatched_close_curly( + self.template, code_start, self.line_starts) + self.code_text = self.template[code_start:close_pos] + yield kind + + if (kind == 'gybBlockOpen'): + # Absorb any '}% \n' + m2 = gyb_block_close.match(self.template, close_pos) + if not m2: + raise ValueError("Invalid block closure") + next_pos = m2.end(0) + else: + assert kind == 'substitutionOpen' + # skip past the closing '}' + next_pos = close_pos + 1 + + # Resume tokenizing after the end of the code. + base_tokens.send(next_pos) + + elif kind == 'gybLines': + + self.code_start_line = self.pos_to_line( + self.token_match.start('gybLines')) + indentation = self.token_match.group('_indent') + + # Strip off the leading indentation and %-sign + source_lines = re.split( + '^' + re.escape(indentation), + self.token_match.group('gybLines') + '\n', + flags=re.MULTILINE)[1:] + + if code_starts_with_dedent_keyword(source_lines): + self.close_lines = True + + last_split = 0 + for line in split_gyb_lines(source_lines): + self.token_kind = 'gybLinesOpen' + self.code_text = ''.join(source_lines[last_split:line]) + yield self.token_kind + last_split = line + self.code_start_line += line - last_split + self.close_lines = False + + self.code_text = ''.join(source_lines[last_split:]) + if self.code_text: + self.token_kind = 'gybLines' + yield self.token_kind + else: + yield self.token_kind + + def next_token(self): + """Move to the next token""" + for kind in self.tokens: + return self.token_kind + + self.token_kind = None + + +class ExecutionContext(object): + + """State we pass around during execution of a template""" + + def __init__(self, line_directive='// ###sourceLocation', + **local_bindings): + self.local_bindings = local_bindings + self.line_directive = line_directive + self.local_bindings['__context__'] = self + self.result_text = [] + self.last_file_line = None + + def append_text(self, text, file, line): + # see if we need to inject a line marker + if self.line_directive: + if (file, line) != self.last_file_line: + # We can only insert the line directive at a line break + if len(self.result_text) == 0 \ + or self.result_text[-1].endswith('\n'): + self.result_text.append('%s(file: "%s", line: %d)\n' % ( + self.line_directive, file, line + 1)) + # But if the new text contains any line breaks, we can create + # one + elif '\n' in text: + i = text.find('\n') + self.result_text.append(text[:i + 1]) + self.last_file_line = ( + self.last_file_line[0], self.last_file_line[1] + 1) + # and try again + self.append_text(text[i + 1:], file, line) + return + + self.result_text.append(text) + self.last_file_line = (file, line + text.count('\n')) + + +class ASTNode(object): + + """Abstract base class for template AST nodes""" + + def __init__(self): + raise NotImplementedError("ASTNode.__init__ is not implemented.") + + def execute(self, context): + raise NotImplementedError("ASTNode.execute is not implemented.") + + def __str__(self, indent=''): + raise NotImplementedError("ASTNode.__str__ is not implemented.") + + def format_children(self, indent): + if not self.children: + return ' []' + + return '\n'.join( + ['', indent + '['] + + [x.__str__(indent + 4 * ' ') for x in self.children] + + [indent + ']']) + + +class Block(ASTNode): + + """A sequence of other AST nodes, to be executed in order""" + + children = [] + + def __init__(self, context): + self.children = [] + + while context.token_kind and not context.close_lines: + if context.token_kind == 'literal': + node = Literal + else: + node = Code + self.children.append(node(context)) + + def execute(self, context): + for x in self.children: + x.execute(context) + + def __str__(self, indent=''): + return indent + 'Block:' + self.format_children(indent) + + +class Literal(ASTNode): + + """An AST node that generates literal text""" + + def __init__(self, context): + self.text = context.token_text + start_position = context.token_match.start(context.token_kind) + self.start_line_number = context.pos_to_line(start_position) + self.filename = context.filename + context.next_token() + + def execute(self, context): + context.append_text(self.text, self.filename, self.start_line_number) + + def __str__(self, indent=''): + return '\n'.join( + [indent + x for x in ['Literal:'] + + strip_trailing_nl(self.text).split('\n')]) + + +class Code(ASTNode): + + """An AST node that is evaluated as Python""" + + code = None + children = () + kind = None + + def __init__(self, context): + + source = '' + source_line_count = 0 + + def accumulate_code(): + s = source + (context.code_start_line - source_line_count) * '\n' \ + + textwrap.dedent(context.code_text) + line_count = context.code_start_line + \ + context.code_text.count('\n') + context.next_token() + return s, line_count + + eval_exec = 'exec' + if context.token_kind.startswith('substitution'): + eval_exec = 'eval' + source, source_line_count = accumulate_code() + source = '(' + source.strip() + ')' + + else: + while context.token_kind == 'gybLinesOpen': + source, source_line_count = accumulate_code() + source += ' __children__[%d].execute(__context__)\n' % len( + self.children) + source_line_count += 1 + + self.children += (Block(context),) + + if context.token_kind == 'gybLinesClose': + context.next_token() + + if context.token_kind == 'gybLines': + source, source_line_count = accumulate_code() + + # Only handle a substitution as part of this code block if + # we don't already have some %-lines. + elif context.token_kind == 'gybBlockOpen': + + # Opening ${...} and %{...}% constructs + source, source_line_count = accumulate_code() + + self.filename = context.filename + self.start_line_number = context.code_start_line + self.code = compile(source, context.filename, eval_exec) + self.source = source + + def execute(self, context): + # Save __children__ from the local bindings + save_children = context.local_bindings.get('__children__') + # Execute the code with our __children__ in scope + context.local_bindings['__children__'] = self.children + context.local_bindings['__file__'] = self.filename + result = eval(self.code, context.local_bindings) + + if context.local_bindings['__children__'] is not self.children: + raise ValueError("The code is not allowed to mutate __children__") + # Restore the bindings + context.local_bindings['__children__'] = save_children + + # If we got a result, the code was an expression, so append + # its value + if result is not None and result != '': + from numbers import Number, Integral + result_string = None + if isinstance(result, Number) and not isinstance(result, Integral): + result_string = repr(result) + else: + result_string = str(result) + context.append_text( + result_string, self.filename, self.start_line_number) + + def __str__(self, indent=''): + source_lines = re.sub(r'^\n', '', strip_trailing_nl( + self.source), flags=re.MULTILINE).split('\n') + if len(source_lines) == 1: + s = indent + 'Code: {' + source_lines[0] + '}' + else: + s = indent + 'Code:\n' + indent + '{\n' + '\n'.join( + indent + 4 * ' ' + l for l in source_lines + ) + '\n' + indent + '}' + return s + self.format_children(indent) + + +def parse_template(filename, text=None): + r"""Return an AST corresponding to the given template file. + + If text is supplied, it is assumed to be the contents of the file, + as a string. + + >>> print(parse_template('dummy.file', text= + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add output line after this line to fix bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''')) + Block: + [ + Code: + { + for x in [1, 2, 3]: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: + { + if x == 1: + __children__[0].execute(__context__) + elif x > 1: # add output line after this line to fix bug + __children__[1].execute(__context__) + } + [ + Block: + [ + Literal: + literal1 + ] + Block: + [ + Code: + { + if x == 2: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + literal2 + ] + ] + ] + ] + ] + ] + ] + + >>> print(parse_template( + ... 'dummy.file', + ... text='%for x in range(10):\n% print(x)\n%end\njuicebox')) + Block: + [ + Code: + { + for x in range(10): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print(x)} [] + ] + ] + Literal: + juicebox + ] + + >>> print(parse_template('/dummy.file', text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''')) + Block: + [ + Literal: + Nothing + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: + { + for i in range(3): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {(i)} [] + Literal: + + ] + ] + ] + Block: + [ + Literal: + THIS SHOULD NOT APPEAR IN THE OUTPUT + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %for x in y: + ... % print(y) + ... ''')) + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %if x: + ... % print(y) + ... AAAA + ... %else: + ... BBBB + ... ''')) + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %if x: + ... % print(y) + ... AAAA + ... %# This is a comment + ... %else: + ... BBBB + ... ''')) + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + # This is a comment + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''\ + ... %for x in y: + ... AAAA + ... %if x: + ... BBBB + ... %end + ... CCCC + ... ''')) + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + AAAA + Code: + { + if x: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + BBBB + ] + ] + Literal: + CCCC + ] + ] + ] + """ + return Block(ParseContext(filename, text)) + + +def execute_template(ast, line_directive='', **local_bindings): + r"""Return the text generated by executing the given template AST. + + Keyword arguments become local variable bindings in the execution context + + >>> ast = parse_template('/dummy.file', text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> out = execute_template(ast, line_directive='//#sourceLocation', x=1) + >>> print(out, end="") + //#sourceLocation(file: "/dummy.file", line: 1) + Nothing + //#sourceLocation(file: "/dummy.file", line: 4) + 0 + //#sourceLocation(file: "/dummy.file", line: 4) + 1 + //#sourceLocation(file: "/dummy.file", line: 4) + 2 + + >>> ast = parse_template('/dummy.file', text= + ... '''Nothing + ... % a = [] + ... % for x in range(3): + ... % a.append(x) + ... % end + ... ${a} + ... ''') + >>> out = execute_template(ast, line_directive='//#sourceLocation', x=1) + >>> print(out, end="") + //#sourceLocation(file: "/dummy.file", line: 1) + Nothing + //#sourceLocation(file: "/dummy.file", line: 6) + [0, 1, 2] + """ + execution_context = ExecutionContext( + line_directive=line_directive, **local_bindings) + ast.execute(execution_context) + return ''.join(execution_context.result_text) + + +def main(): + import argparse + import sys + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Generate Your Boilerplate!', epilog=''' + A GYB template consists of the following elements: + + - Literal text which is inserted directly into the output + + - %% or $$ in literal text, which insert literal '%' and '$' + symbols respectively. + + - Substitutions of the form ${}. The Python + expression is converted to a string and the result is inserted + into the output. + + - Python code delimited by %{...}%. Typically used to inject + definitions (functions, classes, variable bindings) into the + evaluation context of the template. Common indentation is + stripped, so you can add as much indentation to the beginning + of this code as you like + + - Lines beginning with optional whitespace followed by a single + '%' and Python code. %-lines allow you to nest other + constructs inside them. To close a level of nesting, use the + "%end" construct. + + - Lines beginning with optional whitespace and followed by a + single '%' and the token "end", which close open constructs in + %-lines. + + Example template: + + - Hello - + %{ + x = 42 + def succ(a): + return a+1 + }% + + I can assure you that ${x} < ${succ(x)} + + % if int(y) > 7: + % for i in range(3): + y is greater than seven! + % end + % else: + y is less than or equal to seven + % end + + - The End. - + + When run with "gyb -Dy=9", the output is + + - Hello - + + I can assure you that 42 < 43 + + y is greater than seven! + y is greater than seven! + y is greater than seven! + + - The End. - +''' + ) + parser.add_argument( + '-D', action='http://github.com/append', dest='defines', metavar='NAME=VALUE', + default=[], + help='''Bindings to be set in the template's execution context''') + + parser.add_argument( + 'file', type=argparse.FileType(), + help='Path to GYB template file (defaults to stdin)', nargs='?', + default=sys.stdin) + parser.add_argument( + '-o', dest='target', type=argparse.FileType('w'), + help='Output file (defaults to stdout)', default=sys.stdout) + parser.add_argument( + '--test', action='http://github.com/store_true', + default=False, help='Run a self-test') + parser.add_argument( + '--verbose-test', action='http://github.com/store_true', + default=False, help='Run a verbose self-test') + parser.add_argument( + '--dump', action='http://github.com/store_true', + default=False, help='Dump the parsed template to stdout') + parser.add_argument( + '--line-directive', default='// ###sourceLocation', + help='Line directive prefix; empty => no line markers') + + args = parser.parse_args(sys.argv[1:]) + + if args.test or args.verbose_test: + import doctest + selfmod = sys.modules[__name__] + if doctest.testmod(selfmod, verbose=args.verbose_test).failed: + sys.exit(1) + + bindings = dict(x.split('=', 1) for x in args.defines) + ast = parse_template(args.file.name, args.file.read()) + if args.dump: + print(ast) + # Allow the template to import .py files from its own directory + sys.path = [os.path.split(args.file.name)[0] or '.'] + sys.path + + args.target.write(execute_template(ast, args.line_directive, **bindings)) + +if __name__ == '__main__': + main() From 67c650d842be341c40f523f954c11a64942734d6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 22 Sep 2016 09:52:05 -0400 Subject: [PATCH 369/460] Add richer doc comments to gyb'd files --- Sources/Cartesian.swift | 662 ++++++++++++++++++++++++++++++---- Sources/Gen.swift | 2 +- Templates/Cartesian.swift.gyb | 19 +- 3 files changed, 616 insertions(+), 67 deletions(-) diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift index 858c95c..c900e1a 100644 --- a/Sources/Cartesian.swift +++ b/Sources/Cartesian.swift @@ -13,8 +13,11 @@ extension Gen /*: Cartesian*/ { - - /// Zips together 3 generators generator of tuples. + /// Zips together 3 generators into a generator of 3-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> { return Gen .zip( @@ -26,12 +29,21 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform: @escaping (A1, A2, A3) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> R) -> Gen { return zip(ga1, ga2, ga3).map(transform) } - /// Zips together 4 generators generator of tuples. + /// Zips together 4 generators into a generator of 4-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { return Gen .zip( @@ -43,12 +55,23 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform: @escaping (A1, A2, A3, A4) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4).map(transform) } - /// Zips together 5 generators generator of tuples. + /// Zips together 5 generators into a generator of 5-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { return Gen .zip( @@ -60,12 +83,25 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform: @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5).map(transform) } - /// Zips together 6 generators generator of tuples. + /// Zips together 6 generators into a generator of 6-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { return Gen .zip( @@ -77,12 +113,27 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) } - /// Zips together 7 generators generator of tuples. + /// Zips together 7 generators into a generator of 7-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { return Gen .zip( @@ -94,12 +145,29 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) } - /// Zips together 8 generators generator of tuples. + /// Zips together 8 generators into a generator of 8-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { return Gen .zip( @@ -111,12 +179,31 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) } - /// Zips together 9 generators generator of tuples. + /// Zips together 9 generators into a generator of 9-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { return Gen .zip( @@ -128,12 +215,33 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) } - /// Zips together 10 generators generator of tuples. + /// Zips together 10 generators into a generator of 10-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { return Gen .zip( @@ -145,12 +253,35 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) } - /// Zips together 11 generators generator of tuples. + /// Zips together 11 generators into a generator of 11-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { return Gen .zip( @@ -162,12 +293,37 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) } - /// Zips together 12 generators generator of tuples. + /// Zips together 12 generators into a generator of 12-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { return Gen .zip( @@ -179,12 +335,39 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) } - /// Zips together 13 generators generator of tuples. + /// Zips together 13 generators into a generator of 13-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { return Gen .zip( @@ -196,12 +379,41 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) } - /// Zips together 14 generators generator of tuples. + /// Zips together 14 generators into a generator of 14-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { return Gen .zip( @@ -213,12 +425,43 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) } - /// Zips together 15 generators generator of tuples. + /// Zips together 15 generators into a generator of 15-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { return Gen .zip( @@ -230,12 +473,45 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) } - /// Zips together 16 generators generator of tuples. + /// Zips together 16 generators into a generator of 16-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { return Gen .zip( @@ -247,12 +523,47 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) } - /// Zips together 17 generators generator of tuples. + /// Zips together 17 generators into a generator of 17-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { return Gen .zip( @@ -264,12 +575,49 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) } - /// Zips together 18 generators generator of tuples. + /// Zips together 18 generators into a generator of 18-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { return Gen .zip( @@ -281,12 +629,51 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) } - /// Zips together 19 generators generator of tuples. + /// Zips together 19 generators into a generator of 19-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { return Gen .zip( @@ -298,12 +685,53 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) } - /// Zips together 20 generators generator of tuples. + /// Zips together 20 generators into a generator of 20-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { return Gen .zip( @@ -315,12 +743,55 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) } - /// Zips together 21 generators generator of tuples. + /// Zips together 21 generators into a generator of 21-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { return Gen .zip( @@ -332,12 +803,57 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) } - /// Zips together 22 generators generator of tuples. + /// Zips together 22 generators into a generator of 22-tuples. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. + /// - parameter ga22: A generator of values of type `A22`. public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { return Gen .zip( @@ -349,8 +865,32 @@ extension Gen /*: Cartesian*/ { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform: @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. + /// - parameter ga22: A generator of values of type `A22`. + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map(transform) } + } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index f227028..96b88f0 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -173,7 +173,7 @@ extension Gen { } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. + /// given generators produce. public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { return zip(ga1, ga2).map(transform) } diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 8ef03a9..593f5b0 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -19,7 +19,8 @@ extension Gen /*: Cartesian*/ { % for arity in range(3, MAX_ARITY + 1): %{ # Function definition template -type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity + 1)]) +types_list = ['A{0}'.format(n) for n in range(1, arity + 1)] +type_parameter_list = ', '.join(types_list) parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) # Zip body template @@ -32,8 +33,11 @@ expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_pa # Map body template map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) }% - - /// Zips together ${arity} generators generator of tuples. + /// Zips together ${arity} generators into a generator of ${arity}-tuples. + /// +% for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): + /// - parameter ${p}: A generator of values of type `${t}`. +% end public static func zip<${type_parameter_list}>(${parameter_list}) -> Gen<(${type_parameter_list})> { return Gen .zip( @@ -45,9 +49,14 @@ map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1 } /// Returns a new generator that applies a given function to any outputs the - /// two receivers create. - public static func map<${type_parameter_list}, R>(${parameter_list}, transform: @escaping (${type_parameter_list}) -> R) -> Gen { + /// given generators produce. + /// +% for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): + /// - parameter ${p}: A generator of values of type `${t}`. +% end + public static func map<${type_parameter_list}, R>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> R) -> Gen { return zip(${map_zip_argument_list}).map(transform) } + % end } From 543279837d4409d830552a4523bcbcfe31d53db8 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Sat, 1 Oct 2016 21:28:20 -0400 Subject: [PATCH 370/460] remove rawrepresentable arbitrary protocol extension & tests closes #193 --- Sources/Arbitrary.swift | 8 ---- SwiftCheck.xcodeproj/project.pbxproj | 8 ---- .../RawRepresentableSpec.swift | 42 ------------------- 3 files changed, 58 deletions(-) delete mode 100644 Tests/SwiftCheckTests/RawRepresentableSpec.swift diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 703573e..a19bef7 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -74,14 +74,6 @@ extension Integer { } } -extension RawRepresentable where RawValue : Arbitrary & Integer { - /// Uses the default generator for `Integer` values to search for a value - /// that can construct an instance of the reciever's type. - public static var arbitrary : Gen { - return RawValue.arbitrary.map(Self.init).suchThat { $0 != nil }.map { $0! } - } -} - extension Bool : Arbitrary { /// Returns a generator of `Bool`ean values. public static var arbitrary : Gen { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 104b16c..62e631f 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -39,9 +39,6 @@ 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; - 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; - 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */; }; 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; @@ -174,7 +171,6 @@ 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; 825C9AD71D8EE86E003313E1 /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/SwiftCheckTests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/SwiftCheckTests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RawRepresentableSpec.swift; path = Tests/SwiftCheckTests/RawRepresentableSpec.swift; sourceTree = SOURCE_ROOT; }; 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/SwiftCheckTests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/SwiftCheckTests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/SwiftCheckTests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; @@ -326,7 +322,6 @@ 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, 825C9AD71D8EE86E003313E1 /* PathSpec.swift */, 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */, - 825C9AD91D8EE86E003313E1 /* RawRepresentableSpec.swift */, 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */, 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */, 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */, @@ -641,7 +636,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9AFB1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, FA3C185D1D93056D003DEB10 /* CartesianSpec.swift in Sources */, @@ -687,7 +681,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9AF91D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, FA3C185B1D93056D003DEB10 /* CartesianSpec.swift in Sources */, @@ -733,7 +726,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9AFA1D8EE86E003313E1 /* RawRepresentableSpec.swift in Sources */, 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, FA3C185C1D93056D003DEB10 /* CartesianSpec.swift in Sources */, diff --git a/Tests/SwiftCheckTests/RawRepresentableSpec.swift b/Tests/SwiftCheckTests/RawRepresentableSpec.swift deleted file mode 100644 index bef8bdf..0000000 --- a/Tests/SwiftCheckTests/RawRepresentableSpec.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// RawRepresentable+ArbitrarySpec.swift -// SwiftCheck -// -// Created by Brian Gerstle on 5/4/16. -// Copyright © 2016 Typelift. All rights reserved. -// - -import XCTest -import SwiftCheck - -enum ImplicitRawValues : Int { - case foo - case bar - case baz -} - -extension ImplicitRawValues : Arbitrary {} - -enum ExplicitRawIntValues : Int { - case zero = 0 - case one = 1 - case two = 2 -} - -class RawRepresentableSpec : XCTestCase { - func testAll() { - property("only generates Foo, Bar, or Baz") <- forAll { (e: ImplicitRawValues) in - return [.foo, .bar, .baz].contains(e) - } - - property("only generates Zero, One, or Two") <- forAllNoShrink(ExplicitRawIntValues.arbitrary) { e in - return [.zero, .one, .two].contains(e) - } - } - - #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) - static var allTests = testCase([ - ("testAll", testAll), - ]) - #endif -} From 8f15480014fd647822d2758fa505480706e93f92 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Sun, 2 Oct 2016 12:20:27 -0400 Subject: [PATCH 371/460] remove RawRepresentableSpec LinuxMain hook --- Tests/LinuxMain.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 286346b..fc2c0b5 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -21,7 +21,6 @@ XCTMain([ ModifierSpec.allTests, PathSpec.allTests, PropertySpec.allTests, - RawRepresentableSpec.allTests, ReplaySpec.allTests, RoseSpec.allTests, ShrinkSpec.allTests, From 5bc83e1c2cc004ba57b9bd73f5fba6e46c98992f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 9 Oct 2016 18:52:42 -0400 Subject: [PATCH 372/460] Apparently you don't need testing targets. --- Package.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Package.swift b/Package.swift index e807210..b9b0e29 100644 --- a/Package.swift +++ b/Package.swift @@ -4,9 +4,6 @@ let package = Package( name: "SwiftCheck", targets: [ Target(name: "SwiftCheck"), - Target( - name: "SwiftCheckTests", - dependencies: ["SwiftCheck"]), ] ) From 69fb4a43e50be50db6fdf62ada4ae5e2ca869981 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 14 Oct 2016 11:19:46 -0400 Subject: [PATCH 373/460] Fix a space leak in suchThat The old version, while pretty, was recursive and thus O(2n) in the amount of stack space it would eat trying to search for a value. This is tremendously inefficient for large n, which can be the case if the default size of generators is increased at all - which is a thing I like to think we support. --- Sources/Gen.swift | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 96b88f0..69ca097 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -229,10 +229,24 @@ extension Gen { /// satisfy a predicate. All attempts are encoded in the form of an /// `Optional` where values satisfying the predicate are wrapped in `.Some` /// and failing values are `.None`. - public func suchThatOptional(_ p : @escaping (A) -> Bool) -> Gen> { - return Gen>.sized { n in - return attemptBoundedTry(self, 0, max(n, 1), p) - } + public func suchThatOptional(_ pred : @escaping (A) -> Bool) -> Gen> { + return Gen>(unGen: { r, n in + // Attempts a bounded search over the space of generated values of + // a size determined by a monotonically decreasing linear function. + var bound = max(n, 1) + var k = 0 + var scrutinee : A = self.unGen(r, 2 * k + bound) + while !pred(scrutinee) { + if bound == 0 { + return .none + } + + k = k + 1 + bound = bound - 1 + scrutinee = self.unGen(r, 2 * k + bound) + } + return .some(scrutinee) + }) } /// Modifies a Generator such that it produces arrays with a length @@ -371,18 +385,6 @@ private func vary(_ k : S, _ rng : StdGen) -> StdGen { return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func attemptBoundedTry(_ gen : Gen, _ k : Int, _ bound : Int, _ pred : @escaping (A) -> Bool) -> Gen> { - if bound == 0 { - return Gen.pure(.none) - } - return gen.resize(2 * k + bound).flatMap { x in - if pred(x) { - return Gen.pure(.some(x)) - } - return attemptBoundedTry(gen, (k + 1), bound - 1, pred) - } -} - private func size(_ k : S, _ m : Int) -> Int { let n = Double(m) return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) From e92c25b9a68b5574ff75f5e9979d1d21bcb86aa9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 14 Oct 2016 16:04:57 -0400 Subject: [PATCH 374/460] Unroll suchThat --- Sources/Gen.swift | 42 +++++++++++-------- Sources/Test.swift | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 12 ++++-- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcschemes/SwiftCheck.xcscheme | 2 +- Tests/SwiftCheckTests/PropertySpec.swift | 2 +- Tests/SwiftCheckTests/SimpleSpec.swift | 9 ---- 8 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 69ca097..60489f4 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -210,25 +210,29 @@ extension Gen { /// /// Because the Generator will spin until it reaches a non-failing case, /// executing a condition that fails more often than it succeeds may result - /// in a space leak. At that point, it is better to use `suchThatOptional` - /// or `.invert` the test case. + /// in a blocked thread. At that point, it is better to use + /// `suchThatOptional` or `.invert` the test case. public func suchThat(_ p : @escaping (A) -> Bool) -> Gen { - return self.suchThatOptional(p).flatMap { mx in - switch mx { - case .some(let x): - return Gen.pure(x) - case .none: - return Gen.sized { n in - return self.suchThat(p).resize((n + 1)) - } + return Gen(unGen: { r, n in + let valGen = self.suchThatOptional(p) + + var size = n + var r1 = r + var scrutinee : A? = valGen.unGen(r, size) + while scrutinee == nil { + let (rl, rr) = r1.split + size = size + 1 + scrutinee = valGen.unGen(rr, size) + r1 = rl } - } + return scrutinee! + }) } /// Modifies a Generator such that it attempts to generate values that /// satisfy a predicate. All attempts are encoded in the form of an - /// `Optional` where values satisfying the predicate are wrapped in `.Some` - /// and failing values are `.None`. + /// `Optional` where values satisfying the predicate are wrapped in `.some` + /// and failing values are `.none`. public func suchThatOptional(_ pred : @escaping (A) -> Bool) -> Gen> { return Gen>(unGen: { r, n in // Attempts a bounded search over the space of generated values of @@ -331,11 +335,13 @@ extension Gen /*: Monad*/ { /// in the order they were given to the function exactly once. Thus all arrays /// generated are of the same rank as the array that was given. public func sequence(_ ms : [Gen]) -> Gen<[A]> { - return ms.reduce(Gen<[A]>.pure([]), { n, m in - return m.flatMap { x in - return n.flatMap { xs in - return Gen<[A]>.pure(xs + [x]) - } + return Gen<[A]>(unGen: { r, n in + var r1 = r + return ms.map { m in + let (rl, rr) = r1.split + let v = m.unGen(rl, n) + r1 = rr + return v } }) } diff --git a/Sources/Test.swift b/Sources/Test.swift index bb38892..1be7eda 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -1014,7 +1014,7 @@ private func printDistributionGraph(_ st : CheckerState) { } let gAllLabels : [String] = st.collected.map({ (s : Set) in - return Array(s).filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) + return s.filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) }) let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 62e631f..5cddeb2 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -497,7 +497,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0810; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -769,6 +769,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; @@ -801,6 +802,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; @@ -879,8 +881,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; @@ -925,8 +929,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; @@ -1062,7 +1068,7 @@ 84DF760C1B0BD54600C912B0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1100,7 +1106,7 @@ 84DF760D1B0BD54600C912B0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index 81d7615..0881581 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ ) in return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") - }.expectFailure + }.expectFailure property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in let p = p2 ==> p1 diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index 145c1eb..c276b00 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -198,19 +198,10 @@ class SimpleSpec : XCTestCase { return a != b } } - - func testComposeWithMutableType() { - property("composition allows setting values on mutable types") - <- (forAll { (a: ArbitraryMutableFoo, b: ArbitraryMutableFoo) in - return a != b - // !!!: for some reason this always gets a size of 0, so using mapSize as a hack to increase size - }.mapSize { $0 + 100 }) - } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) static var allTests = testCase([ ("testAll", testAll), - ("testComposeWithMutableType", testComposeWithMutableType), ]) #endif } From 9c5cffc7fc300fc9149633b6550b30739eb90da9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 16 Oct 2016 17:18:27 -0400 Subject: [PATCH 375/460] Rename some combinators to follow Swift 3's naming guidelines --- README.md | 8 ++-- Sources/Arbitrary.swift | 13 +++--- Sources/Compose.swift | 4 +- Sources/Gen.swift | 58 ++++++++++++++++++++----- Sources/Property.swift | 6 +-- Tests/SwiftCheckTests/ComplexSpec.swift | 26 +++++------ Tests/SwiftCheckTests/GenSpec.swift | 28 ++++++------ Tests/SwiftCheckTests/LambdaSpec.swift | 2 +- Tests/SwiftCheckTests/PathSpec.swift | 4 +- Tests/SwiftCheckTests/RoseSpec.swift | 2 +- Tests/SwiftCheckTests/SimpleSpec.swift | 5 +-- 11 files changed, 96 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index cae5198..26f92d9 100644 --- a/README.md +++ b/README.md @@ -276,13 +276,13 @@ with custom generators as simple as possible: ```swift let onlyEven = Int.arbitrary.suchThat { $0 % 2 == 0 } -let vowels = Gen.fromElementsOf([ "A", "E", "I", "O", "U" ]) +let vowels = Gen.fromElements(of: [ "A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) -let uppers : Gen= Gen.fromElementsIn("A"..."Z") -let lowers : Gen = Gen.fromElementsIn("a"..."z") -let numbers : Gen = Gen.fromElementsIn("0"..."9") +let uppers : Gen= Gen.fromElements(in: "A"..."Z") +let lowers : Gen = Gen.fromElements(in: "a"..."z") +let numbers : Gen = Gen.fromElements(in: "0"..."9") /// This generator will generate `.none` 1/4 of the time and an arbitrary /// `.some` 3/4 of the time diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index a19bef7..d8b1cf6 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -265,9 +265,8 @@ extension Double : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return numerator.flatMap { a in - return denominator.flatMap { b in Gen.pure(Double(a) / Double(b)) - } + return Gen<(Int64, Int64)>.zip(numerator, denominator).map { a, b in + return Double(a) / Double(b) } } } @@ -300,7 +299,7 @@ extension UnicodeScalar : Arbitrary { extension String : Arbitrary { /// Returns a generator of `String` values. public static var arbitrary : Gen { - let chars = Gen.sized(Character.arbitrary.proliferateSized) + let chars = Gen.sized(Character.arbitrary.proliferate(withSize:)) return chars.flatMap { Gen.pure(String($0)) } } @@ -333,7 +332,7 @@ extension AnyIndex : Arbitrary { extension Mirror : Arbitrary { /// Returns a generator of `Mirror` values. public static var arbitrary : Gen { - let genAny : Gen = Gen.oneOf([ + let genAny : Gen = Gen.one(of: [ Bool.arbitrary.map { x in x as Any }, Int.arbitrary.map { x in x as Any }, UInt.arbitrary.map { x in x as Any }, @@ -342,13 +341,13 @@ extension Mirror : Arbitrary { Character.arbitrary.map { x in x as Any }, ]) - let genAnyWitnessed : Gen = Gen.oneOf([ + let genAnyWitnessed : Gen = Gen.one(of: [ Optional.arbitrary.map { x in x as Any }, Array.arbitrary.map { x in x as Any }, Set.arbitrary.map { x in x as Any }, ]) - return Gen.oneOf([ + return Gen.one(of: [ genAny, genAnyWitnessed, ]).map(Mirror.init) diff --git a/Sources/Compose.swift b/Sources/Compose.swift index dc6b80d..1b348e1 100644 --- a/Sources/Compose.swift +++ b/Sources/Compose.swift @@ -50,8 +50,8 @@ extension Gen { /// /// - seealso: Gen.compose public final class GenComposer { - private var stdgen: StdGen - private var size: Int + private var stdgen : StdGen + private var size : Int fileprivate init(_ stdgen : StdGen, _ size : Int) { self.stdgen = stdgen diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 60489f4..8882336 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,10 +44,10 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElementsOf(_ xs : S) -> Gen + public static func fromElements(of xs : S) -> Gen where S.Index : Comparable & RandomType { - return Gen.fromElementsIn(xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in + return Gen.fromElements(in: xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } } @@ -56,7 +56,7 @@ public struct Gen { /// interval and produces only that value. /// /// The input interval is required to be non-empty. - public static func fromElementsIn(_ xs : ClosedRange) -> Gen { + public static func fromElements(in xs : ClosedRange) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") return choose((xs.lowerBound, xs.upperBound)) @@ -67,7 +67,7 @@ public struct Gen { /// increases with the receiver's size parameter. /// /// The input array is required to be non-empty. - public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { + public static func fromInitialSegments(of xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") return Gen<[S]>.sized { n in @@ -77,8 +77,8 @@ public struct Gen { } /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { - return choose((Int.min + 1, Int.max)).proliferateSized(xs.count).flatMap { ns in + public static func fromShufflingElements(of xs : [S]) -> Gen<[S]> { + return choose((Int.min + 1, Int.max)).proliferate(withSize: xs.count).flatMap { ns in return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) } } @@ -119,7 +119,7 @@ public struct Gen { /// /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. - public static func oneOf(_ gs : S) -> Gen + public static func one(of gs : S) -> Gen where S.Iterator.Element == Gen, S.Index : RandomType & Comparable { assert(gs.count != 0, "oneOf used with empty list") @@ -257,7 +257,7 @@ extension Gen { /// determined by the receiver's size parameter. public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((0, n)).flatMap(self.proliferateSized) + return Gen.choose((0, n)).flatMap(self.proliferate(withSize:)) } } @@ -265,16 +265,54 @@ extension Gen { /// length determined by the receiver's size parameter. public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))).flatMap(self.proliferateSized) + return Gen.choose((1, max(1, n))).flatMap(self.proliferate(withSize:)) } } /// Modifies a Generator such that it only produces arrays of a given length. - public func proliferateSized(_ k : Int) -> Gen<[A]> { + public func proliferate(withSize k : Int) -> Gen<[A]> { return sequence(Array>(repeating: self, count: k)) } } +extension Gen { + @available(*, unavailable, renamed: "fromElements(of:)") + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : Comparable & RandomType + { + return Gen.fromElements(of: xs) + } + + + @available(*, unavailable, renamed: "fromElements(in:)") + public static func fromElementsIn(_ xs : ClosedRange) -> Gen { + return Gen.fromElements(in: xs) + } + + @available(*, unavailable, renamed: "fromInitialSegments(of:)") + public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { + return Gen.fromInitialSegments(of: xs) + } + + @available(*, unavailable, renamed: "fromShufflingElements(of:)") + public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { + return Gen.fromShufflingElements(of: xs) + } + + + @available(*, unavailable, renamed: "one(of:)") + public static func oneOf(_ gs : S) -> Gen + where S.Iterator.Element == Gen, S.Index : RandomType & Comparable + { + return Gen.one(of: gs) + } + + @available(*, unavailable, renamed: "proliferate(withSize:)") + public func proliferateSized(_ k : Int) -> Gen<[A]> { + return self.proliferate(withSize: k) + } +} + // MARK: Instances extension Gen /*: Functor*/ { diff --git a/Sources/Property.swift b/Sources/Property.swift index 6ed35b2..4ded58a 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -66,7 +66,7 @@ public func disjoin(_ ps : Testable...) -> Property { /// any of the given `Testable` expressions. public func conjamb(_ ps : () -> Testable...) -> Property { let ls = ps.lazy.map { $0().property.unProperty } - return Property(Gen.oneOf(ls)).again + return Property(Gen.one(of: ls)).again } extension Testable { @@ -440,9 +440,9 @@ public enum Quantification { /// Existential Quanfication ("there exists"). case existential /// Uniqueness Quantification ("there exists one and only one") - // case Uniqueness +// case Uniqueness /// Counting Quantification ("there exist exactly k") - // case Counting +// case Counting } /// A `TestResult` represents the result of performing a single test. diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 56da96f..c2ce36f 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -9,25 +9,25 @@ import SwiftCheck import XCTest -let upper : Gen= Gen.fromElementsIn("A"..."Z") -let lower : Gen = Gen.fromElementsIn("a"..."z") -let numeric : Gen = Gen.fromElementsIn("0"..."9") -let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) -let hexDigits = Gen.oneOf([ - Gen.fromElementsIn("A"..."F"), +let upper : Gen= Gen.fromElements(in: "A"..."Z") +let lower : Gen = Gen.fromElements(in: "a"..."z") +let numeric : Gen = Gen.fromElements(in: "0"..."9") +let special : Gen = Gen.fromElements(of: ["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +let hexDigits = Gen.one(of: [ + Gen.fromElements(in: "A"..."F"), numeric, ]) class ComplexSpec : XCTestCase { func testEmailAddressProperties() { - let localEmail = Gen.oneOf([ + let localEmail = Gen.one(of: [ upper, lower, numeric, special, ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) - let hostname = Gen.oneOf([ + let hostname = Gen.one(of: [ lower, numeric, Gen.pure("-"), @@ -46,12 +46,12 @@ class ComplexSpec : XCTestCase { func testIPv6Properties() { - let gen1: Gen = hexDigits.proliferateSized(1).map{ String.init($0) + ":" } - let gen2: Gen = hexDigits.proliferateSized(2).map{ String.init($0) + ":" } - let gen3: Gen = hexDigits.proliferateSized(3).map{ String.init($0) + ":" } - let gen4: Gen = hexDigits.proliferateSized(4).map{ String.init($0) + ":" } + let gen1 : Gen = hexDigits.proliferate(withSize: 1).map{ String.init($0) + ":" } + let gen2 : Gen = hexDigits.proliferate(withSize: 2).map{ String.init($0) + ":" } + let gen3 : Gen = hexDigits.proliferate(withSize: 3).map{ String.init($0) + ":" } + let gen4 : Gen = hexDigits.proliferate(withSize: 4).map{ String.init($0) + ":" } - let ipHexDigits = Gen.oneOf([ + let ipHexDigits = Gen.one(of: [ gen1, gen2, gen3, diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index c4148dc..4ad6d73 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -71,30 +71,30 @@ class GenSpec : XCTestCase { return Discard() } let l = Set(xss) - return forAll(Gen<[Int]>.fromElementsOf(xss)) { l.contains($0) } + return forAll(Gen<[Int]>.fromElements(of: xss)) { l.contains($0) } } property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen<[Int]>.fromElementsOf([n1, n2])) { $0 == n1 || $0 == n2 } + return forAll(Gen<[Int]>.fromElements(of: [n1, n2])) { $0 == n1 || $0 == n2 } } property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in return (n1 < n2) ==> { let interval = n1...n2 - return forAll(Gen<[Int]>.fromElementsIn(n1...n2)) { interval.contains($0) } + return forAll(Gen<[Int]>.fromElements(in: n1...n2)) { interval.contains($0) } } } property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in return !xs.isEmpty ==> { - return forAllNoShrink(Gen<[Int]>.fromInitialSegmentsOf(xs)) { (ys : Array) in + return forAllNoShrink(Gen<[Int]>.fromInitialSegments(of: xs)) { (ys : Array) in return xs.starts(with: ys) } } } property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in - return forAllNoShrink(Gen<[Int]>.fromShufflingElementsOf(xs)) { (ys : Array) in + return forAllNoShrink(Gen<[Int]>.fromShufflingElements(of: xs)) { (ys : Array) in return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) } } @@ -104,21 +104,21 @@ class GenSpec : XCTestCase { return Discard() } let l = Set(xss.getArray) - return forAll(Gen.oneOf(xss.getArray.map(Gen.pure))) { l.contains($0) } + return forAll(Gen.one(of: xss.getArray.map(Gen.pure))) { l.contains($0) } } property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in let g1 = Gen.pure(n1) let g2 = Gen.pure(n2) - return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } + return forAll(Gen.one(of: [g1, g2])) { $0 == n1 || $0 == n2 } } property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = Int.arbitrary.proliferateSized(n).map(ArrayOf.init) + let g = Int.arbitrary.proliferate(withSize: n).map(ArrayOf.init) return forAll(g) { $0.getArray.count == n } } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferateSized(0).map(ArrayOf.init)) { + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferate(withSize: 0).map(ArrayOf.init)) { return $0.getArray.isEmpty } @@ -261,8 +261,8 @@ class GenSpec : XCTestCase { func testLaws() { /// Turns out Gen is a really sketchy monad because of the underlying randomness. - let lawfulGen = Gen>.fromElementsOf((0...500).map(Gen.pure)) - let lawfulArrowGen = Gen>>.fromElementsOf(ArrowOf.arbitrary.proliferateSized(10).generate.map(Gen.pure)) + let lawfulGen = Gen>.fromElements(of: (0...500).map(Gen.pure)) + let lawfulArrowGen = Gen>>.fromElements(of: ArrowOf.arbitrary.proliferate(withSize: 10).generate.map(Gen.pure)) property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in return (x.map(id)) == id(x) @@ -331,7 +331,7 @@ internal func • (f : @escaping (B) -> C, g : @escaping (A) -> B) -> ( } private func ==(l : Gen, r : Gen) -> Bool { - return l.proliferateSized(10).generate == r.proliferateSized(10).generate + return l.proliferate(withSize: 10).generate == r.proliferate(withSize: 10).generate } /// `Gen` product is associative and has a natural isomorphism. @@ -343,8 +343,8 @@ private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> let normalizedR = rhs.map { ($0.0, $0.1, $1) } let sampleSize = 10 - let sampleL = normalizedL.proliferateSized(sampleSize).generate - let sampleR = normalizedR.proliferateSized(sampleSize).generate + let sampleL = normalizedL.proliferate(withSize: sampleSize).generate + let sampleR = normalizedR.proliferate(withSize: sampleSize).generate for (tupleL, tupleR) in zip(sampleL, sampleR) { guard tupleL == tupleR else { return false } diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index f38692b..fae6882 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -13,7 +13,7 @@ struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { let unName : String static var arbitrary : Gen { - let gc : Gen = Gen.fromElementsIn("a"..."z") + let gc : Gen = Gen.fromElements(in: "a"..."z") return gc.map { Name(unName: String($0)) } } diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index f49fc9b..bbb6a82 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -14,8 +14,8 @@ struct Path : Arbitrary { private static func pathFrom(_ x : A) -> Gen<[A]> { return Gen.sized { n in - return Gen<[A]>.oneOf( - [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } + return Gen<[A]>.one( + of: [Gen.pure([])] + A.shrink(x).map { pathFrom($0).resize(n - 1) } ).map { [x] + $0 } } } diff --git a/Tests/SwiftCheckTests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift index 6885e01..2369218 100644 --- a/Tests/SwiftCheckTests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -105,7 +105,7 @@ private func arbTree(_ n : Int) -> Gen> { } return Positive.arbitrary.flatMap { m in let n2 = n / (m.getPositive + 1) - return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferateSized(m.getPositive)).flatMap { (a, f) in + return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferate(withSize: m.getPositive)).flatMap { (a, f) in return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) } } diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index c276b00..8cb21c1 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -69,8 +69,7 @@ public struct ArbitraryLargeFoo { extension ArbitraryLargeFoo: Equatable {} public func ==(i: ArbitraryLargeFoo, j: ArbitraryLargeFoo) -> Bool { - return - i.a == j.a + return i.a == j.a && i.b == j.b && i.c == j.c && i.d == j.d @@ -181,7 +180,7 @@ class SimpleSpec : XCTestCase { let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) - let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElementsOf([ + let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElements(of: [ greaterThan_lessThanEqualTo, lessThan_greaterThanEqualTo, equalTo_notEqualTo, From 3123dfa3c7934c2905951d82a59191ffe5e4d165 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 16 Oct 2016 17:42:51 -0400 Subject: [PATCH 376/460] Migrate tutorial --- Tutorial.playground/Contents.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index c4f014e..0409ab8 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -71,7 +71,7 @@ onlyFive.generate // `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the // given Range. Because generation is random, some values may be repeated. -let fromOnetoFive = Gen.fromElementsIn(1...5) +let fromOnetoFive = Gen.fromElements(in: 1...5) fromOnetoFive.generate fromOnetoFive.generate @@ -79,13 +79,13 @@ fromOnetoFive.generate fromOnetoFive.generate fromOnetoFive.generate -let lowerCaseLetters : Gen = Gen.fromElementsIn("a"..."z") +let lowerCaseLetters : Gen = Gen.fromElements(in: "a"..."z") lowerCaseLetters.generate lowerCaseLetters.generate lowerCaseLetters.generate -let upperCaseLetters : Gen = Gen.fromElementsIn("A"..."Z") +let upperCaseLetters : Gen = Gen.fromElements(in: "A"..."Z") upperCaseLetters.generate upperCaseLetters.generate @@ -94,7 +94,7 @@ upperCaseLetters.generate // `Gen.fromElementsOf` works like `Gen.fromElementsIn` but over an Array, not just a Range. // // mnemonic: Use `fromElementsIn` with an INdex. -let specialCharacters = Gen.fromElementsOf([ "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" ]) +let specialCharacters = Gen.fromElements(of: [ "!", "@", "#", "$", "%", "^", "&", "*", "(", ")" ]) specialCharacters.generate specialCharacters.generate @@ -105,7 +105,7 @@ specialCharacters.generate //: amazing ways. // `Gen.oneOf` randomly picks one of the generators from the given list and draws element from it. -let uppersAndLowers = Gen.oneOf([ +let uppersAndLowers = Gen.one(of: [ lowerCaseLetters, upperCaseLetters, ]) @@ -206,12 +206,12 @@ generatorBoundedSizeArrays.generate //: numbers, and certain kinds of special characters. We already have generators for upper and //: lower cased letters, so all we need are special characters and a more complete number generator: -let numeric : Gen = Gen.fromElementsIn("0"..."9") -let special : Gen = Gen.fromElementsOf(["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) +let numeric : Gen = Gen.fromElements(in: "0"..."9") +let special : Gen = Gen.fromElements(of: ["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) //: Now for the actual generator -let allowedLocalCharacters : Gen = Gen.oneOf([ +let allowedLocalCharacters : Gen = Gen.one(of: [ upperCaseLetters, lowerCaseLetters, numeric, @@ -230,7 +230,7 @@ let localEmail = allowedLocalCharacters //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some //: steps here and combine them all into one big generator. -let hostname = Gen.oneOf([ +let hostname = Gen.one(of: [ lowerCaseLetters, numeric, Gen.pure("-"), @@ -505,7 +505,7 @@ func isPrime(_ n : Int) -> Bool { reportProperty("All Prime") <- forAll { (n : Positive) in let primes = sieve(n: n.getPositive) return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElementsOf(primes) + let primeNumberGen = Gen.fromElements(of: primes) return forAll(primeNumberGen) { (p : Int) in return isPrime(p) } @@ -587,7 +587,7 @@ func sieveProperly(_ n : Int) -> [Int] { property("All Prime") <- forAll { (n : Positive) in let primes = sieveProperly(n.getPositive) return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElementsOf(primes) + let primeNumberGen = Gen.fromElements(of: primes) return forAll(primeNumberGen) { (p : Int) in return isPrime(p) } From 73a3190e167fdd3fe6bebd010b063b8037642afe Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 23 Oct 2016 14:51:34 -0400 Subject: [PATCH 377/460] Add cocoapods detritus and bump podspec --- .swift-version | 1 + .travis.yml | 4 ++-- SwiftCheck.podspec | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..9f55b2c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/.travis.yml b/.travis.yml index 9919594..8a592b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,13 +7,13 @@ matrix: language: objective-c osx_image: xcode8 before_install: + - gem install cocoapods - git submodule update --init --recursive - pushd Utilities - ./compile.sh - popd script: - # Restore pod build before shipping for 3.0 - # - pod lib lint + - pod lib lint - carthage build --no-skip-current - os: osx language: objective-c diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index dfdce2e..0f7c283 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.6.2" + s.version = "0.7.1" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE @@ -35,6 +35,6 @@ Pod::Spec.new do |s| s.ios.deployment_target = "8.0" s.tvos.deployment_target = "9.0" s.framework = "XCTest" - s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } + s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "#{s.version}", :submodules => true } s.source_files = "Sources/*.swift" end From f5663365d266a76dd133d057caabca7ecb628c3b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 7 Nov 2016 21:40:53 -0500 Subject: [PATCH 378/460] Tone down the FloatingPoint shrinkers --- Sources/Arbitrary.swift | 28 ++++++++----------- .../SwiftCheckTests/BooleanIdentitySpec.swift | 2 +- Tests/SwiftCheckTests/ShrinkSpec.swift | 12 ++++++++ 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index d8b1cf6..a4aa3ac 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -242,13 +242,11 @@ extension Float : Arbitrary { /// The default shrinking function for `Float` values. public static func shrink(_ x : Float) -> [Float] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) + let tail = Int64(x).shrinkIntegral.map(Float.init(_:)) + if (x.sign == .minus) { + return [abs(x)] + tail + } + return tail } } @@ -273,13 +271,11 @@ extension Double : Arbitrary { /// The default shrinking function for `Double` values. public static func shrink(_ x : Double) -> [Double] { - return unfoldr({ i in - if i == 0.0 { - return .none - } - let n = i / 2.0 - return .some((n, n)) - }, initial: x) + let tail = Int64(x).shrinkIntegral.map(Double.init(_:)) + if (x.sign == .minus) { + return [abs(x)] + tail + } + return tail } } @@ -367,10 +363,10 @@ private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { var acc = [A]() var ini = initial while let next = f(ini) { - acc.insert(next.0, at: 0) + acc.append(next.0) ini = next.1 } - return acc + return acc.reversed() } #if os(Linux) diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index 57ab3cb..a228757 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -10,7 +10,7 @@ import SwiftCheck import XCTest class BooleanIdentitySpec : XCTestCase { - func testAll() { + func testAll() { property("Law of complements") <- forAll { (x : Bool) in return ((x || !x) == true) && ((x && !x) == false) } diff --git a/Tests/SwiftCheckTests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift index 6df6452..4b30b6e 100644 --- a/Tests/SwiftCheckTests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -9,6 +9,12 @@ import SwiftCheck import XCTest +#if os(Linux) + import Glibc +#else + import Darwin +#endif + class ShrinkSpec : XCTestCase { func shrinkArbitrary(_ x : A) -> [A] { let xs = A.shrink(x) @@ -37,6 +43,12 @@ class ShrinkSpec : XCTestCase { return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) } } + + property("Shrinking Double values does not loop") <- forAll { (n : Double) in + let left = pow(n, 0.5) + let right = sqrt(n) + return left == right + }.expectFailure } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) From 44642d8680e04f8c460f841c9d377a5fbab10092 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 30 Nov 2016 14:03:42 -0500 Subject: [PATCH 379/460] Remove dependence on self in ArrowOf and IsoOf `embed` and `project` may have to outlive the block in which they are called. Their destruction should be tied to the destruction of the blocks themselves which occurs after the last usage not the end of the creating block. --- Sources/Modifiers.swift | 40 ++++++----- SwiftCheck.xcodeproj/project.pbxproj | 8 +++ Tests/SwiftCheckTests/FormatterSpec.swift | 83 +++++++++++++++++++++++ 3 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 Tests/SwiftCheckTests/FormatterSpec.swift diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 85356b0..8bf7535 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -516,14 +516,15 @@ fileprivate final class ArrowOfImpl : } convenience init(_ arr : @escaping (T) -> U) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }) + var table = [T:U]() + self.init(table, { (_ : T) -> U in return undefined() }) - self.arr = { [unowned self] x in - if let v = self.table[x] { + self.arr = { x in + if let v = table[x] { return v } let y = arr(x) - self.table[x] = y + table[x] = y return y } } @@ -564,24 +565,25 @@ fileprivate final class IsoOfImpl U, _ project : @escaping (U) -> T) { - self.init(Dictionary(), { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + var table = [T:U]() + self.init(table, { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) - self.embed = { [unowned self] t in - if let v = self.table[t] { + self.embed = { t in + if let v = table[t] { return v } let y = embed(t) - self.table[t] = y + table[t] = y return y } - self.project = { [unowned self] u in - let ts = self.table.filter { $1 == u }.map { $0.0 } - if let k = ts.first, let _ = self.table[k] { + self.project = { u in + let ts = table.filter { $1 == u }.map { $0.0 } + if let k = ts.first, let _ = table[k] { return k } let y = project(u) - self.table[y] = u + table[y] = u return y } } @@ -601,17 +603,19 @@ fileprivate final class IsoOfImpl) -> [IsoOfImpl] { return f.table.flatMap { (x, y) in return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in - return IsoOfImpl({ (z : T) -> U in - if x == z { - return y2 - } - return f.embed(z) + return IsoOfImpl( + { (z : T) -> U in + if x == z { + return y2 + } + return f.embed(z) }, { (z : U) -> T in if y == z { return y1 } return f.project(z) - }) + } + ) }) } } diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 5cddeb2..5a9530b 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -96,6 +96,9 @@ 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; + 828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; + 828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; + 828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; @@ -192,6 +195,7 @@ 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; + 828B7C861DEF575C0066A994 /* FormatterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FormatterSpec.swift; path = Tests/SwiftCheckTests/FormatterSpec.swift; sourceTree = SOURCE_ROOT; }; 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -317,6 +321,7 @@ 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, + 828B7C861DEF575C0066A994 /* FormatterSpec.swift */, 825C9AD41D8EE86E003313E1 /* GenSpec.swift */, 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */, 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, @@ -649,6 +654,7 @@ 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */, 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */, 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); @@ -694,6 +700,7 @@ 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */, 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */, 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); @@ -739,6 +746,7 @@ 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */, + 828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */, 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */, 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, ); diff --git a/Tests/SwiftCheckTests/FormatterSpec.swift b/Tests/SwiftCheckTests/FormatterSpec.swift new file mode 100644 index 0000000..0473313 --- /dev/null +++ b/Tests/SwiftCheckTests/FormatterSpec.swift @@ -0,0 +1,83 @@ +// +// FormatterSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 11/30/16. +// Copyright © 2016 Typelift. All rights reserved. +// +// Spec due to broomburgo (https://github.com/broomburgo) meant to test lifetime +// issues in ArrowOf and IsoOf + +import SwiftCheck +import XCTest + +struct Formatter { + let lengthLimit : UInt + let makeString : (Value) -> String + let makeValue : (String) -> Value + + init(lengthLimit : UInt, makeString : @escaping (Value) -> String, makeValue : @escaping (String) -> Value) { + self.lengthLimit = lengthLimit + self.makeString = makeString + self.makeValue = makeValue + } + + func format(_ value : Value) -> String { + let formatted = makeString(value) + let maxIndex = formatted.index(formatted.startIndex, offsetBy: String.IndexDistance(lengthLimit)) + if maxIndex >= formatted.endIndex { + return formatted + } else { + return formatted.substring(to: maxIndex) + } + } + + func unFormat(_ string : String) -> Value { + let value = makeValue(string) + return value + } +} + +struct ArbitraryFormatter : Arbitrary { + private let formatter : Formatter + init(_ formatter : Formatter) { + self.formatter = formatter + } + + var get : Formatter { + return formatter + } + + static var arbitrary : Gen> { + return Gen.one(of: [ + Gen<(UInt, ArrowOf, ArrowOf)> + .zip(UInt.arbitrary, ArrowOf.arbitrary, ArrowOf.arbitrary) + .map { Formatter(lengthLimit: $0, makeString: $1.getArrow, makeValue: $2.getArrow) } + .map(ArbitraryFormatter.init), + Gen<(UInt, IsoOf)> + .zip(UInt.arbitrary, IsoOf.arbitrary) + .map { Formatter(lengthLimit: $0, makeString: $1.getTo, makeValue: $1.getFrom) } + .map(ArbitraryFormatter.init) + ]) + } +} + +class FormatterSpec : XCTestCase { + func testAlwaysCorrectLength() { + property( + "Any formatted string is shorter or equal than the provided length" + ) <- forAll { (x: Int, af: ArbitraryFormatter) in + let formatter = af.get + let string = formatter.format(x) + _ = formatter.unFormat(string) + return string.distance(from: string.startIndex, to: string.endIndex) <= String.IndexDistance(formatter.lengthLimit) + } + } + + + #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) + static var allTests = testCase([ + ("testAlwaysCorrectLength", testAlwaysCorrectLength), + ]) + #endif +} From 523b2194e14fa5e4858a6d84069a56d3ac670942 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 21 Jan 2017 19:10:23 -0500 Subject: [PATCH 380/460] Fix some hiccups in documentation --- README.md | 19 ++++++++++--------- Tutorial.playground/Contents.swift | 6 +++--- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 26f92d9..34d337b 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ tests to be treated like *data*. To define a program property the `forAll` quantifier is used with a type signature like `(A, B, C, ... Z) -> Testable where A : Arbitrary, B : Arbitrary ... -Z : Arbitrary`. SwiftCheck implements the `Arbitrary` protocol for most STL types -and implements the `Testable` protocol for `Bool` and several other related -types. For example, if we wanted to test the property that every Integer is -equal to itself, we would express it as such: +Z : Arbitrary`. SwiftCheck implements the `Arbitrary` protocol for most Swift +Standard Library types and implements the `Testable` protocol for `Bool` and +several other related types. For example, if we wanted to test the property +that every Integer is equal to itself, we would express it as such: ```swift func testAll() { @@ -193,10 +193,11 @@ Running SwiftCheck again reports a successful sieve of all 100 random cases: Custom Types ============ -SwiftCheck implements random generation for most of the types in the Swift STL. -Any custom types that wish to take part in testing must conform to the included -`Arbitrary` protocol. For the majority of types, this means providing a custom -means of generating random data and shrinking down to an empty array. +SwiftCheck implements random generation for most of the types in the Swift +Standard Library. Any custom types that wish to take part in testing must +conform to the included `Arbitrary` protocol. For the majority of types, this +means providing a custom means of generating random data and shrinking down to +an empty array. For example: @@ -293,7 +294,7 @@ let weightedOptionals = Gen.frequency([ ``` For instances of many complex or "real world" generators, see -[`ComplexSpec.swift`](Tests/ComplexSpec.swift). +[`ComplexSpec.swift`](Tests/SwiftCheckTests/ComplexSpec.swift). System Requirements =================== diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 0409ab8..5caea66 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -288,9 +288,9 @@ emailGen.generate //: for `Int` calls `arc4random_uniform`. //: //: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't -//: generate with another that we can–for a few of the more "difficult" types in the Swift STL, but -//: we also use them in more benign ways too. For example, we can write a modifier type that only -//: generates positive numbers: +//: generate with another that we can–for a few of the more "difficult" types in the Swift Standard +//: Library, but we also use them in more benign ways too. For example, we can write a modifier type +//: that only generates positive numbers: public struct ArbitraryPositive : Arbitrary { public let getPositive : A From 820453a78bd27513748f0dfca8b41d20902ba21d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 9 Oct 2016 18:51:36 -0400 Subject: [PATCH 381/460] Use FileCheck to test printed output --- SwiftCheck.xcodeproj/project.pbxproj | 8 + .../SwiftCheckTests/BooleanIdentitySpec.swift | 80 +- Tests/SwiftCheckTests/FileCheck.swift | 1154 +++++++++++++++++ 3 files changed, 1204 insertions(+), 38 deletions(-) create mode 100644 Tests/SwiftCheckTests/FileCheck.swift diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 5a9530b..e21f6e3 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -102,6 +102,9 @@ 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; + 82F3714C1DA7041300D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; + 82F3714D1DA7041400D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; + 82F3714E1DA7041500D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; @@ -197,6 +200,7 @@ 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; 828B7C861DEF575C0066A994 /* FormatterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FormatterSpec.swift; path = Tests/SwiftCheckTests/FormatterSpec.swift; sourceTree = SOURCE_ROOT; }; 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; + 82F371481DA7010800D60203 /* FileCheck.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FileCheck.swift; path = Tests/SwiftCheckTests/FileCheck.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -315,6 +319,7 @@ 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { isa = PBXGroup; children = ( + 82F371481DA7010800D60203 /* FileCheck.swift */, 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */, @@ -649,6 +654,7 @@ 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */, 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 82F3714C1DA7041300D60203 /* FileCheck.swift in Sources */, 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */, 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */, 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, @@ -695,6 +701,7 @@ 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */, 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 82F3714E1DA7041500D60203 /* FileCheck.swift in Sources */, 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */, 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */, 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, @@ -741,6 +748,7 @@ 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */, 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, + 82F3714D1DA7041400D60203 /* FileCheck.swift in Sources */, 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */, 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */, 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index a228757..746d802 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -10,57 +10,61 @@ import SwiftCheck import XCTest class BooleanIdentitySpec : XCTestCase { - func testAll() { - property("Law of complements") <- forAll { (x : Bool) in - return ((x || !x) == true) && ((x && !x) == false) - } + func testAll() { + assert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Law of complements") <- forAll { (x : Bool) in + return ((x || !x) == true) && ((x && !x) == false) + } - property("Law of double negation") <- forAll { (x : Bool) in - return !(!x) == x - } + property("Law of double negation") <- forAll { (x : Bool) in + return !(!x) == x + } - property("Law of idempotency") <- forAll { (x : Bool) in - return ((x || x) == x) && ((x && x) == x) - } + property("Law of idempotency") <- forAll { (x : Bool) in + return ((x || x) == x) && ((x && x) == x) + } - property("Law of dominance") <- forAll { (x : Bool) in - return ((x || false) == x) && ((x && true) == x) - } + property("Law of dominance") <- forAll { (x : Bool) in + return ((x || false) == x) && ((x && true) == x) + } - property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x || y) == (y || x)) && ((x && y) == (y && x)) - } + property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x || y) == (y || x)) && ((x && y) == (y && x)) + } - property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) - } + property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) + } - property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = !(x && y) == (!x || !y) - let r = !(x || y) == (!x && !y) - return l && r - } + property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r + } - property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x && (x || y)) == x - let r = (x || (x && y)) == x - return l && r - } + property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x && (x || y)) == x + let r = (x || (x && y)) == x + return l && r + } - property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x && (!x || y)) == (x && y) - let r = (x || (!x && y)) == (x || y) - return l && r - } + property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x && (!x || y)) == (x && y) + let r = (x || (!x && y)) == (x || y) + return l && r + } - property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) - } + property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) static var allTests = testCase([ - ("testAll", testAll), + ("testAll", testAll), ]) #endif } diff --git a/Tests/SwiftCheckTests/FileCheck.swift b/Tests/SwiftCheckTests/FileCheck.swift new file mode 100644 index 0000000..88a7601 --- /dev/null +++ b/Tests/SwiftCheckTests/FileCheck.swift @@ -0,0 +1,1154 @@ +// +// FileCheck.swift +// SwiftCheck +// +// Created by Robert Widmann on 10/6/16. +// Copyright © 2016 Typelift. All rights reserved. +// + +import Foundation +#if os(Linux) + import Glibc + + typealias NSRegularExpression = RegularExpression +#else + import Darwin +#endif + +/// `FileCheckOptions` enumerates a set of options that can modify the behavior +/// of the file check verification process. +public struct FileCheckOptions : OptionSet { + /// Retrieves the raw value of this option set. + public let rawValue : UInt64 + + /// Convert from a value of `RawValue`, succeeding unconditionally. + public init(rawValue : UInt64) { + self.rawValue = rawValue + } + + /// Do not treat all horizontal whitespace as equivalent. + public static let strictWhitespace = FileCheckOptions(rawValue: 1 << 0) + /// Add an implicit negative check with this pattern to every positive + /// check. This can be used to ensure that no instances of this pattern + /// occur which are not matched by a positive pattern. + public static let implicitCheckNot = FileCheckOptions(rawValue: 1 << 1) + /// Allow the input file to be empty. This is useful when making checks that + /// some error message does not occur, for example. + public static let allowEmptyInput = FileCheckOptions(rawValue: 1 << 2) + /// Require all positive matches to cover an entire input line. Allows + /// leading and trailing whitespace if `.strictWhitespace` is not also + /// passed. + public static let matchFullLines = FileCheckOptions(rawValue: 1 << 3) +} + +/// `FileCheckFD` represents the standard output streams `FileCheck` is capable +/// of overriding to gather output. +public enum FileCheckFD { + /// Standard output. + case stdout + /// Standard error. + case stderr + /// A custom output stream. + case custom(fileno: Int32, ptr: UnsafeMutablePointer) + + /// Retrieve the file descriptor for this output stream. + var fileno : Int32 { + switch self { + case .stdout: + return STDOUT_FILENO + case .stderr: + return STDERR_FILENO + case let .custom(fileno: fd, ptr: _): + return fd + } + } + + /// Retrieve the FILE pointer for this stream. + var filePtr : UnsafeMutablePointer! { + switch self { + case .stdout: + #if os(Linux) + return Glibc.stdout + #else + return Darwin.stdout + #endif + case .stderr: + #if os(Linux) + return Glibc.stderr + #else + return Darwin.stderr + #endif + case let .custom(fileno: _, ptr: ptr): + return ptr + } + } +} + +/// Reads from the given output stream and runs a file verification procedure +/// by comparing the output to a specified result. +/// +/// FileCheck requires total access to whatever input stream is being used. As +/// such it will override printing to said stream until the given block has +/// finished executing. +/// +/// - parameter FD: The file descriptor to override and read from. +/// - parameter prefixes: Specifies one or more prefixes to match. By default +/// these patterns are prefixed with "CHECK:". +/// - parameter file: The file to check against. Defaults to the file that +/// containing the call to `fileCheckOutput`. +/// - parameter options: Optional arguments to modify the behavior of the check. +/// - parameter blocK: The block in which output will be emitted to the given +/// file descriptor. +public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes : [String] = ["CHECK"], against file : String = #file, options: FileCheckOptions = [], block : () -> ()) -> Bool { + guard let validPrefixes = validateCheckPrefixes(prefixes) else { + print("Supplied check-prefix is invalid! Prefixes must be unique and ", + "start with a letter and contain only alphanumeric characters, ", + "hyphens and underscores") + return false + } + guard let PrefixRE = try? NSRegularExpression(pattern: validPrefixes.joined(separator: "|"), options: []) else { + print("Unable to combine check-prefix strings into a prefix regular ", + "expression! This is likely a bug in FileCheck's verification of ", + "the check-prefix strings. Regular expression parsing failed.") + return false + } + + let input = overrideFDAndCollectOutput(file: FD, of: block) + if (input.isEmpty && !options.contains(.allowEmptyInput)) { + print("FileCheck error: input from file descriptor \(FD) is empty.\n") + return false + } + + guard let contents = try? String(contentsOfFile: file, encoding: .utf8) else { + return false + } + let buf = contents.cString(using: .utf8)?.withUnsafeBufferPointer { buffer in + return readCheckStrings(in: buffer, withPrefixes: validPrefixes, options: options, PrefixRE) + } + guard let checkStrings = buf else { + return false + } + return check(input: input, against: checkStrings) +} + +private func overrideFDAndCollectOutput(file : FileCheckFD, of block : () -> ()) -> String { + fflush(stdout) + let oldFd = dup(file.fileno) + + let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.XXXXXX") + return template.withUnsafeFileSystemRepresentation { buffer in + guard let buffer = buffer else { + return "" + } + + let newFd = mkstemp(UnsafeMutablePointer(mutating: buffer)) + guard newFd != -1 else { + return "" + } + + dup2(newFd, file.fileno) + + block() + + close(newFd) + fflush(file.filePtr) + + + dup2(oldFd, file.fileno) + close(oldFd) + + let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil) + guard let s = try? String(contentsOf: url) else { + return "" + } + return s + } +} + +func validateCheckPrefixes(_ prefixes : [String]) -> [String]? { + let validator = try! NSRegularExpression(pattern: "^[a-zA-Z0-9_-]*$", options: []) + + for prefix in prefixes { + // Reject empty prefixes. + if prefix.isEmpty { + return nil + } + + let range = NSRange( + location: 0, + length: prefix.distance(from: prefix.startIndex, to: prefix.endIndex) + ) + if validator.matches(in: prefix, options: [], range: range).isEmpty { + return nil + } + } + + return [String](Set(prefixes)) +} + +extension CChar { + fileprivate var isPartOfWord : Bool { + return isalnum(Int32(self)) != 0 || UInt8(self) == "-".utf8.first! || UInt8(self) == "_".utf8.first! + } +} + +private func findCheckType(in buf : UnsafeBufferPointer, with prefix : String) -> CheckType { + let nextChar = UInt8(buf[prefix.utf8.count]) + + // Verify that the : is present after the prefix. + if nextChar == ":".utf8.first! { + return .plain + } + if nextChar != "-".utf8.first! { + return .none + } + + let rest = String( + bytesNoCopy: UnsafeMutableRawPointer( + mutating: buf.baseAddress!.advanced(by: prefix.utf8.count + 1) + ), + length: buf.count - (prefix.utf8.count + 1), + encoding: .utf8, + freeWhenDone: false + )! + if rest.hasPrefix("NEXT:") { + return .next + } + + if rest.hasPrefix("SAME:") { + return .same + } + + if rest.hasPrefix("NOT:") { + return .not + } + + if rest.hasPrefix("DAG:") { + return .dag + } + + if rest.hasPrefix("LABEL:") { + return .label + } + + // You can't combine -NOT with another suffix. + let badNotPrefixes = [ + "DAG-NOT:", + "NOT-DAG:", + "NEXT-NOT:", + "NOT-NEXT:", + "SAME-NOT:", + "NOT-SAME:", + ] + if badNotPrefixes.reduce(false, { (acc, s) in acc || rest.hasPrefix(s) }) { + return .badNot + } + + return .none +} + +extension UnsafeBufferPointer { + fileprivate func substr(_ Start : Int, _ Size : Int) -> UnsafeBufferPointer { + return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: Start), count: Size) + } + + fileprivate func dropFront(_ n : Int) -> UnsafeBufferPointer { + precondition(n < self.count) + return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: n), count: self.count - n) + } +} + +func substring(in buffer : UnsafeBufferPointer, with range : NSRange) -> String { + precondition(range.location + range.length <= buffer.count) + let ptr = buffer.substr(range.location, range.length) + return String(bytesNoCopy: UnsafeMutableRawPointer(mutating: ptr.baseAddress!), length: range.length, encoding: .utf8, freeWhenDone: false)! +} + +private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among prefixes : [String], with RE : NSRegularExpression, startingAt startLine: Int) -> (String, CheckType, Int, UnsafeBufferPointer) { + var lineNumber = startLine + var buffer = inbuffer + + while !buffer.isEmpty { + let str = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!), length: buffer.count, encoding: .utf8, freeWhenDone: false)! + let matches = RE.matches(in: str, options: [], range: NSRange(location: 0, length: buffer.count)) + guard let prefix = matches.first else { + return ("", .none, lineNumber, buffer) + } + let skippedPrefix = buffer.substr(0, prefix.range.location) + let prefixStr = substring(in: buffer, with: prefix.range) + + buffer = buffer.dropFront(prefix.range.location) + lineNumber += skippedPrefix.filter({ c in UInt8(c) == "\n".utf8.first! }).count + // Check that the matched prefix isn't a suffix of some other check-like + // word. + // FIXME: This is a very ad-hoc check. it would be better handled in some + // other way. Among other things it seems hard to distinguish between + // intentional and unintentional uses of this feature. + if skippedPrefix.isEmpty || !skippedPrefix.last!.isPartOfWord { + // Now extract the type. + let CheckTy = findCheckType(in: buffer, with: prefixStr) + + + // If we've found a valid check type for this prefix, we're done. + if CheckTy != .none { + return (prefixStr, CheckTy, lineNumber, buffer) + } + } + // If we didn't successfully find a prefix, we need to skip this invalid + // prefix and continue scanning. We directly skip the prefix that was + // matched and any additional parts of that check-like word. + // From the given position, find the next character after the word. + var loc = prefix.range.length + while loc < buffer.count && buffer[loc].isPartOfWord { + loc += 1 + } + buffer = buffer.dropFront(loc) + } + + return ("", .none, lineNumber, buffer) +} + + +private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes prefixes : [String], options: FileCheckOptions, _ RE : NSRegularExpression) -> [CheckString] { + // Keeps track of the line on which CheckPrefix instances are found. + var lineNumber = 1 + + // std::vector DagNotMatches = ImplicitNegativeChecks + var dagNotMatches = [Pattern]() + var contents = [CheckString]() + + var buffer = buf + while true { + // See if a prefix occurs in the memory buffer. + let (usedPrefix, checkTy, ln, newBuffer) = findFirstMatch(in: buffer, among: prefixes, with: RE, startingAt: lineNumber) + if usedPrefix.isEmpty { + break + } + lineNumber = ln + + // Skip the buffer to the end. + buffer = newBuffer.dropFront(usedPrefix.utf8.count + checkTy.size) + + // Complain about useful-looking but unsupported suffixes. + if checkTy == .badNot { + diagnose(.error, "unsupported -NOT combo on prefix '\(usedPrefix)'") + return [] + } + + // Okay, we found the prefix, yay. Remember the rest of the line, but + // ignore leading whitespace. + if !options.contains(.strictWhitespace) || !options.contains(.matchFullLines) { + guard let idx = buffer.index(where: { c in UInt8(c) != " ".utf8.first! && UInt8(c) != "\t".utf8.first! }) else { + return [] + } + buffer = buffer.dropFront(idx) + } + + // Scan ahead to the end of line. + let EOL : Int = buffer.index(of: CChar("\n".utf8.first!)) ?? buffer.index(of: CChar("\r".utf8.first!))! + + // Remember the location of the start of the pattern, for diagnostics. + let PatternLoc : SMLoc = SMLoc(fromPointer: buffer.baseAddress!) + + // Parse the pattern. + let pat : Pattern = Pattern(checking: checkTy) + let subBuffer = UnsafeBufferPointer(start: buffer.baseAddress, count: EOL) + if pat.parse(pattern: subBuffer, withPrefix: usedPrefix, at: lineNumber, options: options) { + return [] + } + + // Verify that CHECK-LABEL lines do not define or use variables + if (checkTy == .label) && pat.hasVariable { + diagnose(.error, "found '\(usedPrefix)-LABEL:' with variable definition or use") + return [] + } + + buffer = UnsafeBufferPointer( + start: buffer.baseAddress!.advanced(by: EOL), + count: buffer.count - EOL + ) + + // Verify that CHECK-NEXT lines have at least one CHECK line before them. + if (checkTy == .next || checkTy == .same) && contents.isEmpty { + let type = (checkTy == .next) ? "NEXT" : "SAME" + diagnose(.error, "found '\(usedPrefix)-\(type)' without previous '\(usedPrefix): line") + return [] + } + + // Handle CHECK-DAG/-NOT. + if checkTy == .dag || checkTy == .not { + dagNotMatches.append(pat) + continue + } + + // Okay, add the string we captured to the output vector and move on. + contents.append(CheckString(pattern: pat, prefix: usedPrefix, loc: PatternLoc)) +// std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) +// DagNotMatches = ImplicitNegativeChecks + } + + // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first + // prefix as a filler for the error message. +// if !DagNotMatches.isEmpty { +// CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(), +// SMLoc::getFromPointer(Buffer.data())) +// std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) +// } + + if contents.isEmpty { + print("error: no check strings found with prefix\(contents.count > 1 ? "es " : " ")") + for prefix in prefixes { + print("\(prefix):") + } + return [] + } + + return contents +} + +/// Check the input to FileCheck provided in the \p Buffer against the \p +/// CheckStrings read from the check file. +/// +/// Returns false if the input fails to satisfy the checks. +private func check(input b : String, against checkStrings : [CheckString]) -> Bool { + var buffer = b + var failedChecks = false + + // This holds all the current filecheck variables. + var variableTable = [String:String]() + + var i = 0 + var j = 0 + var e = checkStrings.count + while true { + var checkRegion : String + if j == e { + checkRegion = buffer + } else { + let checkStr = checkStrings[j] + if checkStr.pattern.type != .label { + j += 1 + continue + } + + // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG + guard let (matchLabelPos, matchLabelLen) = checkStr.check(buffer, true, variableTable) else { + // Immediately bail of CHECK-LABEL fails, nothing else we can do. + return false + } + + checkRegion = buffer.substring(to: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) + buffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) + j += 1 + } + + while i != j { + defer { i += 1 } + + // Check each string within the scanned region, including a second check + // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) + guard let (matchPos, matchLen) = checkStrings[i].check(checkRegion, false, variableTable) else { + failedChecks = true + i = j + break + } + + checkRegion = checkRegion.substring(from: checkRegion.index(checkRegion.startIndex, offsetBy: matchPos + matchLen)) + } + + if j == e { + break + } + } + + // Success if no checks failed. + return !failedChecks +} + + +struct SMLoc { + let unLoc : UnsafePointer? + + init() { + self.unLoc = nil + } + + init(fromPointer: UnsafePointer) { + self.unLoc = fromPointer + } +} + +enum CheckType { + case none + case plain + case next + case same + case not + case dag + case label + case badNot + + /// MatchEOF - When set, this pattern only matches the end of file. This is + /// used for trailing CHECK-NOTs. + case EOF + + // Get the size of the prefix extension. + var size : Int { + switch (self) { + case .none: + return 0 + case .badNot: + return 0 + case .plain: + return ":".utf8.count + case .next: + return "-NEXT:".utf8.count + case .same: + return "-SAME:".utf8.count + case .not: + return "-NOT:".utf8.count + case .dag: + return "-DAG:".utf8.count + case .label: + return "-LABEL:".utf8.count + case .EOF: + fatalError("Should not be using EOF size") + } + } +} + +class Pattern { + let patternLoc : SMLoc = SMLoc() + + let type : CheckType + + /// If non-empty, this pattern is a fixed string match with the specified + /// fixed string. + var fixedString : String = "" + + /// If non-empty, this is a regex pattern. + var regExPattern : String = "" + + /// Contains the number of line this pattern is in. + var lineNumber : Int = 0 + + /// Entries in this vector map to uses of a variable in the pattern, e.g. + /// "foo[[bar]]baz". In this case, the regExPattern will contain "foobaz" + /// and we'll get an entry in this vector that tells us to insert the value + /// of bar at offset 3. + var variableUses : Array<(String, Int)> = [] + + /// Maps definitions of variables to their parenthesized capture numbers. + /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1. + var variableDefs : Dictionary = [:] + + var hasVariable : Bool { + return !(variableUses.isEmpty && self.variableDefs.isEmpty) + } + + init(checking ty : CheckType) { + self.type = ty + } + + private func addBackrefToRegEx(_ backRef : Int) { + assert(backRef >= 1 && backRef <= 9, "Invalid backref number") + let Backref = "\\\(backRef)" + self.regExPattern += Backref + } + + /// - returns: Returns a value on success or nil on a syntax error. + private func evaluateExpression(_ e : String) -> String? { + var expr = e + // The only supported expression is @LINE([\+-]\d+)? + if !expr.hasPrefix("@LINE") { + return nil + } + expr = expr.substring(from: expr.index(expr.startIndex, offsetBy: "@LINE".utf8.count)) + guard let firstC = expr.utf8.first else { + return "\(self.lineNumber)" + } + + if firstC == "+".utf8.first! { + expr = expr.substring(from: expr.index(after: expr.startIndex)) + } else if firstC != "-".utf8.first! { + return nil + } + + guard let offset = Int(expr, radix: 10) else { + return nil + } + return "\(self.lineNumber + offset)" + } + + /// Matches the pattern string against the input buffer. + /// + /// This returns the position that is matched or npos if there is no match. If + /// there is a match, the size of the matched string is returned in \p + /// MatchLen. + /// + /// The \p VariableTable StringMap provides the current values of filecheck + /// variables and is updated if this match defines new values. + func match(_ buffer : String, _ variableTable : [String:String]) -> (Int, Int)? { + var matchLen : Int = 0 + // If this is the EOF pattern, match it immediately. + if self.type == .EOF { + matchLen = 0 + return (buffer.utf8.count, matchLen) + } + + // If this is a fixed string pattern, just match it now. + if !self.fixedString.isEmpty { + matchLen = self.fixedString.utf8.count + if let b = buffer.range(of: self.fixedString)?.lowerBound { + return (buffer.distance(from: buffer.startIndex, to: b), matchLen) + } + return nil + } + + // Regex match. + + // If there are variable uses, we need to create a temporary string with the + // actual value. + var regExToMatch = self.regExPattern + if !variableUses.isEmpty { + var insertOffset = 0 + for (v, offset) in variableUses { + var value : String = "" + + if v.utf8.first! == "@".utf8.first! { + guard let v = self.evaluateExpression(v) else { + return nil + } + value = v + } else { + guard let val = variableTable[v] else { + return nil + } + + // Look up the value and escape it so that we can put it into the regex. + value += NSRegularExpression.escapedPattern(for: val) + } + + // Plop it into the regex at the adjusted offset. + regExToMatch.insert(contentsOf: value.characters, at: regExToMatch.index(regExToMatch.startIndex, offsetBy: offset + insertOffset)) + insertOffset += value.utf8.count + } + } + + // Match the newly constructed regex. + guard let r = try? NSRegularExpression(pattern: regExToMatch, options: []) else { + return nil + } + let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.utf8.count)) + + // Successful regex match. + assert(!matchInfo.isEmpty, "Didn't get any match") + let fullMatch = matchInfo.first! + + // If this defines any variables, remember their values. + for (_, index) in self.variableDefs { + assert(index < matchInfo.count, "Internal paren error") +// VariableTable[VariableDef.0] = MatchInfo[VariableDef.second] + } + + matchLen = fullMatch.range.length + return (fullMatch.range.location, matchLen) + } + + /// Finds the closing sequence of a regex variable usage or definition. + /// + /// \p Str has to point in the beginning of the definition (right after the + /// opening sequence). Returns the offset of the closing sequence within Str, + /// or npos if it was not found. + private func findRegexVarEnd(_ regVar : String) -> Int? { + var string = regVar + // Offset keeps track of the current offset within the input Str + var offset = 0 + // [...] Nesting depth + var bracketDepth = 0 + + while !string.isEmpty { + if string.hasPrefix("]]") && bracketDepth == 0 { + return offset + } + if string.utf8.first! == "\\".utf8.first! { + // Backslash escapes the next char within regexes, so skip them both. + string = string.substring(from: string.index(string.startIndex, offsetBy: 2)) + offset += 2 + } else { + switch (string.utf8.first!) { + case "[".utf8.first!: + bracketDepth += 1 + case "]".utf8.first!: + if bracketDepth == 0 { + diagnose(.error, "missing closing \"]\" for regex variable") + exit(1) + } + bracketDepth -= 1 + default: + break + } + string = string.substring(from: string.index(after: string.startIndex)) + offset += 1 + } + } + + return nil + } + + private func addRegExToRegEx(_ RS : String, _ cur : Int) -> (Bool, Int) { + do { + let r = try NSRegularExpression(pattern: RS, options: []) + self.regExPattern += RS + return (false, cur + r.numberOfCaptureGroups) + } catch let e { + diagnose(.error, "invalid regex: \(e)") + return (true, cur) + } + } + + /// Parses the given string into the Pattern. + /// + /// \p Prefix provides which prefix is being matched, \p SM provides the + /// SourceMgr used for error reports, and \p LineNumber is the line number in + /// the input file from which the pattern string was read. Returns true in + /// case of an error, false otherwise. + func parse(pattern : UnsafeBufferPointer, withPrefix prefix : String, at lineNumber : Int, options: FileCheckOptions) -> Bool { + func mino(_ l : String.Index?, _ r : String.Index?) -> String.Index? { + if l == nil && r == nil { + return nil + } else if l == nil && r != nil { + return r + } else if l != nil && r == nil { + return l + } + return min(l!, r!) + } + + + self.lineNumber = lineNumber + var patternStr = substring(in: pattern, with: NSRange(location: 0, length: pattern.count)) + // let patternLoc = SMLoc(fromPointer: pat.baseAddress!) + + // Check that there is something on the line. + if patternStr.isEmpty { + diagnose(.error, "found empty check string with prefix '\(prefix):'") + return true + } + + // Check to see if this is a fixed string, or if it has regex pieces. + if !options.contains(.matchFullLines) && + (patternStr.utf8.count < 2 || + (patternStr.range(of: "{{") == nil + && + patternStr.range(of: "[[") == nil)) + { + self.fixedString = patternStr + return false + } + + if options.contains(.matchFullLines) { + regExPattern += "^" + if !options.contains(.strictWhitespace) { + regExPattern += " *" + } + } + + // Paren value #0 is for the fully matched string. Any new + // parenthesized values add from there. + var curParen = 1 + + // Otherwise, there is at least one regex piece. Build up the regex pattern + // by escaping scary characters in fixed strings, building up one big regex. + while !patternStr.isEmpty { + // RegEx matches. + if patternStr.range(of: "{{")?.lowerBound == patternStr.startIndex { + // This is the start of a regex match. Scan for the }}. + guard let End = patternStr.range(of: "}}") else { + diagnose(.error, "found start of regex string with no end '}}'") + return true + } + + // Enclose {{}} patterns in parens just like [[]] even though we're not + // capturing the result for any purpose. This is required in case the + // expression contains an alternation like: CHECK: abc{{x|z}}def. We + // want this to turn into: "abc(x|z)def" not "abcx|zdef". + regExPattern += "(" + curParen += 1 + + let (res, paren) = self.addRegExToRegEx(patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2)), curParen) + curParen = paren + if res { + return true + } + regExPattern += ")" + + patternStr = patternStr.substring(from: patternStr.index(End.lowerBound, offsetBy: 2)) + continue + } + + // Named RegEx matches. These are of two forms: [[foo:.*]] which matches .* + // (or some other regex) and assigns it to the FileCheck variable 'foo'. The + // second form is [[foo]] which is a reference to foo. The variable name + // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject + // it. This is to catch some common errors. + if patternStr.hasPrefix("[[") { + // Find the closing bracket pair ending the match. End is going to be an + // offset relative to the beginning of the match string. + guard let end = self.findRegexVarEnd(patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2))) else { + diagnose(.error, "invalid named regex reference, no ]] found") + return true + } + + let matchStr = patternStr.substring( + with: Range( + uncheckedBounds: ( + patternStr.index(patternStr.startIndex, offsetBy: 2), + patternStr.index(patternStr.startIndex, offsetBy: end) + ) + ) + ) + patternStr = patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: end + 4)) + + // Get the regex name (e.g. "foo"). + let nameEnd = matchStr.range(of: ":") + let name : String + if let end = nameEnd?.lowerBound { + name = matchStr.substring(to: end) + } else { + name = "" + } + + if name.isEmpty { + diagnose(.error, "invalid name in named regex: empty name") + return true + } + + // Verify that the name/expression is well formed. FileCheck currently + // supports @LINE, @LINE+number, @LINE-number expressions. The check here + // is relaxed, more strict check is performed in \c EvaluateExpression. + var isExpression = false + for (i, c) in name.utf8.enumerated() { + if i == 0 && c == "@".utf8.first! { + if nameEnd == nil { + diagnose(.error, "invalid name in named regex definition") + return true + } + isExpression = true + continue + } + if (c != "_".utf8.first! && isalnum(Int32(c)) == 0 && + (!isExpression || (c != "+".utf8.first! && c != "-".utf8.first!))) { + diagnose(.error, "invalid name in named regex") + return true + } + } + + // Name can't start with a digit. + if isdigit(Int32(name.utf8.first!)) != 0 { + diagnose(.error, "invalid name in named regex") + return true + } + + // Handle [[foo]]. + guard let ne = nameEnd else { + // Handle variables that were defined earlier on the same line by + // emitting a backreference. + if let VarParenNum = self.variableDefs[name] { + if VarParenNum < 1 || VarParenNum > 9 { + diagnose(.error, "Can't back-reference more than 9 variables") + return true + } + self.addBackrefToRegEx(VarParenNum) + } else { + variableUses.append((name, regExPattern.utf8.count)) + } + continue + } + + // Handle [[foo:.*]]. + self.variableDefs[name] = curParen + regExPattern += "(" + curParen += 1 + + let (res, paren) = self.addRegExToRegEx(matchStr.substring(from: matchStr.index(after: ne.lowerBound)), curParen) + curParen = paren + if res { + return true + } + + regExPattern += ")" + } + + // Handle fixed string matches. + // Find the end, which is the start of the next regex. + let fixedMatchEnd = mino(patternStr.range(of: "{{")?.lowerBound, patternStr.range(of: "[[")?.lowerBound) + self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd!)) + patternStr = patternStr.substring(from: fixedMatchEnd!) + } + + if options.contains(.matchFullLines) { + if !options.contains(.strictWhitespace) { + regExPattern += " *" + regExPattern += "$" + } + } + return false + } +} + +/// Count the number of newlines in the specified range. +func countNumNewlinesBetween(_ r : String) -> (Int, String.Index?) { + var range = r + var NumNewLines = 0 + var firstNewLine : String.Index? = nil + while true { + // Scan for newline. + guard let EOL = range.range(of: "\n")?.lowerBound ?? range.range(of: "\r")?.lowerBound else { + return (NumNewLines, firstNewLine) + } + range = range.substring(from: EOL) + if range.isEmpty { + return (NumNewLines, firstNewLine) + } + + NumNewLines += 1 + + // Handle \n\r and \r\n as a single newline. +// if Range.utf8.count > 1 && (Range.utf8[1] == '\n' || Range[1] == '\r') && (Range[0] != Range[1]) { +// Range = Range.substr(1) +// } + range = range.substring(from: range.index(after: range.startIndex)) + + if NumNewLines == 1 { + firstNewLine = range.startIndex + } + } +} + +/// CheckString - This is a check that we found in the input file. +struct CheckString { + /// Pat - The pattern to match. + let pattern : Pattern + + /// Prefix - Which prefix name this check matched. + let prefix : String + + /// Loc - The location in the match file that the check string was specified. + let loc : SMLoc + + /// DagNotStrings - These are all of the strings that are disallowed from + /// occurring between this match string and the previous one (or start of + /// file). + let dagNotStrings : Array = [] + + /// Match check string and its "not strings" and/or "dag strings". + func check(_ buffer : String, _ isLabelScanMode : Bool, _ variableTable : [String:String]) -> (Int, Int)? { + var lastPos = 0 + + // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL + // bounds we have not processed variable definitions within the bounded block + // yet so cannot handle any final CHECK-DAG yetthis is handled when going + // over the block again (including the last CHECK-LABEL) in normal mode. + if !isLabelScanMode { + // Match "dag strings" (with mixed "not strings" if any). + guard let lp = self.checkDAG(buffer, variableTable) else { + return nil + } + lastPos = lp + } + + // Match itself from the last position after matching CHECK-DAG. + let matchBuffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: lastPos)) + guard let (matchPos, matchLen) = self.pattern.match(matchBuffer, variableTable) else { +// PrintCheckFailed(*this, MatchBuffer, VariableTable) + return nil + } + + // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT + // or CHECK-NOT + if !isLabelScanMode { + let skippedRegion = buffer.substring( + with: Range( + uncheckedBounds: ( + buffer.index(buffer.startIndex, offsetBy: lastPos), + buffer.index(buffer.startIndex, offsetBy: matchPos) + ) + ) + ) + + // If this check is a "CHECK-NEXT", verify that the previous match was on + // the previous line (i.e. that there is one newline between them). + if self.checkNext(skippedRegion) { + return nil + } + + // If this check is a "CHECK-SAME", verify that the previous match was on + // the same line (i.e. that there is no newline between them). + if self.checkSame(skippedRegion) { + return nil + } + + // If this match had "not strings", verify that they don't exist in the + // skipped region. + if self.checkNot(skippedRegion, [], variableTable) { + return nil + } + } + + return (lastPos + matchPos, matchLen) + } + + /// Verify there is no newline in the given buffer. + func checkSame(_ Buffer : String) -> Bool { + if self.pattern.type != .same { + return false + } + + // Count the number of newlines between the previous match and this one. +// assert(Buffer.data() != +// SM.getMemoryBuffer(SM.FindBufferContainingLoc( +// SMLoc::getFromPointer(Buffer.data()))) +// ->getBufferStart() && +// "CHECK-SAME can't be the first check in a file") + + let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(Buffer) + if numNewLines != 0 { + diagnose(.error, self.prefix + "-SAME: is not on the same line as the previous match") + diagnose(.note, "'next' match was here") + diagnose(.note, "previous match ended here") + return true + } + + return false + } + + /// Verify there is a single line in the given buffer. + func checkNext(_ Buffer : String) -> Bool { + if self.pattern.type != .next { + return false + } + + // Count the number of newlines between the previous match and this one. +// assert(Buffer.data() != +// SM.getMemoryBuffer(SM.FindBufferContainingLoc( +// SMLoc::getFromPointer(Buffer.data()))) +// ->getBufferStart(), "CHECK-NEXT can't be the first check in a file") + + let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(Buffer) + if numNewLines == 0 { + diagnose(.error, prefix + "-NEXT: is on the same line as previous match") + diagnose(.note, "'next' match was here") + diagnose(.note, "previous match ended here") + return true + } + + if numNewLines != 1 { + diagnose(.error, prefix + "-NEXT: is not on the line after the previous match") + diagnose(.note, "'next' match was here") + diagnose(.note, "previous match ended here") + diagnose(.note, "non-matching line after previous match is here") + return true + } + + return false + } + + /// Verify there's no "not strings" in the given buffer. + func checkNot(_ Buffer : String, _ NotStrings : [Pattern], _ VariableTable : [String:String]) -> Bool { + for Pat in NotStrings { + assert(Pat.type == .not, "Expect CHECK-NOT!") + + guard let (_, _)/*(Pos, MatchLen)*/ = Pat.match(Buffer, VariableTable) else { + continue + } + + diagnose(.error, self.prefix + "-NOT: string occurred!") + diagnose(.note, self.prefix + "-NOT: pattern specified here") + return true + } + + return false + } + + /// Match "dag strings" and their mixed "not strings". + func checkDAG(_ buffer : String, _ variableTable : [String:String]) -> Int? { + var notStrings = [Pattern]() + if dagNotStrings.isEmpty { + return 0 + } + + var lastPos = 0 + var startPos = lastPos + + for pattern in self.dagNotStrings { + assert((pattern.type == .dag || pattern.type == .not), "Invalid CHECK-DAG or CHECK-NOT!") + + if pattern.type == .not { + notStrings.append(pattern) + continue + } + + assert((pattern.type == .dag), "Expect CHECK-DAG!") + + // CHECK-DAG always matches from the start. + let matchBuffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: startPos)) + // With a group of CHECK-DAGs, a single mismatching means the match on + // that group of CHECK-DAGs fails immediately. + guard let t = pattern.match(matchBuffer, variableTable) else { +// PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable) + return nil + } + var matchPos = t.0 + let matchLen = t.1 + + // Re-calc it as the offset relative to the start of the original string. + matchPos += startPos + + if !notStrings.isEmpty { + if matchPos < lastPos { + // Reordered? + diagnose(.error, prefix + "-DAG: found a match of CHECK-DAG reordering across a CHECK-NOT") + diagnose(.note, prefix + "-DAG: the farthest match of CHECK-DAG is found here") + diagnose(.note, prefix + "-NOT: the crossed pattern specified here") + diagnose(.note, prefix + "-DAG: the reordered pattern specified here") + return nil + } + // All subsequent CHECK-DAGs should be matched from the farthest + // position of all precedent CHECK-DAGs (including this one.) + startPos = lastPos + // If there's CHECK-NOTs between two CHECK-DAGs or from CHECK to + // CHECK-DAG, verify that there's no 'not' strings occurred in that + // region. + let skippedRegion = buffer.substring( + with: Range( + uncheckedBounds: ( + buffer.index(buffer.startIndex, offsetBy: lastPos), + buffer.index(buffer.startIndex, offsetBy: matchPos) + ) + ) + ) + if self.checkNot(skippedRegion, notStrings, variableTable) { + return nil + } + // Clear "not strings". + notStrings.removeAll() + } + + // Update the last position with CHECK-DAG matches. + lastPos = max(matchPos + matchLen, lastPos) + } + + return lastPos + } +} + +enum DiagnosticKind { + case error + case warning + case note +} + +func diagnose(_ kind : DiagnosticKind, _ message : String) { + print(message) +} From 8cf99e0e03a052fbfe26219a2564755559291f47 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 15 Jan 2017 22:31:45 -0700 Subject: [PATCH 382/460] Extend tests --- .../SwiftCheckTests/BooleanIdentitySpec.swift | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index 746d802..672a722 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -11,51 +11,69 @@ import XCTest class BooleanIdentitySpec : XCTestCase { func testAll() { - assert(fileCheckOutput { + XCTAssert(fileCheckOutput { // CHECK: *** Passed 100 tests // CHECK-NEXT: . property("Law of complements") <- forAll { (x : Bool) in return ((x || !x) == true) && ((x && !x) == false) } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of double negation") <- forAll { (x : Bool) in return !(!x) == x } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of idempotency") <- forAll { (x : Bool) in return ((x || x) == x) && ((x && x) == x) } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of dominance") <- forAll { (x : Bool) in return ((x || false) == x) && ((x && true) == x) } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of commutativity") <- forAll { (x : Bool, y : Bool) in return ((x || y) == (y || x)) && ((x && y) == (y && x)) } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in return (((x || y) || z) == (x || (y || z))) && (((x && y) && z) == (x && (y && z))) } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in let l = !(x && y) == (!x || !y) let r = !(x || y) == (!x && !y) return l && r } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("Law of absorbtion") <- forAll { (x : Bool, y : Bool) in let l = (x && (x || y)) == x let r = (x || (x && y)) == x return l && r } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in let l = (x && (!x || y)) == (x && y) let r = (x || (!x && y)) == (x || y) return l && r } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . property("3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in return ((x && y) || (x && z) || (!y && z)) == ((x && y) || (!y && z)) } @@ -64,7 +82,7 @@ class BooleanIdentitySpec : XCTestCase { #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) static var allTests = testCase([ - ("testAll", testAll), + ("testAll", testAll), ]) #endif } From 0af81361db1441c146261d32620eb61fd67df2f1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 15 Jan 2017 22:51:50 -0700 Subject: [PATCH 383/460] Bump swift version --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a592b3..0580adb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,9 +47,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-3.0-release/ubuntu1404/swift-3.0-RELEASE/swift-3.0-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-3.0-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-3.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-3.0.2-release/ubuntu1404/swift-3.0.2-RELEASE/swift-3.0.2-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-3.0.2-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-3.0.2-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd From 0f282fca604cd0c9611e44c7bbb5cce85c8fc09d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 16 Jan 2017 16:41:47 -0700 Subject: [PATCH 384/460] Filecheck more of the things --- Tests/SwiftCheckTests/DiscardSpec.swift | 27 +- Tests/SwiftCheckTests/FileCheck.swift | 62 ++- Tests/SwiftCheckTests/FormatterSpec.swift | 21 +- Tests/SwiftCheckTests/GenSpec.swift | 610 +++++++++++++--------- 4 files changed, 433 insertions(+), 287 deletions(-) diff --git a/Tests/SwiftCheckTests/DiscardSpec.swift b/Tests/SwiftCheckTests/DiscardSpec.swift index efb4601..07a22bc 100644 --- a/Tests/SwiftCheckTests/DiscardSpec.swift +++ b/Tests/SwiftCheckTests/DiscardSpec.swift @@ -11,19 +11,24 @@ import XCTest class DiscardSpec : XCTestCase { func testDiscardFailure() { - property("P != NP") <- Discard() - property("P = NP") <- Discard().expectFailure + XCTAssert(fileCheckOutput { + // CHECK: . + property("P != NP") <- Discard() + // CHECK-NEXT: . + property("P = NP") <- Discard().expectFailure - let args = CheckerArguments( - replay: Optional.some((newStdGen(), 10)), - maxAllowableSuccessfulTests: 200, - maxAllowableDiscardedTests: 0, - maxTestCaseSize: 1000 - ) + let args = CheckerArguments( + replay: Optional.some((newStdGen(), 10)), + maxAllowableSuccessfulTests: 200, + maxAllowableDiscardedTests: 0, + maxTestCaseSize: 1000 + ) - property("Discards forbidden", arguments: args) <- forAll { (x : UInt) in - return Discard() - }.expectFailure + // CHECK-NEXT: . + property("Discards forbidden", arguments: args) <- forAll { (x : UInt) in + return Discard() + }.expectFailure + }) } diff --git a/Tests/SwiftCheckTests/FileCheck.swift b/Tests/SwiftCheckTests/FileCheck.swift index 88a7601..380c711 100644 --- a/Tests/SwiftCheckTests/FileCheck.swift +++ b/Tests/SwiftCheckTests/FileCheck.swift @@ -132,7 +132,7 @@ public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes } private func overrideFDAndCollectOutput(file : FileCheckFD, of block : () -> ()) -> String { - fflush(stdout) + fflush(file.filePtr) let oldFd = dup(file.fileno) let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.XXXXXX") @@ -153,12 +153,11 @@ private func overrideFDAndCollectOutput(file : FileCheckFD, of block : () -> ()) close(newFd) fflush(file.filePtr) - dup2(oldFd, file.fileno) close(oldFd) let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil) - guard let s = try? String(contentsOf: url) else { + guard let s = try? String(contentsOf: url, encoding: .utf8) else { return "" } return s @@ -192,6 +191,13 @@ extension CChar { } } +extension Character { + fileprivate var isPartOfWord : Bool { + let utf8Value = String(self).utf8.first! + return isalnum(Int32(utf8Value)) != 0 || utf8Value == "-".utf8.first! || utf8Value == "_".utf8.first! + } +} + private func findCheckType(in buf : UnsafeBufferPointer, with prefix : String) -> CheckType { let nextChar = UInt8(buf[prefix.utf8.count]) @@ -270,21 +276,35 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among pref while !buffer.isEmpty { let str = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!), length: buffer.count, encoding: .utf8, freeWhenDone: false)! - let matches = RE.matches(in: str, options: [], range: NSRange(location: 0, length: buffer.count)) - guard let prefix = matches.first else { + let match = RE.firstMatch(in: str, options: [], range: NSRange(location: 0, length: str.distance(from: str.startIndex, to: str.endIndex))) + guard let prefix = match else { return ("", .none, lineNumber, buffer) } - let skippedPrefix = buffer.substr(0, prefix.range.location) - let prefixStr = substring(in: buffer, with: prefix.range) + let skippedPrefix = substring(in: buffer, with: NSMakeRange(0, prefix.range.location)) + let prefixStr = str.substring( + with: Range( + uncheckedBounds: ( + str.index(str.startIndex, offsetBy: prefix.range.location), + str.index(str.startIndex, offsetBy: NSMaxRange(prefix.range)) + ) + ) + ) - buffer = buffer.dropFront(prefix.range.location) - lineNumber += skippedPrefix.filter({ c in UInt8(c) == "\n".utf8.first! }).count + // HACK: Conversion between the buffer and `String` causes index + // mismatches when searching for strings. We're instead going to do + // something terribly inefficient here: Use the regular expression to + // look for check prefixes, then use Foundation's Data to find their + // actual locations in the buffer. + let bd = Data(buffer: buffer) + let range = bd.range(of: prefixStr.data(using: .utf8)!)! + buffer = buffer.dropFront(range.lowerBound) + lineNumber += skippedPrefix.characters.filter({ c in c == "\n" }).count // Check that the matched prefix isn't a suffix of some other check-like // word. // FIXME: This is a very ad-hoc check. it would be better handled in some // other way. Among other things it seems hard to distinguish between // intentional and unintentional uses of this feature. - if skippedPrefix.isEmpty || !skippedPrefix.last!.isPartOfWord { + if skippedPrefix.isEmpty || !skippedPrefix.characters.last!.isPartOfWord { // Now extract the type. let CheckTy = findCheckType(in: buffer, with: prefixStr) @@ -639,7 +659,7 @@ class Pattern { guard let r = try? NSRegularExpression(pattern: regExToMatch, options: []) else { return nil } - let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.utf8.count)) + let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.distance(from: buffer.startIndex, to: buffer.endIndex))) // Successful regex match. assert(!matchInfo.isEmpty, "Didn't get any match") @@ -776,7 +796,16 @@ class Pattern { regExPattern += "(" curParen += 1 - let (res, paren) = self.addRegExToRegEx(patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2)), curParen) + let pat = patternStr.substring( + with: Range( + uncheckedBounds: ( + patternStr.index(patternStr.startIndex, offsetBy: 2), + patternStr.index(End.upperBound, offsetBy: -2) + ) + ) + ) + + let (res, paren) = self.addRegExToRegEx(pat, curParen) curParen = paren if res { return true @@ -868,7 +897,7 @@ class Pattern { // Handle [[foo:.*]]. self.variableDefs[name] = curParen - regExPattern += "(" + self.regExPattern += "(" curParen += 1 let (res, paren) = self.addRegExToRegEx(matchStr.substring(from: matchStr.index(after: ne.lowerBound)), curParen) @@ -876,15 +905,14 @@ class Pattern { if res { return true } - - regExPattern += ")" + self.regExPattern += ")" } // Handle fixed string matches. // Find the end, which is the start of the next regex. let fixedMatchEnd = mino(patternStr.range(of: "{{")?.lowerBound, patternStr.range(of: "[[")?.lowerBound) - self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd!)) - patternStr = patternStr.substring(from: fixedMatchEnd!) + self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd ?? patternStr.endIndex)) + patternStr = patternStr.substring(from: fixedMatchEnd ?? patternStr.endIndex) } if options.contains(.matchFullLines) { diff --git a/Tests/SwiftCheckTests/FormatterSpec.swift b/Tests/SwiftCheckTests/FormatterSpec.swift index 0473313..f774140 100644 --- a/Tests/SwiftCheckTests/FormatterSpec.swift +++ b/Tests/SwiftCheckTests/FormatterSpec.swift @@ -64,14 +64,19 @@ struct ArbitraryFormatter : Arbitrar class FormatterSpec : XCTestCase { func testAlwaysCorrectLength() { - property( - "Any formatted string is shorter or equal than the provided length" - ) <- forAll { (x: Int, af: ArbitraryFormatter) in - let formatter = af.get - let string = formatter.format(x) - _ = formatter.unFormat(string) - return string.distance(from: string.startIndex, to: string.endIndex) <= String.IndexDistance(formatter.lengthLimit) - } + /// CHECK: *** Passed 100 tests + /// CHECK-NEXT: . + XCTAssert(fileCheckOutput { + property( + "Any formatted string is shorter or equal than the provided length" + ) <- forAll { (x: Int, af: ArbitraryFormatter) in + let formatter = af.get + let string = formatter.format(x) + _ = formatter.unFormat(string) + return string.distance(from: string.startIndex, to: string.endIndex) <= String.IndexDistance(formatter.lengthLimit) + } + + }) } diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index 4ad6d73..f40a5f9 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -12,300 +12,408 @@ import Foundation class GenSpec : XCTestCase { func testAll() { - property("Gen.frequency behaves") <- { - let g = Gen.frequency([ - (10, Gen.pure(0)), - (5, Gen.pure(1)), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.choose stays in bounds") <- forAll { (x : Int, y : Int) in - let (mx, mn) = (Swift.max(x, y), Swift.min(x, y)) - return forAll(Gen.choose((mn, mx))) { n in - return mn <= n && n <= mx - } - } - - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int.min <= x && x <= Int.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int8.min <= x && x <= Int8.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int16.min <= x && x <= Int16.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int32.min <= x && x <= Int32.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int64.min <= x && x <= Int64.max } - - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt.min <= x && x <= UInt.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt8.min <= x && x <= UInt8.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt16.min <= x && x <= UInt16.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt32.min <= x && x <= UInt32.max } - property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt64.min <= x && x <= UInt64.max } - - property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } - } - - property("Gen.weighted behaves") <- { - let g = Gen.weighted([ - (10, 0), - (5, 1), - ]) - - return forAll(g) { (i : Int) in - return true - } - } - - property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in - return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } - } - - property("The only value Gen.pure generates is the given value") <- { - let g = Gen.pure(0) - return forAll(g) { $0 == 0 } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in - if xss.isEmpty { - return Discard() - } - let l = Set(xss) - return forAll(Gen<[Int]>.fromElements(of: xss)) { l.contains($0) } - } - - property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen<[Int]>.fromElements(of: [n1, n2])) { $0 == n1 || $0 == n2 } - } - - property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in - return (n1 < n2) ==> { - let interval = n1...n2 - return forAll(Gen<[Int]>.fromElements(in: n1...n2)) { interval.contains($0) } - } - } - - property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in - return !xs.isEmpty ==> { - return forAllNoShrink(Gen<[Int]>.fromInitialSegments(of: xs)) { (ys : Array) in - return xs.starts(with: ys) + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.frequency behaves") <- { + let g = Gen.frequency([ + (10, Gen.pure(0)), + (5, Gen.pure(1)), + ]) + + return forAll(g) { (i : Int) in + return true } } - } - property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in - return forAllNoShrink(Gen<[Int]>.fromShufflingElements(of: xs)) { (ys : Array) in - return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.choose stays in bounds") <- forAll { (x : Int, y : Int) in + let (mx, mn) = (Swift.max(x, y), Swift.min(x, y)) + return forAll(Gen.choose((mn, mx))) { n in + return mn <= n && n <= mx + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int.min <= x && x <= Int.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int8.min <= x && x <= Int8.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int16.min <= x && x <= Int16.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int32.min <= x && x <= Int32.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in Int64.min <= x && x <= Int64.max } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt.min <= x && x <= UInt.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt8.min <= x && x <= UInt8.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt16.min <= x && x <= UInt16.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt32.min <= x && x <= UInt32.max } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.chooseAny stays in bounds") <- forAll(Gen.chooseAny()) { x in UInt64.min <= x && x <= UInt64.max } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.frequency with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.frequency(Array(repeating: (1, Gen.pure(0)), count: n))) { $0 == 0 } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.weighted behaves") <- { + let g = Gen.weighted([ + (10, 0), + (5, 1), + ]) + + return forAll(g) { (i : Int) in + return true + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.weighted with N arguments behaves") <- forAll(Gen.choose((1, 1000))) { n in + return forAll(Gen.weighted(Array(repeating: (1, 0), count: n))) { $0 == 0 } } - } - property("oneOf n") <- forAll { (xss : ArrayOf) in - if xss.getArray.isEmpty { - return Discard() + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("The only value Gen.pure generates is the given value") <- { + let g = Gen.pure(0) + return forAll(g) { $0 == 0 } } - let l = Set(xss.getArray) - return forAll(Gen.one(of: xss.getArray.map(Gen.pure))) { l.contains($0) } - } - property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in - let g1 = Gen.pure(n1) - let g2 = Gen.pure(n2) - return forAll(Gen.one(of: [g1, g2])) { $0 == n1 || $0 == n2 } - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (xss : Array) in + if xss.isEmpty { + return Discard() + } + let l = Set(xss) + return forAll(Gen<[Int]>.fromElements(of: xss)) { l.contains($0) } + } - property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = Int.arbitrary.proliferate(withSize: n).map(ArrayOf.init) - return forAll(g) { $0.getArray.count == n } - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in + return forAll(Gen<[Int]>.fromElements(of: [n1, n2])) { $0 == n1 || $0 == n2 } + } - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferate(withSize: 0).map(ArrayOf.init)) { - return $0.getArray.isEmpty - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in + return (n1 < n2) ==> { + let interval = n1...n2 + return forAll(Gen<[Int]>.fromElements(in: n1...n2)) { interval.contains($0) } + } + } - property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in - var n : Int = 0 - return forAll(Gen.sized { xx in - n = xx - return Int.arbitrary - }.resize(n)) { (x : Int) in - return x <= n + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in + return !xs.isEmpty ==> { + return forAllNoShrink(Gen<[Int]>.fromInitialSegments(of: xs)) { (ys : Array) in + return xs.starts(with: ys) + } + } } - } - property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in - var n : Int = 0 - return forAllNoShrink(Gen<[Int]>.sized({ xx in - n = xx - return [Int].arbitrary - }).resize(n)) { (xs : [Int]) in - return xs.count <= n + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in + return forAllNoShrink(Gen<[Int]>.fromShufflingElements(of: xs)) { (ys : Array) in + return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) + } } - } - property("Gen.suchThat in series obeys both predicates") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !(str.isEmpty || str.range(of: ",") != nil) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("oneOf n") <- forAll { (xss : ArrayOf) in + if xss.getArray.isEmpty { + return Discard() + } + let l = Set(xss.getArray) + return forAll(Gen.one(of: xss.getArray.map(Gen.pure))) { l.contains($0) } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in + let g1 = Gen.pure(n1) + let g2 = Gen.pure(n2) + return forAll(Gen.one(of: [g1, g2])) { $0 == n1 || $0 == n2 } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in + let g = Int.arbitrary.proliferate(withSize: n).map(ArrayOf.init) + return forAll(g) { $0.getArray.count == n } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferate(withSize: 0).map(ArrayOf.init)) { + return $0.getArray.isEmpty + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.resize bounds sizes for integers") <- forAll { (x : Int) in + var n : Int = 0 + return forAll(Gen.sized { xx in + n = xx + return Int.arbitrary + }.resize(n)) { (x : Int) in + return x <= n + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.resize bounds count for arrays") <- forAll { (x : Int) in + var n : Int = 0 + return forAllNoShrink(Gen<[Int]>.sized({ xx in + n = xx + return [Int].arbitrary + }).resize(n)) { (xs : [Int]) in + return xs.count <= n + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.suchThat in series obeys both predicates") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !(str.isEmpty || str.range(of: ",") != nil) + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.suchThat in series obeys its first property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return !str.isEmpty + } } - } - property("Gen.suchThat in series obeys its first property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return !str.isEmpty + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.suchThat in series obeys its last property") <- { + let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) + return forAll(g) { str in + return str.range(of: ",") == nil + } } - } - property("Gen.suchThat in series obeys its last property") <- { - let g = String.arbitrary.suchThat({ !$0.isEmpty }).suchThat({ $0.range(of: ",") == nil }) - return forAll(g) { str in - return str.range(of: ",") == nil + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in + return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in + return ss == xs + } } - } - property("Gen.sequence occurs in order") <- forAll { (xs : [String]) in - return forAllNoShrink(sequence(xs.map(Gen.pure))) { ss in - return ss == xs + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) -> Property in + let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) + return forAllNoShrink(g) { $0 == (x, y) } } - } - property("Gen.zip2 behaves") <- forAll { (x : Int, y : Int) -> Property in - let g = Gen<(Int, Int)>.zip(Gen.pure(x), Gen.pure(y)) - return forAllNoShrink(g) { $0 == (x, y) } - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in + let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) + let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) + return rightBiasedZip ~= leftBiasedZip + } - property("Gen.zip2 obeys the Cartesian associativity law") <- forAll { (x : Int, y : Int, z : Int) in - let rightBiasedZip: Gen<(Int, (Int, Int))> = .zip(.pure(x), .zip(.pure(y), .pure(z))) - let leftBiasedZip: Gen<((Int, Int), Int)> = .zip(.zip(.pure(x), .pure(y)), .pure(z)) - return rightBiasedZip ~= leftBiasedZip - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in + let fx = Gen.pure(x) + let ff = Gen>.pure(f).map { $0.getArrow } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + } - property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in - let fx = Gen.pure(x) - let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in + Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) + } - property("Gen.zip2 obeys the Monoidal Functor left identity law") <- forAll { (x : Int) in - Gen<(Void, Int)>.zip(.pure(()), .pure(x)).map { $0.1 } == .pure(x) - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in + Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) + } - property("Gen.zip2 obeys the Monoidal Functor right identity law") <- forAll { (x : Int) in - Gen<(Int, Void)>.zip(.pure(x), .pure(())).map { $0.0 } == .pure(x) - } - - property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in - let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) - return forAllNoShrink(g) { (x1, y1, z1) in - return (x1, y1, z1) == (x, y, z) - } - } - - property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in - let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) - return forAllNoShrink(g) { (x1, y1, z1, w1) in - return (x1, y1, z1, w1) == (x, y, z, w) - } - } - - property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in - let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in - return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in + let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) + return forAllNoShrink(g) { (x1, y1, z1) in + return (x1, y1, z1) == (x, y, z) + } } - } - - property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in + let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) + return forAllNoShrink(g) { (x1, y1, z1, w1) in + return (x1, y1, z1, w1) == (x, y, z, w) + } } - } - property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && c1 == c + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in + let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in + return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + } } - } - property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1) == (c, d) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + } } - } - property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1) == (c, d, e) + && c1 == c } } - } - property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - return forAll { (e : Int, f : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1, f1) == (c, d, e, f) + && (c1, d1) == (c, d) + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1) == (c, d, e) + } + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in + return forAll { (e : Int, f : Int) in + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) + return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in + return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + && (c1, d1, e1, f1) == (c, d, e, f) + } } } - } + }) } func testLaws() { - /// Turns out Gen is a really sketchy monad because of the underlying randomness. - let lawfulGen = Gen>.fromElements(of: (0...500).map(Gen.pure)) - let lawfulArrowGen = Gen>>.fromElements(of: ArrowOf.arbitrary.proliferate(withSize: 10).generate.map(Gen.pure)) - - property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.map(id)) == id(x) - } - - property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in - return forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.map(f.getArrow • g.getArrow)) == (x.map(g.getArrow).map(f.getArrow)) - } - } - - property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in - return (x.ap(Gen.pure(id))) == x - } - - property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return x.ap(g.ap(f.map(curry(•)))) == x.ap(g).ap(f) - } - - property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in - let f = fl.map({ $0.getArrow }) - let g = gl.map({ $0.getArrow }) - return x.ap(g.ap(f.ap(Gen.pure(curry(•))))) == x.ap(g).ap(f) - } - - property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - return Gen.pure(a).flatMap(f) == f(a) - } - - property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in - return (m.flatMap(Gen.pure)) == m - } - - property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in - let f : (Int) -> Gen = Gen.pure • fa.getArrow - let g : (Int) -> Gen = Gen.pure • ga.getArrow - return forAllNoShrink(lawfulGen) { (m : Gen) in - return m.flatMap(f).flatMap(g) == m.flatMap({ x in f(x).flatMap(g) }) - } - } + XCTAssert(fileCheckOutput(withPrefixes: ["LAW"]) { + /// Turns out Gen is a really sketchy monad because of the underlying randomness. + let lawfulGen = Gen>.fromElements(of: (0...500).map(Gen.pure)) + let lawfulArrowGen = Gen>>.fromElements(of: ArrowOf.arbitrary.proliferate(withSize: 10).generate.map(Gen.pure)) + + // LAW: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Functor identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.map(id)) == id(x) + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Functor composition law") <- forAll { (f : ArrowOf, g : ArrowOf) in + return forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.map(f.getArrow • g.getArrow)) == (x.map(g.getArrow).map(f.getArrow)) + } + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Applicative identity law") <- forAllNoShrink(lawfulGen) { (x : Gen) in + return (x.ap(Gen.pure(id))) == x + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the first Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return x.ap(g.ap(f.map(curry(•)))) == x.ap(g).ap(f) + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the second Applicative composition law") <- forAllNoShrink(lawfulArrowGen, lawfulArrowGen, lawfulGen) { (fl : Gen>, gl : Gen>, x : Gen) in + let f = fl.map({ $0.getArrow }) + let g = gl.map({ $0.getArrow }) + return x.ap(g.ap(f.ap(Gen.pure(curry(•))))) == x.ap(g).ap(f) + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Monad left identity law") <- forAll { (a : Int, fa : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + return Gen.pure(a).flatMap(f) == f(a) + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Monad right identity law") <- forAllNoShrink(lawfulGen) { (m : Gen) in + return (m.flatMap(Gen.pure)) == m + } + + // LAW-NEXT: *** Passed 100 tests + // LAW-NEXT: . + property("Gen obeys the Monad associativity law") <- forAll { (fa : ArrowOf, ga : ArrowOf) in + let f : (Int) -> Gen = Gen.pure • fa.getArrow + let g : (Int) -> Gen = Gen.pure • ga.getArrow + return forAllNoShrink(lawfulGen) { (m : Gen) in + return m.flatMap(f).flatMap(g) == m.flatMap({ x in f(x).flatMap(g) }) + } + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) From 16738fa39510c90a3df5e9ab4480239854b8e532 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 17 Jan 2017 22:25:36 -0500 Subject: [PATCH 385/460] FileCheck most of the things --- SwiftCheck.xcodeproj/project.pbxproj | 3 + Tests/SwiftCheckTests/ComplexSpec.swift | 87 ++-- Tests/SwiftCheckTests/FileCheck.swift | 496 ++++++++++++---------- Tests/SwiftCheckTests/FormatterSpec.swift | 4 +- Tests/SwiftCheckTests/LambdaSpec.swift | 2 +- Tests/SwiftCheckTests/ModifierSpec.swift | 100 +++-- Tests/SwiftCheckTests/PathSpec.swift | 8 +- Tests/SwiftCheckTests/PropertySpec.swift | 264 +++++++----- Tests/SwiftCheckTests/ShrinkSpec.swift | 52 ++- Tests/SwiftCheckTests/SimpleSpec.swift | 144 ++++--- Tests/SwiftCheckTests/TestSpec.swift | 90 ++-- 11 files changed, 712 insertions(+), 538 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index e21f6e3..8d7d46f 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -269,7 +269,10 @@ FAAB9E781D91B96C0097AC78 /* Templates */, 844FCC8E198B320500EB242A /* Products */, ); + indentWidth = 4; sourceTree = ""; + tabWidth = 4; + usesTabs = 1; }; 844FCC8E198B320500EB242A /* Products */ = { isa = PBXGroup; diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index c2ce36f..4b2187c 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -20,49 +20,56 @@ let hexDigits = Gen.one(of: [ class ComplexSpec : XCTestCase { func testEmailAddressProperties() { - let localEmail = Gen.one(of: [ - upper, - lower, - numeric, - special, - ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) - - let hostname = Gen.one(of: [ - lower, - numeric, - Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) - - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) - - let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) - - let args = CheckerArguments(maxTestCaseSize: 10) - - property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in - return e.characters.filter({ $0 == "@" }).count == 1 - }.once + XCTAssert(fileCheckOutput(withPrefixes: ["CHECKEMAIL"]) { + let localEmail = Gen.one(of: [ + upper, + lower, + numeric, + special, + ]).proliferateNonEmpty.suchThat({ $0[($0.endIndex - 1)] != "." }).map(String.init(stringInterpolationSegment:)) + + let hostname = Gen.one(of: [ + lower, + numeric, + Gen.pure("-"), + ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) + + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) + + let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) + + let args = CheckerArguments(maxTestCaseSize: 10) + + /// CHECKEMAIL: *** Passed 1 test + /// CHECKEMAIL-NEXT: . + property("Generated email addresses contain 1 @", arguments: args) <- forAll(emailGen) { (e : String) in + return e.characters.filter({ $0 == "@" }).count == 1 + }.once + }) } func testIPv6Properties() { - - let gen1 : Gen = hexDigits.proliferate(withSize: 1).map{ String.init($0) + ":" } - let gen2 : Gen = hexDigits.proliferate(withSize: 2).map{ String.init($0) + ":" } - let gen3 : Gen = hexDigits.proliferate(withSize: 3).map{ String.init($0) + ":" } - let gen4 : Gen = hexDigits.proliferate(withSize: 4).map{ String.init($0) + ":" } - - let ipHexDigits = Gen.one(of: [ - gen1, - gen2, - gen3, - gen4 - ]) - - let ipGen = glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]).map { $0.initial } - - property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in - return e.characters.filter({ $0 == ":" }).count == 3 - } + XCTAssert(fileCheckOutput(withPrefixes: ["CHECKIPV6"]) { + let gen1 : Gen = hexDigits.proliferate(withSize: 1).map{ String.init($0) + ":" } + let gen2 : Gen = hexDigits.proliferate(withSize: 2).map{ String.init($0) + ":" } + let gen3 : Gen = hexDigits.proliferate(withSize: 3).map{ String.init($0) + ":" } + let gen4 : Gen = hexDigits.proliferate(withSize: 4).map{ String.init($0) + ":" } + + let ipHexDigits = Gen.one(of: [ + gen1, + gen2, + gen3, + gen4 + ]) + + let ipGen = glue([ipHexDigits, ipHexDigits, ipHexDigits, ipHexDigits]).map { $0.initial } + + /// CHECKIPV6: *** Passed 100 tests + /// CHECKIPV6-NEXT: . + property("Generated IPs contain 3 sections") <- forAll(ipGen) { (e : String) in + return e.characters.filter({ $0 == ":" }).count == 3 + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) diff --git a/Tests/SwiftCheckTests/FileCheck.swift b/Tests/SwiftCheckTests/FileCheck.swift index 380c711..2788442 100644 --- a/Tests/SwiftCheckTests/FileCheck.swift +++ b/Tests/SwiftCheckTests/FileCheck.swift @@ -93,11 +93,11 @@ public enum FileCheckFD { /// /// - parameter FD: The file descriptor to override and read from. /// - parameter prefixes: Specifies one or more prefixes to match. By default -/// these patterns are prefixed with "CHECK:". +/// these patterns are prefixed with "CHECK". /// - parameter file: The file to check against. Defaults to the file that /// containing the call to `fileCheckOutput`. /// - parameter options: Optional arguments to modify the behavior of the check. -/// - parameter blocK: The block in which output will be emitted to the given +/// - parameter block: The block in which output will be emitted to the given /// file descriptor. public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes : [String] = ["CHECK"], against file : String = #file, options: FileCheckOptions = [], block : () -> ()) -> Bool { guard let validPrefixes = validateCheckPrefixes(prefixes) else { @@ -132,36 +132,37 @@ public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes } private func overrideFDAndCollectOutput(file : FileCheckFD, of block : () -> ()) -> String { - fflush(file.filePtr) - let oldFd = dup(file.fileno) + fflush(file.filePtr) + let oldFd = dup(file.fileno) - let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.XXXXXX") - return template.withUnsafeFileSystemRepresentation { buffer in - guard let buffer = buffer else { - return "" - } + let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.XXXXXX") + return template.withUnsafeFileSystemRepresentation { buffer in + guard let buffer = buffer else { + return "" + } + + let newFd = mkstemp(UnsafeMutablePointer(mutating: buffer)) + guard newFd != -1 else { + return "" + } - let newFd = mkstemp(UnsafeMutablePointer(mutating: buffer)) - guard newFd != -1 else { - return "" - } + dup2(newFd, file.fileno) - dup2(newFd, file.fileno) + block() - block() + close(newFd) + fflush(file.filePtr) - close(newFd) - fflush(file.filePtr) - dup2(oldFd, file.fileno) - close(oldFd) + dup2(oldFd, file.fileno) + close(oldFd) - let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil) - guard let s = try? String(contentsOf: url, encoding: .utf8) else { - return "" - } - return s - } + let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil) + guard let s = try? String(contentsOf: url, encoding: .utf8) else { + return "" + } + return s + } } func validateCheckPrefixes(_ prefixes : [String]) -> [String]? { @@ -187,25 +188,29 @@ func validateCheckPrefixes(_ prefixes : [String]) -> [String]? { extension CChar { fileprivate var isPartOfWord : Bool { - return isalnum(Int32(self)) != 0 || UInt8(self) == "-".utf8.first! || UInt8(self) == "_".utf8.first! + return isalnum(Int32(self)) != 0 || self == ("-" as Character).utf8CodePoint || self == ("_" as Character).utf8CodePoint } } extension Character { + var utf8CodePoint : CChar { + return String(self).cString(using: .utf8)!.first! + } + fileprivate var isPartOfWord : Bool { - let utf8Value = String(self).utf8.first! - return isalnum(Int32(utf8Value)) != 0 || utf8Value == "-".utf8.first! || utf8Value == "_".utf8.first! + let utf8Value = self.utf8CodePoint + return isalnum(Int32(utf8Value)) != 0 || self == "-" || self == "_" } } private func findCheckType(in buf : UnsafeBufferPointer, with prefix : String) -> CheckType { - let nextChar = UInt8(buf[prefix.utf8.count]) + let nextChar = buf[prefix.utf8.count] // Verify that the : is present after the prefix. - if nextChar == ":".utf8.first! { + if nextChar == (":" as Character).utf8CodePoint { return .plain } - if nextChar != "-".utf8.first! { + if nextChar != ("-" as Character).utf8CodePoint { return .none } @@ -216,7 +221,7 @@ private func findCheckType(in buf : UnsafeBufferPointer, with prefix : St length: buf.count - (prefix.utf8.count + 1), encoding: .utf8, freeWhenDone: false - )! + )! if rest.hasPrefix("NEXT:") { return .next } @@ -245,7 +250,7 @@ private func findCheckType(in buf : UnsafeBufferPointer, with prefix : St "NOT-NEXT:", "SAME-NOT:", "NOT-SAME:", - ] + ] if badNotPrefixes.reduce(false, { (acc, s) in acc || rest.hasPrefix(s) }) { return .badNot } @@ -254,8 +259,8 @@ private func findCheckType(in buf : UnsafeBufferPointer, with prefix : St } extension UnsafeBufferPointer { - fileprivate func substr(_ Start : Int, _ Size : Int) -> UnsafeBufferPointer { - return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: Start), count: Size) + fileprivate func substr(_ start : Int, _ size : Int) -> UnsafeBufferPointer { + return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: start), count: size) } fileprivate func dropFront(_ n : Int) -> UnsafeBufferPointer { @@ -290,7 +295,7 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among pref ) ) - // HACK: Conversion between the buffer and `String` causes index + // HACK: Conversion between the buffer and `String` causes index // mismatches when searching for strings. We're instead going to do // something terribly inefficient here: Use the regular expression to // look for check prefixes, then use Foundation's Data to find their @@ -306,12 +311,12 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among pref // intentional and unintentional uses of this feature. if skippedPrefix.isEmpty || !skippedPrefix.characters.last!.isPartOfWord { // Now extract the type. - let CheckTy = findCheckType(in: buffer, with: prefixStr) + let checkTy = findCheckType(in: buffer, with: prefixStr) // If we've found a valid check type for this prefix, we're done. - if CheckTy != .none { - return (prefixStr, CheckTy, lineNumber, buffer) + if checkTy != .none { + return (prefixStr, checkTy, lineNumber, buffer) } } // If we didn't successfully find a prefix, we need to skip this invalid @@ -328,7 +333,6 @@ private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among pref return ("", .none, lineNumber, buffer) } - private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes prefixes : [String], options: FileCheckOptions, _ RE : NSRegularExpression) -> [CheckString] { // Keeps track of the line on which CheckPrefix instances are found. var lineNumber = 1 @@ -351,50 +355,52 @@ private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes // Complain about useful-looking but unsupported suffixes. if checkTy == .badNot { - diagnose(.error, "unsupported -NOT combo on prefix '\(usedPrefix)'") + let loc = CheckLoc.inBuffer(buffer.baseAddress!, buf) + diagnose(.error, loc, "unsupported -NOT combo on prefix '\(usedPrefix)'") return [] } - // Okay, we found the prefix, yay. Remember the rest of the line, but + // Okay, we found the prefix, yay. Remember the rest of the line, but // ignore leading whitespace. if !options.contains(.strictWhitespace) || !options.contains(.matchFullLines) { - guard let idx = buffer.index(where: { c in UInt8(c) != " ".utf8.first! && UInt8(c) != "\t".utf8.first! }) else { + guard let idx = buffer.index(where: { c in c != (" " as Character).utf8CodePoint && c != ("\t" as Character).utf8CodePoint }) else { return [] } buffer = buffer.dropFront(idx) } // Scan ahead to the end of line. - let EOL : Int = buffer.index(of: CChar("\n".utf8.first!)) ?? buffer.index(of: CChar("\r".utf8.first!))! + let EOL : Int = buffer.index(of: ("\n" as Character).utf8CodePoint) ?? buffer.index(of: ("\r" as Character).utf8CodePoint)! // Remember the location of the start of the pattern, for diagnostics. - let PatternLoc : SMLoc = SMLoc(fromPointer: buffer.baseAddress!) + let patternLoc = CheckLoc.inBuffer(buffer.baseAddress!, buf) // Parse the pattern. let pat : Pattern = Pattern(checking: checkTy) let subBuffer = UnsafeBufferPointer(start: buffer.baseAddress, count: EOL) - if pat.parse(pattern: subBuffer, withPrefix: usedPrefix, at: lineNumber, options: options) { + if pat.parse(in: buf, pattern: subBuffer, withPrefix: usedPrefix, at: lineNumber, options: options) { return [] } // Verify that CHECK-LABEL lines do not define or use variables if (checkTy == .label) && pat.hasVariable { - diagnose(.error, "found '\(usedPrefix)-LABEL:' with variable definition or use") + diagnose(.error, patternLoc, "found '\(usedPrefix)-LABEL:' with variable definition or use") return [] } - buffer = UnsafeBufferPointer( - start: buffer.baseAddress!.advanced(by: EOL), - count: buffer.count - EOL - ) - // Verify that CHECK-NEXT lines have at least one CHECK line before them. if (checkTy == .next || checkTy == .same) && contents.isEmpty { let type = (checkTy == .next) ? "NEXT" : "SAME" - diagnose(.error, "found '\(usedPrefix)-\(type)' without previous '\(usedPrefix): line") + let loc = CheckLoc.inBuffer(buffer.baseAddress!, buf) + diagnose(.error, loc, "found '\(usedPrefix)-\(type)' without previous '\(usedPrefix): line") return [] } + buffer = UnsafeBufferPointer( + start: buffer.baseAddress!.advanced(by: EOL), + count: buffer.count - EOL + ) + // Handle CHECK-DAG/-NOT. if checkTy == .dag || checkTy == .not { dagNotMatches.append(pat) @@ -402,30 +408,39 @@ private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes } // Okay, add the string we captured to the output vector and move on. - contents.append(CheckString(pattern: pat, prefix: usedPrefix, loc: PatternLoc)) -// std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) -// DagNotMatches = ImplicitNegativeChecks + contents.append(CheckString(pattern: pat, prefix: usedPrefix, loc: patternLoc)) + // std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) + // DagNotMatches = ImplicitNegativeChecks } // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first // prefix as a filler for the error message. -// if !DagNotMatches.isEmpty { -// CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(), -// SMLoc::getFromPointer(Buffer.data())) -// std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) -// } - + // if !DagNotMatches.isEmpty { + // CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(), + // SMLoc::getFromPointer(Buffer.data())) + // std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) + // } if contents.isEmpty { - print("error: no check strings found with prefix\(contents.count > 1 ? "es " : " ")") + print("error: no check strings found with prefix\(contents.count == 1 ? " " : "es ")") for prefix in prefixes { print("\(prefix):") } return [] } - return contents } - +private final class BoxedTable { + var table : [String:String] = [:] + init() {} + subscript(_ i : String) -> String? { + set { + self.table[i] = newValue! + } + get { + return self.table[i] + } + } +} /// Check the input to FileCheck provided in the \p Buffer against the \p /// CheckStrings read from the check file. /// @@ -433,10 +448,8 @@ private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes private func check(input b : String, against checkStrings : [CheckString]) -> Bool { var buffer = b var failedChecks = false - // This holds all the current filecheck variables. - var variableTable = [String:String]() - + var variableTable = BoxedTable() var i = 0 var j = 0 var e = checkStrings.count @@ -450,21 +463,17 @@ private func check(input b : String, against checkStrings : [CheckString]) -> Bo j += 1 continue } - // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG guard let (matchLabelPos, matchLabelLen) = checkStr.check(buffer, true, variableTable) else { // Immediately bail of CHECK-LABEL fails, nothing else we can do. return false } - checkRegion = buffer.substring(to: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) buffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) j += 1 } - while i != j { defer { i += 1 } - // Check each string within the scanned region, including a second check // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) guard let (matchPos, matchLen) = checkStrings[i].check(checkRegion, false, variableTable) else { @@ -472,32 +481,39 @@ private func check(input b : String, against checkStrings : [CheckString]) -> Bo i = j break } - checkRegion = checkRegion.substring(from: checkRegion.index(checkRegion.startIndex, offsetBy: matchPos + matchLen)) } - if j == e { break } } - // Success if no checks failed. return !failedChecks } - - -struct SMLoc { - let unLoc : UnsafePointer? - - init() { - self.unLoc = nil - } - - init(fromPointer: UnsafePointer) { - self.unLoc = fromPointer +private enum CheckLoc { + case inBuffer(UnsafePointer, UnsafeBufferPointer) + case string(String) + var message : String { + switch self { + case let .inBuffer(ptr, buf): + var startPtr = ptr + while startPtr != buf.baseAddress! && startPtr.predecessor().pointee != ("\n" as Character).utf8CodePoint { + startPtr = startPtr.predecessor() + } + var endPtr = ptr + while endPtr != buf.baseAddress!.advanced(by: buf.endIndex) && endPtr.successor().pointee != ("\n" as Character).utf8CodePoint { + endPtr = endPtr.successor() + } + // One more for good measure. + if endPtr != buf.baseAddress!.advanced(by: buf.endIndex) { + endPtr = endPtr.successor() + } + return substring(in: buf, with: NSMakeRange(buf.baseAddress!.distance(to: startPtr), startPtr.distance(to: endPtr))) + case let .string(s): + return s + } } } - enum CheckType { case none case plain @@ -507,11 +523,9 @@ enum CheckType { case dag case label case badNot - /// MatchEOF - When set, this pattern only matches the end of file. This is /// used for trailing CHECK-NOTs. case EOF - // Get the size of the prefix extension. var size : Int { switch (self) { @@ -536,46 +550,35 @@ enum CheckType { } } } - -class Pattern { - let patternLoc : SMLoc = SMLoc() - +private class Pattern { + var patternLoc : CheckLoc = CheckLoc.string("") let type : CheckType - /// If non-empty, this pattern is a fixed string match with the specified /// fixed string. var fixedString : String = "" - /// If non-empty, this is a regex pattern. var regExPattern : String = "" - /// Contains the number of line this pattern is in. var lineNumber : Int = 0 - /// Entries in this vector map to uses of a variable in the pattern, e.g. /// "foo[[bar]]baz". In this case, the regExPattern will contain "foobaz" /// and we'll get an entry in this vector that tells us to insert the value /// of bar at offset 3. var variableUses : Array<(String, Int)> = [] - /// Maps definitions of variables to their parenthesized capture numbers. /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1. var variableDefs : Dictionary = [:] - var hasVariable : Bool { return !(variableUses.isEmpty && self.variableDefs.isEmpty) } - init(checking ty : CheckType) { self.type = ty } - private func addBackrefToRegEx(_ backRef : Int) { assert(backRef >= 1 && backRef <= 9, "Invalid backref number") let Backref = "\\\(backRef)" self.regExPattern += Backref } - /// - returns: Returns a value on success or nil on a syntax error. private func evaluateExpression(_ e : String) -> String? { var expr = e @@ -584,22 +587,19 @@ class Pattern { return nil } expr = expr.substring(from: expr.index(expr.startIndex, offsetBy: "@LINE".utf8.count)) - guard let firstC = expr.utf8.first else { + guard let firstC = expr.characters.first else { return "\(self.lineNumber)" } - - if firstC == "+".utf8.first! { + if firstC == "+" { expr = expr.substring(from: expr.index(after: expr.startIndex)) - } else if firstC != "-".utf8.first! { + } else if firstC != "-" { return nil } - guard let offset = Int(expr, radix: 10) else { return nil } return "\(self.lineNumber + offset)" } - /// Matches the pattern string against the input buffer. /// /// This returns the position that is matched or npos if there is no match. If @@ -608,14 +608,13 @@ class Pattern { /// /// The \p VariableTable StringMap provides the current values of filecheck /// variables and is updated if this match defines new values. - func match(_ buffer : String, _ variableTable : [String:String]) -> (Int, Int)? { + func match(_ buffer : String, _ variableTable : BoxedTable) -> (Int, Int)? { var matchLen : Int = 0 // If this is the EOF pattern, match it immediately. if self.type == .EOF { matchLen = 0 return (buffer.utf8.count, matchLen) } - // If this is a fixed string pattern, just match it now. if !self.fixedString.isEmpty { matchLen = self.fixedString.utf8.count @@ -624,18 +623,15 @@ class Pattern { } return nil } - // Regex match. - // If there are variable uses, we need to create a temporary string with the // actual value. var regExToMatch = self.regExPattern - if !variableUses.isEmpty { + if !self.variableUses.isEmpty { var insertOffset = 0 - for (v, offset) in variableUses { + for (v, offset) in self.variableUses { var value : String = "" - - if v.utf8.first! == "@".utf8.first! { + if let c = v.characters.first, c == "@" { guard let v = self.evaluateExpression(v) else { return nil } @@ -644,72 +640,77 @@ class Pattern { guard let val = variableTable[v] else { return nil } - // Look up the value and escape it so that we can put it into the regex. value += NSRegularExpression.escapedPattern(for: val) } - // Plop it into the regex at the adjusted offset. regExToMatch.insert(contentsOf: value.characters, at: regExToMatch.index(regExToMatch.startIndex, offsetBy: offset + insertOffset)) insertOffset += value.utf8.count } } - // Match the newly constructed regex. guard let r = try? NSRegularExpression(pattern: regExToMatch, options: []) else { return nil } - let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.distance(from: buffer.startIndex, to: buffer.endIndex))) - + let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.utf8.count)) // Successful regex match. - assert(!matchInfo.isEmpty, "Didn't get any match") - let fullMatch = matchInfo.first! - + guard let fullMatch = matchInfo.first else { + fatalError("Didn't get any matches!") + } // If this defines any variables, remember their values. - for (_, index) in self.variableDefs { - assert(index < matchInfo.count, "Internal paren error") -// VariableTable[VariableDef.0] = MatchInfo[VariableDef.second] + for (v, index) in self.variableDefs { + assert(index < fullMatch.numberOfRanges, "Internal paren error") + #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + let r = fullMatch.rangeAt(index) + #else + let r = fullMatch.range(at: index) + #endif + variableTable[v] = buffer.substring( + with: Range( + uncheckedBounds: ( + buffer.index(buffer.startIndex, offsetBy: r.location), + buffer.index(buffer.startIndex, offsetBy: NSMaxRange(r)) + ) + ) + ) } - matchLen = fullMatch.range.length return (fullMatch.range.location, matchLen) } - /// Finds the closing sequence of a regex variable usage or definition. /// /// \p Str has to point in the beginning of the definition (right after the /// opening sequence). Returns the offset of the closing sequence within Str, /// or npos if it was not found. - private func findRegexVarEnd(_ regVar : String) -> Int? { + private func findRegexVarEnd(_ regVar : String) -> String.Index? { var string = regVar // Offset keeps track of the current offset within the input Str - var offset = 0 + var offset = regVar.startIndex // [...] Nesting depth var bracketDepth = 0 - - while !string.isEmpty { + while let firstChar = string.characters.first { if string.hasPrefix("]]") && bracketDepth == 0 { return offset } - if string.utf8.first! == "\\".utf8.first! { + if firstChar == "\\" { // Backslash escapes the next char within regexes, so skip them both. string = string.substring(from: string.index(string.startIndex, offsetBy: 2)) - offset += 2 + offset = regVar.index(offset, offsetBy: 2) } else { - switch (string.utf8.first!) { - case "[".utf8.first!: + switch firstChar { + case "[": bracketDepth += 1 - case "]".utf8.first!: + case "]": if bracketDepth == 0 { - diagnose(.error, "missing closing \"]\" for regex variable") - exit(1) + diagnose(.error, .string(regVar), "missing closing \"]\" for regex variable") + return nil } bracketDepth -= 1 default: break } string = string.substring(from: string.index(after: string.startIndex)) - offset += 1 + offset = regVar.index(after: offset) } } @@ -722,7 +723,7 @@ class Pattern { self.regExPattern += RS return (false, cur + r.numberOfCaptureGroups) } catch let e { - diagnose(.error, "invalid regex: \(e)") + diagnose(.error, self.patternLoc, "invalid regex: \(e)") return (true, cur) } } @@ -733,7 +734,7 @@ class Pattern { /// SourceMgr used for error reports, and \p LineNumber is the line number in /// the input file from which the pattern string was read. Returns true in /// case of an error, false otherwise. - func parse(pattern : UnsafeBufferPointer, withPrefix prefix : String, at lineNumber : Int, options: FileCheckOptions) -> Bool { + func parse(in buf : UnsafeBufferPointer, pattern : UnsafeBufferPointer, withPrefix prefix : String, at lineNumber : Int, options: FileCheckOptions) -> Bool { func mino(_ l : String.Index?, _ r : String.Index?) -> String.Index? { if l == nil && r == nil { return nil @@ -748,11 +749,11 @@ class Pattern { self.lineNumber = lineNumber var patternStr = substring(in: pattern, with: NSRange(location: 0, length: pattern.count)) - // let patternLoc = SMLoc(fromPointer: pat.baseAddress!) + self.patternLoc = CheckLoc.inBuffer(pattern.baseAddress!, buf) // Check that there is something on the line. if patternStr.isEmpty { - diagnose(.error, "found empty check string with prefix '\(prefix):'") + diagnose(.error, self.patternLoc, "found empty check string with prefix '\(prefix):'") return true } @@ -761,7 +762,7 @@ class Pattern { (patternStr.utf8.count < 2 || (patternStr.range(of: "{{") == nil && - patternStr.range(of: "[[") == nil)) + patternStr.range(of: "[[") == nil)) { self.fixedString = patternStr return false @@ -785,7 +786,8 @@ class Pattern { if patternStr.range(of: "{{")?.lowerBound == patternStr.startIndex { // This is the start of a regex match. Scan for the }}. guard let End = patternStr.range(of: "}}") else { - diagnose(.error, "found start of regex string with no end '}}'") + let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) + diagnose(.error, loc, "found start of regex string with no end '}}'") return true } @@ -796,16 +798,15 @@ class Pattern { regExPattern += "(" curParen += 1 - let pat = patternStr.substring( + let substr = patternStr.substring( with: Range( uncheckedBounds: ( patternStr.index(patternStr.startIndex, offsetBy: 2), - patternStr.index(End.upperBound, offsetBy: -2) + End.lowerBound ) ) ) - - let (res, paren) = self.addRegExToRegEx(pat, curParen) + let (res, paren) = self.addRegExToRegEx(substr, curParen) curParen = paren if res { return true @@ -824,20 +825,15 @@ class Pattern { if patternStr.hasPrefix("[[") { // Find the closing bracket pair ending the match. End is going to be an // offset relative to the beginning of the match string. - guard let end = self.findRegexVarEnd(patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2))) else { - diagnose(.error, "invalid named regex reference, no ]] found") + let regVar = patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2)) + guard let end = self.findRegexVarEnd(regVar) else { + let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) + diagnose(.error, loc, "invalid named regex reference, no ]] found") return true } - let matchStr = patternStr.substring( - with: Range( - uncheckedBounds: ( - patternStr.index(patternStr.startIndex, offsetBy: 2), - patternStr.index(patternStr.startIndex, offsetBy: end) - ) - ) - ) - patternStr = patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: end + 4)) + let matchStr = regVar.substring(to: end) + patternStr = patternStr.substring(from: patternStr.index(end, offsetBy: 4)) // Get the regex name (e.g. "foo"). let nameEnd = matchStr.range(of: ":") @@ -845,11 +841,12 @@ class Pattern { if let end = nameEnd?.lowerBound { name = matchStr.substring(to: end) } else { - name = "" + name = matchStr } if name.isEmpty { - diagnose(.error, "invalid name in named regex: empty name") + let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) + diagnose(.error, loc, "invalid name in named regex: empty name") return true } @@ -857,25 +854,25 @@ class Pattern { // supports @LINE, @LINE+number, @LINE-number expressions. The check here // is relaxed, more strict check is performed in \c EvaluateExpression. var isExpression = false - for (i, c) in name.utf8.enumerated() { - if i == 0 && c == "@".utf8.first! { + let diagLoc = CheckLoc.inBuffer(pattern.baseAddress!, buf) + for (i, c) in name.characters.enumerated() { + if i == 0 && c == "@" { if nameEnd == nil { - diagnose(.error, "invalid name in named regex definition") + diagnose(.error, diagLoc, "invalid name in named regex definition") return true } isExpression = true continue } - if (c != "_".utf8.first! && isalnum(Int32(c)) == 0 && - (!isExpression || (c != "+".utf8.first! && c != "-".utf8.first!))) { - diagnose(.error, "invalid name in named regex") + if c != "_" && isalnum(Int32(c.utf8CodePoint)) == 0 && (!isExpression || (c != "+" && c != "-")) { + diagnose(.error, diagLoc, "invalid name in named regex") return true } } // Name can't start with a digit. if isdigit(Int32(name.utf8.first!)) != 0 { - diagnose(.error, "invalid name in named regex") + diagnose(.error, diagLoc, "invalid name in named regex") return true } @@ -883,21 +880,21 @@ class Pattern { guard let ne = nameEnd else { // Handle variables that were defined earlier on the same line by // emitting a backreference. - if let VarParenNum = self.variableDefs[name] { - if VarParenNum < 1 || VarParenNum > 9 { - diagnose(.error, "Can't back-reference more than 9 variables") + if let varParenNum = self.variableDefs[name] { + if varParenNum < 1 || varParenNum > 9 { + diagnose(.error, diagLoc, "Can't back-reference more than 9 variables") return true } - self.addBackrefToRegEx(VarParenNum) + self.addBackrefToRegEx(varParenNum) } else { - variableUses.append((name, regExPattern.utf8.count)) + variableUses.append((name, regExPattern.characters.count)) } continue } // Handle [[foo:.*]]. self.variableDefs[name] = curParen - self.regExPattern += "(" + regExPattern += "(" curParen += 1 let (res, paren) = self.addRegExToRegEx(matchStr.substring(from: matchStr.index(after: ne.lowerBound)), curParen) @@ -905,14 +902,19 @@ class Pattern { if res { return true } - self.regExPattern += ")" + + regExPattern += ")" } // Handle fixed string matches. // Find the end, which is the start of the next regex. - let fixedMatchEnd = mino(patternStr.range(of: "{{")?.lowerBound, patternStr.range(of: "[[")?.lowerBound) - self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd ?? patternStr.endIndex)) - patternStr = patternStr.substring(from: fixedMatchEnd ?? patternStr.endIndex) + if let fixedMatchEnd = mino(patternStr.range(of: "{{")?.lowerBound, patternStr.range(of: "[[")?.lowerBound) { + self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd)) + patternStr = patternStr.substring(from: fixedMatchEnd) + } else { + // No more matches, time to quit. + break + } } if options.contains(.matchFullLines) { @@ -943,9 +945,9 @@ func countNumNewlinesBetween(_ r : String) -> (Int, String.Index?) { NumNewLines += 1 // Handle \n\r and \r\n as a single newline. -// if Range.utf8.count > 1 && (Range.utf8[1] == '\n' || Range[1] == '\r') && (Range[0] != Range[1]) { -// Range = Range.substr(1) -// } + // if Range.utf8.count > 1 && (Range.utf8[1] == '\n' || Range[1] == '\r') && (Range[0] != Range[1]) { + // Range = Range.substr(1) + // } range = range.substring(from: range.index(after: range.startIndex)) if NumNewLines == 1 { @@ -955,7 +957,7 @@ func countNumNewlinesBetween(_ r : String) -> (Int, String.Index?) { } /// CheckString - This is a check that we found in the input file. -struct CheckString { +private struct CheckString { /// Pat - The pattern to match. let pattern : Pattern @@ -963,7 +965,7 @@ struct CheckString { let prefix : String /// Loc - The location in the match file that the check string was specified. - let loc : SMLoc + let loc : CheckLoc /// DagNotStrings - These are all of the strings that are disallowed from /// occurring between this match string and the previous one (or start of @@ -971,7 +973,7 @@ struct CheckString { let dagNotStrings : Array = [] /// Match check string and its "not strings" and/or "dag strings". - func check(_ buffer : String, _ isLabelScanMode : Bool, _ variableTable : [String:String]) -> (Int, Int)? { + func check(_ buffer : String, _ isLabelScanMode : Bool, _ variableTable : BoxedTable) -> (Int, Int)? { var lastPos = 0 // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL @@ -989,7 +991,7 @@ struct CheckString { // Match itself from the last position after matching CHECK-DAG. let matchBuffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: lastPos)) guard let (matchPos, matchLen) = self.pattern.match(matchBuffer, variableTable) else { -// PrintCheckFailed(*this, MatchBuffer, VariableTable) + diagnose(.error, self.loc, self.prefix + ": could not find '\(self.pattern.fixedString)' in input") return nil } @@ -1004,16 +1006,17 @@ struct CheckString { ) ) ) + let rest = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: matchPos)) // If this check is a "CHECK-NEXT", verify that the previous match was on // the previous line (i.e. that there is one newline between them). - if self.checkNext(skippedRegion) { + if self.checkNext(skippedRegion, rest) { return nil } // If this check is a "CHECK-SAME", verify that the previous match was on // the same line (i.e. that there is no newline between them). - if self.checkSame(skippedRegion) { + if self.checkSame(skippedRegion, rest) { return nil } @@ -1028,23 +1031,28 @@ struct CheckString { } /// Verify there is no newline in the given buffer. - func checkSame(_ Buffer : String) -> Bool { + private func checkSame(_ buffer : String, _ rest : String) -> Bool { if self.pattern.type != .same { return false } // Count the number of newlines between the previous match and this one. -// assert(Buffer.data() != -// SM.getMemoryBuffer(SM.FindBufferContainingLoc( -// SMLoc::getFromPointer(Buffer.data()))) -// ->getBufferStart() && -// "CHECK-SAME can't be the first check in a file") - - let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(Buffer) + // assert(Buffer.data() != + // SM.getMemoryBuffer(SM.FindBufferContainingLoc( + // SMLoc::getFromPointer(Buffer.data()))) + // ->getBufferStart() && + // "CHECK-SAME can't be the first check in a file") + let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(buffer) if numNewLines != 0 { - diagnose(.error, self.prefix + "-SAME: is not on the same line as the previous match") - diagnose(.note, "'next' match was here") - diagnose(.note, "previous match ended here") + diagnose(.error, self.loc, self.prefix + "-SAME: is not on the same line as the previous match") + rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "'next' match was here") + } + buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "previous match ended here") + } return true } @@ -1052,30 +1060,44 @@ struct CheckString { } /// Verify there is a single line in the given buffer. - func checkNext(_ Buffer : String) -> Bool { + private func checkNext(_ buffer : String, _ rest : String) -> Bool { if self.pattern.type != .next { return false } // Count the number of newlines between the previous match and this one. -// assert(Buffer.data() != -// SM.getMemoryBuffer(SM.FindBufferContainingLoc( -// SMLoc::getFromPointer(Buffer.data()))) -// ->getBufferStart(), "CHECK-NEXT can't be the first check in a file") - - let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(Buffer) + // assert(Buffer.data() != + // SM.getMemoryBuffer(SM.FindBufferContainingLoc( + // SMLoc::getFromPointer(Buffer.data()))) + // ->getBufferStart(), "CHECK-NEXT can't be the first check in a file") + let (numNewLines, firstNewLine) = countNumNewlinesBetween(buffer) if numNewLines == 0 { - diagnose(.error, prefix + "-NEXT: is on the same line as previous match") - diagnose(.note, "'next' match was here") - diagnose(.note, "previous match ended here") + diagnose(.error, self.loc, prefix + "-NEXT: is on the same line as previous match") + rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "'next' match was here") + } + buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "previous match ended here") + } return true } if numNewLines != 1 { - diagnose(.error, prefix + "-NEXT: is not on the line after the previous match") - diagnose(.note, "'next' match was here") - diagnose(.note, "previous match ended here") - diagnose(.note, "non-matching line after previous match is here") + diagnose(.error, self.loc, prefix + "-NEXT: is not on the line after the previous match") + rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "'next' match was here") + } + buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) + diagnose(.note, loc, "previous match ended here") + if let fnl = firstNewLine { + let noteLoc = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: buffer.distance(from: buffer.startIndex, to: fnl)), buf) + diagnose(.note, noteLoc, "non-matching line after previous match is here") + } + } return true } @@ -1083,16 +1105,18 @@ struct CheckString { } /// Verify there's no "not strings" in the given buffer. - func checkNot(_ Buffer : String, _ NotStrings : [Pattern], _ VariableTable : [String:String]) -> Bool { - for Pat in NotStrings { - assert(Pat.type == .not, "Expect CHECK-NOT!") + private func checkNot(_ buffer : String, _ notStrings : [Pattern], _ variableTable : BoxedTable) -> Bool { + for pat in notStrings { + assert(pat.type == .not, "Expect CHECK-NOT!") - guard let (_, _)/*(Pos, MatchLen)*/ = Pat.match(Buffer, VariableTable) else { + guard let (Pos, _)/*(Pos, MatchLen)*/ = pat.match(buffer, variableTable) else { continue } - - diagnose(.error, self.prefix + "-NOT: string occurred!") - diagnose(.note, self.prefix + "-NOT: pattern specified here") + buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: Pos), buf) + diagnose(.error, loc, self.prefix + "-NOT: string occurred!") + } + diagnose(.note, pat.patternLoc, self.prefix + "-NOT: pattern specified here") return true } @@ -1100,7 +1124,7 @@ struct CheckString { } /// Match "dag strings" and their mixed "not strings". - func checkDAG(_ buffer : String, _ variableTable : [String:String]) -> Int? { + func checkDAG(_ buffer : String, _ variableTable : BoxedTable) -> Int? { var notStrings = [Pattern]() if dagNotStrings.isEmpty { return 0 @@ -1124,7 +1148,7 @@ struct CheckString { // With a group of CHECK-DAGs, a single mismatching means the match on // that group of CHECK-DAGs fails immediately. guard let t = pattern.match(matchBuffer, variableTable) else { -// PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable) + // PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable) return nil } var matchPos = t.0 @@ -1136,10 +1160,14 @@ struct CheckString { if !notStrings.isEmpty { if matchPos < lastPos { // Reordered? - diagnose(.error, prefix + "-DAG: found a match of CHECK-DAG reordering across a CHECK-NOT") - diagnose(.note, prefix + "-DAG: the farthest match of CHECK-DAG is found here") - diagnose(.note, prefix + "-NOT: the crossed pattern specified here") - diagnose(.note, prefix + "-DAG: the reordered pattern specified here") + buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in + let loc1 = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: matchPos), buf) + diagnose(.error, loc1, prefix + "-DAG: found a match of CHECK-DAG reordering across a CHECK-NOT") + let loc2 = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: lastPos), buf) + diagnose(.note, loc2, prefix + "-DAG: the farthest match of CHECK-DAG is found here") + } + diagnose(.note, notStrings[0].patternLoc, prefix + "-NOT: the crossed pattern specified here") + diagnose(.note, pattern.patternLoc, prefix + "-DAG: the reordered pattern specified here") return nil } // All subsequent CHECK-DAGs should be matched from the farthest @@ -1162,21 +1190,25 @@ struct CheckString { // Clear "not strings". notStrings.removeAll() } - + // Update the last position with CHECK-DAG matches. lastPos = max(matchPos + matchLen, lastPos) } - + return lastPos } } -enum DiagnosticKind { +private enum DiagnosticKind { case error case warning case note } -func diagnose(_ kind : DiagnosticKind, _ message : String) { +private func diagnose(_ kind : DiagnosticKind, _ loc : CheckLoc, _ message : String) { print(message) + let msg = loc.message + if !msg.isEmpty { + print(msg) + } } diff --git a/Tests/SwiftCheckTests/FormatterSpec.swift b/Tests/SwiftCheckTests/FormatterSpec.swift index f774140..6a332ac 100644 --- a/Tests/SwiftCheckTests/FormatterSpec.swift +++ b/Tests/SwiftCheckTests/FormatterSpec.swift @@ -64,9 +64,9 @@ struct ArbitraryFormatter : Arbitrar class FormatterSpec : XCTestCase { func testAlwaysCorrectLength() { - /// CHECK: *** Passed 100 tests - /// CHECK-NEXT: . XCTAssert(fileCheckOutput { + /// CHECK: *** Passed 100 tests + /// CHECK-NEXT: . property( "Any formatted string is shorter or equal than the provided length" ) <- forAll { (x: Int, af: ArbitraryFormatter) in diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index fae6882..accfb78 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -175,7 +175,7 @@ class LambdaSpec : XCTestCase { return a.free.contains(x) ==> subst_x_b_a.free == a.free.subtracting([x]).union(b.free) } - }.expectFailure + }.expectFailure property("Substitution of a free variable into a fresh expr is idempotent", arguments: tiny) <- forAll { (a : Exp, x : Name, b : Exp) in return showResult(a.subst(x, b)) { subst_x_b_a in diff --git a/Tests/SwiftCheckTests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift index fb9dd4e..a77f6e3 100644 --- a/Tests/SwiftCheckTests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -11,54 +11,78 @@ import XCTest class ModifierSpec : XCTestCase { func testModifiers() { - property("All blind variables print '(*)'") <- forAll { (x : Blind) in - return x.description == "(*)" - } + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("All blind variables print '(*)'") <- forAll { (x : Blind) in + return x.description == "(*)" + } - property("Static propositions never shrink") <- forAll { (x : Static) in - return Static.shrink(x).isEmpty - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Static propositions never shrink") <- forAll { (x : Static) in + return Static.shrink(x).isEmpty + } - property("Pointers behave") <- forAll { (x : PointerOf) in - return x.size != 0 - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Pointers behave") <- forAll { (x : PointerOf) in + return x.size != 0 + } - property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in - return x.getPositive > 0 - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Positive propositions only generate positive numbers") <- forAll { (x : Positive) in + return x.getPositive > 0 + } - property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in - return x.getNonZero != 0 - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("NonZero propositions never generate zero") <- forAll { (x : NonZero) in + return x.getNonZero != 0 + } - property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in - return x.getNonNegative >= 0 - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("NonNegative propositions only generate non negative numbers") <- forAll { (x : NonNegative) in + return x.getNonNegative >= 0 + } - property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in - return true - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in + return true + } - property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in - return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" - ^&&^ - (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: (100%, {{Left|Right}} identity, {{Left|Right}} identity) + property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in + return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" + ^&&^ + (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" + } - property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in - return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in + return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) + } - property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in - return iso.getFrom(iso.getTo(x)) == x - ^&&^ - iso.getTo(iso.getFrom(y)) == y - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("IsoOf generates a real isomorphism") <- forAll { (x : Int, y : String, iso : IsoOf) in + return iso.getFrom(iso.getTo(x)) == x + ^&&^ + iso.getTo(iso.getFrom(y)) == y + } - property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in - let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in + let f = pred.getArrow + return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index bbb6a82..9a5af12 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -68,25 +68,25 @@ class PathSpec : XCTestCase { property("Int") <- forAll { (x : Path) in return somePath({ x in return (x < 1000000 || x > -1000000) - }, x) + }, x) } property("Int32") <- forAll { (x : Path) in return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 - }, x) + }, x) } property("UInt") <- forAll { (x : Path) in return somePath({ x in return (x < 1000000 || x > 0) - }, x) + }, x) } property("UInt32") <- forAll { (x : Path) in return path({ x in return (x >= 0 || -100 >= 0) && x <= 100 - }, x) + }, x) } property("Large Int") <- forAll { (x : Path>) in diff --git a/Tests/SwiftCheckTests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift index e35cd66..96d1736 100644 --- a/Tests/SwiftCheckTests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -43,130 +43,180 @@ func ==(l : Property, r : Bool) -> Bool { class PropertySpec : XCTestCase { func testProperties() { - property("Once really only tests a property once") <- forAll { (n : Int) in - var bomb : Optional = .some(n) - return forAll { (_ : Int) in - let b = bomb! // Will explode if we test more than once - bomb = nil - return b == n - }.once - } - - property("Again undoes once") <- forAll { (n : Int) in - var counter : Int = 0 - quickCheck(forAll { (_ : Int) in - counter += 1 - return true - }.once.again) - return counter > 1 - } - - property("Once undoes again") <- forAll { (n : Int) in - var bomb : Optional = .some(n) - return forAll { (_ : Int) in - let b = bomb! // Will explode if we test more than once - bomb = nil - return b == n - }.again.once - } - - property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in - return conjamb({ - return true "picked 1" + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Once really only tests a property once") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.once + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Again undoes once") <- forAll { (n : Int) in + var counter : Int = 0 + quickCheck(forAll { (_ : Int) in + counter += 1 + return true + }.once.again) + return counter > 1 + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Once undoes again") <- forAll { (n : Int) in + var bomb : Optional = .some(n) + return forAll { (_ : Int) in + let b = bomb! // Will explode if we test more than once + bomb = nil + return b == n + }.again.once + } + + // CHECK: : + // CHECK-NEXT: {{[0-9]+}}%, picked {{[1-3]}} + // CHECK-NEXT: {{[0-9]+}}%, picked {{[1-3]}} + // CHECK-NEXT: {{[0-9]+}}%, picked {{[1-3]}} + property("Conjamb randomly picks from multiple generators") <- forAll { (n : Int, m : Int, o : Int) in + return conjamb({ + return true "picked 1" }, { return true "picked 2" }, { return true "picked 3" - }) - } + }) + } - property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in - return n == n + // CHECK-NEXT: +++ OK, failed as expected. Proposition: Invert turns passing properties to failing properties + // CHECK-NEXT: (after {{[0-9]+}} test{{[s]*}}): + // CHECK-NEXT: 0 + // CHECK-NEXT: . + property("Invert turns passing properties to failing properties") <- forAll { (n : Int) in + return n == n }.invert.expectFailure - property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in - return n != n + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Invert turns failing properties to passing properties") <- forAll { (n : Int) in + return n != n }.invert - property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in - throw SwiftCheckError.bogus + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Invert turns throwing properties to passing properties") <- forAll { (n : Int) in + throw SwiftCheckError.bogus }.invert - property("Invert does not affect discards") <- forAll { (n : Int) in - return Discard() + // CHECK-NEXT: . + property("Invert does not affect discards") <- forAll { (n : Int) in + return Discard() }.invert - property("Existential Quantification works") <- exists { (x : Int) in - return true - } - - property("Cover reports failures properly") <- forAll { (s : Set) in - return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") - }.expectFailure + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Existential Quantification works") <- exists { (x : Int) in + return true + } - property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in - let p = p2 ==> p1 - return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) - } + // CHECK-NEXT: +++ OK, failed as expected. + // CHECK-NEXT: *** Insufficient coverage after 100 tests + // CHECK-NEXT: (only {{[0-9]+}}% large, not {{[0-9]+}}%) + property("Cover reports failures properly") <- forAll { (s : Set) in + return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") + }.expectFailure + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in + let p = p2 ==> p1 + return (p == p1) ^||^ (p ^&&^ p1 ^&&^ p2) + } - property("==> Short Circuits") <- forAll { (n : Int) in - func isPositive(_ n : Int) -> Bool { - if n > 0 { - return true - } else if (n & 1) == 0 { - fatalError("Should never get here") - } else { - return isPositive(n) // or here + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("==> Short Circuits") <- forAll { (n : Int) in + func isPositive(_ n : Int) -> Bool { + if n > 0 { + return true + } else if (n & 1) == 0 { + fatalError("Should never get here") + } else { + return isPositive(n) // or here + } } + return (n > 0) ==> isPositive(n) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of complements") <- forAll { (x : Bool) in + return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of double negation") <- forAll { (x : Bool) in + return x.invert.invert == x + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of idempotency") <- forAll { (x : Bool) in + return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of dominance") <- forAll { (x : Bool) in + return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in + return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in + return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) + let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) + return l ^&&^ r + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x ^||^ y)) == x + let r = (x ^||^ (x ^&&^ y)) == x + return l ^&&^ r + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in + let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) + let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) + return l ^&&^ r + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in + return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) } - return (n > 0) ==> isPositive(n) - } - - property("Prop Law of complements") <- forAll { (x : Bool) in - return ((x ^||^ x.invert) == true) ^&&^ ((x ^&&^ x.invert) == false) - } - - property("Prop Law of double negation") <- forAll { (x : Bool) in - return x.invert.invert == x - } - - property("Prop Law of idempotency") <- forAll { (x : Bool) in - return ((x ^||^ x) == x) ^&&^ ((x ^&&^ x) == x) - } - - property("Prop Law of dominance") <- forAll { (x : Bool) in - return ((x ^||^ false) == x) ^&&^ ((x ^&&^ true) == x) - } - - property("Prop Law of commutativity") <- forAll { (x : Bool, y : Bool) in - return ((x ^||^ y) == (y ^||^ x)) ^&&^ ((x ^&&^ y) == (y ^&&^ x)) - } - - property("Prop Law of associativity") <- forAll { (x : Bool, y : Bool, z : Bool) in - return (((x ^||^ y) ^||^ z) == (x ^||^ (y ^||^ z))) ^&&^ (((x ^&&^ y) ^&&^ z) == (x ^&&^ (y ^&&^ z))) - } - - property("Prop DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ y).invert == (x.invert ^||^ y.invert) - let r = (x ^||^ y).invert == (x.invert ^&&^ y.invert) - return l ^&&^ r - } - - property("Prop Law of absorbtion") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x ^||^ y)) == x - let r = (x ^||^ (x ^&&^ y)) == x - return l ^&&^ r - } - - property("Prop 2-part Simplification Laws") <- forAll { (x : Bool, y : Bool) in - let l = (x ^&&^ (x.invert ^||^ y)) == (x ^&&^ y) - let r = (x ^||^ (x.invert ^&&^ y)) == (x ^||^ y) - return l ^&&^ r - } - - property("Prop 3-part Simplification Law") <- forAll { (x : Bool, y : Bool, z : Bool) in - return ((x ^&&^ y) ^||^ (x ^&&^ z) ^||^ (y.invert ^&&^ z)) == ((x ^&&^ y) ^||^ (y.invert ^&&^ z)) - } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) diff --git a/Tests/SwiftCheckTests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift index 4b30b6e..4cbaf0a 100644 --- a/Tests/SwiftCheckTests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -25,30 +25,44 @@ class ShrinkSpec : XCTestCase { } func testAll() { - property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in - return !Set(Int.shrink(n)).contains(n) - } + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Shrink of an integer does not contain that integer") <- forAll { (n : Int) in + return !Set(Int.shrink(n)).contains(n) + } - property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in - return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Shrinking a non-zero integer always gives 0") <- forAll { (n : Int) in + return (n != 0) ==> Set(self.shrinkArbitrary(n)).contains(0) + } - property("Shrinking an array never gives back the original") <- forAll { (l : Array) in - return Array.shrink(l).filter({ $0 == l }).isEmpty - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Shrinking an array never gives back the original") <- forAll { (l : Array) in + return Array.shrink(l).filter({ $0 == l }).isEmpty + } - property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in - return (!l.getArray.isEmpty && l.getArray != [0]) ==> { - let ls = self.shrinkArbitrary(l).map { $0.getArray } - return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in + return (!l.getArray.isEmpty && l.getArray != [0]) ==> { + let ls = self.shrinkArbitrary(l).map { $0.getArray } + return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) + } } - } - property("Shrinking Double values does not loop") <- forAll { (n : Double) in - let left = pow(n, 0.5) - let right = sqrt(n) - return left == right - }.expectFailure + // CHECK-NEXT: +++ OK, failed as expected. Proposition: Shrinking Double values does not loop + // CHECK-NEXT: Falsifiable (after {{[0-9]+}} test{{[s]*}}): + // CHECK-NEXT: {{[+-]?([0-9]*[.])?[0-9]+}} + // CHECK-NEXT: . + property("Shrinking Double values does not loop") <- forAll { (n : Double) in + let left = pow(n, 0.5) + let right = sqrt(n) + return left == right + }.expectFailure + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index 8cb21c1..faeb8ec 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -129,73 +129,97 @@ let composedArbitraryLargeFoo = Gen.compose { c in class SimpleSpec : XCTestCase { func testAll() { - property("Integer Equality is Reflexive") <- forAll { (i : Int8) in - return i == i - } + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Integer Equality is Reflexive") <- forAll { (i : Int8) in + return i == i + } - property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in - return i == i - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Unsigned Integer Equality is Reflexive") <- forAll { (i : UInt8) in + return i == i + } - property("Float Equality is Reflexive") <- forAll { (i : Float) in - return i == i - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Float Equality is Reflexive") <- forAll { (i : Float) in + return i == i + } - property("Double Equality is Reflexive") <- forAll { (i : Double) in - return i == i - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Double Equality is Reflexive") <- forAll { (i : Double) in + return i == i + } - property("String Equality is Reflexive") <- forAll { (s : String) in - return s == s - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("String Equality is Reflexive") <- forAll { (s : String) in + return s == s + } - property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in - return i.x == i.x && i.y == i.y - } - - property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in - return i.a == i.a - && i.b == i.b - && i.c == i.c - && i.d == i.d - && i.e == i.e - && i.f == i.f - && i.g == i.g - && i.h == i.h - && i.i == i.i - && i.j == i.j - && i.k == i.k - && i.l == i.l - && i.m == i.m - && i.n == i.n - } - - property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in - return - (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) - || - (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) - } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("ArbitraryFoo Properties are Reflexive") <- forAll { (i : ArbitraryFoo) in + return i.x == i.x && i.y == i.y + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("ArbitraryLargeFoo Properties are Reflexive") <- forAll { (i : ArbitraryLargeFoo) in + return i.a == i.a + && i.b == i.b + && i.c == i.c + && i.d == i.d + && i.e == i.e + && i.f == i.f + && i.g == i.g + && i.h == i.h + && i.i == i.i + && i.j == i.j + && i.k == i.k + && i.l == i.l + && i.m == i.m + && i.n == i.n + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("All generated Charaters are valid Unicode") <- forAll { (c : Character) in + return + (c >= ("\u{0000}" as Character) && c <= ("\u{D7FF}" as Character)) + || + (c >= ("\u{E000}" as Character) && c <= ("\u{10FFFF}" as Character)) + } - let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) - let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) - let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) - let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElements(of: [ - greaterThan_lessThanEqualTo, - lessThan_greaterThanEqualTo, - equalTo_notEqualTo, - ]) - - property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in - return forAll { (x : UInt8, y : UInt8) in - return op(x, y) ==== !iop(x, y) + let greaterThan_lessThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((>), (<=)) + let lessThan_greaterThanEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((<), (>=)) + let equalTo_notEqualTo: ((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool) = ((==), (!=)) + let inverses = Gen<((UInt8, UInt8) -> Bool, (UInt8, UInt8) -> Bool)>.fromElements(of: [ + greaterThan_lessThanEqualTo, + lessThan_greaterThanEqualTo, + equalTo_notEqualTo, + ]) + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in + return forAll { (x : UInt8, y : UInt8) in + return op(x, y) ==== !iop(x, y) + } } - } - - property("composition generates high-entropy, arbitrary values") - <- forAll(composedArbitraryLargeFoo, composedArbitraryLargeFoo) { a, b in - return a != b - } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("composition generates high-entropy, arbitrary values") <- forAll( + composedArbitraryLargeFoo, + composedArbitraryLargeFoo + ) { a, b in + return a != b + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index f1c78ce..a9faec1 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -11,44 +11,64 @@ import XCTest class TestSpec : XCTestCase { func testAll() { - let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } - - property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in - return true - } - - property("Optionals behave") <- forAll { (xs : Int?) in - return true - } - - property("Sets behave") <- forAll { (xs : Set) in - return true - } - - property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in - return (xs.reversed().reversed() == xs) "Left identity" - ^&&^ - (xs == xs.reversed().reversed()) "Right identity" - } - - property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in - return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" - ^&&^ - ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") - }.expectFailure - - property("map behaves") <- forAll { (xs : Array) in - return forAll { (f : ArrowOf) in - return xs.map(f.getArrow) == xs.map(f.getArrow) + let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } + XCTAssert(fileCheckOutput { + // CHECK: *** Passed 100 tests + // CHECK-NEXT: . + property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in + return true } - } - property("filter behaves") <- forAll { (xs : Array) in - return forAll { (pred : ArrowOf) in - let f = pred.getArrow - return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Optionals behave") <- forAll { (xs : Int?) in + return true } - } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Sets behave") <- forAll { (xs : Set) in + return true + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: (100%, {{Right|Left}} identity, {{Right|Left}} identity) + // CHECK: Failed: (Bad Sort Right) + // CHECK-NEXT: Pass the seed values {{[0-9]+}} {{[0-9]+}} to replay the test. + property("The reverse of the reverse of an array is that array") <- forAll { (xs : Array) in + return + (xs.reversed().reversed() == xs) "Left identity" + ^&&^ + (xs == xs.reversed().reversed()) "Right identity" + } + + /// CHECK: +++ OK, failed as expected. Proposition: Failing conjunctions print labelled properties + /// CHECK-NEXT: Falsifiable (after 1 test): + /// CHECK-NEXT: [] + /// CHECK-NEXT: . + property("Failing conjunctions print labelled properties") <- forAll { (xs : Array) in + return (xs.sorted().sorted() == xs.sorted()).verbose "Sort Left" + ^&&^ + ((xs.sorted() != xs.sorted().sorted()).verbose "Bad Sort Right") + }.expectFailure + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("map behaves") <- forAll { (xs : Array) in + return forAll { (f : ArrowOf) in + return xs.map(f.getArrow) == xs.map(f.getArrow) + } + } + + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("filter behaves") <- forAll { (xs : Array) in + return forAll { (pred : ArrowOf) in + let f = pred.getArrow + return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + } + } + }) } #if !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)) From 867270cd3a1392e4f184937e878df579b7c2041a Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 22 Jan 2017 03:18:54 -0500 Subject: [PATCH 386/460] Plug a hole in some math on very large integers Yet another hack to keep this framework from depending on an arbitrary precision arithmetic library. Here, there are 512 integers (from Int.max to (Int.max - 512)) that cause Builtin.fptosi_FPIEEE64_Int64 to vomit. Instead, do something terrible and calculate the distance from `max` and perform the calculation that should have just occured pre-conversion one more time. --- Sources/Random.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/Random.swift b/Sources/Random.swift index 5fd3a12..c138c70 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -209,7 +209,16 @@ extension Int64 : RandomType { } let (v, rng_) = entropize(1, 0, gen) - return (Int64(Double(l) + (v.truncatingRemainder(dividingBy: k))), rng_) + let ret = Double(l) + v.truncatingRemainder(dividingBy: k) + // HACK: There exist the following 512 integers that cannot be + // safely converted by `Builtin.fptosi_FPIEEE64_Int64`. Instead we + // calculate their distance from `max` and perform the calculation + // in integer-land by hand. + if Double(Int64.max - 512) <= ret && ret <= Double(Int64.max) { + let deviation = Int64(Double(Int64.max) - ret) + return (Int64.max - deviation, rng_) + } + return (Int64(ret), rng_) } } } From f2c1fae3d7ab13146e234b01732cac43c6040dd7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Feb 2017 13:54:40 -0500 Subject: [PATCH 387/460] Cleanup some messes I left in the docs --- README.md | 2 +- Sources/Arbitrary.swift | 2 +- Sources/CoArbitrary.swift | 2 +- Sources/Gen.swift | 20 +++++++++---------- Sources/Modifiers.swift | 4 ++-- Sources/Random.swift | 14 ++++++------- Sources/Rose.swift | 26 ++++++++++++------------- Sources/Testable.swift | 11 ++++++----- Tests/SwiftCheckTests/ComplexSpec.swift | 2 +- 9 files changed, 42 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 34d337b..0ad16f2 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ let vowels = Gen.fromElements(of: [ "A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) -let uppers : Gen= Gen.fromElements(in: "A"..."Z") +let uppers : Gen = Gen.fromElements(in: "A"..."Z") let lowers : Gen = Gen.fromElements(in: "a"..."z") let numbers : Gen = Gen.fromElements(in: "0"..."9") diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index a4aa3ac..fc50eee 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -10,7 +10,7 @@ /// /// While testing, SwiftCheck will invoke `arbitrary` a given amount of times /// (usually 100 if the default settings are used). During that time, the -/// receiver has an opportunity to call through to any data or sources of +/// callee has an opportunity to call through to any data or sources of /// randomness it needs to return what it deems an "Arbitrary" value. /// /// Shrinking is reduction in the complexity of a tested value to remove noise diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index e0a3089..147e3fa 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -17,7 +17,7 @@ /// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the receiver to return a function that perturbs a + /// Uses an instance of the this type to return a function that perturbs a /// generator. static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index 8882336..a266096 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -13,7 +13,7 @@ /// generator relies on its size to help control aspects like the length of /// generated arrays and the magnitude of integral values. public struct Gen { - /// The function underlying the receiver. + /// The function underlying the generator. /// /// +--- An RNG /// | +--- The size of generated values. @@ -64,7 +64,7 @@ public struct Gen { /// Constructs a Generator that uses a given array to produce smaller arrays /// composed of its initial segments. The size of each initial segment - /// increases with the receiver's size parameter. + /// increases with the generator's size parameter. /// /// The input array is required to be non-empty. public static func fromInitialSegments(of xs : [S]) -> Gen<[S]> { @@ -182,7 +182,7 @@ extension Gen { // MARK: Generator Modifiers extension Gen { - /// Shakes up the receiver's internal Random Number Generator with a seed. + /// Shakes up the generator's internal Random Number Generator with a seed. public func variant(_ seed : S) -> Gen { return Gen(unGen: { rng, n in return self.unGen(vary(seed, rng), n) @@ -218,7 +218,7 @@ extension Gen { var size = n var r1 = r - var scrutinee : A? = valGen.unGen(r, size) + var scrutinee : A? = valGen.unGen(r1, size) while scrutinee == nil { let (rl, rr) = r1.split size = size + 1 @@ -254,7 +254,7 @@ extension Gen { } /// Modifies a Generator such that it produces arrays with a length - /// determined by the receiver's size parameter. + /// determined by the generator's size parameter. public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((0, n)).flatMap(self.proliferate(withSize:)) @@ -262,7 +262,7 @@ extension Gen { } /// Modifies a Generator such that it produces non-empty arrays with a - /// length determined by the receiver's size parameter. + /// length determined by the generator's size parameter. public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in return Gen.choose((1, max(1, n))).flatMap(self.proliferate(withSize:)) @@ -317,13 +317,13 @@ extension Gen { extension Gen /*: Functor*/ { /// Returns a new generator that applies a given function to any outputs the - /// receiver creates. + /// generator creates. /// /// This function is most useful for converting between generators of inter- /// related types. For example, you might have a Generator of `Character` /// values that you then `.proliferate` into an `Array` of `Character`s. You - /// can then use `fmap` to convert that generator of `Array`s to a generator of - /// `String`s. + /// can then use `map` to convert that generator of `Array`s to a generator + /// of `String`s. public func map(_ f : @escaping (A) -> B) -> Gen { return Gen(unGen: { r, n in return f(self.unGen(r, n)) @@ -340,7 +340,7 @@ extension Gen /*: Applicative*/ { } /// Given a generator of functions, applies any generated function to any - /// outputs the receiver creates. + /// outputs the generator creates. public func ap(_ fn : Gen<(A) -> B>) -> Gen { return Gen(unGen: { r, n in let (r1, r2) = r.split diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 8bf7535..60ab079 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -225,7 +225,7 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { /// A textual representation of `self`. public var description : String { - return "\(self.getOptional)" + return "\(String(describing: self.getOptional))" } /// Returns a generator for `OptionalOf` values. @@ -626,7 +626,7 @@ private final class PointerOfImpl : Arbitrary { let size : Int var description : String { - return "\(self.ptr)" + return "\(String(describing: self.ptr))" } init(_ ptr : UnsafeMutablePointer, _ size : Int) { diff --git a/Sources/Random.swift b/Sources/Random.swift index c138c70..bbb175f 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -10,16 +10,15 @@ /// type. It is analogous to `GeneratorType`, but rather than consume a /// sequence it uses sources of randomness to generate values indefinitely. public protocol RandomGeneneratorType { - /// The next operation returns an Int that is uniformly distributed in the - /// range returned by `genRange` (including both end points), and a new - /// generator. + /// Returns an `Int` that is uniformly distributed in the range returned by + /// `genRange` (including both end points), and a new random value generator. var next : (Int, Self) { get } - /// The genRange operation yields the range of values returned by the - /// generator. + /// Yields the range of values returned by the generator. /// /// This property must return integers in ascending order. var genRange : (Int, Int) { get } - /// Splits the receiver into two distinct random value generators. + /// Splits the current random value generator into two distinct random value + /// generators. var split : (Self, Self) { get } } @@ -69,7 +68,8 @@ public struct StdGen : RandomGeneneratorType { return (z_, StdGen(s1__, s2__)) } - /// Splits the receiver and returns two distinct random number generators. + /// Splits the random number generator and returns two distinct random + /// number generators. public var split : (StdGen, StdGen) { let s1 = self.seed1 let s2 = self.seed2 diff --git a/Sources/Rose.swift b/Sources/Rose.swift index c47bfae..511b751 100644 --- a/Sources/Rose.swift +++ b/Sources/Rose.swift @@ -6,22 +6,22 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// A `Rose` is a modified Rose Tree, or multi-way tree, for representing the +/// A `Rose` is a modified rose tree, or multi-way tree, for representing the /// steps necessary for testing a property. The first case, .MkRose, consists /// of a value and a list of trees. The second, case, .IORose, is a suspended -/// IO action SwiftCheck must execute in order to produce another Rose tree. +/// IO action SwiftCheck must execute in order to produce another rose tree. /// All values in a `Rose` are lazy. /// /// In practice SwiftCheck will minimize the side-effects performed in a given /// `IORose` to printing values to the console and executing callbacks. public enum Rose { - /// A normal branch in the Rose Tree. + /// A normal branch in the rose tree. case mkRose(() -> A, () -> [Rose]) - /// An IO branch in the Rose Tree. That is, a branch that must execute + /// An IO branch in the rose tree. That is, a branch that must execute /// side effects before revealing further structure. case ioRose(() -> Rose) - /// Case analysis for a Rose Tree. + /// Case analysis for a rose tree. public func onRose(_ f : @escaping (A, [Rose]) -> Rose) -> Rose { switch self { case .mkRose(let x, let rs): @@ -44,7 +44,7 @@ public enum Rose { } extension Rose /*: Functor*/ { - /// Maps a function over all the nodes of a Rose Tree. + /// Maps a function over all the nodes of a rose tree. /// /// For `.MkRose` branches the computation is applied to the node's value /// then application recurses into the sub-trees. For `.IORose` branches @@ -60,12 +60,12 @@ extension Rose /*: Functor*/ { } extension Rose /*: Applicative*/ { - /// Lifts a value into a Rose Tree. + /// Lifts a value into a rose tree. public static func pure(_ a : A) -> Rose { return .mkRose({ a }, { [] }) } - /// Applies a Rose Tree of functions to the receiver to yield a new Rose + /// Applies a rose tree of functions to the rose tree to yield a new Rose /// Tree of values. /// /// For `.MkRose` branches the computation is applied to the node's value @@ -83,21 +83,21 @@ extension Rose /*: Applicative*/ { } extension Rose /*: Monad*/ { - /// Maps the values in the receiver to Rose Trees and joins them all + /// Maps the values in the rose tree to rose trees and joins them all /// together. public func flatMap(_ fn : @escaping (A) -> Rose) -> Rose { return joinRose(self.map(fn)) } } -/// Lifts functions to functions over Rose Trees. +/// Lifts functions to functions over rose trees. public func liftM(_ f : @escaping (A) -> R, _ m1 : Rose) -> Rose { return m1.flatMap { x1 in return Rose.pure(f(x1)) } } -/// Flattens a Rose Tree of Rose Trees by a single level. +/// Flattens a rose tree of rose trees by a single level. /// /// For `.IORose` branches the join is suspended. For `.MkRose` branches, the /// kind of subtree at the node dictates the behavior of the join. For @@ -118,7 +118,7 @@ public func joinRose(_ rs : Rose>) -> Rose { } } -/// Sequences an array of Rose Trees into a Rose Tree of an array. +/// Sequences an array of rose trees into a rose tree of an array. public func sequence(_ ms : [Rose]) -> Rose<[A]> { return ms.reduce(Rose<[A]>.pure([]), { n, m in return m.flatMap { x in @@ -129,7 +129,7 @@ public func sequence(_ ms : [Rose]) -> Rose<[A]> { }) } -/// Sequences the result of mapping values to Rose trees into a single rose tree +/// Sequences the result of mapping values to rose trees into a single rose tree /// of an array of values. public func mapM(_ f : (A) -> Rose, xs : [A]) -> Rose<[B]> { return sequence(xs.map(f)) diff --git a/Sources/Testable.swift b/Sources/Testable.swift index 1e35fe2..b9e1f6e 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -45,9 +45,9 @@ public struct Property : Testable { public struct Prop : Testable { var unProp : Rose - /// Returns a property that tests the receiver. + /// Returns a property that tests the `Prop`. public var property : Property { - // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) + // return Property(Gen.pure(Prop(unProp: .IORose(protectRose({ self.unProp }))))) return Property(Gen.pure(Prop(unProp: .ioRose({ self.unProp })))) } } @@ -64,15 +64,16 @@ public struct Discard : Testable { } extension TestResult : Testable { - /// Returns a property that tests the receiver. + /// Returns a property that evaluates to this test result. public var property : Property { return Property(Gen.pure(Prop(unProp: Rose.pure(self)))) } } extension Bool : Testable { - /// Returns a property that evaluates to a test success if the receiver is - /// `true`, else returns a property that evaluates to a test failure. + /// Returns a property that evaluates to a test success if this boolean + /// value is `true`, else returns a property that evaluates to a test + /// failure. public var property : Property { return TestResult.liftBool(self).property } diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 4b2187c..73cd10f 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -9,7 +9,7 @@ import SwiftCheck import XCTest -let upper : Gen= Gen.fromElements(in: "A"..."Z") +let upper : Gen = Gen.fromElements(in: "A"..."Z") let lower : Gen = Gen.fromElements(in: "a"..."z") let numeric : Gen = Gen.fromElements(in: "0"..."9") let special : Gen = Gen.fromElements(of: ["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) From 43b0f34a03629f66ab4c225e7ccc8c15b0e4fb06 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Feb 2017 14:08:31 -0500 Subject: [PATCH 388/460] Round out the documentation --- .travis.yml | 5 ++--- Sources/Lattice.swift | 7 ++++++- Sources/Modifiers.swift | 31 ++++++++++++++++++++++++++++--- Sources/Testable.swift | 3 ++- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0580adb..b4e7498 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,10 +35,9 @@ matrix: - echo $SIMULATOR_ID - echo $iOS_DEVICE_NAME - echo $iOS_RUNTIME_VERSION - # !!!: Start simulator w/ desired device—helps avoid issues w/ Xcode timing out when waiting for simulator to become ready - - open -b com.apple.iphonesimulator --args -CurrentDeviceUDID $SIMULATOR_ID + - xcodebuild build-for-testing -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c - # -- End iOS -- + - xcodebuild build-for-testing -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - os: linux language: generic diff --git a/Sources/Lattice.swift b/Sources/Lattice.swift index 2d22ac5..9f7dd67 100644 --- a/Sources/Lattice.swift +++ b/Sources/Lattice.swift @@ -105,11 +105,16 @@ extension AnyIndex : LatticeType { #if os(Linux) import Glibc - /// Matches http://www.opensource.apple.com/source/gcc/gcc-934.3/float.h + // Matches http://www.opensource.apple.com/source/gcc/gcc-934.3/float.h + + /// Maximum value of `Float`. public var FLT_MAX: Float = 3.40282347e+38 + /// Minimum value of `Float`. public var FLT_MIN: Float = 1.17549435e-38 + /// Maximum value of `Double`. public var DBL_MAX: Double = 1.7976931348623157e+308 + /// Minimum value of `Double`. public var DBL_MIN: Double = 2.2250738585072014e-308 #else import Darwin diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 60ab079..3e9cc17 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -55,6 +55,7 @@ public struct Blind : Arbitrary, CustomStringConvertible { /// Retrieves the underlying value. public let getBlind : A + /// Creates a new `Blind` modifier from an underlying value. public init(_ blind : A) { self.getBlind = blind } @@ -78,8 +79,9 @@ public struct Blind : Arbitrary, CustomStringConvertible { } extension Blind : CoArbitrary { - // Take the lazy way out. + /// Uses the underlying value to perturb a generator. public static func coarbitrary(_ x : Blind) -> ((Gen) -> Gen) { + // Take the lazy way out. return coarbitraryPrintable(x) } } @@ -89,6 +91,7 @@ public struct Static : Arbitrary, CustomStringConvertible { /// Retrieves the underlying value. public let getStatic : A + /// Creates a new `Static` modifier from an underlying value. public init(_ fixed : A) { self.getStatic = fixed } @@ -105,8 +108,9 @@ public struct Static : Arbitrary, CustomStringConvertible { } extension Static : CoArbitrary { - // Take the lazy way out. + /// Uses the underlying value to perturb a generator. public static func coarbitrary(_ x : Static) -> ((Gen) -> Gen) { + // Take the lazy way out. return coarbitraryPrintable(x) } } @@ -121,6 +125,7 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { return ContiguousArray(self.getArray) } + /// Creates a new `ArrayOf` modifier from an underlying array of values. public init(_ array : [A]) { self.getArray = array } @@ -142,6 +147,7 @@ public struct ArrayOf : Arbitrary, CustomStringConvertible { } extension ArrayOf : CoArbitrary { + /// Uses the underlying array of values to perturb a generator. public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { let a = x.getArray if a.isEmpty { @@ -162,6 +168,11 @@ public struct OrderedArrayOf : Arbitrary, CustomStri return ContiguousArray(self.getOrderedArray) } + /// Creates a new `OrderedArrayOf` modifier from an underlying array of + /// values. + /// + /// The values in the array are not required to be sorted, they will + /// be sorted by the initializer. public init(_ array : [A]) { self.getOrderedArray = array.sorted() } @@ -188,6 +199,8 @@ public struct DictionaryOf : Arbitrary, /// Retrieves the underlying dictionary of values. public let getDictionary : Dictionary + /// Creates a new `DictionaryOf` modifier from an underlying dictionary of + /// key-value pairs. public init(_ dict : Dictionary) { self.getDictionary = dict } @@ -209,6 +222,7 @@ public struct DictionaryOf : Arbitrary, } extension DictionaryOf : CoArbitrary { + /// Uses the underlying array of values to perturb a generator. public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { return Dictionary.coarbitrary(x.getDictionary) } @@ -219,6 +233,7 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { /// Retrieves the underlying optional value. public let getOptional : A? + /// Creates a new `OptionalOf` modifier from an underlying `Optional` value. public init(_ opt : A?) { self.getOptional = opt } @@ -240,6 +255,7 @@ public struct OptionalOf : Arbitrary, CustomStringConvertible { } extension OptionalOf : CoArbitrary { + /// Uses the underlying presence or lack of a value to perturb a generator. public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { if let _ = x.getOptional { return { $0.variant(0) } @@ -253,6 +269,7 @@ public struct SetOf : Arbitrary, CustomStringConvertib /// Retrieves the underlying set of values. public let getSet : Set + /// Creates a new `SetOf` modifier from an underlying set of values. public init(_ set : Set) { self.getSet = set } @@ -282,6 +299,7 @@ public struct SetOf : Arbitrary, CustomStringConvertib } extension SetOf : CoArbitrary { + /// Uses the underlying set of values to perturb a generator. public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { if x.getSet.isEmpty { return { $0.variant(0) } @@ -384,6 +402,7 @@ public struct Large : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A + /// Creates a new `Large` modifier from a given bounded integral value. public init(_ lrg : A) { self.getLarge = lrg } @@ -409,6 +428,7 @@ public struct Positive : Arbitrary, CustomStringCo /// Retrieves the underlying positive value. public let getPositive : A + /// Creates a new `Positive` modifier from a given signed integral value. public init(_ pos : A) { self.getPositive = pos } @@ -430,8 +450,9 @@ public struct Positive : Arbitrary, CustomStringCo } extension Positive : CoArbitrary { - // Take the lazy way out. + /// Uses the underlying positive integral value to perturb a generator. public static func coarbitrary(_ x : Positive) -> ((Gen) -> Gen) { + // Take the lazy way out. return coarbitraryPrintable(x) } } @@ -441,6 +462,7 @@ public struct NonZero : Arbitrary, CustomStringConverti /// Retrieves the underlying non-zero value. public let getNonZero : A + /// Creates a new `NonZero` modifier from a given integral value. public init(_ non : A) { self.getNonZero = non } @@ -462,6 +484,7 @@ public struct NonZero : Arbitrary, CustomStringConverti } extension NonZero : CoArbitrary { + /// Uses the underlying non-zero integral value to perturb a generator. public static func coarbitrary(_ x : NonZero) -> ((Gen) -> Gen) { return x.getNonZero.coarbitraryIntegral() } @@ -472,6 +495,7 @@ public struct NonNegative : Arbitrary, CustomStringConv /// Retrieves the underlying non-negative value. public let getNonNegative : A + /// Creates a new `NonNegative` modifier from a given integral value. public init(_ non : A) { self.getNonNegative = non } @@ -493,6 +517,7 @@ public struct NonNegative : Arbitrary, CustomStringConv } extension NonNegative : CoArbitrary { + /// Uses the underlying non-negative integral value to perturb a generator. public static func coarbitrary(_ x : NonNegative) -> ((Gen) -> Gen) { return x.getNonNegative.coarbitraryIntegral() } diff --git a/Sources/Testable.swift b/Sources/Testable.swift index b9e1f6e..fc199f2 100644 --- a/Sources/Testable.swift +++ b/Sources/Testable.swift @@ -54,7 +54,8 @@ public struct Prop : Testable { /// When returned from a test case, that particular case is discarded. public struct Discard : Testable { - /// Create a `Discard` suitable for + /// Create a `Discard` suitable for disregarding a test case as though a + /// precondition was false. public init() { } /// Returns a property that always rejects whatever result occurs. From af816f2ccefd85d78d4df25d4aa780fd20b9ba95 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 8 Feb 2017 15:25:26 -0500 Subject: [PATCH 389/460] Bump the podspec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 0f7c283..ec5c555 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.7.1" + s.version = "0.7.3" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From e9cfe4a85b0c72edf5c32b161bbdcf06dc8f1daa Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 7 Mar 2017 15:47:08 -0500 Subject: [PATCH 390/460] Update to Swift 3.1 --- .travis.yml | 11 +++++------ Sources/Arbitrary.swift | 4 ++-- Sources/Lattice.swift | 8 ++++---- Sources/Modifiers.swift | 6 +++--- Tests/SwiftCheckTests/FileCheck.swift | 2 -- Tests/SwiftCheckTests/ModifierSpec.swift | 2 +- 6 files changed, 15 insertions(+), 18 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4e7498..00bd39b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,8 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode8 + osx_image: xcode8.3 before_install: - - gem install cocoapods - git submodule update --init --recursive - pushd Utilities - ./compile.sh @@ -17,7 +16,7 @@ matrix: - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode8 + osx_image: xcode8.3 before_install: - git submodule update --init --recursive - pushd Utilities @@ -46,9 +45,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-3.0.2-release/ubuntu1404/swift-3.0.2-RELEASE/swift-3.0.2-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-3.0.2-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-3.0.2-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-3.1-release/ubuntu1404/swift-3.1-RELEASE/swift-3.1-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-3.1-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-3.1-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index fc50eee..fdb3645 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -244,7 +244,7 @@ extension Float : Arbitrary { public static func shrink(_ x : Float) -> [Float] { let tail = Int64(x).shrinkIntegral.map(Float.init(_:)) if (x.sign == .minus) { - return [abs(x)] + tail + return [Swift.abs(x)] + tail } return tail } @@ -273,7 +273,7 @@ extension Double : Arbitrary { public static func shrink(_ x : Double) -> [Double] { let tail = Int64(x).shrinkIntegral.map(Double.init(_:)) if (x.sign == .minus) { - return [abs(x)] + tail + return [Swift.abs(x)] + tail } return tail } diff --git a/Sources/Lattice.swift b/Sources/Lattice.swift index 9f7dd67..22b8c47 100644 --- a/Sources/Lattice.swift +++ b/Sources/Lattice.swift @@ -57,24 +57,24 @@ extension Int64 : LatticeType {} extension Float : LatticeType { /// The lower limit of the `Float` type. public static var min : Float { - return FLT_MIN + return Float.leastNormalMagnitude } /// The upper limit of the `Float` type. public static var max : Float { - return FLT_MAX + return Float.greatestFiniteMagnitude } } extension Double : LatticeType { /// The lower limit of the `Double` type. public static var min : Double { - return DBL_MIN + return Double.leastNormalMagnitude } /// The upper limit of the `Double` type. public static var max : Double { - return DBL_MAX + return Double.greatestFiniteMagnitude } } diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 3e9cc17..8806934 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -313,8 +313,8 @@ public struct PointerOf : Arbitrary, CustomStringConvertible { fileprivate let _impl : PointerOfImpl /// Retrieves the underlying pointer value. - public var getPointer : UnsafePointer { - return UnsafePointer(self._impl.ptr!) + public var getPointer : UnsafeBufferPointer { + return UnsafeBufferPointer(start: self._impl.ptr, count: self.size) } public var size : Int { @@ -673,7 +673,7 @@ private final class PointerOfImpl : Arbitrary { return Gen.pure(PointerOfImpl(UnsafeMutablePointer.allocate(capacity: size), size)) } let pt = UnsafeMutablePointer.allocate(capacity: n) - let gt = sequence(Array((0..) in - return x.size != 0 + return x.size != 0 && x.getPointer.count == x.size } // CHECK-NEXT: *** Passed 100 tests From 1e599c945daef819e603f65621b7fa9a3d7e05a8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 28 Mar 2017 22:37:06 -0400 Subject: [PATCH 391/460] XXX --- Sources/CoArbitrary.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index 147e3fa..704b555 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -17,7 +17,7 @@ /// given generator (more than likely using `Gen.variant()`) based on the value /// it observes. public protocol CoArbitrary { - /// Uses an instance of the this type to return a function that perturbs a + /// Uses an instance of this type to return a function that perturbs a /// generator. static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } From 06290382f48a784a8c7ab7d5a8db5c8196a59ab5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 28 Mar 2017 23:06:23 -0400 Subject: [PATCH 392/460] Bump podspec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index ec5c555..6f0ba91 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.7.3" + s.version = "0.8.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 24de8f8e094c77a9351aa4a1ef5013fd2c773f82 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 3 Apr 2017 13:08:21 -0400 Subject: [PATCH 393/460] Update README --- README.md | 44 +++++++++++++++--------------- Tutorial.playground/Contents.swift | 4 +-- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0ad16f2..bfb3e9c 100644 --- a/README.md +++ b/README.md @@ -113,28 +113,28 @@ a list of primes less than some n: /// mark l[i] /// } /// - Remaining indices of unmarked numbers are primes -func sieve(n : Int) -> [Int] { - if n <= 1 { - return [Int]() - } - - var marked : [Bool] = (0...n).map(const(false)) - marked[0] = true - marked[1] = true - - for p in 2.. [Int] { + if n <= 1 { + return [] + } + + var marked : [Bool] = (0...n).map { _ in false } + marked[0] = true + marked[1] = true + + for p in 2.. [Int] { +func sieve(_ n : Int) -> [Int] { if n <= 1 { return [] } @@ -503,7 +503,7 @@ func isPrime(_ n : Int) -> Bool { //: following property: reportProperty("All Prime") <- forAll { (n : Positive) in - let primes = sieve(n: n.getPositive) + let primes = sieve(n.getPositive) return primes.count > 1 ==> { let primeNumberGen = Gen.fromElements(of: primes) return forAll(primeNumberGen) { (p : Int) in From 78da1b53dfd58917a3fc639e20631bf1adc5396d Mon Sep 17 00:00:00 2001 From: Elviro Rocca Date: Sat, 8 Jul 2017 22:06:25 +0200 Subject: [PATCH 394/460] fixed Travis iOS_DEVICE_NAME target --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 00bd39b..1a9b676 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ matrix: - xcodebuild test -scheme SwiftCheck | xcpretty -c # -- Start iOS -- # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - - iOS_DEVICE_NAME="iPad Pro (12.9 inch)" + - iOS_DEVICE_NAME="iPad Pro (12.9-inch)" - iOS_RUNTIME_VERSION="10.0" # Get simulator identifier for desired device/runtime pair - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") From 4b180c94e5677a2ed4a940a6b350a69dc8a27edc Mon Sep 17 00:00:00 2001 From: Sho Ikeda Date: Sun, 9 Jul 2017 01:54:37 +0900 Subject: [PATCH 395/460] Make Carthage build cache work Update the project configurations for generating `SwiftCheck-Swift.h` to let Carthage know Swift version by which the framework is built. --- SwiftCheck.xcodeproj/project.pbxproj | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 8d7d46f..8d61755 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -808,8 +808,6 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = appletvos; SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -841,8 +839,6 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = appletvos; SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; @@ -1002,8 +998,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 3.0; }; @@ -1036,8 +1030,6 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; }; @@ -1113,8 +1105,6 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -1147,8 +1137,6 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; From 4ee502f8acc512ff6ea8a8f3709d14b9f7f077f3 Mon Sep 17 00:00:00 2001 From: Yusuke Hosonuma Date: Mon, 17 Jul 2017 21:31:54 +0900 Subject: [PATCH 396/460] Update README --- README.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index bfb3e9c..6afe412 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // features. `^&&^` is the conjunction operator for properties that turns // both properties into a larger property that only holds when both sub-properties // hold. `` is the labelling operator allowing us to name each sub-part - // in output generated by SwiftCheck. For example, this property reports: + // in output generated by SwiftCheck. For example, this property reports: // // *** Passed 100 tests // (100% , Right identity, Left identity) @@ -114,27 +114,27 @@ a list of primes less than some n: /// } /// - Remaining indices of unmarked numbers are primes func sieve(_ n : Int) -> [Int] { - if n <= 1 { - return [] - } - - var marked : [Bool] = (0...n).map { _ in false } - marked[0] = true - marked[1] = true - - for p in 2.. = Gen.fromElements(in: "0"..."9") /// This generator will generate `.none` 1/4 of the time and an arbitrary /// `.some` 3/4 of the time let weightedOptionals = Gen.frequency([ - (1, Gen.pure(nil)), - (3, Int.arbitrary.map(Optional.some)) + (1, Gen.pure(nil)), + (3, Int.arbitrary.map(Optional.some)) ]) ``` From 808bb3ea41cd2e8491aa2c068c718652426bf259 Mon Sep 17 00:00:00 2001 From: Rob Mayoff Date: Wed, 19 Jul 2017 00:52:09 -0500 Subject: [PATCH 397/460] credit the creator of the RNG --- Sources/Random.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/Random.swift b/Sources/Random.swift index bbb175f..a4b9497 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -52,6 +52,9 @@ public struct StdGen : RandomGeneneratorType { /// Returns an `Int` generated uniformly within the bounds of the generator /// and a new distinct random number generator. public var next : (Int, StdGen) { + // P. L'Ecuyer, ``Efficient and Portable Combined Random Number Generators'', Communications of the ACM, 31 (1988), 742--749 and 774. + // https://www.iro.umontreal.ca/~lecuyer/myftp/papers/cacm88.pdf + let s1 = self.seed1 let s2 = self.seed2 From a817ab389fffa91fc0e2d6fd6034e1ac2dc97973 Mon Sep 17 00:00:00 2001 From: Tiago Martinho Date: Wed, 19 Jul 2017 12:13:43 +0200 Subject: [PATCH 398/460] Use the trailing closure syntax --- Tutorial.playground/Contents.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 08b261a..5119fdc 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -224,7 +224,7 @@ let allowedLocalCharacters : Gen = Gen.one(of: [ let localEmail = allowedLocalCharacters .proliferateNonEmpty // Make a non-empty array of characters - .suchThat({ $0[$0.index(before: $0.endIndex)] != "." }) // Such that the last character isn't a dot. + .suchThat { $0[$0.index(before: $0.endIndex)] != "." } // Such that the last character isn't a dot. .map { String($0) } // Then make a string. //: The RFC says that the host name can only consist of lowercase letters, numbers, and dashes. We'll skip some @@ -240,7 +240,7 @@ let hostname = Gen.one(of: [ let tld = lowerCaseLetters .proliferateNonEmpty - .suchThat({ $0.count > 1 }) + .suchThat { $0.count > 1 } .map { String($0) } //: So now that we've got all the pieces, so how do we put them together to make the final generator? Well, how @@ -367,9 +367,9 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in // `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. -reportProperty("Obviously wrong") <- forAll({ (x : Int) in +reportProperty("Obviously wrong") <- forAll { (x : Int) in return x != x -}).whenFail { // `whenFail` attaches a callback to the test when we fail. +}.whenFail { // `whenFail` attaches a callback to the test when we fail. print("Oh noes!") } From d9d23cdc778493dbc92548fea9c04952c968a88b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 28 Aug 2017 11:19:15 -0400 Subject: [PATCH 399/460] Migate and update to Swift 3.2 --- .travis.yml | 10 ++++---- Sources/Arbitrary.swift | 4 ++-- Sources/Gen.swift | 23 ++++++++++++++----- Sources/Lattice.swift | 4 ++-- Sources/Modifiers.swift | 2 +- Sources/Property.swift | 4 ++-- Sources/WitnessedArbitrary.swift | 12 ++++------ SwiftCheck.xcodeproj/project.pbxproj | 12 ++++++++++ .../SwiftCheckTests/BooleanIdentitySpec.swift | 1 + Tests/SwiftCheckTests/PathSpec.swift | 4 ++-- Tutorial.playground/Contents.swift | 4 ++-- 11 files changed, 51 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1a9b676..118a1f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode8.3 + osx_image: xcode9 before_install: - git submodule update --init --recursive - pushd Utilities @@ -16,7 +16,7 @@ matrix: - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode8.3 + osx_image: xcode9 before_install: - git submodule update --init --recursive - pushd Utilities @@ -45,9 +45,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-3.1-release/ubuntu1404/swift-3.1-RELEASE/swift-3.1-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-3.1-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-3.1-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-4.0-release/ubuntu1404/swift-4.0-RELEASE/swift-4.0-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-4.0-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-4.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index fdb3645..7e928ae 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -61,7 +61,7 @@ extension Arbitrary { } } -extension Integer { +extension FixedWidthInteger { /// Shrinks any `IntegerType`. public var shrinkIntegral : [Self] { return unfoldr({ i in @@ -70,7 +70,7 @@ extension Integer { } let n = i / 2 return .some((n, n)) - }, initial: self < 0 ? (Self.multiplyWithOverflow(self, -1).0) : self) + }, initial: self < 0 ? self.multipliedReportingOverflow(by: -1).partialValue : self) } } diff --git a/Sources/Gen.swift b/Sources/Gen.swift index a266096..bb14b50 100644 --- a/Sources/Gen.swift +++ b/Sources/Gen.swift @@ -44,14 +44,25 @@ public struct Gen { /// collection and produces only that value. /// /// The input collection is required to be non-empty. - public static func fromElements(of xs : S) -> Gen - where S.Index : Comparable & RandomType + public static func fromElements(of xs : S) -> Gen + where S.Index : RandomType { return Gen.fromElements(in: xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } } + /// Constructs a Generator that selects a random value from the given + /// collection and produces only that value. + /// + /// The input collection is required to be non-empty. + public static func fromElements(of xs : Set) -> Gen { + precondition(!xs.isEmpty) + return Gen.fromElements(in: 0...xs.distance(from: xs.startIndex, to: xs.endIndex)-1).map { i in + return xs[xs.index(xs.startIndex, offsetBy: i)] + } + } + /// Constructs a Generator that selects a random value from the given /// interval and produces only that value. /// @@ -120,7 +131,7 @@ public struct Gen { /// If control over the distribution of generators is needed, see /// `Gen.frequency` or `Gen.weighted`. public static func one(of gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType & Comparable + where S.Iterator.Element == Gen, S.Index : RandomType { assert(gs.count != 0, "oneOf used with empty list") @@ -277,8 +288,8 @@ extension Gen { extension Gen { @available(*, unavailable, renamed: "fromElements(of:)") - public static func fromElementsOf(_ xs : S) -> Gen - where S.Index : Comparable & RandomType + public static func fromElementsOf(_ xs : S) -> Gen + where S.Index : RandomType { return Gen.fromElements(of: xs) } @@ -302,7 +313,7 @@ extension Gen { @available(*, unavailable, renamed: "one(of:)") public static func oneOf(_ gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType & Comparable + where S.Iterator.Element == Gen, S.Index : RandomType { return Gen.one(of: gs) } diff --git a/Sources/Lattice.swift b/Sources/Lattice.swift index 22b8c47..f71a64c 100644 --- a/Sources/Lattice.swift +++ b/Sources/Lattice.swift @@ -79,12 +79,12 @@ extension Double : LatticeType { } extension AnyIndex : LatticeType { - /// The lower limit of the `AnyForwardIndex` type. + /// The lower limit of the `AnyIndex` type. public static var min : AnyIndex { return AnyIndex(Int64.min) } - /// The upper limit of the `AnyForwardIndex` type. + /// The upper limit of the `AnyIndex` type. public static var max : AnyIndex { return AnyIndex(Int64.max) } diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 8806934..8e34882 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -398,7 +398,7 @@ extension IsoOf : CustomReflectable { /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. -public struct Large : Arbitrary { +public struct Large : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A diff --git a/Sources/Property.swift b/Sources/Property.swift index 4ded58a..9716ede 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -597,7 +597,7 @@ private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> Te return { protect(exception("Exception"), x: r) } } -internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { +internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l r.forEach { (k, v) in if let val = map.updateValue(v, forKey: k) { @@ -607,7 +607,7 @@ internal func unionWith(_ f : (V, V) -> V, l : Dictionary return map } -private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { +private func insertWith(_ f : (V, V) -> V, k : K, v : V, m : Dictionary) -> Dictionary { var res = m let oldV = res[k] if let existV = oldV { diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index f99b1fa..46fb5f6 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -192,9 +192,7 @@ extension Dictionary where Key : Arbitrary, Value : Arbitrary { /// The default shrinking function for `Dictionary`s of arbitrary `Key`s and /// `Value`s. public static func shrink(_ d : Dictionary) -> [Dictionary] { - return d.map { Dictionary(zip(Key.shrink($0), Value.shrink($1)).map({ (k, v) -> (key: Key, value: Value) in - (key: k, value: v) - })) } + return d.map { t in Dictionary(zip(Key.shrink(t.key), Value.shrink(t.value)), uniquingKeysWith: { (_, v) in v }) } } } @@ -205,7 +203,7 @@ extension EmptyCollection : Arbitrary { } } -extension Range where Bound : Comparable & Arbitrary { +extension Range where Bound : Arbitrary { /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in @@ -221,14 +219,14 @@ extension Range where Bound : Comparable & Arbitrary { } } -extension LazyCollection where Base : Collection & Arbitrary, Base.Index : Comparable { +extension LazyCollection where Base : Arbitrary { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } -extension LazySequence where Base : Sequence & Arbitrary { +extension LazySequence where Base : Arbitrary { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary @@ -259,7 +257,7 @@ extension Repeated : WitnessedArbitrary { } } -extension Set where Element : Arbitrary & Hashable { +extension Set where Element : Arbitrary { /// Returns a generator of `Set`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 8d61755..d5652f9 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -808,6 +808,7 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -840,6 +841,7 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -860,6 +862,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; @@ -877,6 +880,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -999,6 +1003,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; }; name = Debug; @@ -1031,6 +1036,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; }; name = Release; @@ -1053,6 +1059,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; }; name = Debug; @@ -1072,6 +1079,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; }; name = Release; @@ -1105,6 +1113,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -1138,6 +1147,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -1166,6 +1176,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; }; name = Debug; @@ -1186,6 +1197,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 3.0; VALIDATE_PRODUCT = YES; }; diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index 672a722..ea5ba2e 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -9,6 +9,7 @@ import SwiftCheck import XCTest + class BooleanIdentitySpec : XCTestCase { func testAll() { XCTAssert(fileCheckOutput { diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index 9a5af12..bfe6ba1 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -52,13 +52,13 @@ struct Extremal : Arbitrary { } class PathSpec : XCTestCase { - private static func smallProp(_ pth : Path) -> Bool { + private static func smallProp(_ pth : Path) -> Bool { return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 }, pth) } - private static func largeProp(_ pth : Path) -> Property { + private static func largeProp(_ pth : Path) -> Property { return somePath({ x in return (x < -1000000 || x > 1000000) }, pth) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 5119fdc..e84c172 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -292,7 +292,7 @@ emailGen.generate //: Library, but we also use them in more benign ways too. For example, we can write a modifier type //: that only generates positive numbers: -public struct ArbitraryPositive : Arbitrary { +public struct ArbitraryPositive : Arbitrary { public let getPositive : A public init(_ pos : A) { self.getPositive = pos } @@ -342,7 +342,7 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) + return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) // ^ This property says that if we filter an array then apply the predicate // to all its elements, then they should all respond with `true`. } From 2b391ea27a1c1c969de3e66442da73e9314dc132 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 20 Sep 2017 12:11:16 -0400 Subject: [PATCH 400/460] Bump podspec version --- .swift-version | 2 +- SwiftCheck.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.swift-version b/.swift-version index 9f55b2c..a3ec5a4 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.0 +3.2 diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 6f0ba91..b4a225c 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.8.0" + s.version = "0.8.1" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From a333f8ad622a87d6033f9ddf746bf8fc0da06c65 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 2 May 2017 14:54:11 -0400 Subject: [PATCH 401/460] Drag the framework into the future --- Sources/Arbitrary.swift | 29 ++++-- Sources/Cartesian.swift | 120 +++++++++++----------- Sources/Check.swift | 6 +- Sources/CoArbitrary.swift | 4 +- Sources/Gen.swift | 52 ++-------- Sources/Modifiers.swift | 25 +++-- Sources/Property.swift | 77 +++++++------- Sources/Random.swift | 20 ++-- Sources/Test.swift | 11 +- Sources/WitnessedArbitrary.swift | 2 +- Templates/Cartesian.swift.gyb | 9 +- Tests/SwiftCheckTests/ComplexSpec.swift | 2 +- Tests/SwiftCheckTests/FormatterSpec.swift | 4 +- Tests/SwiftCheckTests/GenSpec.swift | 46 ++++----- Tests/SwiftCheckTests/ModifierSpec.swift | 2 +- Tests/SwiftCheckTests/PathSpec.swift | 5 +- Tests/SwiftCheckTests/ReplaySpec.swift | 2 +- Tests/SwiftCheckTests/RoseSpec.swift | 6 +- Tests/SwiftCheckTests/SimpleSpec.swift | 20 ++-- Tests/SwiftCheckTests/TestSpec.swift | 2 +- 20 files changed, 215 insertions(+), 229 deletions(-) diff --git a/Sources/Arbitrary.swift b/Sources/Arbitrary.swift index 7e928ae..9f9c288 100644 --- a/Sources/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -89,6 +89,19 @@ extension Bool : Arbitrary { } } +extension BinaryInteger { + /// Shrinks any `Numeric` type. + public var shrinkIntegral : [Self] { + return unfoldr({ i in + if i <= 0 { + return .none + } + let n = i / 2 + return .some((n, n)) + }, initial: self < 0 ? (self * -1) : self) + } +} + extension Int : Arbitrary { /// Returns a generator of `Int` values. public static var arbitrary : Gen { @@ -107,7 +120,7 @@ extension Int8 : Arbitrary { /// Returns a generator of `Int8` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int8(truncatingBitPattern: -n), Int8(truncatingBitPattern: n))) + return Gen.choose((Int8(extendingOrTruncating: -n), Int8(extendingOrTruncating: n))) } } @@ -121,7 +134,7 @@ extension Int16 : Arbitrary { /// Returns a generator of `Int16` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int16(truncatingBitPattern: -n), Int16(truncatingBitPattern: n))) + return Gen.choose((Int16(extendingOrTruncating: -n), Int16(extendingOrTruncating: n))) } } @@ -135,7 +148,7 @@ extension Int32 : Arbitrary { /// Returns a generator of `Int32` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int32(truncatingBitPattern: -n), Int32(truncatingBitPattern: n))) + return Gen.choose((Int32(extendingOrTruncating: -n), Int32(extendingOrTruncating: n))) } } @@ -175,7 +188,7 @@ extension UInt8 : Arbitrary { /// Returns a generator of `UInt8` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.sized { n in Gen.choose((0, UInt8(truncatingBitPattern: n))) } + return Gen.sized { n in Gen.choose((0, UInt8(extendingOrTruncating: n))) } } } @@ -188,7 +201,7 @@ extension UInt8 : Arbitrary { extension UInt16 : Arbitrary { /// Returns a generator of `UInt16` values. public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt16(truncatingBitPattern: n))) } + return Gen.sized { n in Gen.choose((0, UInt16(extendingOrTruncating: n))) } } /// The default shrinking function for `UInt16` values. @@ -200,7 +213,7 @@ extension UInt16 : Arbitrary { extension UInt32 : Arbitrary { /// Returns a generator of `UInt32` values. public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt32(truncatingBitPattern: n))) } + return Gen.sized { n in Gen.choose((0, UInt32(extendingOrTruncating: n))) } } /// The default shrinking function for `UInt32` values. @@ -263,8 +276,8 @@ extension Double : Arbitrary { let numerator = Gen.choose((Int64(-n) * precision, Int64(n) * precision)) let denominator = Gen.choose((1, precision)) - return Gen<(Int64, Int64)>.zip(numerator, denominator).map { a, b in - return Double(a) / Double(b) + return Gen<(Int64, Int64)>.zip(numerator, denominator).map { t in + return Double(t.0) / Double(t.1) } } } diff --git a/Sources/Cartesian.swift b/Sources/Cartesian.swift index c900e1a..628d0e9 100644 --- a/Sources/Cartesian.swift +++ b/Sources/Cartesian.swift @@ -23,8 +23,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2), ga3 - ).map { - ($0.0, $0.1, $1) + ).map { t in + (t.0.0, t.0.1, t.1) } } @@ -35,7 +35,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga2: A generator of values of type `A2`. /// - parameter ga3: A generator of values of type `A3`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map(transform) + return zip(ga1, ga2, ga3).map({ t in transform(t.0, t.1, t.2) }) } /// Zips together 4 generators into a generator of 4-tuples. @@ -49,8 +49,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3), ga4 - ).map { - ($0.0, $0.1, $0.2, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.1) } } @@ -62,7 +62,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga3: A generator of values of type `A3`. /// - parameter ga4: A generator of values of type `A4`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map(transform) + return zip(ga1, ga2, ga3, ga4).map({ t in transform(t.0, t.1, t.2, t.3) }) } /// Zips together 5 generators into a generator of 5-tuples. @@ -77,8 +77,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4), ga5 - ).map { - ($0.0, $0.1, $0.2, $0.3, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.1) } } @@ -91,7 +91,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga4: A generator of values of type `A4`. /// - parameter ga5: A generator of values of type `A5`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5).map({ t in transform(t.0, t.1, t.2, t.3, t.4) }) } /// Zips together 6 generators into a generator of 6-tuples. @@ -107,8 +107,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5), ga6 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.1) } } @@ -122,7 +122,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga5: A generator of values of type `A5`. /// - parameter ga6: A generator of values of type `A6`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5) }) } /// Zips together 7 generators into a generator of 7-tuples. @@ -139,8 +139,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6), ga7 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.1) } } @@ -155,7 +155,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga6: A generator of values of type `A6`. /// - parameter ga7: A generator of values of type `A7`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6) }) } /// Zips together 8 generators into a generator of 8-tuples. @@ -173,8 +173,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7), ga8 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.1) } } @@ -190,7 +190,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga7: A generator of values of type `A7`. /// - parameter ga8: A generator of values of type `A8`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7) }) } /// Zips together 9 generators into a generator of 9-tuples. @@ -209,8 +209,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8), ga9 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.1) } } @@ -227,7 +227,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga8: A generator of values of type `A8`. /// - parameter ga9: A generator of values of type `A9`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8) }) } /// Zips together 10 generators into a generator of 10-tuples. @@ -247,8 +247,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9), ga10 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.1) } } @@ -266,7 +266,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga9: A generator of values of type `A9`. /// - parameter ga10: A generator of values of type `A10`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9) }) } /// Zips together 11 generators into a generator of 11-tuples. @@ -287,8 +287,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10), ga11 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.1) } } @@ -307,7 +307,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga10: A generator of values of type `A10`. /// - parameter ga11: A generator of values of type `A11`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10) }) } /// Zips together 12 generators into a generator of 12-tuples. @@ -329,8 +329,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11), ga12 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.1) } } @@ -350,7 +350,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga11: A generator of values of type `A11`. /// - parameter ga12: A generator of values of type `A12`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11) }) } /// Zips together 13 generators into a generator of 13-tuples. @@ -373,8 +373,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12), ga13 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.1) } } @@ -395,7 +395,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga12: A generator of values of type `A12`. /// - parameter ga13: A generator of values of type `A13`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12) }) } /// Zips together 14 generators into a generator of 14-tuples. @@ -419,8 +419,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13), ga14 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.1) } } @@ -442,7 +442,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga13: A generator of values of type `A13`. /// - parameter ga14: A generator of values of type `A14`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13) }) } /// Zips together 15 generators into a generator of 15-tuples. @@ -467,8 +467,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14), ga15 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.1) } } @@ -491,7 +491,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga14: A generator of values of type `A14`. /// - parameter ga15: A generator of values of type `A15`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14) }) } /// Zips together 16 generators into a generator of 16-tuples. @@ -517,8 +517,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15), ga16 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.1) } } @@ -542,7 +542,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga15: A generator of values of type `A15`. /// - parameter ga16: A generator of values of type `A16`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15) }) } /// Zips together 17 generators into a generator of 17-tuples. @@ -569,8 +569,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16), ga17 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.1) } } @@ -595,7 +595,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga16: A generator of values of type `A16`. /// - parameter ga17: A generator of values of type `A17`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16) }) } /// Zips together 18 generators into a generator of 18-tuples. @@ -623,8 +623,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17), ga18 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.1) } } @@ -650,7 +650,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga17: A generator of values of type `A17`. /// - parameter ga18: A generator of values of type `A18`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17) }) } /// Zips together 19 generators into a generator of 19-tuples. @@ -679,8 +679,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18), ga19 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.1) } } @@ -707,7 +707,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga18: A generator of values of type `A18`. /// - parameter ga19: A generator of values of type `A19`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18) }) } /// Zips together 20 generators into a generator of 20-tuples. @@ -737,8 +737,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19), ga20 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.1) } } @@ -766,7 +766,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga19: A generator of values of type `A19`. /// - parameter ga20: A generator of values of type `A20`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19) }) } /// Zips together 21 generators into a generator of 21-tuples. @@ -797,8 +797,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20), ga21 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $0.19, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.0.19, t.1) } } @@ -827,7 +827,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga20: A generator of values of type `A20`. /// - parameter ga21: A generator of values of type `A21`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20) }) } /// Zips together 22 generators into a generator of 22-tuples. @@ -859,8 +859,8 @@ extension Gen /*: Cartesian*/ { .zip( .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21), ga22 - ).map { - ($0.0, $0.1, $0.2, $0.3, $0.4, $0.5, $0.6, $0.7, $0.8, $0.9, $0.10, $0.11, $0.12, $0.13, $0.14, $0.15, $0.16, $0.17, $0.18, $0.19, $0.20, $1) + ).map { t in + (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.0.19, t.0.20, t.1) } } @@ -890,7 +890,7 @@ extension Gen /*: Cartesian*/ { /// - parameter ga21: A generator of values of type `A21`. /// - parameter ga22: A generator of values of type `A22`. public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map(transform) + return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20, t.21) }) } } diff --git a/Sources/Check.swift b/Sources/Check.swift index 455ae07..ffdb948 100644 --- a/Sources/Check.swift +++ b/Sources/Check.swift @@ -148,8 +148,7 @@ public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return + default: () } } @@ -162,8 +161,7 @@ public func <- (checker : AssertiveQuickCheck, test : () -> Testable) { XCTFail("Expected property to fail but it didn't. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) case let .insufficientCoverage(_, seed, sz, _, _): XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) - default: - return + default: () } } diff --git a/Sources/CoArbitrary.swift b/Sources/CoArbitrary.swift index 704b555..836e6c1 100644 --- a/Sources/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -22,7 +22,7 @@ public protocol CoArbitrary { static func coarbitrary(_ x : Self) -> ((Gen) -> Gen) } -extension Integer { +extension BinaryInteger { /// A coarbitrary implementation for any IntegerType public func coarbitraryIntegral() -> (Gen) -> Gen { return { $0.variant(self) } @@ -71,7 +71,7 @@ extension String : CoArbitrary { } return comp( Character.coarbitrary(x[x.startIndex]), - String.coarbitrary(x[x.characters.index(after: x.startIndex).. { public static func weighted(_ xs : S) -> Gen where S.Iterator.Element == (Int, A) { - return frequency(xs.map { ($0, Gen.pure($1)) }) + return frequency(xs.map { t in (t.0, Gen.pure(t.1)) }) } } @@ -186,7 +186,7 @@ extension Gen { /// Returns a new generator that applies a given function to any outputs the /// given generators produce. public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map(transform) + return zip(ga1, ga2).map({ t in transform(t.0, t.1) }) } } @@ -194,7 +194,7 @@ extension Gen { extension Gen { /// Shakes up the generator's internal Random Number Generator with a seed. - public func variant(_ seed : S) -> Gen { + public func variant(_ seed : S) -> Gen { return Gen(unGen: { rng, n in return self.unGen(vary(seed, rng), n) }) @@ -286,44 +286,6 @@ extension Gen { } } -extension Gen { - @available(*, unavailable, renamed: "fromElements(of:)") - public static func fromElementsOf(_ xs : S) -> Gen - where S.Index : RandomType - { - return Gen.fromElements(of: xs) - } - - - @available(*, unavailable, renamed: "fromElements(in:)") - public static func fromElementsIn(_ xs : ClosedRange) -> Gen { - return Gen.fromElements(in: xs) - } - - @available(*, unavailable, renamed: "fromInitialSegments(of:)") - public static func fromInitialSegmentsOf(_ xs : [S]) -> Gen<[S]> { - return Gen.fromInitialSegments(of: xs) - } - - @available(*, unavailable, renamed: "fromShufflingElements(of:)") - public static func fromShufflingElementsOf(_ xs : [S]) -> Gen<[S]> { - return Gen.fromShufflingElements(of: xs) - } - - - @available(*, unavailable, renamed: "one(of:)") - public static func oneOf(_ gs : S) -> Gen - where S.Iterator.Element == Gen, S.Index : RandomType - { - return Gen.one(of: gs) - } - - @available(*, unavailable, renamed: "proliferate(withSize:)") - public func proliferateSized(_ k : Int) -> Gen<[A]> { - return self.proliferate(withSize: k) - } -} - // MARK: Instances extension Gen /*: Functor*/ { @@ -345,7 +307,7 @@ extension Gen /*: Functor*/ { extension Gen /*: Applicative*/ { /// Lifts a value into a generator that will only generate that value. public static func pure(_ a : A) -> Gen { - return Gen(unGen: { _ in + return Gen(unGen: { (_,_) in return a }) } @@ -434,15 +396,15 @@ private func delay() -> Gen<(Gen) -> A> { }) } -private func vary(_ k : S, _ rng : StdGen) -> StdGen { +private func vary(_ k : S, _ rng : StdGen) -> StdGen { let s = rng.split let gen = ((k % 2) == 0) ? s.0 : s.1 return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func size(_ k : S, _ m : Int) -> Int { +private func size(_ k : S, _ m : Int) -> Int { let n = Double(m) - return Int((log(n + 1)) * Double(k.toIntMax()) / log(100)) + return Int((log(n + 1)) * (Double(exactly: k) ?? 0.0) / log(100)) } private func selectOne(_ xs : [A]) -> [(A, [A])] { diff --git a/Sources/Modifiers.swift b/Sources/Modifiers.swift index 8e34882..806829d 100644 --- a/Sources/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -398,7 +398,7 @@ extension IsoOf : CustomReflectable { /// By default, SwiftCheck generates values drawn from a small range. `Large` /// gives you values drawn from the entire range instead. -public struct Large : Arbitrary { +public struct Large : Arbitrary { /// Retrieves the underlying large value. public let getLarge : A @@ -424,7 +424,7 @@ public struct Large : Arbitrar } /// Guarantees that every generated integer is greater than 0. -public struct Positive : Arbitrary, CustomStringConvertible { +public struct Positive : Arbitrary, CustomStringConvertible { /// Retrieves the underlying positive value. public let getPositive : A @@ -458,7 +458,7 @@ extension Positive : CoArbitrary { } /// Guarantees that every generated integer is never 0. -public struct NonZero : Arbitrary, CustomStringConvertible { +public struct NonZero : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-zero value. public let getNonZero : A @@ -491,7 +491,7 @@ extension NonZero : CoArbitrary { } /// Guarantees that every generated integer is greater than or equal to 0. -public struct NonNegative : Arbitrary, CustomStringConvertible { +public struct NonNegative : Arbitrary, CustomStringConvertible { /// Retrieves the underlying non-negative value. public let getNonNegative : A @@ -565,9 +565,10 @@ fileprivate final class ArrowOfImpl : } static func shrink(_ f : ArrowOfImpl) -> [ArrowOfImpl] { - return f.table.flatMap { (x, y) in - return U.shrink(y).map({ (y2 : U) -> ArrowOfImpl in - return ArrowOfImpl({ (z : T) -> U in + return f.table.flatMap { (t) -> [ArrowOfImpl] in + let (x, y) = t + return U.shrink(y).map({ y2 in + return ArrowOfImpl({ z in if x == z { return y2 } @@ -603,7 +604,7 @@ fileprivate final class IsoOfImpl) -> [IsoOfImpl] { - return f.table.flatMap { (x, y) in - return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ (y1 , y2) -> IsoOfImpl in + return f.table.flatMap { (t) -> [IsoOfImpl] in + let (x, y) = t + return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ t in + let (y1 , y2) = t return IsoOfImpl( { (z : T) -> U in if x == z { diff --git a/Sources/Property.swift b/Sources/Property.swift index 9716ede..7dc6237 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -161,7 +161,7 @@ extension Testable { /// /// - returns: A `Property` that prints the counterexample value on failure. public func counterexample(_ example : String) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { _ in + return self.withCallback(Callback.afterFinalFailure(kind: .counterexample) { (_,_) in return print(example) }) } @@ -173,7 +173,7 @@ extension Testable { /// /// - returns: A `Property` that executes the given callback block on failure. public func whenFail(_ callback : @escaping () -> ()) -> Property { - return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { _ in + return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (_,_) in return callback() }) } @@ -599,7 +599,7 @@ private func protectResult(_ r : @escaping () throws -> TestResult) -> (() -> Te internal func unionWith(_ f : (V, V) -> V, l : Dictionary, r : Dictionary) -> Dictionary { var map = l - r.forEach { (k, v) in + for (k, v) in r { if let val = map.updateValue(v, forKey: k) { map.updateValue(f(val, v), forKey: k) } @@ -668,52 +668,51 @@ private func printLabels(_ st : TestResult) { } else if st.labels.count == 1, let pt = st.labels.first { print("(\(pt.0))") } else { - let gAllLabels = st.labels.map({ (l, _) in - return l + ", " + let gAllLabels = st.labels.map({ t in + return t.0 + ", " }).reduce("", +) print("(" + gAllLabels[gAllLabels.startIndex.. TestResult, xs : [Rose]) -> Rose { - if xs.isEmpty { + guard let p = xs.first else { return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) - } else if let p = xs.first { - return .ioRose(/*protectRose*/({ - let rose = p.reduce - switch rose { - case .mkRose(let result, _): - if !result().expect { - return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) - } + } + return .ioRose(/*protectRose*/({ + let rose = p.reduce + switch rose { + case .mkRose(let result, _): + if !result().expect { + return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction")) + } - switch result().ok { - case .some(true): - return conj(comp(addLabels(result()), comp(addCallbacks(result()), k)), xs: [Rose](xs[1..](xs[1..](xs[1..](xs[1.., q : Rose) -> Rose { @@ -733,7 +732,7 @@ private func disj(_ p : Rose, q : Rose) -> Rose.pure(result2) case .some(false): - let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { _ in return print("") })] + let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { (_, _) in return print("") })] return Rose.pure(TestResult( ok: .some(false), expect: true, diff --git a/Sources/Random.swift b/Sources/Random.swift index a4b9497..c2d2cf8 100644 --- a/Sources/Random.swift +++ b/Sources/Random.swift @@ -157,7 +157,7 @@ extension Int : RandomType { public static func randomInRange(_ range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int(truncatingBitPattern: bb), gg) + return (Int(extendingOrTruncating: bb), gg) } } @@ -166,7 +166,7 @@ extension Int8 : RandomType { public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int8(truncatingBitPattern: bb), gg) + return (Int8(extendingOrTruncating: bb), gg) } } @@ -175,7 +175,7 @@ extension Int16 : RandomType { public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int16(truncatingBitPattern: bb), gg) + return (Int16(extendingOrTruncating: bb), gg) } } @@ -184,7 +184,7 @@ extension Int32 : RandomType { public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int32(truncatingBitPattern: bb), gg) + return (Int32(extendingOrTruncating: bb), gg) } } @@ -231,7 +231,7 @@ extension UInt : RandomType { public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt(truncatingBitPattern: bb), gg) + return (UInt(extendingOrTruncating: bb), gg) } } @@ -240,7 +240,7 @@ extension UInt8 : RandomType { public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt8(truncatingBitPattern: bb), gg) + return (UInt8(extendingOrTruncating: bb), gg) } } @@ -249,7 +249,7 @@ extension UInt16 : RandomType { public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt16(truncatingBitPattern: bb), gg) + return (UInt16(extendingOrTruncating: bb), gg) } } @@ -258,7 +258,7 @@ extension UInt32 : RandomType { public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt32(truncatingBitPattern: bb), gg) + return (UInt32(extendingOrTruncating: bb), gg) } } @@ -359,8 +359,8 @@ private func mkStdRNG(_ o : Int) -> StdGen { } let (sec, psec) = (tt.tv_sec, tt.tv_nsec) - let (ll, _) = Int.multiplyWithOverflow(Int(sec), 12345) - return mkStdGen32(Int.addWithOverflow(ll, Int.addWithOverflow(psec, Int.addWithOverflow(ct, o).0).0).0) + let (ll, _) = Int(sec).multipliedReportingOverflow(by: 12345) + return mkStdGen32(ll.addingReportingOverflow(psec.addingReportingOverflow(ct.addingReportingOverflow(o).0).0).0) } private func clock_gettime(_ : Int, _ t : UnsafeMutablePointer) -> ClockTimeResult { diff --git a/Sources/Test.swift b/Sources/Test.swift index 1be7eda..0b01ebb 100644 --- a/Sources/Test.swift +++ b/Sources/Test.swift @@ -598,7 +598,7 @@ internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> name: args.name, maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests, maxAllowableDiscardedTests: args.maxAllowableDiscardedTests, - computeSize: { computeSize(args, vals: $0) }, + computeSize: { (t, u) in computeSize(args, vals: (t, u)) }, successfulTestCount: 0, discardedTestCount: 0, labels: [:], @@ -977,7 +977,7 @@ private func dispatchAfterTestCallbacks(_ st : CheckerState, res : TestResult) { case let .afterTest(_, f): f(st, res) default: - break + () } } } @@ -992,7 +992,7 @@ private func dispatchAfterFinalFailureCallbacks(_ st : CheckerState, res : TestR case let .afterFinalFailure(_, f): f(st, res) default: - break + () } } } @@ -1021,7 +1021,8 @@ private func printDistributionGraph(_ st : CheckerState) { let allLabels : [String] = Array(gPrint.sorted().reversed()) var covers = [String]() - st.labels.forEach { (l, reqP) in + st.labels.forEach { t in + let (l, reqP) = t let p = labelPercentage(l, st: st) if p < reqP { covers += ["only \(p)% " + l + ", not \(reqP)%"] @@ -1050,7 +1051,7 @@ private func pluralize(_ s : String, _ i : Int) -> String { private func insufficientCoverage(_ st : CheckerState) -> Bool { return st.labels - .map({ (l, reqP) in labelPercentage(l, st: st) < reqP }) + .map({ t in labelPercentage(t.0, st: st) < t.1 }) .reduce(false, { $0 || $1 }) } diff --git a/Sources/WitnessedArbitrary.swift b/Sources/WitnessedArbitrary.swift index 46fb5f6..41df792 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/WitnessedArbitrary.swift @@ -240,7 +240,7 @@ extension Repeated where Element : Arbitrary { return repeatElement(element , count: count) } - return Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary).map(constructor) + return Gen<(Element, Int)>.zip(Element.arbitrary, Int.arbitrary).map({ t in constructor(t.0, t.1) }) } } diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 593f5b0..41ca5f5 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -27,7 +27,8 @@ parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, ar previous_parameter_range = range(1, arity) previous_zip_arguments = ', '.join(['ga{0}'.format(n) for n in previous_parameter_range]) -expanded_previous_tuple = ', '.join(['$0.{0}'.format(n - 1) for n in previous_parameter_range]) +expanded_previous_tuple = ', '.join(['t.0.{0}'.format(n - 1) for n in previous_parameter_range]) +expanded_previous_tuple2 = ', '.join(['t.{0}'.format(n) for n in range(0, arity)]) # Map body template @@ -43,8 +44,8 @@ map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1 .zip( .zip(${previous_zip_arguments}), ga${arity} - ).map { - (${expanded_previous_tuple}, $$1) + ).map { t in + (${expanded_previous_tuple}, t.1) } } @@ -55,7 +56,7 @@ map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1 /// - parameter ${p}: A generator of values of type `${t}`. % end public static func map<${type_parameter_list}, R>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> R) -> Gen { - return zip(${map_zip_argument_list}).map(transform) + return zip(${map_zip_argument_list}).map({ t in transform(${expanded_previous_tuple2}) }) } % end diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 73cd10f..cbfacbc 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -88,6 +88,6 @@ func glue(_ parts : [Gen]) -> Gen { extension String { fileprivate var initial : String { - return self[self.startIndex.. : Arbitrar return Gen.one(of: [ Gen<(UInt, ArrowOf, ArrowOf)> .zip(UInt.arbitrary, ArrowOf.arbitrary, ArrowOf.arbitrary) - .map { Formatter(lengthLimit: $0, makeString: $1.getArrow, makeValue: $2.getArrow) } + .map { t in Formatter(lengthLimit: t.0, makeString: t.1.getArrow, makeValue: t.2.getArrow) } .map(ArbitraryFormatter.init), Gen<(UInt, IsoOf)> .zip(UInt.arbitrary, IsoOf.arbitrary) - .map { Formatter(lengthLimit: $0, makeString: $1.getTo, makeValue: $1.getFrom) } + .map { t in Formatter(lengthLimit: t.0, makeString: t.1.getTo, makeValue: t.1.getFrom) } .map(ArbitraryFormatter.init) ]) } diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index f40a5f9..1243f21 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -252,7 +252,7 @@ class GenSpec : XCTestCase { property("Gen.ap is consistent with Gen.zip2") <- forAll { (x : Int, f : ArrowOf) in let fx = Gen.pure(x) let ff = Gen>.pure(f).map { $0.getArrow } - return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { f, x in f(x) } + return fx.ap(ff) == Gen<((Int) -> Int, Int)>.zip(ff, fx).map { (t) in t.0(t.1) } } // CHECK-NEXT: *** Passed 100 tests @@ -271,8 +271,8 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip3 behaves") <- forAll { (x : Int, y : Int, z : Int) in let g = Gen<(Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z)) - return forAllNoShrink(g) { (x1, y1, z1) in - return (x1, y1, z1) == (x, y, z) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2) == (x, y, z) } } @@ -280,8 +280,8 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip4 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int) in let g = Gen<(Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w)) - return forAllNoShrink(g) { (x1, y1, z1, w1) in - return (x1, y1, z1, w1) == (x, y, z, w) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3) == (x, y, z, w) } } @@ -289,8 +289,8 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip5 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int) in let g = Gen<(Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1) in - return (x1, y1, z1, w1, a1) == (x, y, z, w, a) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4) == (x, y, z, w, a) } } @@ -298,8 +298,8 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip6 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) } } @@ -307,9 +307,9 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip7 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && c1 == c + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) + && t.6 == c } } @@ -317,9 +317,9 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1) == (c, d) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) + && (t.6, t.7) == (c, d) } } @@ -328,9 +328,9 @@ class GenSpec : XCTestCase { property("Gen.zip9 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in return forAll { (e : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1) == (c, d, e) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) + && (t.6, t.7, t.8) == (c, d, e) } } } @@ -340,9 +340,9 @@ class GenSpec : XCTestCase { property("Gen.zip10 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in return forAll { (e : Int, f : Int) in let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d), Gen.pure(e), Gen.pure(f)) - return forAllNoShrink(g) { (x1, y1, z1, w1, a1, b1, c1, d1, e1, f1) in - return (x1, y1, z1, w1, a1, b1) == (x, y, z, w, a, b) - && (c1, d1, e1, f1) == (c, d, e, f) + return forAllNoShrink(g) { (t) in + return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) + && (t.6, t.7, t.8, t.9) == (c, d, e, f) } } } @@ -447,8 +447,8 @@ private func ==(l : Gen, r : Gen) -> Bool { /// - Returns: True *iff* `(a1, a2, a3) == (b1, b2, b3)` /// where `lhs = Gen((a1, (a2, a3)))` and `rhs = Gen(((b1, b2), b3))`. private func ~= (lhs : Gen<(Int, (Int, Int))>, rhs : Gen<((Int, Int), Int)>) -> Bool { - let normalizedL = lhs.map { ($0, $1.0, $1.1) } - let normalizedR = rhs.map { ($0.0, $0.1, $1) } + let normalizedL = lhs.map { t in (t.0, t.1.0, t.1.1) } + let normalizedR = rhs.map { t in (t.0.0, t.0.1, t.1) } let sampleSize = 10 let sampleL = normalizedL.proliferate(withSize: sampleSize).generate diff --git a/Tests/SwiftCheckTests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift index 0130b9b..c99b909 100644 --- a/Tests/SwiftCheckTests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -80,7 +80,7 @@ class ModifierSpec : XCTestCase { // CHECK-NEXT: . property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + return (xs.getArray.filter(f).reduce(true, { (acc, val) in acc && f(val) }) as Bool) } }) } diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index bfe6ba1..95f45ad 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -52,13 +52,13 @@ struct Extremal : Arbitrary { } class PathSpec : XCTestCase { - private static func smallProp(_ pth : Path) -> Bool { + private static func smallProp(_ pth : Path) -> Bool { return path({ x in return (x >= -100 || -100 >= 0) && x <= 100 }, pth) } - private static func largeProp(_ pth : Path) -> Property { + private static func largeProp(_ pth : Path) -> Property { return somePath({ x in return (x < -1000000 || x > 1000000) }, pth) @@ -104,4 +104,3 @@ class PathSpec : XCTestCase { ]) #endif } - diff --git a/Tests/SwiftCheckTests/ReplaySpec.swift b/Tests/SwiftCheckTests/ReplaySpec.swift index 7d02134..841f14b 100644 --- a/Tests/SwiftCheckTests/ReplaySpec.swift +++ b/Tests/SwiftCheckTests/ReplaySpec.swift @@ -12,7 +12,7 @@ import XCTest class ReplaySpec : XCTestCase { func testAll() { property("Test is replayed at specific args") <- forAll { (seedl : Int, seedr : Int, size : Int) in - let replayArgs = CheckerArguments(replay: .some(StdGen(seedl, seedr), size)) + let replayArgs = CheckerArguments(replay: .some((StdGen(seedl, seedr), size))) var foundArgs : [Int] = [] property("Replay at \(seedl), \(seedr)", arguments: replayArgs) <- forAll { (x : Int) in foundArgs.append(x) diff --git a/Tests/SwiftCheckTests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift index 2369218..0356576 100644 --- a/Tests/SwiftCheckTests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -105,8 +105,10 @@ private func arbTree(_ n : Int) -> Gen> { } return Positive.arbitrary.flatMap { m in let n2 = n / (m.getPositive + 1) - return Gen<(A, [A])>.zip(A.arbitrary, arbTree(n2).proliferate(withSize: m.getPositive)).flatMap { (a, f) in - return Gen.pure(RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } }))) + let gg : Gen<(A, [RoseTreeOf])> = Gen<(A, [RoseTreeOf])>.zip(A.arbitrary, arbTree(n2).proliferate(withSize: m.getPositive)) + return gg.map { (t) -> RoseTreeOf in + let (a, f) = t + return RoseTreeOf(.mkRose({ a }, { f.map { $0.getRose } })) } } } diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index faeb8ec..2a1e1a9 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -9,6 +9,14 @@ import SwiftCheck import XCTest +private func pack(_ f : @escaping (A, B) -> C) -> ((A, B)) -> C { + return f +} + +private func pack(_ f : @escaping (A, B, C, D, E, F, G, H, I, J, K, L, M, N) -> O) -> ((A, B, C, D, E, F, G, H, I, J, K, L, M, N)) -> O { + return f +} + public struct ArbitraryFoo { let x : Int let y : Int @@ -20,7 +28,7 @@ public struct ArbitraryFoo { extension ArbitraryFoo : Arbitrary { public static var arbitrary : Gen { - return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(ArbitraryFoo.init) + return Gen<(Int, Int)>.zip(Int.arbitrary, Int.arbitrary).map(pack(ArbitraryFoo.init)) } } @@ -100,9 +108,9 @@ extension ArbitraryLargeFoo : Arbitrary { Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), Gen<(Bool, Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary, Bool.arbitrary) - ) { t2 in - (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t2.0, t2.1, t2.2, t2.3) - }.map(ArbitraryLargeFoo.init) + ) { (t21, t22, t23, t24) in + (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t21, t22, t23, t24) + }.map(pack(ArbitraryLargeFoo.init)) } } } @@ -205,9 +213,9 @@ class SimpleSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("Inverses work") <- forAllNoShrink(inverses) { (op, iop) in + property("Inverses work") <- forAllNoShrink(inverses) { (t) in return forAll { (x : UInt8, y : UInt8) in - return op(x, y) ==== !iop(x, y) + return t.0(x, y) ==== !t.1(x, y) } } diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index a9faec1..a7d6b51 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -65,7 +65,7 @@ class TestSpec : XCTestCase { property("filter behaves") <- forAll { (xs : Array) in return forAll { (pred : ArrowOf) in let f = pred.getArrow - return (xs.filter(f).reduce(true, { $0.0 && f($0.1) }) as Bool) + return (xs.filter(f).reduce(true, { (acc, val) in acc && f(val) }) as Bool) } } }) From 8d686fbb0512935a25e0176f0f0c04ccc31372cb Mon Sep 17 00:00:00 2001 From: TJ Usiyan Date: Sat, 10 Jun 2017 16:57:03 -0400 Subject: [PATCH 402/460] Compile in swift 3.2 --- SwiftCheck.xcodeproj/project.pbxproj | 18 +++++++++++++++--- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcshareddata/xcschemes/SwiftCheck.xcscheme | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index d5652f9..d6692d7 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -510,7 +510,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -521,11 +521,11 @@ }; 844FCC8C198B320500EB242A = { CreatedOnToolsVersion = 6.0; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; }; 844FCC97198B320500EB242A = { CreatedOnToolsVersion = 6.0; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; TestTargetID = 844FCC8C198B320500EB242A; }; 84DF75F71B0BD54600C912B0 = { @@ -895,14 +895,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -943,14 +949,20 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index 0881581..94a37e7 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ Date: Sat, 8 Jul 2017 22:06:25 +0200 Subject: [PATCH 403/460] Drag the framework into the future: - Migrated code-base to Swift 4 - Migrated dir structure to SPM 4.0 format - Updated Travis to use Xcode9 and latest Swift for Linux - Added Docker and .dockerignore to .gitignore to aid Linux testing - Temporarily disabled `WitnessedArbitrary` extension `AnySequence` on all platforms. (View //FIXME: comment in `WitnessedArbitrary`.) - Temporarily disabled `WitnessedArbitrary` extension `AnyBidirectionalCollection` on non-linux platforms. (View //FIXME: comment in `WitnessedArbitrary`.) --- .gitignore | 4 + .swift-version | 2 +- .travis.yml | 4 +- Package.resolved | 16 + Package.swift | 17 +- Sources/{ => SwiftCheck}/Arbitrary.swift | 0 Sources/{ => SwiftCheck}/Cartesian.swift | 0 Sources/{ => SwiftCheck}/Check.swift | 0 Sources/{ => SwiftCheck}/CoArbitrary.swift | 0 Sources/{ => SwiftCheck}/Compose.swift | 0 Sources/{ => SwiftCheck}/Gen.swift | 4 +- Sources/{ => SwiftCheck}/Lattice.swift | 0 Sources/{ => SwiftCheck}/Modifiers.swift | 0 Sources/{ => SwiftCheck}/Property.swift | 0 Sources/{ => SwiftCheck}/Random.swift | 0 Sources/{ => SwiftCheck}/Rose.swift | 0 Sources/{ => SwiftCheck}/State.swift | 0 Sources/{ => SwiftCheck}/SwiftCheck.h | 0 Sources/{ => SwiftCheck}/Test.swift | 0 Sources/{ => SwiftCheck}/Testable.swift | 0 Sources/{ => SwiftCheck}/Witness.swift | 0 .../{ => SwiftCheck}/WitnessedArbitrary.swift | 16 +- SwiftCheck.podspec | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 650 +++++++++--------- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 + .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 + .../xcschemes/SwiftCheck.xcscheme | 2 + Tests/SwiftCheckTests/ComplexSpec.swift | 4 +- Tests/SwiftCheckTests/FailureSpec.swift | 16 +- Tests/SwiftCheckTests/FileCheck.swift | 8 +- Tutorial.playground/Contents.swift | 303 ++++---- Utilities/compile.sh | 2 +- 32 files changed, 564 insertions(+), 490 deletions(-) create mode 100644 Package.resolved rename Sources/{ => SwiftCheck}/Arbitrary.swift (100%) rename Sources/{ => SwiftCheck}/Cartesian.swift (100%) rename Sources/{ => SwiftCheck}/Check.swift (100%) rename Sources/{ => SwiftCheck}/CoArbitrary.swift (100%) rename Sources/{ => SwiftCheck}/Compose.swift (100%) rename Sources/{ => SwiftCheck}/Gen.swift (99%) rename Sources/{ => SwiftCheck}/Lattice.swift (100%) rename Sources/{ => SwiftCheck}/Modifiers.swift (100%) rename Sources/{ => SwiftCheck}/Property.swift (100%) rename Sources/{ => SwiftCheck}/Random.swift (100%) rename Sources/{ => SwiftCheck}/Rose.swift (100%) rename Sources/{ => SwiftCheck}/State.swift (100%) rename Sources/{ => SwiftCheck}/SwiftCheck.h (100%) rename Sources/{ => SwiftCheck}/Test.swift (100%) rename Sources/{ => SwiftCheck}/Testable.swift (100%) rename Sources/{ => SwiftCheck}/Witness.swift (100%) rename Sources/{ => SwiftCheck}/WitnessedArbitrary.swift (96%) diff --git a/.gitignore b/.gitignore index f69cd72..a613019 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,7 @@ build/ # Python *.pyc + +# Docker +.dockerignore +Dockerfile \ No newline at end of file diff --git a/.swift-version b/.swift-version index a3ec5a4..5186d07 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -3.2 +4.0 diff --git a/.travis.yml b/.travis.yml index 118a1f9..a3c04dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,8 +27,8 @@ matrix: - xcodebuild test -scheme SwiftCheck | xcpretty -c # -- Start iOS -- # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - - iOS_DEVICE_NAME="iPad Pro (12.9-inch)" - - iOS_RUNTIME_VERSION="10.0" + - iOS_DEVICE_NAME="iPad Pro (12.9-inch) (2nd generation)" + - iOS_RUNTIME_VERSION="11.0" # Get simulator identifier for desired device/runtime pair - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") - echo $SIMULATOR_ID diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..d2f10aa --- /dev/null +++ b/Package.resolved @@ -0,0 +1,16 @@ +{ + "object": { + "pins": [ + { + "package": "Operadics", + "repositoryURL": "https://github.com/tcldr/Operadics.git", + "state": { + "branch": "swift-4", + "revision": "8ee78809312caa4c82625fa7a5cba40fb16f10fd", + "version": null + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift index b9b0e29..5df1844 100644 --- a/Package.swift +++ b/Package.swift @@ -1,9 +1,24 @@ +// swift-tools-version:4.0 + import PackageDescription let package = Package( name: "SwiftCheck", + products: [ + .library( + name: "SwiftCheck", + targets: ["SwiftCheck"]), + ], + dependencies: [ + .package(url: "https://github.com/tcldr/Operadics.git", .branch("swift-4")) + ], targets: [ - Target(name: "SwiftCheck"), + .target( + name: "SwiftCheck", + dependencies: ["Operadics"]), + .testTarget( + name: "SwiftCheckTests", + dependencies: ["SwiftCheck"]), ] ) diff --git a/Sources/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift similarity index 100% rename from Sources/Arbitrary.swift rename to Sources/SwiftCheck/Arbitrary.swift diff --git a/Sources/Cartesian.swift b/Sources/SwiftCheck/Cartesian.swift similarity index 100% rename from Sources/Cartesian.swift rename to Sources/SwiftCheck/Cartesian.swift diff --git a/Sources/Check.swift b/Sources/SwiftCheck/Check.swift similarity index 100% rename from Sources/Check.swift rename to Sources/SwiftCheck/Check.swift diff --git a/Sources/CoArbitrary.swift b/Sources/SwiftCheck/CoArbitrary.swift similarity index 100% rename from Sources/CoArbitrary.swift rename to Sources/SwiftCheck/CoArbitrary.swift diff --git a/Sources/Compose.swift b/Sources/SwiftCheck/Compose.swift similarity index 100% rename from Sources/Compose.swift rename to Sources/SwiftCheck/Compose.swift diff --git a/Sources/Gen.swift b/Sources/SwiftCheck/Gen.swift similarity index 99% rename from Sources/Gen.swift rename to Sources/SwiftCheck/Gen.swift index 29d3d58..044a707 100644 --- a/Sources/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -402,9 +402,9 @@ private func vary(_ k : S, _ rng : StdGen) -> StdGen { return (k == (k / 2)) ? gen : vary(k / 2, rng) } -private func size(_ k : S, _ m : Int) -> Int { +private func size(_ k : Int, _ m : Int) -> Int { let n = Double(m) - return Int((log(n + 1)) * (Double(exactly: k) ?? 0.0) / log(100)) + return Int((log(n + 1)) * Double(k) / log(100)) } private func selectOne(_ xs : [A]) -> [(A, [A])] { diff --git a/Sources/Lattice.swift b/Sources/SwiftCheck/Lattice.swift similarity index 100% rename from Sources/Lattice.swift rename to Sources/SwiftCheck/Lattice.swift diff --git a/Sources/Modifiers.swift b/Sources/SwiftCheck/Modifiers.swift similarity index 100% rename from Sources/Modifiers.swift rename to Sources/SwiftCheck/Modifiers.swift diff --git a/Sources/Property.swift b/Sources/SwiftCheck/Property.swift similarity index 100% rename from Sources/Property.swift rename to Sources/SwiftCheck/Property.swift diff --git a/Sources/Random.swift b/Sources/SwiftCheck/Random.swift similarity index 100% rename from Sources/Random.swift rename to Sources/SwiftCheck/Random.swift diff --git a/Sources/Rose.swift b/Sources/SwiftCheck/Rose.swift similarity index 100% rename from Sources/Rose.swift rename to Sources/SwiftCheck/Rose.swift diff --git a/Sources/State.swift b/Sources/SwiftCheck/State.swift similarity index 100% rename from Sources/State.swift rename to Sources/SwiftCheck/State.swift diff --git a/Sources/SwiftCheck.h b/Sources/SwiftCheck/SwiftCheck.h similarity index 100% rename from Sources/SwiftCheck.h rename to Sources/SwiftCheck/SwiftCheck.h diff --git a/Sources/Test.swift b/Sources/SwiftCheck/Test.swift similarity index 100% rename from Sources/Test.swift rename to Sources/SwiftCheck/Test.swift diff --git a/Sources/Testable.swift b/Sources/SwiftCheck/Testable.swift similarity index 100% rename from Sources/Testable.swift rename to Sources/SwiftCheck/Testable.swift diff --git a/Sources/Witness.swift b/Sources/SwiftCheck/Witness.swift similarity index 100% rename from Sources/Witness.swift rename to Sources/SwiftCheck/Witness.swift diff --git a/Sources/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift similarity index 96% rename from Sources/WitnessedArbitrary.swift rename to Sources/SwiftCheck/WitnessedArbitrary.swift index 41df792..ab71987 100644 --- a/Sources/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -43,17 +43,24 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } } +//FIXME: This works as of Xcode 9 beta 3 but is disabled until Travis has Xcode 9 > beta 3 +#if os(Linux) extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element /// Given a witness and a function to test, converts them into a universally /// quantified property over `AnyBidirectionalCollection`s. public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnyBidirectionalCollection) -> Testable) -> Property { - return forAllShrink(AnyBidirectionalCollection.arbitrary, shrinker: AnyBidirectionalCollection.shrink, f: { bl in - return pf(AnyBidirectionalCollection(bl.map(wit))) - }) + return forAllShrink( + AnyBidirectionalCollection.arbitrary, + shrinker: AnyBidirectionalCollection.shrink, + f: { bl in + return pf(AnyBidirectionalCollection(bl.map(wit))) + } + ) } } +#endif extension AnySequence where Element : Arbitrary { /// Returns a generator of `AnySequence`s of arbitrary `Element`s. @@ -67,6 +74,8 @@ extension AnySequence where Element : Arbitrary { } } +//FIXME: This does not compile as of Xcode 9 beta 3 / 4.0-DEVELOPMENT-SNAPSHOT-2017-07-06 +#if false extension AnySequence : WitnessedArbitrary { public typealias Param = Element @@ -78,6 +87,7 @@ extension AnySequence : WitnessedArbitrary { }) } } +#endif extension ArraySlice where Element : Arbitrary { /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index b4a225c..99e8d93 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -36,5 +36,5 @@ Pod::Spec.new do |s| s.tvos.deployment_target = "9.0" s.framework = "XCTest" s.source = { :git => "https://github.com/typelift/SwiftCheck.git", :tag => "#{s.version}", :submodules => true } - s.source_files = "Sources/*.swift" + s.source_files = "Sources/SwiftCheck/*.swift" end diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index d6692d7..bdd2367 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,113 +7,113 @@ objects = { /* Begin PBXBuildFile section */ + 6A761B9E1F14E92100A7D74F /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B771F14E91400A7D74F /* Arbitrary.swift */; }; + 6A761B9F1F14E92100A7D74F /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B781F14E91400A7D74F /* Cartesian.swift */; }; + 6A761BA01F14E92100A7D74F /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B791F14E91400A7D74F /* Check.swift */; }; + 6A761BA11F14E92100A7D74F /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7A1F14E91400A7D74F /* CoArbitrary.swift */; }; + 6A761BA21F14E92100A7D74F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7B1F14E91500A7D74F /* Compose.swift */; }; + 6A761BA31F14E92100A7D74F /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7C1F14E91500A7D74F /* Gen.swift */; }; + 6A761BA41F14E92100A7D74F /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7D1F14E91500A7D74F /* Lattice.swift */; }; + 6A761BA51F14E92100A7D74F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7E1F14E91500A7D74F /* Modifiers.swift */; }; + 6A761BA61F14E92100A7D74F /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7F1F14E91500A7D74F /* Property.swift */; }; + 6A761BA71F14E92100A7D74F /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B801F14E91500A7D74F /* Random.swift */; }; + 6A761BA81F14E92100A7D74F /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B811F14E91500A7D74F /* Rose.swift */; }; + 6A761BA91F14E92100A7D74F /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B821F14E91500A7D74F /* State.swift */; }; + 6A761BAA1F14E92100A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6A761BAB1F14E92100A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; + 6A761BAC1F14E92100A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; + 6A761BAD1F14E92100A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; + 6A761BAE1F14E92100A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; + 6A761BAF1F14E92100A7D74F /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B771F14E91400A7D74F /* Arbitrary.swift */; }; + 6A761BB01F14E92200A7D74F /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B781F14E91400A7D74F /* Cartesian.swift */; }; + 6A761BB11F14E92200A7D74F /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B791F14E91400A7D74F /* Check.swift */; }; + 6A761BB21F14E92200A7D74F /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7A1F14E91400A7D74F /* CoArbitrary.swift */; }; + 6A761BB31F14E92200A7D74F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7B1F14E91500A7D74F /* Compose.swift */; }; + 6A761BB41F14E92200A7D74F /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7C1F14E91500A7D74F /* Gen.swift */; }; + 6A761BB51F14E92200A7D74F /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7D1F14E91500A7D74F /* Lattice.swift */; }; + 6A761BB61F14E92200A7D74F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7E1F14E91500A7D74F /* Modifiers.swift */; }; + 6A761BB71F14E92200A7D74F /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7F1F14E91500A7D74F /* Property.swift */; }; + 6A761BB81F14E92200A7D74F /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B801F14E91500A7D74F /* Random.swift */; }; + 6A761BB91F14E92200A7D74F /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B811F14E91500A7D74F /* Rose.swift */; }; + 6A761BBA1F14E92200A7D74F /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B821F14E91500A7D74F /* State.swift */; }; + 6A761BBB1F14E92200A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6A761BBC1F14E92200A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; + 6A761BBD1F14E92200A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; + 6A761BBE1F14E92200A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; + 6A761BBF1F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; + 6A761BC01F14E92200A7D74F /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B771F14E91400A7D74F /* Arbitrary.swift */; }; + 6A761BC11F14E92200A7D74F /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B781F14E91400A7D74F /* Cartesian.swift */; }; + 6A761BC21F14E92200A7D74F /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B791F14E91400A7D74F /* Check.swift */; }; + 6A761BC31F14E92200A7D74F /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7A1F14E91400A7D74F /* CoArbitrary.swift */; }; + 6A761BC41F14E92200A7D74F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7B1F14E91500A7D74F /* Compose.swift */; }; + 6A761BC51F14E92200A7D74F /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7C1F14E91500A7D74F /* Gen.swift */; }; + 6A761BC61F14E92200A7D74F /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7D1F14E91500A7D74F /* Lattice.swift */; }; + 6A761BC71F14E92200A7D74F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7E1F14E91500A7D74F /* Modifiers.swift */; }; + 6A761BC81F14E92200A7D74F /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B7F1F14E91500A7D74F /* Property.swift */; }; + 6A761BC91F14E92200A7D74F /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B801F14E91500A7D74F /* Random.swift */; }; + 6A761BCA1F14E92200A7D74F /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B811F14E91500A7D74F /* Rose.swift */; }; + 6A761BCB1F14E92200A7D74F /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B821F14E91500A7D74F /* State.swift */; }; + 6A761BCC1F14E92200A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6A761BCD1F14E92200A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; + 6A761BCE1F14E92200A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; + 6A761BCF1F14E92200A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; + 6A761BD01F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; + 6A761BD11F14E93900A7D74F /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */; }; + 6A761BD21F14E93900A7D74F /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */; }; + 6A761BD31F14E93900A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; + 6A761BD41F14E93900A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; + 6A761BD51F14E93900A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; + 6A761BD61F14E93900A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; + 6A761BD71F14E93900A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; + 6A761BD81F14E93900A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; + 6A761BD91F14E93900A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; + 6A761BDA1F14E93900A7D74F /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B961F14E91500A7D74F /* ModifierSpec.swift */; }; + 6A761BDB1F14E93900A7D74F /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B971F14E91500A7D74F /* PathSpec.swift */; }; + 6A761BDC1F14E93900A7D74F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B981F14E91500A7D74F /* PropertySpec.swift */; }; + 6A761BDD1F14E93900A7D74F /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B991F14E91500A7D74F /* ReplaySpec.swift */; }; + 6A761BDE1F14E93900A7D74F /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9A1F14E91500A7D74F /* RoseSpec.swift */; }; + 6A761BDF1F14E93900A7D74F /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */; }; + 6A761BE01F14E93900A7D74F /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */; }; + 6A761BE11F14E93900A7D74F /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9D1F14E91500A7D74F /* TestSpec.swift */; }; + 6A761BE21F14E93A00A7D74F /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */; }; + 6A761BE31F14E93A00A7D74F /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */; }; + 6A761BE41F14E93A00A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; + 6A761BE51F14E93A00A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; + 6A761BE61F14E93A00A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; + 6A761BE71F14E93A00A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; + 6A761BE81F14E93A00A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; + 6A761BE91F14E93A00A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; + 6A761BEA1F14E93A00A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; + 6A761BEB1F14E93A00A7D74F /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B961F14E91500A7D74F /* ModifierSpec.swift */; }; + 6A761BEC1F14E93A00A7D74F /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B971F14E91500A7D74F /* PathSpec.swift */; }; + 6A761BED1F14E93A00A7D74F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B981F14E91500A7D74F /* PropertySpec.swift */; }; + 6A761BEE1F14E93A00A7D74F /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B991F14E91500A7D74F /* ReplaySpec.swift */; }; + 6A761BEF1F14E93A00A7D74F /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9A1F14E91500A7D74F /* RoseSpec.swift */; }; + 6A761BF01F14E93A00A7D74F /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */; }; + 6A761BF11F14E93A00A7D74F /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */; }; + 6A761BF21F14E93A00A7D74F /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9D1F14E91500A7D74F /* TestSpec.swift */; }; + 6A761BF31F14E93B00A7D74F /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */; }; + 6A761BF41F14E93B00A7D74F /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */; }; + 6A761BF51F14E93B00A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; + 6A761BF61F14E93B00A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; + 6A761BF71F14E93B00A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; + 6A761BF81F14E93B00A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; + 6A761BF91F14E93B00A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; + 6A761BFA1F14E93B00A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; + 6A761BFB1F14E93B00A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; + 6A761BFC1F14E93B00A7D74F /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B961F14E91500A7D74F /* ModifierSpec.swift */; }; + 6A761BFD1F14E93B00A7D74F /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B971F14E91500A7D74F /* PathSpec.swift */; }; + 6A761BFE1F14E93B00A7D74F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B981F14E91500A7D74F /* PropertySpec.swift */; }; + 6A761BFF1F14E93B00A7D74F /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B991F14E91500A7D74F /* ReplaySpec.swift */; }; + 6A761C001F14E93B00A7D74F /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9A1F14E91500A7D74F /* RoseSpec.swift */; }; + 6A761C011F14E93B00A7D74F /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */; }; + 6A761C021F14E93B00A7D74F /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */; }; + 6A761C031F14E93B00A7D74F /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9D1F14E91500A7D74F /* TestSpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */; }; - 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */; }; - 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */; }; - 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */; }; - 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */; }; - 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD41D8EE86E003313E1 /* GenSpec.swift */; }; - 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */; }; - 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */; }; - 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD71D8EE86E003313E1 /* PathSpec.swift */; }; - 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */; }; - 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */; }; - 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */; }; - 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */; }; - 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */; }; - 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; - 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D81601C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; - 826D81611C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81621C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81631C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; - 826D81671C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D81681C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D81691C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; - 826D816A1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816B1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D816C1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; - 826D81701C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81711C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81721C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; - 826D81731C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81741C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81751C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; - 826D81761C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81771C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81781C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; - 826D81791C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817A1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817B1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; - 826D817C1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817D1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817E1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 826D817F1C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81801C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81811C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; - 826D81821C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81831C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81841C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; - 826D81851C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81861C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81871C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* Check.swift */; }; - 826D81881C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D81891C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D818A1C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; - 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; - 828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; - 828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; - 828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 828B7C861DEF575C0066A994 /* FormatterSpec.swift */; }; - 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA08CE1D6FFBD20068D32F /* Compose.swift */; }; - 82F3714C1DA7041300D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; - 82F3714D1DA7041400D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; - 82F3714E1DA7041500D60203 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F371481DA7010800D60203 /* FileCheck.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - FA3C185B1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; - FA3C185C1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; - FA3C185D1D93056D003DEB10 /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */; }; - FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; - FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; - FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAAB9E881D91C28F0097AC78 /* Cartesian.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -164,51 +164,52 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 6A761B751F14E91400A7D74F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6A761B771F14E91400A7D74F /* Arbitrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arbitrary.swift; sourceTree = ""; }; + 6A761B781F14E91400A7D74F /* Cartesian.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cartesian.swift; sourceTree = ""; }; + 6A761B791F14E91400A7D74F /* Check.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Check.swift; sourceTree = ""; }; + 6A761B7A1F14E91400A7D74F /* CoArbitrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoArbitrary.swift; sourceTree = ""; }; + 6A761B7B1F14E91500A7D74F /* Compose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Compose.swift; sourceTree = ""; }; + 6A761B7C1F14E91500A7D74F /* Gen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gen.swift; sourceTree = ""; }; + 6A761B7D1F14E91500A7D74F /* Lattice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; }; + 6A761B7E1F14E91500A7D74F /* Modifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; }; + 6A761B7F1F14E91500A7D74F /* Property.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; }; + 6A761B801F14E91500A7D74F /* Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; + 6A761B811F14E91500A7D74F /* Rose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Rose.swift; sourceTree = ""; }; + 6A761B821F14E91500A7D74F /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; + 6A761B831F14E91500A7D74F /* SwiftCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftCheck.h; sourceTree = ""; }; + 6A761B841F14E91500A7D74F /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; + 6A761B851F14E91500A7D74F /* Testable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; }; + 6A761B861F14E91500A7D74F /* Witness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; }; + 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WitnessedArbitrary.swift; sourceTree = ""; }; + 6A761B881F14E91500A7D74F /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; + 6A761B8A1F14E91500A7D74F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 6A761B8B1F14E91500A7D74F /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; + 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BooleanIdentitySpec.swift; sourceTree = ""; }; + 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CartesianSpec.swift; sourceTree = ""; }; + 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; + 6A761B901F14E91500A7D74F /* DiscardSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; }; + 6A761B911F14E91500A7D74F /* FailureSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; + 6A761B921F14E91500A7D74F /* FileCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCheck.swift; sourceTree = ""; }; + 6A761B931F14E91500A7D74F /* FormatterSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormatterSpec.swift; sourceTree = ""; }; + 6A761B941F14E91500A7D74F /* GenSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; }; + 6A761B951F14E91500A7D74F /* LambdaSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; + 6A761B961F14E91500A7D74F /* ModifierSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; }; + 6A761B971F14E91500A7D74F /* PathSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathSpec.swift; sourceTree = ""; }; + 6A761B981F14E91500A7D74F /* PropertySpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; }; + 6A761B991F14E91500A7D74F /* ReplaySpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; + 6A761B9A1F14E91500A7D74F /* RoseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoseSpec.swift; sourceTree = ""; }; + 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; }; + 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; }; + 6A761B9D1F14E91500A7D74F /* TestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 825C9AC81D8EE445003313E1 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = SOURCE_ROOT; }; - 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/SwiftCheckTests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/SwiftCheckTests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/SwiftCheckTests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/SwiftCheckTests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD41D8EE86E003313E1 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/SwiftCheckTests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/SwiftCheckTests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD71D8EE86E003313E1 /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/SwiftCheckTests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/SwiftCheckTests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/SwiftCheckTests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/SwiftCheckTests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/SwiftCheckTests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; - 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; - 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; - 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; - 826D814B1C953D070022266C /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lattice.swift; path = Sources/Lattice.swift; sourceTree = SOURCE_ROOT; }; - 826D814C1C953D070022266C /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = Sources/Modifiers.swift; sourceTree = SOURCE_ROOT; }; - 826D814E1C953D070022266C /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = SOURCE_ROOT; }; - 826D814F1C953D070022266C /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Random.swift; path = Sources/Random.swift; sourceTree = SOURCE_ROOT; }; - 826D81501C953D070022266C /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Rose.swift; path = Sources/Rose.swift; sourceTree = SOURCE_ROOT; }; - 826D81511C953D070022266C /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = State.swift; path = Sources/State.swift; sourceTree = SOURCE_ROOT; }; - 826D81521C953D070022266C /* SwiftCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = Sources/SwiftCheck.h; sourceTree = SOURCE_ROOT; }; - 826D81531C953D070022266C /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Test.swift; path = Sources/Test.swift; sourceTree = SOURCE_ROOT; }; - 826D81541C953D070022266C /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Testable.swift; path = Sources/Testable.swift; sourceTree = SOURCE_ROOT; }; - 826D81551C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; - 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; - 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; - 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; - 828B7C861DEF575C0066A994 /* FormatterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FormatterSpec.swift; path = Tests/SwiftCheckTests/FormatterSpec.swift; sourceTree = SOURCE_ROOT; }; - 82BA08CE1D6FFBD20068D32F /* Compose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Compose.swift; path = Sources/Compose.swift; sourceTree = SOURCE_ROOT; }; - 82F371481DA7010800D60203 /* FileCheck.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FileCheck.swift; path = Tests/SwiftCheckTests/FileCheck.swift; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CartesianSpec.swift.gyb; sourceTree = ""; }; - FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CartesianSpec.swift; path = Tests/SwiftCheckTests/CartesianSpec.swift; sourceTree = SOURCE_ROOT; }; FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; - FAAB9E881D91C28F0097AC78 /* Cartesian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cartesian.swift; path = Sources/Cartesian.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -260,97 +261,98 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 844FCC83198B320500EB242A = { + 6A761B741F14E91400A7D74F /* Sources */ = { isa = PBXGroup; children = ( - 826D81521C953D070022266C /* SwiftCheck.h */, - 844FCC8F198B320500EB242A /* SwiftCheck */, - 844FCC9C198B320500EB242A /* SwiftCheckTests */, - FAAB9E781D91B96C0097AC78 /* Templates */, - 844FCC8E198B320500EB242A /* Products */, + 6A761B751F14E91400A7D74F /* Info.plist */, + 6A761B761F14E91400A7D74F /* SwiftCheck */, ); - indentWidth = 4; + path = Sources; sourceTree = ""; - tabWidth = 4; - usesTabs = 1; }; - 844FCC8E198B320500EB242A /* Products */ = { + 6A761B761F14E91400A7D74F /* SwiftCheck */ = { isa = PBXGroup; children = ( - 844FCC8D198B320500EB242A /* SwiftCheck.framework */, - 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */, - 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */, - 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */, - 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */, - 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */, + 6A761B831F14E91500A7D74F /* SwiftCheck.h */, + 6A761B771F14E91400A7D74F /* Arbitrary.swift */, + 6A761B781F14E91400A7D74F /* Cartesian.swift */, + 6A761B791F14E91400A7D74F /* Check.swift */, + 6A761B7A1F14E91400A7D74F /* CoArbitrary.swift */, + 6A761B7B1F14E91500A7D74F /* Compose.swift */, + 6A761B7C1F14E91500A7D74F /* Gen.swift */, + 6A761B7D1F14E91500A7D74F /* Lattice.swift */, + 6A761B7E1F14E91500A7D74F /* Modifiers.swift */, + 6A761B7F1F14E91500A7D74F /* Property.swift */, + 6A761B801F14E91500A7D74F /* Random.swift */, + 6A761B811F14E91500A7D74F /* Rose.swift */, + 6A761B821F14E91500A7D74F /* State.swift */, + 6A761B841F14E91500A7D74F /* Test.swift */, + 6A761B851F14E91500A7D74F /* Testable.swift */, + 6A761B861F14E91500A7D74F /* Witness.swift */, + 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */, ); - name = Products; + path = SwiftCheck; sourceTree = ""; }; - 844FCC8F198B320500EB242A /* SwiftCheck */ = { + 6A761B891F14E91500A7D74F /* Tests */ = { isa = PBXGroup; children = ( - 826D81461C953D070022266C /* Arbitrary.swift */, - FAAB9E881D91C28F0097AC78 /* Cartesian.swift */, - 826D81551C953D070022266C /* Check.swift */, - 826D81481C953D070022266C /* CoArbitrary.swift */, - 82BA08CE1D6FFBD20068D32F /* Compose.swift */, - 826D81491C953D070022266C /* Gen.swift */, - 826D814B1C953D070022266C /* Lattice.swift */, - 826D814C1C953D070022266C /* Modifiers.swift */, - 826D814E1C953D070022266C /* Property.swift */, - 826D814F1C953D070022266C /* Random.swift */, - 826D81501C953D070022266C /* Rose.swift */, - 826D81511C953D070022266C /* State.swift */, - 826D81531C953D070022266C /* Test.swift */, - 826D81541C953D070022266C /* Testable.swift */, - 826D81561C953D070022266C /* Witness.swift */, - 826D81571C953D070022266C /* WitnessedArbitrary.swift */, - 844FCC90198B320500EB242A /* Supporting Files */, + 6A761B8A1F14E91500A7D74F /* Info.plist */, + 6A761B8B1F14E91500A7D74F /* LinuxMain.swift */, + 6A761B8C1F14E91500A7D74F /* SwiftCheckTests */, ); - path = SwiftCheck; + path = Tests; sourceTree = ""; }; - 844FCC90198B320500EB242A /* Supporting Files */ = { + 6A761B8C1F14E91500A7D74F /* SwiftCheckTests */ = { isa = PBXGroup; children = ( - 826D814A1C953D070022266C /* Info.plist */, + 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */, + 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */, + 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */, + 6A761B901F14E91500A7D74F /* DiscardSpec.swift */, + 6A761B911F14E91500A7D74F /* FailureSpec.swift */, + 6A761B921F14E91500A7D74F /* FileCheck.swift */, + 6A761B931F14E91500A7D74F /* FormatterSpec.swift */, + 6A761B941F14E91500A7D74F /* GenSpec.swift */, + 6A761B951F14E91500A7D74F /* LambdaSpec.swift */, + 6A761B961F14E91500A7D74F /* ModifierSpec.swift */, + 6A761B971F14E91500A7D74F /* PathSpec.swift */, + 6A761B981F14E91500A7D74F /* PropertySpec.swift */, + 6A761B991F14E91500A7D74F /* ReplaySpec.swift */, + 6A761B9A1F14E91500A7D74F /* RoseSpec.swift */, + 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */, + 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */, + 6A761B9D1F14E91500A7D74F /* TestSpec.swift */, ); - name = "Supporting Files"; + path = SwiftCheckTests; sourceTree = ""; }; - 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { + 844FCC83198B320500EB242A = { isa = PBXGroup; children = ( - 82F371481DA7010800D60203 /* FileCheck.swift */, - 825C9AC81D8EE445003313E1 /* LinuxMain.swift */, - 825C9AD01D8EE86E003313E1 /* BooleanIdentitySpec.swift */, - FA3C185A1D93056D003DEB10 /* CartesianSpec.swift */, - 825C9AD11D8EE86E003313E1 /* ComplexSpec.swift */, - 825C9AD21D8EE86E003313E1 /* DiscardSpec.swift */, - 825C9AD31D8EE86E003313E1 /* FailureSpec.swift */, - 828B7C861DEF575C0066A994 /* FormatterSpec.swift */, - 825C9AD41D8EE86E003313E1 /* GenSpec.swift */, - 825C9AD51D8EE86E003313E1 /* LambdaSpec.swift */, - 825C9AD61D8EE86E003313E1 /* ModifierSpec.swift */, - 825C9AD71D8EE86E003313E1 /* PathSpec.swift */, - 825C9AD81D8EE86E003313E1 /* PropertySpec.swift */, - 825C9ADA1D8EE86E003313E1 /* ReplaySpec.swift */, - 825C9ADB1D8EE86E003313E1 /* RoseSpec.swift */, - 825C9ADC1D8EE86E003313E1 /* ShrinkSpec.swift */, - 825C9ADD1D8EE86E003313E1 /* SimpleSpec.swift */, - 825C9ACC1D8EE84F003313E1 /* TestSpec.swift */, - 844FCC9D198B320500EB242A /* Supporting Files */, + 6A761B881F14E91500A7D74F /* Package.swift */, + 6A761B741F14E91400A7D74F /* Sources */, + 6A761B891F14E91500A7D74F /* Tests */, + FAAB9E781D91B96C0097AC78 /* Templates */, + 844FCC8E198B320500EB242A /* Products */, ); - path = SwiftCheckTests; + indentWidth = 4; sourceTree = ""; + tabWidth = 4; + usesTabs = 1; }; - 844FCC9D198B320500EB242A /* Supporting Files */ = { + 844FCC8E198B320500EB242A /* Products */ = { isa = PBXGroup; children = ( - 826D81C61C953D350022266C /* Info.plist */, + 844FCC8D198B320500EB242A /* SwiftCheck.framework */, + 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */, + 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */, + 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */, + 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */, + 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */, ); - name = "Supporting Files"; + name = Products; sourceTree = ""; }; FAAB9E781D91B96C0097AC78 /* Templates */ = { @@ -369,7 +371,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 826D817E1C953D070022266C /* SwiftCheck.h in Headers */, + 6A761BCC1F14E92200A7D74F /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -377,7 +379,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 826D817C1C953D070022266C /* SwiftCheck.h in Headers */, + 6A761BAA1F14E92100A7D74F /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -385,7 +387,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 826D817D1C953D070022266C /* SwiftCheck.h in Headers */, + 6A761BBB1F14E92200A7D74F /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -515,9 +517,11 @@ TargetAttributes = { 8240CCB01C3A123600EF4D29 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; }; 8240CCB91C3A123700EF4D29 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0900; }; 844FCC8C198B320500EB242A = { CreatedOnToolsVersion = 6.0; @@ -530,11 +534,11 @@ }; 84DF75F71B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; }; 84DF76011B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0800; + LastSwiftMigration = 0900; }; }; }; @@ -626,22 +630,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D81721C953D070022266C /* Property.swift in Sources */, - 826D81691C953D070022266C /* Lattice.swift in Sources */, - 826D81751C953D070022266C /* Random.swift in Sources */, - 826D81841C953D070022266C /* Testable.swift in Sources */, - FAAB9E8B1D91C28F0097AC78 /* Cartesian.swift in Sources */, - 826D818A1C953D070022266C /* Witness.swift in Sources */, - 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, - 826D816C1C953D070022266C /* Modifiers.swift in Sources */, - 826D81811C953D070022266C /* Test.swift in Sources */, - 826D81871C953D070022266C /* Check.swift in Sources */, - 826D81781C953D070022266C /* Rose.swift in Sources */, - 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81631C953D070022266C /* Gen.swift in Sources */, - 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08D11D6FFBD20068D32F /* Compose.swift in Sources */, - 826D817B1C953D070022266C /* State.swift in Sources */, + 6A761BC81F14E92200A7D74F /* Property.swift in Sources */, + 6A761BC61F14E92200A7D74F /* Lattice.swift in Sources */, + 6A761BC91F14E92200A7D74F /* Random.swift in Sources */, + 6A761BCE1F14E92200A7D74F /* Testable.swift in Sources */, + 6A761BC11F14E92200A7D74F /* Cartesian.swift in Sources */, + 6A761BC01F14E92200A7D74F /* Arbitrary.swift in Sources */, + 6A761BC51F14E92200A7D74F /* Gen.swift in Sources */, + 6A761BCD1F14E92200A7D74F /* Test.swift in Sources */, + 6A761BC71F14E92200A7D74F /* Modifiers.swift in Sources */, + 6A761BD01F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */, + 6A761BCA1F14E92200A7D74F /* Rose.swift in Sources */, + 6A761BC31F14E92200A7D74F /* CoArbitrary.swift in Sources */, + 6A761BC21F14E92200A7D74F /* Check.swift in Sources */, + 6A761BC41F14E92200A7D74F /* Compose.swift in Sources */, + 6A761BCF1F14E92200A7D74F /* Witness.swift in Sources */, + 6A761BCB1F14E92200A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -649,23 +653,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9B071D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B041D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - FA3C185D1D93056D003DEB10 /* CartesianSpec.swift in Sources */, - 825C9ACF1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEC1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF51D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE61D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AEF1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 82F3714C1DA7041300D60203 /* FileCheck.swift in Sources */, - 825C9AE91D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9B011D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE31D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9AE01D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF21D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 828B7C8C1DEF58D10066A994 /* FormatterSpec.swift in Sources */, - 825C9AF81D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFE1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, + 6A761C021F14E93B00A7D74F /* SimpleSpec.swift in Sources */, + 6A761C031F14E93B00A7D74F /* TestSpec.swift in Sources */, + 6A761BF31F14E93B00A7D74F /* BooleanIdentitySpec.swift in Sources */, + 6A761BFD1F14E93B00A7D74F /* PathSpec.swift in Sources */, + 6A761BF61F14E93B00A7D74F /* DiscardSpec.swift in Sources */, + 6A761BF71F14E93B00A7D74F /* FailureSpec.swift in Sources */, + 6A761BF51F14E93B00A7D74F /* ComplexSpec.swift in Sources */, + 6A761BFE1F14E93B00A7D74F /* PropertySpec.swift in Sources */, + 6A761BFF1F14E93B00A7D74F /* ReplaySpec.swift in Sources */, + 6A761BFB1F14E93B00A7D74F /* LambdaSpec.swift in Sources */, + 6A761BFC1F14E93B00A7D74F /* ModifierSpec.swift in Sources */, + 6A761BF91F14E93B00A7D74F /* FormatterSpec.swift in Sources */, + 6A761BFA1F14E93B00A7D74F /* GenSpec.swift in Sources */, + 6A761BF81F14E93B00A7D74F /* FileCheck.swift in Sources */, + 6A761BF41F14E93B00A7D74F /* CartesianSpec.swift in Sources */, + 6A761C011F14E93B00A7D74F /* ShrinkSpec.swift in Sources */, + 6A761C001F14E93B00A7D74F /* RoseSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -673,22 +677,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D81701C953D070022266C /* Property.swift in Sources */, - 826D81671C953D070022266C /* Lattice.swift in Sources */, - 826D81731C953D070022266C /* Random.swift in Sources */, - 826D81821C953D070022266C /* Testable.swift in Sources */, - FAAB9E891D91C28F0097AC78 /* Cartesian.swift in Sources */, - 826D81881C953D070022266C /* Witness.swift in Sources */, - 826D81581C953D070022266C /* Arbitrary.swift in Sources */, - 826D816A1C953D070022266C /* Modifiers.swift in Sources */, - 826D817F1C953D070022266C /* Test.swift in Sources */, - 826D81851C953D070022266C /* Check.swift in Sources */, - 826D81761C953D070022266C /* Rose.swift in Sources */, - 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81611C953D070022266C /* Gen.swift in Sources */, - 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08CF1D6FFBD20068D32F /* Compose.swift in Sources */, - 826D81791C953D070022266C /* State.swift in Sources */, + 6A761BA61F14E92100A7D74F /* Property.swift in Sources */, + 6A761BA41F14E92100A7D74F /* Lattice.swift in Sources */, + 6A761BA71F14E92100A7D74F /* Random.swift in Sources */, + 6A761BAC1F14E92100A7D74F /* Testable.swift in Sources */, + 6A761B9F1F14E92100A7D74F /* Cartesian.swift in Sources */, + 6A761B9E1F14E92100A7D74F /* Arbitrary.swift in Sources */, + 6A761BA31F14E92100A7D74F /* Gen.swift in Sources */, + 6A761BAB1F14E92100A7D74F /* Test.swift in Sources */, + 6A761BA51F14E92100A7D74F /* Modifiers.swift in Sources */, + 6A761BAE1F14E92100A7D74F /* WitnessedArbitrary.swift in Sources */, + 6A761BA81F14E92100A7D74F /* Rose.swift in Sources */, + 6A761BA11F14E92100A7D74F /* CoArbitrary.swift in Sources */, + 6A761BA01F14E92100A7D74F /* Check.swift in Sources */, + 6A761BA21F14E92100A7D74F /* Compose.swift in Sources */, + 6A761BAD1F14E92100A7D74F /* Witness.swift in Sources */, + 6A761BA91F14E92100A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -696,23 +700,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9B051D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B021D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - FA3C185B1D93056D003DEB10 /* CartesianSpec.swift in Sources */, - 825C9ACD1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEA1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF31D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE41D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AED1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 82F3714E1DA7041500D60203 /* FileCheck.swift in Sources */, - 825C9AE71D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9AFF1D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE11D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9ADE1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF01D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 828B7C8A1DEF58CF0066A994 /* FormatterSpec.swift in Sources */, - 825C9AF61D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFC1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, + 6A761BE01F14E93900A7D74F /* SimpleSpec.swift in Sources */, + 6A761BE11F14E93900A7D74F /* TestSpec.swift in Sources */, + 6A761BD11F14E93900A7D74F /* BooleanIdentitySpec.swift in Sources */, + 6A761BDB1F14E93900A7D74F /* PathSpec.swift in Sources */, + 6A761BD41F14E93900A7D74F /* DiscardSpec.swift in Sources */, + 6A761BD51F14E93900A7D74F /* FailureSpec.swift in Sources */, + 6A761BD31F14E93900A7D74F /* ComplexSpec.swift in Sources */, + 6A761BDC1F14E93900A7D74F /* PropertySpec.swift in Sources */, + 6A761BDD1F14E93900A7D74F /* ReplaySpec.swift in Sources */, + 6A761BD91F14E93900A7D74F /* LambdaSpec.swift in Sources */, + 6A761BDA1F14E93900A7D74F /* ModifierSpec.swift in Sources */, + 6A761BD71F14E93900A7D74F /* FormatterSpec.swift in Sources */, + 6A761BD81F14E93900A7D74F /* GenSpec.swift in Sources */, + 6A761BD61F14E93900A7D74F /* FileCheck.swift in Sources */, + 6A761BD21F14E93900A7D74F /* CartesianSpec.swift in Sources */, + 6A761BDF1F14E93900A7D74F /* ShrinkSpec.swift in Sources */, + 6A761BDE1F14E93900A7D74F /* RoseSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -720,22 +724,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 826D81711C953D070022266C /* Property.swift in Sources */, - 826D81681C953D070022266C /* Lattice.swift in Sources */, - 826D81741C953D070022266C /* Random.swift in Sources */, - 826D81831C953D070022266C /* Testable.swift in Sources */, - FAAB9E8A1D91C28F0097AC78 /* Cartesian.swift in Sources */, - 826D81891C953D070022266C /* Witness.swift in Sources */, - 826D81591C953D070022266C /* Arbitrary.swift in Sources */, - 826D816B1C953D070022266C /* Modifiers.swift in Sources */, - 826D81801C953D070022266C /* Test.swift in Sources */, - 826D81861C953D070022266C /* Check.swift in Sources */, - 826D81771C953D070022266C /* Rose.swift in Sources */, - 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, - 826D81621C953D070022266C /* Gen.swift in Sources */, - 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, - 82BA08D01D6FFBD20068D32F /* Compose.swift in Sources */, - 826D817A1C953D070022266C /* State.swift in Sources */, + 6A761BB71F14E92200A7D74F /* Property.swift in Sources */, + 6A761BB51F14E92200A7D74F /* Lattice.swift in Sources */, + 6A761BB81F14E92200A7D74F /* Random.swift in Sources */, + 6A761BBD1F14E92200A7D74F /* Testable.swift in Sources */, + 6A761BB01F14E92200A7D74F /* Cartesian.swift in Sources */, + 6A761BAF1F14E92100A7D74F /* Arbitrary.swift in Sources */, + 6A761BB41F14E92200A7D74F /* Gen.swift in Sources */, + 6A761BBC1F14E92200A7D74F /* Test.swift in Sources */, + 6A761BB61F14E92200A7D74F /* Modifiers.swift in Sources */, + 6A761BBF1F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */, + 6A761BB91F14E92200A7D74F /* Rose.swift in Sources */, + 6A761BB21F14E92200A7D74F /* CoArbitrary.swift in Sources */, + 6A761BB11F14E92200A7D74F /* Check.swift in Sources */, + 6A761BB31F14E92200A7D74F /* Compose.swift in Sources */, + 6A761BBE1F14E92200A7D74F /* Witness.swift in Sources */, + 6A761BBA1F14E92200A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -743,23 +747,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 825C9B061D8EE86E003313E1 /* SimpleSpec.swift in Sources */, - 825C9B031D8EE86E003313E1 /* ShrinkSpec.swift in Sources */, - FA3C185C1D93056D003DEB10 /* CartesianSpec.swift in Sources */, - 825C9ACE1D8EE84F003313E1 /* TestSpec.swift in Sources */, - 825C9AEB1D8EE86E003313E1 /* GenSpec.swift in Sources */, - 825C9AF41D8EE86E003313E1 /* PathSpec.swift in Sources */, - 825C9AE51D8EE86E003313E1 /* DiscardSpec.swift in Sources */, - 825C9AEE1D8EE86E003313E1 /* LambdaSpec.swift in Sources */, - 82F3714D1DA7041400D60203 /* FileCheck.swift in Sources */, - 825C9AE81D8EE86E003313E1 /* FailureSpec.swift in Sources */, - 825C9B001D8EE86E003313E1 /* RoseSpec.swift in Sources */, - 825C9AE21D8EE86E003313E1 /* ComplexSpec.swift in Sources */, - 825C9ADF1D8EE86E003313E1 /* BooleanIdentitySpec.swift in Sources */, - 825C9AF11D8EE86E003313E1 /* ModifierSpec.swift in Sources */, - 828B7C8B1DEF58D00066A994 /* FormatterSpec.swift in Sources */, - 825C9AF71D8EE86E003313E1 /* PropertySpec.swift in Sources */, - 825C9AFD1D8EE86E003313E1 /* ReplaySpec.swift in Sources */, + 6A761BF11F14E93A00A7D74F /* SimpleSpec.swift in Sources */, + 6A761BF21F14E93A00A7D74F /* TestSpec.swift in Sources */, + 6A761BE21F14E93A00A7D74F /* BooleanIdentitySpec.swift in Sources */, + 6A761BEC1F14E93A00A7D74F /* PathSpec.swift in Sources */, + 6A761BE51F14E93A00A7D74F /* DiscardSpec.swift in Sources */, + 6A761BE61F14E93A00A7D74F /* FailureSpec.swift in Sources */, + 6A761BE41F14E93A00A7D74F /* ComplexSpec.swift in Sources */, + 6A761BED1F14E93A00A7D74F /* PropertySpec.swift in Sources */, + 6A761BEE1F14E93A00A7D74F /* ReplaySpec.swift in Sources */, + 6A761BEA1F14E93A00A7D74F /* LambdaSpec.swift in Sources */, + 6A761BEB1F14E93A00A7D74F /* ModifierSpec.swift in Sources */, + 6A761BE81F14E93A00A7D74F /* FormatterSpec.swift in Sources */, + 6A761BE91F14E93A00A7D74F /* GenSpec.swift in Sources */, + 6A761BE71F14E93A00A7D74F /* FileCheck.swift in Sources */, + 6A761BE31F14E93A00A7D74F /* CartesianSpec.swift in Sources */, + 6A761BF01F14E93A00A7D74F /* ShrinkSpec.swift in Sources */, + 6A761BEF1F14E93A00A7D74F /* RoseSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -808,8 +812,10 @@ PRODUCT_NAME = SwiftCheck; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -842,7 +848,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -853,6 +859,7 @@ 8240CCC41C3A123700EF4D29 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; @@ -863,7 +870,7 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -871,6 +878,7 @@ 8240CCC51C3A123700EF4D29 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; COPY_PHASE_STRIP = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -881,7 +889,7 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -1016,7 +1024,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1049,13 +1057,14 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Release; }; 844FCCA7198B320500EB242A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -1072,13 +1081,14 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; 844FCCA8198B320500EB242A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( @@ -1092,7 +1102,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -1125,8 +1135,10 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1160,7 +1172,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1171,6 +1183,7 @@ 84DF760F1B0BD54600C912B0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1189,13 +1202,14 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; 84DF76101B0BD54600C912B0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; @@ -1210,7 +1224,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index 94a37e7..e1d02b1 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -40,6 +40,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES"> , among pref let bd = Data(buffer: buffer) let range = bd.range(of: prefixStr.data(using: .utf8)!)! buffer = buffer.dropFront(range.lowerBound) - lineNumber += skippedPrefix.characters.filter({ c in c == "\n" }).count + lineNumber += skippedPrefix.filter({ c in c == "\n" }).characters.count // Check that the matched prefix isn't a suffix of some other check-like // word. // FIXME: This is a very ad-hoc check. it would be better handled in some @@ -658,11 +658,7 @@ private class Pattern { // If this defines any variables, remember their values. for (v, index) in self.variableDefs { assert(index < fullMatch.numberOfRanges, "Internal paren error") - #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) - let r = fullMatch.rangeAt(index) - #else - let r = fullMatch.range(at: index) - #endif + let r = fullMatch.range(at: index) variableTable[v] = buffer.substring( with: Range( uncheckedBounds: ( diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index e84c172..631c102 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -6,7 +6,7 @@ import Foundation.NSDate //: # Prerequisites //: This tutorial assumes that you have a fairly good grasp of Swift, its syntax, and terms like -//: +//: //: * [(Data) Type](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html) //: * [Protocol-Oriented Programming](https://developer.apple.com/videos/wwdc/2015/?id=408) //: * [Test-Driven Development](https://en.wikipedia.org/wiki/Test-driven_development) @@ -23,16 +23,16 @@ import Foundation.NSDate //: SwiftCheck is a testing library that augments libraries like `XCTest` and `Quick` by giving //: them the ability to automatically test program properties. A property is a particular facet of -//: an algorithm, method, data structure, or program that must *hold* (that is, remain valid) even -//: when fed random or pseudo-random data. If that all seems complicated, it may be simpler to -//: think of Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements +//: an algorithm, method, data structure, or program that must *hold* (that is, remain valid) even +//: when fed random or pseudo-random data. If that all seems complicated, it may be simpler to +//: think of Property Testing like Fuzz Testing, but with the outcome being to satisfy requirements //: rather than break the program. Throughout this tutorial, simplifications like the above will be //: made to aid your understanding. Towards the end of it, we will begin to remove many of these //: "training wheels" and reveal the real concepts and types of the operations in the library, which //: are often much more powerful and generic than previously presented. //: -//: Unlike Unit Testing, Property Testing is antithetical to the use of state and global variables. Property -//: Tests are local, atomic entities that ideally only use the data given to them to match a +//: Unlike Unit Testing, Property Testing is antithetical to the use of state and global variables. Property +//: Tests are local, atomic entities that ideally only use the data given to them to match a //: user-defined specification for the behavior of a program or algorithm. While this may //: seem draconian, the upshot of following these [unwritten] rules is that the produced tests become //: "law-like", as in a [Mathematical or Scientific Law](https://en.wikipedia.org/wiki/Laws_of_science). @@ -46,8 +46,8 @@ import Foundation.NSDate //: # `Gen`erators //: In Swift, when one thinks of a Generator, they usually think of the `GeneratorType` protocol or -//: the many many individual structures the Swift Standard Library exposes to allow loops to work -//: with data structures like `[T]` and `Set`. In *SwiftCheck*, we also have Generators, but we spell +//: the many many individual structures the Swift Standard Library exposes to allow loops to work +//: with data structures like `[T]` and `Set`. In *SwiftCheck*, we also have Generators, but we spell //: them `Gen`erators, as in the universal Generator type `Gen`. //: //: `Gen` is a struct defined generically over any kind of type that looks like this: @@ -56,8 +56,8 @@ import Foundation.NSDate // struct Gen { } // //: `Gen`, unlike `GeneratorType`, is not backed by a concrete data structure like an `Array` or -//: `Dictionary`, but is instead constructed by invoking methods that refine the kind of data that -//: gets generated. Below are some examples of `Gen`erators that generate random instances of +//: `Dictionary`, but is instead constructed by invoking methods that refine the kind of data that +//: gets generated. Below are some examples of `Gen`erators that generate random instances of //: simple data types. // `Gen.pure` constructs a generator that *only* produces the given value. @@ -69,7 +69,7 @@ onlyFive.generate onlyFive.generate onlyFive.generate -// `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the +// `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the // given Range. Because generation is random, some values may be repeated. let fromOnetoFive = Gen.fromElements(in: 1...5) @@ -101,14 +101,14 @@ specialCharacters.generate specialCharacters.generate specialCharacters.generate -//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in +//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in //: amazing ways. // `Gen.oneOf` randomly picks one of the generators from the given list and draws element from it. let uppersAndLowers = Gen.one(of: [ - lowerCaseLetters, - upperCaseLetters, -]) + lowerCaseLetters, + upperCaseLetters, + ]) uppersAndLowers.generate uppersAndLowers.generate @@ -123,15 +123,15 @@ pairsOfNumbers.generate pairsOfNumbers.generate pairsOfNumbers.generate -//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck -//: includes a number of functions for creating `Gen`erators with "weights" attached to their +//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck +//: includes a number of functions for creating `Gen`erators with "weights" attached to their //: elements. // This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. let weightedGen = Gen.weighted([ - (1, nil), - (3, .some(5)), -]) + (1, nil), + (3, .some(5)), + ]) weightedGen.generate weightedGen.generate @@ -140,9 +140,9 @@ weightedGen.generate // `Gen.frequency` works like `Gen.weighted` and `Gen.oneOf` put together. let biasedUppersAndLowers = Gen.frequency([ - (1, uppersAndLowers), - (3, lowerCaseLetters), -]) + (1, uppersAndLowers), + (3, lowerCaseLetters), + ]) //: `Gen`erators can even filter, modify, or combine the elements they create. @@ -153,7 +153,7 @@ oneToFiveEven.generate oneToFiveEven.generate oneToFiveEven.generate -// `proliferate` turns a generator of single elements into a generator of arrays of those elements. +// `proliferate` turns a generator of single elements into a generator of arrays of those elements. let characterArray = uppersAndLowers.proliferate characterArray.generate @@ -180,15 +180,15 @@ fromTwoToSix.generate fromTwoToSix.generate fromTwoToSix.generate -// `Gen.flatMap` works exactly like `Array`'s `flatMap`, but instead of concatenating the generated -// arrays it produces a new generator that picks values from among the newly created generators +// `Gen.flatMap` works exactly like `Array`'s `flatMap`, but instead of concatenating the generated +// arrays it produces a new generator that picks values from among the newly created generators // produced by the function. // -// While that definition may *technically* be what occurs, it is better to think of `flatMap` as a -// way of making a generator depend on another. For example, you can use a generator of sizes to +// While that definition may *technically* be what occurs, it is better to think of `flatMap` as a +// way of making a generator depend on another. For example, you can use a generator of sizes to // limit the length of generators of arrays: let generatorBoundedSizeArrays = fromOnetoFive.flatMap { len in - return characterArray.suchThat { xs in xs.count <= len } + return characterArray.suchThat { xs in xs.count <= len } } generatorBoundedSizeArrays.generate @@ -212,11 +212,11 @@ let special : Gen = Gen.fromElements(of: ["!", "#", "$", " //: Now for the actual generator let allowedLocalCharacters : Gen = Gen.one(of: [ - upperCaseLetters, - lowerCaseLetters, - numeric, - special, -]) + upperCaseLetters, + lowerCaseLetters, + numeric, + special, + ]) //: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `map` @@ -231,10 +231,10 @@ let localEmail = allowedLocalCharacters //: steps here and combine them all into one big generator. let hostname = Gen.one(of: [ - lowerCaseLetters, - numeric, - Gen.pure("-"), -]).proliferateNonEmpty.map { String($0) } + lowerCaseLetters, + numeric, + Gen.pure("-"), + ]).proliferateNonEmpty.map { String($0) } //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. @@ -248,7 +248,7 @@ let tld = lowerCaseLetters // Concatenates an array of `String` `Gen`erators together in order. func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", +) } + return sequence(parts).map { $0.reduce("", +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) @@ -288,18 +288,18 @@ emailGen.generate //: for `Int` calls `arc4random_uniform`. //: //: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't -//: generate with another that we can–for a few of the more "difficult" types in the Swift Standard +//: generate with another that we can–for a few of the more "difficult" types in the Swift Standard //: Library, but we also use them in more benign ways too. For example, we can write a modifier type //: that only generates positive numbers: -public struct ArbitraryPositive : Arbitrary { - public let getPositive : A - - public init(_ pos : A) { self.getPositive = pos } - - public static var arbitrary : Gen> { - return A.arbitrary.map { ArbitraryPositive.init(abs($0)) } - } +public struct ArbitraryPositive : Arbitrary { + public let getPositive : A + + public init(_ pos : A) { self.getPositive = pos } + + public static var arbitrary : Gen> { + return A.arbitrary.map { ArbitraryPositive.init(abs($0)) } + } } ArbitraryPositive.arbitrary.generate.getPositive @@ -329,7 +329,7 @@ ArbitraryPositive.arbitrary.generate.getPositive // | | // v v property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in - return xs.reversed().reversed() == xs + return xs.reversed().reversed() == xs } // From now on, all of our examples will take the form above. @@ -341,17 +341,17 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // | | can generate *functions*!! // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in - let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) - // ^ This property says that if we filter an array then apply the predicate - // to all its elements, then they should all respond with `true`. + let f = pred.getArrow + return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) + // ^ This property says that if we filter an array then apply the predicate + // to all its elements, then they should all respond with `true`. } // How about a little Boolean Algebra too? property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = !(x && y) == (!x || !y) - let r = !(x || y) == (!x && !y) - return l && r + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r } //: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not @@ -367,10 +367,10 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in // `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. -reportProperty("Obviously wrong") <- forAll { (x : Int) in - return x != x -}.whenFail { // `whenFail` attaches a callback to the test when we fail. - print("Oh noes!") +reportProperty("Obviously wrong") <- forAll({ (x : Int) in + return x != x +}).whenFail { // `whenFail` attaches a callback to the test when we fail. + print("Oh noes!") } //: If you open the console for the playground, you'll see output very similar to the following: @@ -424,19 +424,19 @@ Array.shrink([1, 2, 3]) // will often be times when those default shrinkers don't cut it, or you need more control over // what happens when you generate or shrink values. Modifier Types to the rescue! struct ArbitraryEmail : Arbitrary { - let getEmail : String - - init(email : String) { self.getEmail = email } - - static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } + let getEmail : String + + init(email : String) { self.getEmail = email } + + static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } } // Let's be wrong for the sake of example property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in - return !email.getEmail.contains(".") -}.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` - // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail - // and live up to your expectations, SwiftCheck treats that as a failure of the test case. + return !email.getEmail.contains(".") + }.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` +// to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail +// and live up to your expectations, SwiftCheck treats that as a failure of the test case. //: # All Together Now! @@ -456,27 +456,27 @@ import func Darwin.sqrt // } // - Remaining indices of unmarked numbers are primes func sieve(_ n : Int) -> [Int] { - if n <= 1 { - return [] - } - - var marked : [Bool] = (0...n).map { _ in false } - marked[0] = true - marked[1] = true - - for p in 2.. [Int] { // Short and sweet check if a number is prime by enumerating from 2...⌈√(x)⌉ and checking // for a nonzero modulus. func isPrime(_ n : Int) -> Bool { - if n == 0 || n == 1 { - return false - } else if n == 2 { - return true - } - - let max = Int(ceil(sqrt(Double(n)))) - for i in 2...max { - if n % i == 0 { - return false - } - } - return true + if n == 0 || n == 1 { + return false + } else if n == 2 { + return true + } + + let max = Int(ceil(sqrt(Double(n)))) + for i in 2...max { + if n % i == 0 { + return false + } + } + return true } //: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the //: following property: reportProperty("All Prime") <- forAll { (n : Positive) in - let primes = sieve(n.getPositive) - return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElements(of: primes) - return forAll(primeNumberGen) { (p : Int) in - return isPrime(p) - } - } + let primes = sieve(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElements(of: primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } } //: This test introduces several new concepts that we'll go through 1-by-1: @@ -559,39 +559,39 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: Looks like we used `to:` when we meant `through:`. Let's try again: func sieveProperly(_ n : Int) -> [Int] { - if n <= 1 { - return [] - } - - var marked : [Bool] = (0...n).map { _ in false } - marked[0] = true - marked[1] = true - - for p in 2..) in - let primes = sieveProperly(n.getPositive) - return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElements(of: primes) - return forAll(primeNumberGen) { (p : Int) in - return isPrime(p) - } - } + let primes = sieveProperly(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElements(of: primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } } //: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm @@ -603,8 +603,8 @@ property("All Prime") <- forAll { (n : Positive) in //: Just for fun, let's try a simpler property that checks the same outcome: property("All Prime") <- forAll { (n : Positive) in - // Sieving Properly then filtering for primes is the same as just Sieving, right? - return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) + // Sieving Properly then filtering for primes is the same as just Sieving, right? + return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } //: # One More Thing @@ -626,11 +626,11 @@ property("All Prime") <- forAll { (n : Positive) in //: every so often on one particular value: reportProperty("Screw this value in particular") <- forAll { (n : UInt) in - if (n == 42) { - return false - } - - return true + if (n == 42) { + return false + } + + return true } //: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because @@ -640,11 +640,11 @@ reportProperty("Screw this value in particular") <- forAll { (n : UInt) in /// size to completely replicate a particular set of values that caused the first test to fail. let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in - if (n == 42) { - return false - } - return true -}.verbose + if (n == 42) { + return false + } + return true + }.verbose //: # Conclusion @@ -664,3 +664,4 @@ reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in //: * [The Original (slightly outdated) QuickCheck Tutorial](http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html) //: //: Go forth and test. + diff --git a/Utilities/compile.sh b/Utilities/compile.sh index cb9d933..122cdae 100755 --- a/Utilities/compile.sh +++ b/Utilities/compile.sh @@ -1,4 +1,4 @@ #!/bin/sh -./gyb --line-directive '' -o ../Sources/Cartesian.swift ../Templates/Cartesian.swift.gyb +./gyb --line-directive '' -o ../Sources/SwiftCheck/Cartesian.swift ../Templates/Cartesian.swift.gyb ./gyb --line-directive '' -o ../Tests/SwiftCheckTests/CartesianSpec.swift ../Templates/CartesianSpec.swift.gyb From 72e1b116de819c86c4f3c48dfb1be5235f5ae513 Mon Sep 17 00:00:00 2001 From: Tristan Celder Date: Sat, 15 Jul 2017 12:12:08 +0200 Subject: [PATCH 404/460] Point Package.swift to official deps --- Package.resolved | 6 +++--- Package.swift | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Package.resolved b/Package.resolved index d2f10aa..09a8836 100644 --- a/Package.resolved +++ b/Package.resolved @@ -3,10 +3,10 @@ "pins": [ { "package": "Operadics", - "repositoryURL": "https://github.com/tcldr/Operadics.git", + "repositoryURL": "https://github.com/typelift/Operadics.git", "state": { - "branch": "swift-4", - "revision": "8ee78809312caa4c82625fa7a5cba40fb16f10fd", + "branch": "swift-develop", + "revision": "743e71210ea319dfd9f0e39268c5e18877debc7f", "version": null } } diff --git a/Package.swift b/Package.swift index 5df1844..39d3dbc 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( targets: ["SwiftCheck"]), ], dependencies: [ - .package(url: "https://github.com/tcldr/Operadics.git", .branch("swift-4")) + .package(url: "https://github.com/typelift/Operadics.git", .branch("swift-develop")) ], targets: [ .target( From e722235b09eebe4b9241178c80e274f24424ac70 Mon Sep 17 00:00:00 2001 From: Dylan Lukes Date: Mon, 14 Aug 2017 14:16:51 -0400 Subject: [PATCH 405/460] xcode 9 beta 5 deprecation fixes: truncatingIfNeeded + string slicing --- Sources/SwiftCheck/Arbitrary.swift | 12 ++++++------ Sources/SwiftCheck/CoArbitrary.swift | 2 +- Sources/SwiftCheck/Random.swift | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index 9f9c288..5b176e1 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -120,7 +120,7 @@ extension Int8 : Arbitrary { /// Returns a generator of `Int8` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int8(extendingOrTruncating: -n), Int8(extendingOrTruncating: n))) + return Gen.choose((Int8(truncatingIfNeeded: -n), Int8(truncatingIfNeeded: n))) } } @@ -134,7 +134,7 @@ extension Int16 : Arbitrary { /// Returns a generator of `Int16` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int16(extendingOrTruncating: -n), Int16(extendingOrTruncating: n))) + return Gen.choose((Int16(truncatingIfNeeded: -n), Int16(truncatingIfNeeded: n))) } } @@ -148,7 +148,7 @@ extension Int32 : Arbitrary { /// Returns a generator of `Int32` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.choose((Int32(extendingOrTruncating: -n), Int32(extendingOrTruncating: n))) + return Gen.choose((Int32(truncatingIfNeeded: -n), Int32(truncatingIfNeeded: n))) } } @@ -188,7 +188,7 @@ extension UInt8 : Arbitrary { /// Returns a generator of `UInt8` values. public static var arbitrary : Gen { return Gen.sized { n in - return Gen.sized { n in Gen.choose((0, UInt8(extendingOrTruncating: n))) } + return Gen.sized { n in Gen.choose((0, UInt8(truncatingIfNeeded: n))) } } } @@ -201,7 +201,7 @@ extension UInt8 : Arbitrary { extension UInt16 : Arbitrary { /// Returns a generator of `UInt16` values. public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt16(extendingOrTruncating: n))) } + return Gen.sized { n in Gen.choose((0, UInt16(truncatingIfNeeded: n))) } } /// The default shrinking function for `UInt16` values. @@ -213,7 +213,7 @@ extension UInt16 : Arbitrary { extension UInt32 : Arbitrary { /// Returns a generator of `UInt32` values. public static var arbitrary : Gen { - return Gen.sized { n in Gen.choose((0, UInt32(extendingOrTruncating: n))) } + return Gen.sized { n in Gen.choose((0, UInt32(truncatingIfNeeded: n))) } } /// The default shrinking function for `UInt32` values. diff --git a/Sources/SwiftCheck/CoArbitrary.swift b/Sources/SwiftCheck/CoArbitrary.swift index 836e6c1..53f1388 100644 --- a/Sources/SwiftCheck/CoArbitrary.swift +++ b/Sources/SwiftCheck/CoArbitrary.swift @@ -71,7 +71,7 @@ extension String : CoArbitrary { } return comp( Character.coarbitrary(x[x.startIndex]), - String.coarbitrary(x.substring(with: x.characters.index(after: x.startIndex)..(_ range : (Int, Int), gen : G) -> (Int, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int(extendingOrTruncating: bb), gg) + return (Int(truncatingIfNeeded: bb), gg) } } @@ -166,7 +166,7 @@ extension Int8 : RandomType { public static func randomInRange(_ range : (Int8, Int8), gen : G) -> (Int8, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int8(extendingOrTruncating: bb), gg) + return (Int8(truncatingIfNeeded: bb), gg) } } @@ -175,7 +175,7 @@ extension Int16 : RandomType { public static func randomInRange(_ range : (Int16, Int16), gen : G) -> (Int16, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int16(extendingOrTruncating: bb), gg) + return (Int16(truncatingIfNeeded: bb), gg) } } @@ -184,7 +184,7 @@ extension Int32 : RandomType { public static func randomInRange(_ range : (Int32, Int32), gen : G) -> (Int32, G) { let (minl, maxl) = range let (bb, gg) = Int64.randomInRange((Int64(minl), Int64(maxl)), gen: gen) - return (Int32(extendingOrTruncating: bb), gg) + return (Int32(truncatingIfNeeded: bb), gg) } } @@ -231,7 +231,7 @@ extension UInt : RandomType { public static func randomInRange(_ range : (UInt, UInt), gen : G) -> (UInt, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt(extendingOrTruncating: bb), gg) + return (UInt(truncatingIfNeeded: bb), gg) } } @@ -240,7 +240,7 @@ extension UInt8 : RandomType { public static func randomInRange(_ range : (UInt8, UInt8), gen : G) -> (UInt8, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt8(extendingOrTruncating: bb), gg) + return (UInt8(truncatingIfNeeded: bb), gg) } } @@ -249,7 +249,7 @@ extension UInt16 : RandomType { public static func randomInRange(_ range : (UInt16, UInt16), gen : G) -> (UInt16, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt16(extendingOrTruncating: bb), gg) + return (UInt16(truncatingIfNeeded: bb), gg) } } @@ -258,7 +258,7 @@ extension UInt32 : RandomType { public static func randomInRange(_ range : (UInt32, UInt32), gen : G) -> (UInt32, G) { let (minl, maxl) = range let (bb, gg) = UInt64.randomInRange((UInt64(minl), UInt64(maxl)), gen: gen) - return (UInt32(extendingOrTruncating: bb), gg) + return (UInt32(truncatingIfNeeded: bb), gg) } } From 7444b55a8a2057d3e7a5da325e7fbb816b57f798 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 20 Sep 2017 12:41:09 -0400 Subject: [PATCH 406/460] Final nitpicks and fixes --- .gitignore | 2 +- Sources/SwiftCheck/WitnessedArbitrary.swift | 3 - Tests/SwiftCheckTests/ComplexSpec.swift | 2 +- Tests/SwiftCheckTests/FormatterSpec.swift | 2 +- Tutorial.playground/Contents.swift | 303 ++++++++++---------- 5 files changed, 154 insertions(+), 158 deletions(-) diff --git a/.gitignore b/.gitignore index a613019..104821a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,4 @@ build/ # Docker .dockerignore -Dockerfile \ No newline at end of file +Dockerfile diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index ab71987..8c5e6f6 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -74,8 +74,6 @@ extension AnySequence where Element : Arbitrary { } } -//FIXME: This does not compile as of Xcode 9 beta 3 / 4.0-DEVELOPMENT-SNAPSHOT-2017-07-06 -#if false extension AnySequence : WitnessedArbitrary { public typealias Param = Element @@ -87,7 +85,6 @@ extension AnySequence : WitnessedArbitrary { }) } } -#endif extension ArraySlice where Element : Arbitrary { /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 2d8f6fa..20b9767 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -88,6 +88,6 @@ func glue(_ parts : [Gen]) -> Gen { extension String { fileprivate var initial : String { - return self.substring(with: self.startIndex.. { if maxIndex >= formatted.endIndex { return formatted } else { - return formatted.substring(to: maxIndex) + return String(formatted[..`. In *SwiftCheck*, we also have Generators, but we spell +//: the many many individual structures the Swift Standard Library exposes to allow loops to work +//: with data structures like `[T]` and `Set`. In *SwiftCheck*, we also have Generators, but we spell //: them `Gen`erators, as in the universal Generator type `Gen`. //: //: `Gen` is a struct defined generically over any kind of type that looks like this: @@ -56,8 +56,8 @@ import Foundation.NSDate // struct Gen { } // //: `Gen`, unlike `GeneratorType`, is not backed by a concrete data structure like an `Array` or -//: `Dictionary`, but is instead constructed by invoking methods that refine the kind of data that -//: gets generated. Below are some examples of `Gen`erators that generate random instances of +//: `Dictionary`, but is instead constructed by invoking methods that refine the kind of data that +//: gets generated. Below are some examples of `Gen`erators that generate random instances of //: simple data types. // `Gen.pure` constructs a generator that *only* produces the given value. @@ -69,7 +69,7 @@ onlyFive.generate onlyFive.generate onlyFive.generate -// `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the +// `Gen.fromElementsIn` constructs a generator that pulls values from inside the bounds of the // given Range. Because generation is random, some values may be repeated. let fromOnetoFive = Gen.fromElements(in: 1...5) @@ -101,14 +101,14 @@ specialCharacters.generate specialCharacters.generate specialCharacters.generate -//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in +//: But SwiftCheck `Gen`erators aren't just flat types, they stack and compose and fit together in //: amazing ways. // `Gen.oneOf` randomly picks one of the generators from the given list and draws element from it. let uppersAndLowers = Gen.one(of: [ - lowerCaseLetters, - upperCaseLetters, - ]) + lowerCaseLetters, + upperCaseLetters, +]) uppersAndLowers.generate uppersAndLowers.generate @@ -123,15 +123,15 @@ pairsOfNumbers.generate pairsOfNumbers.generate pairsOfNumbers.generate -//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck -//: includes a number of functions for creating `Gen`erators with "weights" attached to their +//: `Gen`erators don't have to always generate their elements with equal frequency. SwiftCheck +//: includes a number of functions for creating `Gen`erators with "weights" attached to their //: elements. // This generator ideally generates nil 1/4 (1 / (1 + 3)) of the time and `.Some(5)` 3/4 of the time. let weightedGen = Gen.weighted([ - (1, nil), - (3, .some(5)), - ]) + (1, nil), + (3, .some(5)), +]) weightedGen.generate weightedGen.generate @@ -140,9 +140,9 @@ weightedGen.generate // `Gen.frequency` works like `Gen.weighted` and `Gen.oneOf` put together. let biasedUppersAndLowers = Gen.frequency([ - (1, uppersAndLowers), - (3, lowerCaseLetters), - ]) + (1, uppersAndLowers), + (3, lowerCaseLetters), +]) //: `Gen`erators can even filter, modify, or combine the elements they create. @@ -153,7 +153,7 @@ oneToFiveEven.generate oneToFiveEven.generate oneToFiveEven.generate -// `proliferate` turns a generator of single elements into a generator of arrays of those elements. +// `proliferate` turns a generator of single elements into a generator of arrays of those elements. let characterArray = uppersAndLowers.proliferate characterArray.generate @@ -180,15 +180,15 @@ fromTwoToSix.generate fromTwoToSix.generate fromTwoToSix.generate -// `Gen.flatMap` works exactly like `Array`'s `flatMap`, but instead of concatenating the generated -// arrays it produces a new generator that picks values from among the newly created generators +// `Gen.flatMap` works exactly like `Array`'s `flatMap`, but instead of concatenating the generated +// arrays it produces a new generator that picks values from among the newly created generators // produced by the function. // -// While that definition may *technically* be what occurs, it is better to think of `flatMap` as a -// way of making a generator depend on another. For example, you can use a generator of sizes to +// While that definition may *technically* be what occurs, it is better to think of `flatMap` as a +// way of making a generator depend on another. For example, you can use a generator of sizes to // limit the length of generators of arrays: let generatorBoundedSizeArrays = fromOnetoFive.flatMap { len in - return characterArray.suchThat { xs in xs.count <= len } + return characterArray.suchThat { xs in xs.count <= len } } generatorBoundedSizeArrays.generate @@ -212,11 +212,11 @@ let special : Gen = Gen.fromElements(of: ["!", "#", "$", " //: Now for the actual generator let allowedLocalCharacters : Gen = Gen.one(of: [ - upperCaseLetters, - lowerCaseLetters, - numeric, - special, - ]) + upperCaseLetters, + lowerCaseLetters, + numeric, + special, +]) //: Now we need a `String` made of these characters. so we'll just `proliferate` an array of characters and `map` @@ -231,10 +231,10 @@ let localEmail = allowedLocalCharacters //: steps here and combine them all into one big generator. let hostname = Gen.one(of: [ - lowerCaseLetters, - numeric, - Gen.pure("-"), - ]).proliferateNonEmpty.map { String($0) } + lowerCaseLetters, + numeric, + Gen.pure("-"), +]).proliferateNonEmpty.map { String($0) } //: Finally, the RFC says the TLD for the address can only consist of lowercase letters with a length larger than 1. @@ -248,7 +248,7 @@ let tld = lowerCaseLetters // Concatenates an array of `String` `Gen`erators together in order. func glue(_ parts : [Gen]) -> Gen { - return sequence(parts).map { $0.reduce("", +) } + return sequence(parts).map { $0.reduce("", +) } } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) @@ -288,18 +288,18 @@ emailGen.generate //: for `Int` calls `arc4random_uniform`. //: //: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't -//: generate with another that we can–for a few of the more "difficult" types in the Swift Standard +//: generate with another that we can–for a few of the more "difficult" types in the Swift Standard //: Library, but we also use them in more benign ways too. For example, we can write a modifier type //: that only generates positive numbers: -public struct ArbitraryPositive : Arbitrary { - public let getPositive : A - - public init(_ pos : A) { self.getPositive = pos } - - public static var arbitrary : Gen> { - return A.arbitrary.map { ArbitraryPositive.init(abs($0)) } - } +public struct ArbitraryPositive : Arbitrary { + public let getPositive : A + + public init(_ pos : A) { self.getPositive = pos } + + public static var arbitrary : Gen> { + return A.arbitrary.map { ArbitraryPositive.init(abs($0)) } + } } ArbitraryPositive.arbitrary.generate.getPositive @@ -329,7 +329,7 @@ ArbitraryPositive.arbitrary.generate.getPositive // | | // v v property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in - return xs.reversed().reversed() == xs + return xs.reversed().reversed() == xs } // From now on, all of our examples will take the form above. @@ -341,17 +341,17 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // | | can generate *functions*!! // v v property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in - let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) - // ^ This property says that if we filter an array then apply the predicate - // to all its elements, then they should all respond with `true`. + let f = pred.getArrow + return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) + // ^ This property says that if we filter an array then apply the predicate + // to all its elements, then they should all respond with `true`. } // How about a little Boolean Algebra too? property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in - let l = !(x && y) == (!x || !y) - let r = !(x || y) == (!x && !y) - return l && r + let l = !(x && y) == (!x || !y) + let r = !(x || y) == (!x && !y) + return l && r } //: The thing to notice about all of these examples is that there isn't a `Gen`erator in sight. Not @@ -367,10 +367,10 @@ property("DeMorgan's Law") <- forAll { (x : Bool, y : Bool) in // `reportProperty` is a variation of `property` that doesn't assert on failure. It does, however, // still print all failures to the console. We use it here because XCTest does not like it when you // assert outside of a test case. -reportProperty("Obviously wrong") <- forAll({ (x : Int) in - return x != x -}).whenFail { // `whenFail` attaches a callback to the test when we fail. - print("Oh noes!") +reportProperty("Obviously wrong") <- forAll { (x : Int) in + return x != x +}.whenFail { // `whenFail` attaches a callback to the test when we fail. + print("Oh noes!") } //: If you open the console for the playground, you'll see output very similar to the following: @@ -424,19 +424,19 @@ Array.shrink([1, 2, 3]) // will often be times when those default shrinkers don't cut it, or you need more control over // what happens when you generate or shrink values. Modifier Types to the rescue! struct ArbitraryEmail : Arbitrary { - let getEmail : String - - init(email : String) { self.getEmail = email } - - static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } + let getEmail : String + + init(email : String) { self.getEmail = email } + + static var arbitrary : Gen { return emailGen.map(ArbitraryEmail.init) } } // Let's be wrong for the sake of example property("email addresses don't come with a TLD") <- forAll { (email : ArbitraryEmail) in - return !email.getEmail.contains(".") - }.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` -// to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail -// and live up to your expectations, SwiftCheck treats that as a failure of the test case. + return !email.getEmail.contains(".") +}.expectFailure // It turns out true things aren't the only thing we can test. We can `expectFailure` + // to make SwiftCheck, well, expect failure. Beware, however, that if you don't fail + // and live up to your expectations, SwiftCheck treats that as a failure of the test case. //: # All Together Now! @@ -456,27 +456,27 @@ import func Darwin.sqrt // } // - Remaining indices of unmarked numbers are primes func sieve(_ n : Int) -> [Int] { - if n <= 1 { - return [] - } - - var marked : [Bool] = (0...n).map { _ in false } - marked[0] = true - marked[1] = true - - for p in 2.. [Int] { // Short and sweet check if a number is prime by enumerating from 2...⌈√(x)⌉ and checking // for a nonzero modulus. func isPrime(_ n : Int) -> Bool { - if n == 0 || n == 1 { - return false - } else if n == 2 { - return true - } - - let max = Int(ceil(sqrt(Double(n)))) - for i in 2...max { - if n % i == 0 { - return false - } - } - return true + if n == 0 || n == 1 { + return false + } else if n == 2 { + return true + } + + let max = Int(ceil(sqrt(Double(n)))) + for i in 2...max { + if n % i == 0 { + return false + } + } + return true } //: We would like to test whether our sieve works properly, so we run it through SwiftCheck with the //: following property: reportProperty("All Prime") <- forAll { (n : Positive) in - let primes = sieve(n.getPositive) - return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElements(of: primes) - return forAll(primeNumberGen) { (p : Int) in - return isPrime(p) - } - } + let primes = sieve(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElements(of: primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } } //: This test introduces several new concepts that we'll go through 1-by-1: @@ -559,39 +559,39 @@ reportProperty("All Prime") <- forAll { (n : Positive) in //: Looks like we used `to:` when we meant `through:`. Let's try again: func sieveProperly(_ n : Int) -> [Int] { - if n <= 1 { - return [] - } - - var marked : [Bool] = (0...n).map { _ in false } - marked[0] = true - marked[1] = true - - for p in 2..) in - let primes = sieveProperly(n.getPositive) - return primes.count > 1 ==> { - let primeNumberGen = Gen.fromElements(of: primes) - return forAll(primeNumberGen) { (p : Int) in - return isPrime(p) - } - } + let primes = sieveProperly(n.getPositive) + return primes.count > 1 ==> { + let primeNumberGen = Gen.fromElements(of: primes) + return forAll(primeNumberGen) { (p : Int) in + return isPrime(p) + } + } } //: And that's how you test with SwiftCheck. When properties fail, it means some part of your algorithm @@ -603,8 +603,8 @@ property("All Prime") <- forAll { (n : Positive) in //: Just for fun, let's try a simpler property that checks the same outcome: property("All Prime") <- forAll { (n : Positive) in - // Sieving Properly then filtering for primes is the same as just Sieving, right? - return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) + // Sieving Properly then filtering for primes is the same as just Sieving, right? + return sieveProperly(n.getPositive).filter(isPrime) == sieveProperly(n.getPositive) } //: # One More Thing @@ -626,11 +626,11 @@ property("All Prime") <- forAll { (n : Positive) in //: every so often on one particular value: reportProperty("Screw this value in particular") <- forAll { (n : UInt) in - if (n == 42) { - return false - } - - return true + if (n == 42) { + return false + } + + return true } //: But with a replay seed of (1391985334, 382376411) we can always reproduce the failure because @@ -640,11 +640,11 @@ reportProperty("Screw this value in particular") <- forAll { (n : UInt) in /// size to completely replicate a particular set of values that caused the first test to fail. let replayArgs = CheckerArguments(replay: (StdGen(1391985334, 382376411), 100)) reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in - if (n == 42) { - return false - } - return true - }.verbose + if (n == 42) { + return false + } + return true +}.verbose //: # Conclusion @@ -664,4 +664,3 @@ reportProperty("Replay", arguments: replayArgs) <- forAll { (n : UInt) in //: * [The Original (slightly outdated) QuickCheck Tutorial](http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html) //: //: Go forth and test. - From 7c9a5ce8985ec4e8c33d23a7a67180ec188b33f5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 22 Sep 2017 01:15:37 -0400 Subject: [PATCH 407/460] Factor FileCheck out as a framework (#244) --- .gitignore | 1 + .gitmodules | 3 + Cartfile | 1 + Cartfile.resolved | 1 + Carthage/Checkouts/FileCheck | 1 + Package.resolved | 16 - Package.swift | 21 +- SwiftCheck.xcodeproj/project.pbxproj | 82 +- Templates/CartesianSpec.swift.gyb | 3 + .../SwiftCheckTests/BooleanIdentitySpec.swift | 4 +- Tests/SwiftCheckTests/CartesianSpec.swift | 3 + Tests/SwiftCheckTests/ComplexSpec.swift | 3 + Tests/SwiftCheckTests/DiscardSpec.swift | 3 + Tests/SwiftCheckTests/FailureSpec.swift | 3 + Tests/SwiftCheckTests/FileCheck.swift | 1208 ----------------- Tests/SwiftCheckTests/FormatterSpec.swift | 3 + Tests/SwiftCheckTests/GenSpec.swift | 3 + Tests/SwiftCheckTests/LambdaSpec.swift | 3 + Tests/SwiftCheckTests/ModifierSpec.swift | 3 + Tests/SwiftCheckTests/PathSpec.swift | 3 + Tests/SwiftCheckTests/PropertySpec.swift | 3 + Tests/SwiftCheckTests/ReplaySpec.swift | 3 + Tests/SwiftCheckTests/RoseSpec.swift | 3 + Tests/SwiftCheckTests/ShrinkSpec.swift | 3 + Tests/SwiftCheckTests/SimpleSpec.swift | 3 + Tests/SwiftCheckTests/TestSpec.swift | 3 + 26 files changed, 132 insertions(+), 1254 deletions(-) create mode 100644 .gitmodules create mode 160000 Carthage/Checkouts/FileCheck delete mode 100644 Package.resolved delete mode 100644 Tests/SwiftCheckTests/FileCheck.swift diff --git a/.gitignore b/.gitignore index 104821a..4c0b927 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ DerivedData Carthage/Build Carthage/Checkouts build/ +Package.resolved # Python *.pyc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..79aa9e1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Carthage/Checkouts/FileCheck"] + path = Carthage/Checkouts/FileCheck + url = https://github.com/trill-lang/FileCheck.git diff --git a/Cartfile b/Cartfile index e69de29..91c16f2 100644 --- a/Cartfile +++ b/Cartfile @@ -0,0 +1 @@ +github "trill-lang/FileCheck" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index e69de29..32291f6 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -0,0 +1 @@ +github "trill-lang/FileCheck" "0.0.3" diff --git a/Carthage/Checkouts/FileCheck b/Carthage/Checkouts/FileCheck new file mode 160000 index 0000000..482e229 --- /dev/null +++ b/Carthage/Checkouts/FileCheck @@ -0,0 +1 @@ +Subproject commit 482e22960391b02e3630ae3af4dce64d16dd63e7 diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index 09a8836..0000000 --- a/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Operadics", - "repositoryURL": "https://github.com/typelift/Operadics.git", - "state": { - "branch": "swift-develop", - "revision": "743e71210ea319dfd9f0e39268c5e18877debc7f", - "version": null - } - } - ] - }, - "version": 1 -} diff --git a/Package.swift b/Package.swift index 39d3dbc..4d2dbe1 100644 --- a/Package.swift +++ b/Package.swift @@ -5,20 +5,19 @@ import PackageDescription let package = Package( name: "SwiftCheck", products: [ - .library( - name: "SwiftCheck", - targets: ["SwiftCheck"]), - ], - dependencies: [ - .package(url: "https://github.com/typelift/Operadics.git", .branch("swift-develop")) + .library( + name: "SwiftCheck", + targets: ["SwiftCheck"]), + ], + dependencies: [ + .package(url: "https://github.com/trill-lang/FileCheck.git", .branch("master")) ], targets: [ .target( - name: "SwiftCheck", - dependencies: ["Operadics"]), - .testTarget( - name: "SwiftCheckTests", - dependencies: ["SwiftCheck"]), + name: "SwiftCheck"), + .testTarget( + name: "SwiftCheckTests", + dependencies: ["SwiftCheck", "FileCheck"]), ] ) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index bdd2367..ca6890b 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -63,7 +63,6 @@ 6A761BD31F14E93900A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; 6A761BD41F14E93900A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; 6A761BD51F14E93900A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; - 6A761BD61F14E93900A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; 6A761BD71F14E93900A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; 6A761BD81F14E93900A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; 6A761BD91F14E93900A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; @@ -80,7 +79,6 @@ 6A761BE41F14E93A00A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; 6A761BE51F14E93A00A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; 6A761BE61F14E93A00A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; - 6A761BE71F14E93A00A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; 6A761BE81F14E93A00A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; 6A761BE91F14E93A00A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; 6A761BEA1F14E93A00A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; @@ -97,7 +95,6 @@ 6A761BF51F14E93B00A7D74F /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */; }; 6A761BF61F14E93B00A7D74F /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B901F14E91500A7D74F /* DiscardSpec.swift */; }; 6A761BF71F14E93B00A7D74F /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B911F14E91500A7D74F /* FailureSpec.swift */; }; - 6A761BF81F14E93B00A7D74F /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B921F14E91500A7D74F /* FileCheck.swift */; }; 6A761BF91F14E93B00A7D74F /* FormatterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B931F14E91500A7D74F /* FormatterSpec.swift */; }; 6A761BFA1F14E93B00A7D74F /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B941F14E91500A7D74F /* GenSpec.swift */; }; 6A761BFB1F14E93B00A7D74F /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B951F14E91500A7D74F /* LambdaSpec.swift */; }; @@ -109,6 +106,24 @@ 6A761C011F14E93B00A7D74F /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */; }; 6A761C021F14E93B00A7D74F /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */; }; 6A761C031F14E93B00A7D74F /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B9D1F14E91500A7D74F /* TestSpec.swift */; }; + 8235D34A1F72DCFF00207FA1 /* CheckString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3471F72DCEA00207FA1 /* CheckString.swift */; }; + 8235D34B1F72DD0300207FA1 /* ColoredStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3441F72DCEA00207FA1 /* ColoredStream.swift */; }; + 8235D34C1F72DD0B00207FA1 /* Diagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3461F72DCEA00207FA1 /* Diagnostics.swift */; }; + 8235D34D1F72DD0B00207FA1 /* EditDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3491F72DCEA00207FA1 /* EditDistance.swift */; }; + 8235D34E1F72DD0B00207FA1 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3451F72DCEA00207FA1 /* FileCheck.swift */; }; + 8235D34F1F72DD0B00207FA1 /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3481F72DCEA00207FA1 /* Pattern.swift */; }; + 8235D3501F72DD1B00207FA1 /* CheckString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3471F72DCEA00207FA1 /* CheckString.swift */; }; + 8235D3511F72DD1B00207FA1 /* ColoredStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3441F72DCEA00207FA1 /* ColoredStream.swift */; }; + 8235D3521F72DD1B00207FA1 /* Diagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3461F72DCEA00207FA1 /* Diagnostics.swift */; }; + 8235D3531F72DD1B00207FA1 /* EditDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3491F72DCEA00207FA1 /* EditDistance.swift */; }; + 8235D3541F72DD1B00207FA1 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3451F72DCEA00207FA1 /* FileCheck.swift */; }; + 8235D3551F72DD1B00207FA1 /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3481F72DCEA00207FA1 /* Pattern.swift */; }; + 8235D3561F72DD2200207FA1 /* CheckString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3471F72DCEA00207FA1 /* CheckString.swift */; }; + 8235D3571F72DD2200207FA1 /* ColoredStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3441F72DCEA00207FA1 /* ColoredStream.swift */; }; + 8235D3581F72DD2200207FA1 /* Diagnostics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3461F72DCEA00207FA1 /* Diagnostics.swift */; }; + 8235D3591F72DD2200207FA1 /* EditDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3491F72DCEA00207FA1 /* EditDistance.swift */; }; + 8235D35A1F72DD2200207FA1 /* FileCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3451F72DCEA00207FA1 /* FileCheck.swift */; }; + 8235D35B1F72DD2200207FA1 /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8235D3481F72DCEA00207FA1 /* Pattern.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -190,7 +205,6 @@ 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; 6A761B901F14E91500A7D74F /* DiscardSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; }; 6A761B911F14E91500A7D74F /* FailureSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; - 6A761B921F14E91500A7D74F /* FileCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileCheck.swift; sourceTree = ""; }; 6A761B931F14E91500A7D74F /* FormatterSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormatterSpec.swift; sourceTree = ""; }; 6A761B941F14E91500A7D74F /* GenSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; }; 6A761B951F14E91500A7D74F /* LambdaSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; @@ -202,6 +216,12 @@ 6A761B9B1F14E91500A7D74F /* ShrinkSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; }; 6A761B9C1F14E91500A7D74F /* SimpleSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; }; 6A761B9D1F14E91500A7D74F /* TestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; }; + 8235D3441F72DCEA00207FA1 /* ColoredStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColoredStream.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/ColoredStream.swift; sourceTree = SOURCE_ROOT; }; + 8235D3451F72DCEA00207FA1 /* FileCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FileCheck.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/FileCheck.swift; sourceTree = SOURCE_ROOT; }; + 8235D3461F72DCEA00207FA1 /* Diagnostics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Diagnostics.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/Diagnostics.swift; sourceTree = SOURCE_ROOT; }; + 8235D3471F72DCEA00207FA1 /* CheckString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CheckString.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/CheckString.swift; sourceTree = SOURCE_ROOT; }; + 8235D3481F72DCEA00207FA1 /* Pattern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Pattern.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/Pattern.swift; sourceTree = SOURCE_ROOT; }; + 8235D3491F72DCEA00207FA1 /* EditDistance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = EditDistance.swift; path = Carthage/Checkouts/FileCheck/Sources/FileCheck/EditDistance.swift; sourceTree = SOURCE_ROOT; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -299,6 +319,12 @@ children = ( 6A761B8A1F14E91500A7D74F /* Info.plist */, 6A761B8B1F14E91500A7D74F /* LinuxMain.swift */, + 8235D3471F72DCEA00207FA1 /* CheckString.swift */, + 8235D3441F72DCEA00207FA1 /* ColoredStream.swift */, + 8235D3461F72DCEA00207FA1 /* Diagnostics.swift */, + 8235D3491F72DCEA00207FA1 /* EditDistance.swift */, + 8235D3451F72DCEA00207FA1 /* FileCheck.swift */, + 8235D3481F72DCEA00207FA1 /* Pattern.swift */, 6A761B8C1F14E91500A7D74F /* SwiftCheckTests */, ); path = Tests; @@ -312,7 +338,6 @@ 6A761B8F1F14E91500A7D74F /* ComplexSpec.swift */, 6A761B901F14E91500A7D74F /* DiscardSpec.swift */, 6A761B911F14E91500A7D74F /* FailureSpec.swift */, - 6A761B921F14E91500A7D74F /* FileCheck.swift */, 6A761B931F14E91500A7D74F /* FormatterSpec.swift */, 6A761B941F14E91500A7D74F /* GenSpec.swift */, 6A761B951F14E91500A7D74F /* LambdaSpec.swift */, @@ -653,6 +678,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8235D34C1F72DD0B00207FA1 /* Diagnostics.swift in Sources */, + 8235D34D1F72DD0B00207FA1 /* EditDistance.swift in Sources */, + 8235D34E1F72DD0B00207FA1 /* FileCheck.swift in Sources */, + 8235D34F1F72DD0B00207FA1 /* Pattern.swift in Sources */, 6A761C021F14E93B00A7D74F /* SimpleSpec.swift in Sources */, 6A761C031F14E93B00A7D74F /* TestSpec.swift in Sources */, 6A761BF31F14E93B00A7D74F /* BooleanIdentitySpec.swift in Sources */, @@ -666,9 +695,10 @@ 6A761BFC1F14E93B00A7D74F /* ModifierSpec.swift in Sources */, 6A761BF91F14E93B00A7D74F /* FormatterSpec.swift in Sources */, 6A761BFA1F14E93B00A7D74F /* GenSpec.swift in Sources */, - 6A761BF81F14E93B00A7D74F /* FileCheck.swift in Sources */, 6A761BF41F14E93B00A7D74F /* CartesianSpec.swift in Sources */, 6A761C011F14E93B00A7D74F /* ShrinkSpec.swift in Sources */, + 8235D34A1F72DCFF00207FA1 /* CheckString.swift in Sources */, + 8235D34B1F72DD0300207FA1 /* ColoredStream.swift in Sources */, 6A761C001F14E93B00A7D74F /* RoseSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -700,6 +730,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8235D3561F72DD2200207FA1 /* CheckString.swift in Sources */, + 8235D3571F72DD2200207FA1 /* ColoredStream.swift in Sources */, + 8235D3581F72DD2200207FA1 /* Diagnostics.swift in Sources */, + 8235D3591F72DD2200207FA1 /* EditDistance.swift in Sources */, + 8235D35A1F72DD2200207FA1 /* FileCheck.swift in Sources */, + 8235D35B1F72DD2200207FA1 /* Pattern.swift in Sources */, 6A761BE01F14E93900A7D74F /* SimpleSpec.swift in Sources */, 6A761BE11F14E93900A7D74F /* TestSpec.swift in Sources */, 6A761BD11F14E93900A7D74F /* BooleanIdentitySpec.swift in Sources */, @@ -713,7 +749,6 @@ 6A761BDA1F14E93900A7D74F /* ModifierSpec.swift in Sources */, 6A761BD71F14E93900A7D74F /* FormatterSpec.swift in Sources */, 6A761BD81F14E93900A7D74F /* GenSpec.swift in Sources */, - 6A761BD61F14E93900A7D74F /* FileCheck.swift in Sources */, 6A761BD21F14E93900A7D74F /* CartesianSpec.swift in Sources */, 6A761BDF1F14E93900A7D74F /* ShrinkSpec.swift in Sources */, 6A761BDE1F14E93900A7D74F /* RoseSpec.swift in Sources */, @@ -747,6 +782,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8235D3501F72DD1B00207FA1 /* CheckString.swift in Sources */, + 8235D3511F72DD1B00207FA1 /* ColoredStream.swift in Sources */, + 8235D3521F72DD1B00207FA1 /* Diagnostics.swift in Sources */, + 8235D3531F72DD1B00207FA1 /* EditDistance.swift in Sources */, + 8235D3541F72DD1B00207FA1 /* FileCheck.swift in Sources */, + 8235D3551F72DD1B00207FA1 /* Pattern.swift in Sources */, 6A761BF11F14E93A00A7D74F /* SimpleSpec.swift in Sources */, 6A761BF21F14E93A00A7D74F /* TestSpec.swift in Sources */, 6A761BE21F14E93A00A7D74F /* BooleanIdentitySpec.swift in Sources */, @@ -760,7 +801,6 @@ 6A761BEB1F14E93A00A7D74F /* ModifierSpec.swift in Sources */, 6A761BE81F14E93A00A7D74F /* FormatterSpec.swift in Sources */, 6A761BE91F14E93A00A7D74F /* GenSpec.swift in Sources */, - 6A761BE71F14E93A00A7D74F /* FileCheck.swift in Sources */, 6A761BE31F14E93A00A7D74F /* CartesianSpec.swift in Sources */, 6A761BF01F14E93A00A7D74F /* ShrinkSpec.swift in Sources */, 6A761BEF1F14E93A00A7D74F /* RoseSpec.swift in Sources */, @@ -848,7 +888,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -865,12 +905,13 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -884,12 +925,13 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -1024,7 +1066,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1057,7 +1099,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -1077,11 +1119,12 @@ ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1098,11 +1141,12 @@ GCC_OPTIMIZATION_LEVEL = s; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; }; name = Release; }; @@ -1172,7 +1216,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1196,13 +1240,14 @@ INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -1218,13 +1263,14 @@ INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Templates/CartesianSpec.swift.gyb b/Templates/CartesianSpec.swift.gyb index 0697ae1..d42637f 100644 --- a/Templates/CartesianSpec.swift.gyb +++ b/Templates/CartesianSpec.swift.gyb @@ -16,6 +16,9 @@ MAX_ARITY = 22 import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif import Foundation final class CartesianSpec : XCTestCase { diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index ea5ba2e..4a19c87 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -8,7 +8,9 @@ import SwiftCheck import XCTest - +#if !XCODE_BUILD +import FileCheck +#endif class BooleanIdentitySpec : XCTestCase { func testAll() { diff --git a/Tests/SwiftCheckTests/CartesianSpec.swift b/Tests/SwiftCheckTests/CartesianSpec.swift index 3619bb3..fbd9fe5 100644 --- a/Tests/SwiftCheckTests/CartesianSpec.swift +++ b/Tests/SwiftCheckTests/CartesianSpec.swift @@ -13,6 +13,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif import Foundation final class CartesianSpec : XCTestCase { diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 20b9767..52943ea 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif let upper : Gen = Gen.fromElements(in: "A"..."Z") let lower : Gen = Gen.fromElements(in: "a"..."z") diff --git a/Tests/SwiftCheckTests/DiscardSpec.swift b/Tests/SwiftCheckTests/DiscardSpec.swift index 07a22bc..3f2fe71 100644 --- a/Tests/SwiftCheckTests/DiscardSpec.swift +++ b/Tests/SwiftCheckTests/DiscardSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif class DiscardSpec : XCTestCase { func testDiscardFailure() { diff --git a/Tests/SwiftCheckTests/FailureSpec.swift b/Tests/SwiftCheckTests/FailureSpec.swift index 21d83e5..9e2d1d3 100644 --- a/Tests/SwiftCheckTests/FailureSpec.swift +++ b/Tests/SwiftCheckTests/FailureSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif #if os(Linux) import Glibc diff --git a/Tests/SwiftCheckTests/FileCheck.swift b/Tests/SwiftCheckTests/FileCheck.swift deleted file mode 100644 index d953253..0000000 --- a/Tests/SwiftCheckTests/FileCheck.swift +++ /dev/null @@ -1,1208 +0,0 @@ -// -// FileCheck.swift -// SwiftCheck -// -// Created by Robert Widmann on 10/6/16. -// Copyright © 2016 Typelift. All rights reserved. -// - -import Foundation -#if os(Linux) - import Glibc -#else - import Darwin -#endif - -/// `FileCheckOptions` enumerates a set of options that can modify the behavior -/// of the file check verification process. -public struct FileCheckOptions : OptionSet { - /// Retrieves the raw value of this option set. - public let rawValue : UInt64 - - /// Convert from a value of `RawValue`, succeeding unconditionally. - public init(rawValue : UInt64) { - self.rawValue = rawValue - } - - /// Do not treat all horizontal whitespace as equivalent. - public static let strictWhitespace = FileCheckOptions(rawValue: 1 << 0) - /// Add an implicit negative check with this pattern to every positive - /// check. This can be used to ensure that no instances of this pattern - /// occur which are not matched by a positive pattern. - public static let implicitCheckNot = FileCheckOptions(rawValue: 1 << 1) - /// Allow the input file to be empty. This is useful when making checks that - /// some error message does not occur, for example. - public static let allowEmptyInput = FileCheckOptions(rawValue: 1 << 2) - /// Require all positive matches to cover an entire input line. Allows - /// leading and trailing whitespace if `.strictWhitespace` is not also - /// passed. - public static let matchFullLines = FileCheckOptions(rawValue: 1 << 3) -} - -/// `FileCheckFD` represents the standard output streams `FileCheck` is capable -/// of overriding to gather output. -public enum FileCheckFD { - /// Standard output. - case stdout - /// Standard error. - case stderr - /// A custom output stream. - case custom(fileno: Int32, ptr: UnsafeMutablePointer) - - /// Retrieve the file descriptor for this output stream. - var fileno : Int32 { - switch self { - case .stdout: - return STDOUT_FILENO - case .stderr: - return STDERR_FILENO - case let .custom(fileno: fd, ptr: _): - return fd - } - } - - /// Retrieve the FILE pointer for this stream. - var filePtr : UnsafeMutablePointer! { - switch self { - case .stdout: - #if os(Linux) - return Glibc.stdout - #else - return Darwin.stdout - #endif - case .stderr: - #if os(Linux) - return Glibc.stderr - #else - return Darwin.stderr - #endif - case let .custom(fileno: _, ptr: ptr): - return ptr - } - } -} - -/// Reads from the given output stream and runs a file verification procedure -/// by comparing the output to a specified result. -/// -/// FileCheck requires total access to whatever input stream is being used. As -/// such it will override printing to said stream until the given block has -/// finished executing. -/// -/// - parameter FD: The file descriptor to override and read from. -/// - parameter prefixes: Specifies one or more prefixes to match. By default -/// these patterns are prefixed with "CHECK". -/// - parameter file: The file to check against. Defaults to the file that -/// containing the call to `fileCheckOutput`. -/// - parameter options: Optional arguments to modify the behavior of the check. -/// - parameter block: The block in which output will be emitted to the given -/// file descriptor. -public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes : [String] = ["CHECK"], against file : String = #file, options: FileCheckOptions = [], block : () -> ()) -> Bool { - guard let validPrefixes = validateCheckPrefixes(prefixes) else { - print("Supplied check-prefix is invalid! Prefixes must be unique and ", - "start with a letter and contain only alphanumeric characters, ", - "hyphens and underscores") - return false - } - guard let PrefixRE = try? NSRegularExpression(pattern: validPrefixes.joined(separator: "|"), options: []) else { - print("Unable to combine check-prefix strings into a prefix regular ", - "expression! This is likely a bug in FileCheck's verification of ", - "the check-prefix strings. Regular expression parsing failed.") - return false - } - - let input = overrideFDAndCollectOutput(file: FD, of: block) - if (input.isEmpty && !options.contains(.allowEmptyInput)) { - print("FileCheck error: input from file descriptor \(FD) is empty.\n") - return false - } - - guard let contents = try? String(contentsOfFile: file, encoding: .utf8) else { - return false - } - let buf = contents.cString(using: .utf8)?.withUnsafeBufferPointer { buffer in - return readCheckStrings(in: buffer, withPrefixes: validPrefixes, options: options, PrefixRE) - } - guard let checkStrings = buf else { - return false - } - return check(input: input, against: checkStrings) -} - -private func overrideFDAndCollectOutput(file : FileCheckFD, of block : () -> ()) -> String { - fflush(file.filePtr) - let oldFd = dup(file.fileno) - - let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("output.XXXXXX") - return template.withUnsafeFileSystemRepresentation { buffer in - guard let buffer = buffer else { - return "" - } - - let newFd = mkstemp(UnsafeMutablePointer(mutating: buffer)) - guard newFd != -1 else { - return "" - } - - dup2(newFd, file.fileno) - - block() - - close(newFd) - fflush(file.filePtr) - - - dup2(oldFd, file.fileno) - close(oldFd) - - let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil) - guard let s = try? String(contentsOf: url, encoding: .utf8) else { - return "" - } - return s - } -} - -func validateCheckPrefixes(_ prefixes : [String]) -> [String]? { - let validator = try! NSRegularExpression(pattern: "^[a-zA-Z0-9_-]*$", options: []) - - for prefix in prefixes { - // Reject empty prefixes. - if prefix.isEmpty { - return nil - } - - let range = NSRange( - location: 0, - length: prefix.distance(from: prefix.startIndex, to: prefix.endIndex) - ) - if validator.matches(in: prefix, options: [], range: range).isEmpty { - return nil - } - } - - return [String](Set(prefixes)) -} - -extension CChar { - fileprivate var isPartOfWord : Bool { - return isalnum(Int32(self)) != 0 || self == ("-" as Character).utf8CodePoint || self == ("_" as Character).utf8CodePoint - } -} - -extension Character { - var utf8CodePoint : CChar { - return String(self).cString(using: .utf8)!.first! - } - - fileprivate var isPartOfWord : Bool { - let utf8Value = self.utf8CodePoint - return isalnum(Int32(utf8Value)) != 0 || self == "-" || self == "_" - } -} - -private func findCheckType(in buf : UnsafeBufferPointer, with prefix : String) -> CheckType { - let nextChar = buf[prefix.utf8.count] - - // Verify that the : is present after the prefix. - if nextChar == (":" as Character).utf8CodePoint { - return .plain - } - if nextChar != ("-" as Character).utf8CodePoint { - return .none - } - - let rest = String( - bytesNoCopy: UnsafeMutableRawPointer( - mutating: buf.baseAddress!.advanced(by: prefix.utf8.count + 1) - ), - length: buf.count - (prefix.utf8.count + 1), - encoding: .utf8, - freeWhenDone: false - )! - if rest.hasPrefix("NEXT:") { - return .next - } - - if rest.hasPrefix("SAME:") { - return .same - } - - if rest.hasPrefix("NOT:") { - return .not - } - - if rest.hasPrefix("DAG:") { - return .dag - } - - if rest.hasPrefix("LABEL:") { - return .label - } - - // You can't combine -NOT with another suffix. - let badNotPrefixes = [ - "DAG-NOT:", - "NOT-DAG:", - "NEXT-NOT:", - "NOT-NEXT:", - "SAME-NOT:", - "NOT-SAME:", - ] - if badNotPrefixes.reduce(false, { (acc, s) in acc || rest.hasPrefix(s) }) { - return .badNot - } - - return .none -} - -extension UnsafeBufferPointer { - fileprivate func substr(_ start : Int, _ size : Int) -> UnsafeBufferPointer { - return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: start), count: size) - } - - fileprivate func dropFront(_ n : Int) -> UnsafeBufferPointer { - precondition(n < self.count) - return UnsafeBufferPointer(start: self.baseAddress!.advanced(by: n), count: self.count - n) - } -} - -func substring(in buffer : UnsafeBufferPointer, with range : NSRange) -> String { - precondition(range.location + range.length <= buffer.count) - let ptr = buffer.substr(range.location, range.length) - return String(bytesNoCopy: UnsafeMutableRawPointer(mutating: ptr.baseAddress!), length: range.length, encoding: .utf8, freeWhenDone: false)! -} - -private func findFirstMatch(in inbuffer : UnsafeBufferPointer, among prefixes : [String], with RE : NSRegularExpression, startingAt startLine: Int) -> (String, CheckType, Int, UnsafeBufferPointer) { - var lineNumber = startLine - var buffer = inbuffer - - while !buffer.isEmpty { - let str = String(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!), length: buffer.count, encoding: .utf8, freeWhenDone: false)! - let match = RE.firstMatch(in: str, options: [], range: NSRange(location: 0, length: str.distance(from: str.startIndex, to: str.endIndex))) - guard let prefix = match else { - return ("", .none, lineNumber, buffer) - } - let skippedPrefix = substring(in: buffer, with: NSMakeRange(0, prefix.range.location)) - let prefixStr = str.substring( - with: Range( - uncheckedBounds: ( - str.index(str.startIndex, offsetBy: prefix.range.location), - str.index(str.startIndex, offsetBy: NSMaxRange(prefix.range)) - ) - ) - ) - - // HACK: Conversion between the buffer and `String` causes index - // mismatches when searching for strings. We're instead going to do - // something terribly inefficient here: Use the regular expression to - // look for check prefixes, then use Foundation's Data to find their - // actual locations in the buffer. - let bd = Data(buffer: buffer) - let range = bd.range(of: prefixStr.data(using: .utf8)!)! - buffer = buffer.dropFront(range.lowerBound) - lineNumber += skippedPrefix.filter({ c in c == "\n" }).characters.count - // Check that the matched prefix isn't a suffix of some other check-like - // word. - // FIXME: This is a very ad-hoc check. it would be better handled in some - // other way. Among other things it seems hard to distinguish between - // intentional and unintentional uses of this feature. - if skippedPrefix.isEmpty || !skippedPrefix.characters.last!.isPartOfWord { - // Now extract the type. - let checkTy = findCheckType(in: buffer, with: prefixStr) - - - // If we've found a valid check type for this prefix, we're done. - if checkTy != .none { - return (prefixStr, checkTy, lineNumber, buffer) - } - } - // If we didn't successfully find a prefix, we need to skip this invalid - // prefix and continue scanning. We directly skip the prefix that was - // matched and any additional parts of that check-like word. - // From the given position, find the next character after the word. - var loc = prefix.range.length - while loc < buffer.count && buffer[loc].isPartOfWord { - loc += 1 - } - buffer = buffer.dropFront(loc) - } - - return ("", .none, lineNumber, buffer) -} - -private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes prefixes : [String], options: FileCheckOptions, _ RE : NSRegularExpression) -> [CheckString] { - // Keeps track of the line on which CheckPrefix instances are found. - var lineNumber = 1 - - // std::vector DagNotMatches = ImplicitNegativeChecks - var dagNotMatches = [Pattern]() - var contents = [CheckString]() - - var buffer = buf - while true { - // See if a prefix occurs in the memory buffer. - let (usedPrefix, checkTy, ln, newBuffer) = findFirstMatch(in: buffer, among: prefixes, with: RE, startingAt: lineNumber) - if usedPrefix.isEmpty { - break - } - lineNumber = ln - - // Skip the buffer to the end. - buffer = newBuffer.dropFront(usedPrefix.utf8.count + checkTy.size) - - // Complain about useful-looking but unsupported suffixes. - if checkTy == .badNot { - let loc = CheckLoc.inBuffer(buffer.baseAddress!, buf) - diagnose(.error, loc, "unsupported -NOT combo on prefix '\(usedPrefix)'") - return [] - } - - // Okay, we found the prefix, yay. Remember the rest of the line, but - // ignore leading whitespace. - if !options.contains(.strictWhitespace) || !options.contains(.matchFullLines) { - guard let idx = buffer.index(where: { c in c != (" " as Character).utf8CodePoint && c != ("\t" as Character).utf8CodePoint }) else { - return [] - } - buffer = buffer.dropFront(idx) - } - - // Scan ahead to the end of line. - let EOL : Int = buffer.index(of: ("\n" as Character).utf8CodePoint) ?? buffer.index(of: ("\r" as Character).utf8CodePoint)! - - // Remember the location of the start of the pattern, for diagnostics. - let patternLoc = CheckLoc.inBuffer(buffer.baseAddress!, buf) - - // Parse the pattern. - let pat : Pattern = Pattern(checking: checkTy) - let subBuffer = UnsafeBufferPointer(start: buffer.baseAddress, count: EOL) - if pat.parse(in: buf, pattern: subBuffer, withPrefix: usedPrefix, at: lineNumber, options: options) { - return [] - } - - // Verify that CHECK-LABEL lines do not define or use variables - if (checkTy == .label) && pat.hasVariable { - diagnose(.error, patternLoc, "found '\(usedPrefix)-LABEL:' with variable definition or use") - return [] - } - - // Verify that CHECK-NEXT lines have at least one CHECK line before them. - if (checkTy == .next || checkTy == .same) && contents.isEmpty { - let type = (checkTy == .next) ? "NEXT" : "SAME" - let loc = CheckLoc.inBuffer(buffer.baseAddress!, buf) - diagnose(.error, loc, "found '\(usedPrefix)-\(type)' without previous '\(usedPrefix): line") - return [] - } - - buffer = UnsafeBufferPointer( - start: buffer.baseAddress!.advanced(by: EOL), - count: buffer.count - EOL - ) - - // Handle CHECK-DAG/-NOT. - if checkTy == .dag || checkTy == .not { - dagNotMatches.append(pat) - continue - } - - // Okay, add the string we captured to the output vector and move on. - contents.append(CheckString(pattern: pat, prefix: usedPrefix, loc: patternLoc)) - // std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) - // DagNotMatches = ImplicitNegativeChecks - } - - // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first - // prefix as a filler for the error message. - // if !DagNotMatches.isEmpty { - // CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(), - // SMLoc::getFromPointer(Buffer.data())) - // std::swap(DagNotMatches, CheckStrings.back().DagNotStrings) - // } - if contents.isEmpty { - print("error: no check strings found with prefix\(contents.count == 1 ? " " : "es ")") - for prefix in prefixes { - print("\(prefix):") - } - return [] - } - return contents -} -private final class BoxedTable { - var table : [String:String] = [:] - init() {} - subscript(_ i : String) -> String? { - set { - self.table[i] = newValue! - } - get { - return self.table[i] - } - } -} -/// Check the input to FileCheck provided in the \p Buffer against the \p -/// CheckStrings read from the check file. -/// -/// Returns false if the input fails to satisfy the checks. -private func check(input b : String, against checkStrings : [CheckString]) -> Bool { - var buffer = b - var failedChecks = false - // This holds all the current filecheck variables. - var variableTable = BoxedTable() - var i = 0 - var j = 0 - var e = checkStrings.count - while true { - var checkRegion : String - if j == e { - checkRegion = buffer - } else { - let checkStr = checkStrings[j] - if checkStr.pattern.type != .label { - j += 1 - continue - } - // Scan to next CHECK-LABEL match, ignoring CHECK-NOT and CHECK-DAG - guard let (matchLabelPos, matchLabelLen) = checkStr.check(buffer, true, variableTable) else { - // Immediately bail of CHECK-LABEL fails, nothing else we can do. - return false - } - checkRegion = buffer.substring(to: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) - buffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: matchLabelPos + matchLabelLen)) - j += 1 - } - while i != j { - defer { i += 1 } - // Check each string within the scanned region, including a second check - // of any final CHECK-LABEL (to verify CHECK-NOT and CHECK-DAG) - guard let (matchPos, matchLen) = checkStrings[i].check(checkRegion, false, variableTable) else { - failedChecks = true - i = j - break - } - checkRegion = checkRegion.substring(from: checkRegion.index(checkRegion.startIndex, offsetBy: matchPos + matchLen)) - } - if j == e { - break - } - } - // Success if no checks failed. - return !failedChecks -} -private enum CheckLoc { - case inBuffer(UnsafePointer, UnsafeBufferPointer) - case string(String) - var message : String { - switch self { - case let .inBuffer(ptr, buf): - var startPtr = ptr - while startPtr != buf.baseAddress! && startPtr.predecessor().pointee != ("\n" as Character).utf8CodePoint { - startPtr = startPtr.predecessor() - } - var endPtr = ptr - while endPtr != buf.baseAddress!.advanced(by: buf.endIndex) && endPtr.successor().pointee != ("\n" as Character).utf8CodePoint { - endPtr = endPtr.successor() - } - // One more for good measure. - if endPtr != buf.baseAddress!.advanced(by: buf.endIndex) { - endPtr = endPtr.successor() - } - return substring(in: buf, with: NSMakeRange(buf.baseAddress!.distance(to: startPtr), startPtr.distance(to: endPtr))) - case let .string(s): - return s - } - } -} -enum CheckType { - case none - case plain - case next - case same - case not - case dag - case label - case badNot - /// MatchEOF - When set, this pattern only matches the end of file. This is - /// used for trailing CHECK-NOTs. - case EOF - // Get the size of the prefix extension. - var size : Int { - switch (self) { - case .none: - return 0 - case .badNot: - return 0 - case .plain: - return ":".utf8.count - case .next: - return "-NEXT:".utf8.count - case .same: - return "-SAME:".utf8.count - case .not: - return "-NOT:".utf8.count - case .dag: - return "-DAG:".utf8.count - case .label: - return "-LABEL:".utf8.count - case .EOF: - fatalError("Should not be using EOF size") - } - } -} -private class Pattern { - var patternLoc : CheckLoc = CheckLoc.string("") - let type : CheckType - /// If non-empty, this pattern is a fixed string match with the specified - /// fixed string. - var fixedString : String = "" - /// If non-empty, this is a regex pattern. - var regExPattern : String = "" - /// Contains the number of line this pattern is in. - var lineNumber : Int = 0 - /// Entries in this vector map to uses of a variable in the pattern, e.g. - /// "foo[[bar]]baz". In this case, the regExPattern will contain "foobaz" - /// and we'll get an entry in this vector that tells us to insert the value - /// of bar at offset 3. - var variableUses : Array<(String, Int)> = [] - /// Maps definitions of variables to their parenthesized capture numbers. - /// E.g. for the pattern "foo[[bar:.*]]baz", VariableDefs will map "bar" to 1. - var variableDefs : Dictionary = [:] - var hasVariable : Bool { - return !(variableUses.isEmpty && self.variableDefs.isEmpty) - } - init(checking ty : CheckType) { - self.type = ty - } - private func addBackrefToRegEx(_ backRef : Int) { - assert(backRef >= 1 && backRef <= 9, "Invalid backref number") - let Backref = "\\\(backRef)" - self.regExPattern += Backref - } - /// - returns: Returns a value on success or nil on a syntax error. - private func evaluateExpression(_ e : String) -> String? { - var expr = e - // The only supported expression is @LINE([\+-]\d+)? - if !expr.hasPrefix("@LINE") { - return nil - } - expr = expr.substring(from: expr.index(expr.startIndex, offsetBy: "@LINE".utf8.count)) - guard let firstC = expr.characters.first else { - return "\(self.lineNumber)" - } - if firstC == "+" { - expr = expr.substring(from: expr.index(after: expr.startIndex)) - } else if firstC != "-" { - return nil - } - guard let offset = Int(expr, radix: 10) else { - return nil - } - return "\(self.lineNumber + offset)" - } - /// Matches the pattern string against the input buffer. - /// - /// This returns the position that is matched or npos if there is no match. If - /// there is a match, the size of the matched string is returned in \p - /// MatchLen. - /// - /// The \p VariableTable StringMap provides the current values of filecheck - /// variables and is updated if this match defines new values. - func match(_ buffer : String, _ variableTable : BoxedTable) -> (Int, Int)? { - var matchLen : Int = 0 - // If this is the EOF pattern, match it immediately. - if self.type == .EOF { - matchLen = 0 - return (buffer.utf8.count, matchLen) - } - // If this is a fixed string pattern, just match it now. - if !self.fixedString.isEmpty { - matchLen = self.fixedString.utf8.count - if let b = buffer.range(of: self.fixedString)?.lowerBound { - return (buffer.distance(from: buffer.startIndex, to: b), matchLen) - } - return nil - } - // Regex match. - // If there are variable uses, we need to create a temporary string with the - // actual value. - var regExToMatch = self.regExPattern - if !self.variableUses.isEmpty { - var insertOffset = 0 - for (v, offset) in self.variableUses { - var value : String = "" - if let c = v.characters.first, c == "@" { - guard let v = self.evaluateExpression(v) else { - return nil - } - value = v - } else { - guard let val = variableTable[v] else { - return nil - } - // Look up the value and escape it so that we can put it into the regex. - value += NSRegularExpression.escapedPattern(for: val) - } - // Plop it into the regex at the adjusted offset. - regExToMatch.insert(contentsOf: value.characters, at: regExToMatch.index(regExToMatch.startIndex, offsetBy: offset + insertOffset)) - insertOffset += value.utf8.count - } - } - // Match the newly constructed regex. - guard let r = try? NSRegularExpression(pattern: regExToMatch, options: []) else { - return nil - } - let matchInfo = r.matches(in: buffer, options: [], range: NSRange(location: 0, length: buffer.utf8.count)) - // Successful regex match. - guard let fullMatch = matchInfo.first else { - fatalError("Didn't get any matches!") - } - // If this defines any variables, remember their values. - for (v, index) in self.variableDefs { - assert(index < fullMatch.numberOfRanges, "Internal paren error") - let r = fullMatch.range(at: index) - variableTable[v] = buffer.substring( - with: Range( - uncheckedBounds: ( - buffer.index(buffer.startIndex, offsetBy: r.location), - buffer.index(buffer.startIndex, offsetBy: NSMaxRange(r)) - ) - ) - ) - } - matchLen = fullMatch.range.length - return (fullMatch.range.location, matchLen) - } - /// Finds the closing sequence of a regex variable usage or definition. - /// - /// \p Str has to point in the beginning of the definition (right after the - /// opening sequence). Returns the offset of the closing sequence within Str, - /// or npos if it was not found. - private func findRegexVarEnd(_ regVar : String) -> String.Index? { - var string = regVar - // Offset keeps track of the current offset within the input Str - var offset = regVar.startIndex - // [...] Nesting depth - var bracketDepth = 0 - while let firstChar = string.characters.first { - if string.hasPrefix("]]") && bracketDepth == 0 { - return offset - } - if firstChar == "\\" { - // Backslash escapes the next char within regexes, so skip them both. - string = string.substring(from: string.index(string.startIndex, offsetBy: 2)) - offset = regVar.index(offset, offsetBy: 2) - } else { - switch firstChar { - case "[": - bracketDepth += 1 - case "]": - if bracketDepth == 0 { - diagnose(.error, .string(regVar), "missing closing \"]\" for regex variable") - return nil - } - bracketDepth -= 1 - default: - break - } - string = string.substring(from: string.index(after: string.startIndex)) - offset = regVar.index(after: offset) - } - } - - return nil - } - - private func addRegExToRegEx(_ RS : String, _ cur : Int) -> (Bool, Int) { - do { - let r = try NSRegularExpression(pattern: RS, options: []) - self.regExPattern += RS - return (false, cur + r.numberOfCaptureGroups) - } catch let e { - diagnose(.error, self.patternLoc, "invalid regex: \(e)") - return (true, cur) - } - } - - /// Parses the given string into the Pattern. - /// - /// \p Prefix provides which prefix is being matched, \p SM provides the - /// SourceMgr used for error reports, and \p LineNumber is the line number in - /// the input file from which the pattern string was read. Returns true in - /// case of an error, false otherwise. - func parse(in buf : UnsafeBufferPointer, pattern : UnsafeBufferPointer, withPrefix prefix : String, at lineNumber : Int, options: FileCheckOptions) -> Bool { - func mino(_ l : String.Index?, _ r : String.Index?) -> String.Index? { - if l == nil && r == nil { - return nil - } else if l == nil && r != nil { - return r - } else if l != nil && r == nil { - return l - } - return min(l!, r!) - } - - - self.lineNumber = lineNumber - var patternStr = substring(in: pattern, with: NSRange(location: 0, length: pattern.count)) - self.patternLoc = CheckLoc.inBuffer(pattern.baseAddress!, buf) - - // Check that there is something on the line. - if patternStr.isEmpty { - diagnose(.error, self.patternLoc, "found empty check string with prefix '\(prefix):'") - return true - } - - // Check to see if this is a fixed string, or if it has regex pieces. - if !options.contains(.matchFullLines) && - (patternStr.utf8.count < 2 || - (patternStr.range(of: "{{") == nil - && - patternStr.range(of: "[[") == nil)) - { - self.fixedString = patternStr - return false - } - - if options.contains(.matchFullLines) { - regExPattern += "^" - if !options.contains(.strictWhitespace) { - regExPattern += " *" - } - } - - // Paren value #0 is for the fully matched string. Any new - // parenthesized values add from there. - var curParen = 1 - - // Otherwise, there is at least one regex piece. Build up the regex pattern - // by escaping scary characters in fixed strings, building up one big regex. - while !patternStr.isEmpty { - // RegEx matches. - if patternStr.range(of: "{{")?.lowerBound == patternStr.startIndex { - // This is the start of a regex match. Scan for the }}. - guard let End = patternStr.range(of: "}}") else { - let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) - diagnose(.error, loc, "found start of regex string with no end '}}'") - return true - } - - // Enclose {{}} patterns in parens just like [[]] even though we're not - // capturing the result for any purpose. This is required in case the - // expression contains an alternation like: CHECK: abc{{x|z}}def. We - // want this to turn into: "abc(x|z)def" not "abcx|zdef". - regExPattern += "(" - curParen += 1 - - let substr = patternStr.substring( - with: Range( - uncheckedBounds: ( - patternStr.index(patternStr.startIndex, offsetBy: 2), - End.lowerBound - ) - ) - ) - let (res, paren) = self.addRegExToRegEx(substr, curParen) - curParen = paren - if res { - return true - } - regExPattern += ")" - - patternStr = patternStr.substring(from: patternStr.index(End.lowerBound, offsetBy: 2)) - continue - } - - // Named RegEx matches. These are of two forms: [[foo:.*]] which matches .* - // (or some other regex) and assigns it to the FileCheck variable 'foo'. The - // second form is [[foo]] which is a reference to foo. The variable name - // itself must be of the form "[a-zA-Z_][0-9a-zA-Z_]*", otherwise we reject - // it. This is to catch some common errors. - if patternStr.hasPrefix("[[") { - // Find the closing bracket pair ending the match. End is going to be an - // offset relative to the beginning of the match string. - let regVar = patternStr.substring(from: patternStr.index(patternStr.startIndex, offsetBy: 2)) - guard let end = self.findRegexVarEnd(regVar) else { - let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) - diagnose(.error, loc, "invalid named regex reference, no ]] found") - return true - } - - let matchStr = regVar.substring(to: end) - patternStr = patternStr.substring(from: patternStr.index(end, offsetBy: 4)) - - // Get the regex name (e.g. "foo"). - let nameEnd = matchStr.range(of: ":") - let name : String - if let end = nameEnd?.lowerBound { - name = matchStr.substring(to: end) - } else { - name = matchStr - } - - if name.isEmpty { - let loc = CheckLoc.inBuffer(pattern.baseAddress!, buf) - diagnose(.error, loc, "invalid name in named regex: empty name") - return true - } - - // Verify that the name/expression is well formed. FileCheck currently - // supports @LINE, @LINE+number, @LINE-number expressions. The check here - // is relaxed, more strict check is performed in \c EvaluateExpression. - var isExpression = false - let diagLoc = CheckLoc.inBuffer(pattern.baseAddress!, buf) - for (i, c) in name.characters.enumerated() { - if i == 0 && c == "@" { - if nameEnd == nil { - diagnose(.error, diagLoc, "invalid name in named regex definition") - return true - } - isExpression = true - continue - } - if c != "_" && isalnum(Int32(c.utf8CodePoint)) == 0 && (!isExpression || (c != "+" && c != "-")) { - diagnose(.error, diagLoc, "invalid name in named regex") - return true - } - } - - // Name can't start with a digit. - if isdigit(Int32(name.utf8.first!)) != 0 { - diagnose(.error, diagLoc, "invalid name in named regex") - return true - } - - // Handle [[foo]]. - guard let ne = nameEnd else { - // Handle variables that were defined earlier on the same line by - // emitting a backreference. - if let varParenNum = self.variableDefs[name] { - if varParenNum < 1 || varParenNum > 9 { - diagnose(.error, diagLoc, "Can't back-reference more than 9 variables") - return true - } - self.addBackrefToRegEx(varParenNum) - } else { - variableUses.append((name, regExPattern.characters.count)) - } - continue - } - - // Handle [[foo:.*]]. - self.variableDefs[name] = curParen - regExPattern += "(" - curParen += 1 - - let (res, paren) = self.addRegExToRegEx(matchStr.substring(from: matchStr.index(after: ne.lowerBound)), curParen) - curParen = paren - if res { - return true - } - - regExPattern += ")" - } - - // Handle fixed string matches. - // Find the end, which is the start of the next regex. - if let fixedMatchEnd = mino(patternStr.range(of: "{{")?.lowerBound, patternStr.range(of: "[[")?.lowerBound) { - self.regExPattern += NSRegularExpression.escapedPattern(for: patternStr.substring(to: fixedMatchEnd)) - patternStr = patternStr.substring(from: fixedMatchEnd) - } else { - // No more matches, time to quit. - break - } - } - - if options.contains(.matchFullLines) { - if !options.contains(.strictWhitespace) { - regExPattern += " *" - regExPattern += "$" - } - } - return false - } -} - -/// Count the number of newlines in the specified range. -func countNumNewlinesBetween(_ r : String) -> (Int, String.Index?) { - var range = r - var NumNewLines = 0 - var firstNewLine : String.Index? = nil - while true { - // Scan for newline. - guard let EOL = range.range(of: "\n")?.lowerBound ?? range.range(of: "\r")?.lowerBound else { - return (NumNewLines, firstNewLine) - } - range = range.substring(from: EOL) - if range.isEmpty { - return (NumNewLines, firstNewLine) - } - - NumNewLines += 1 - - // Handle \n\r and \r\n as a single newline. - // if Range.utf8.count > 1 && (Range.utf8[1] == '\n' || Range[1] == '\r') && (Range[0] != Range[1]) { - // Range = Range.substr(1) - // } - range = range.substring(from: range.index(after: range.startIndex)) - - if NumNewLines == 1 { - firstNewLine = range.startIndex - } - } -} - -/// CheckString - This is a check that we found in the input file. -private struct CheckString { - /// Pat - The pattern to match. - let pattern : Pattern - - /// Prefix - Which prefix name this check matched. - let prefix : String - - /// Loc - The location in the match file that the check string was specified. - let loc : CheckLoc - - /// DagNotStrings - These are all of the strings that are disallowed from - /// occurring between this match string and the previous one (or start of - /// file). - let dagNotStrings : Array = [] - - /// Match check string and its "not strings" and/or "dag strings". - func check(_ buffer : String, _ isLabelScanMode : Bool, _ variableTable : BoxedTable) -> (Int, Int)? { - var lastPos = 0 - - // IsLabelScanMode is true when we are scanning forward to find CHECK-LABEL - // bounds we have not processed variable definitions within the bounded block - // yet so cannot handle any final CHECK-DAG yetthis is handled when going - // over the block again (including the last CHECK-LABEL) in normal mode. - if !isLabelScanMode { - // Match "dag strings" (with mixed "not strings" if any). - guard let lp = self.checkDAG(buffer, variableTable) else { - return nil - } - lastPos = lp - } - - // Match itself from the last position after matching CHECK-DAG. - let matchBuffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: lastPos)) - guard let (matchPos, matchLen) = self.pattern.match(matchBuffer, variableTable) else { - diagnose(.error, self.loc, self.prefix + ": could not find '\(self.pattern.fixedString)' in input") - return nil - } - - // Similar to the above, in "label-scan mode" we can't yet handle CHECK-NEXT - // or CHECK-NOT - if !isLabelScanMode { - let skippedRegion = buffer.substring( - with: Range( - uncheckedBounds: ( - buffer.index(buffer.startIndex, offsetBy: lastPos), - buffer.index(buffer.startIndex, offsetBy: matchPos) - ) - ) - ) - let rest = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: matchPos)) - - // If this check is a "CHECK-NEXT", verify that the previous match was on - // the previous line (i.e. that there is one newline between them). - if self.checkNext(skippedRegion, rest) { - return nil - } - - // If this check is a "CHECK-SAME", verify that the previous match was on - // the same line (i.e. that there is no newline between them). - if self.checkSame(skippedRegion, rest) { - return nil - } - - // If this match had "not strings", verify that they don't exist in the - // skipped region. - if self.checkNot(skippedRegion, [], variableTable) { - return nil - } - } - - return (lastPos + matchPos, matchLen) - } - - /// Verify there is no newline in the given buffer. - private func checkSame(_ buffer : String, _ rest : String) -> Bool { - if self.pattern.type != .same { - return false - } - - // Count the number of newlines between the previous match and this one. - // assert(Buffer.data() != - // SM.getMemoryBuffer(SM.FindBufferContainingLoc( - // SMLoc::getFromPointer(Buffer.data()))) - // ->getBufferStart() && - // "CHECK-SAME can't be the first check in a file") - let (numNewLines, _ /*firstNewLine*/) = countNumNewlinesBetween(buffer) - if numNewLines != 0 { - diagnose(.error, self.loc, self.prefix + "-SAME: is not on the same line as the previous match") - rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "'next' match was here") - } - buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "previous match ended here") - } - return true - } - - return false - } - - /// Verify there is a single line in the given buffer. - private func checkNext(_ buffer : String, _ rest : String) -> Bool { - if self.pattern.type != .next { - return false - } - - // Count the number of newlines between the previous match and this one. - // assert(Buffer.data() != - // SM.getMemoryBuffer(SM.FindBufferContainingLoc( - // SMLoc::getFromPointer(Buffer.data()))) - // ->getBufferStart(), "CHECK-NEXT can't be the first check in a file") - let (numNewLines, firstNewLine) = countNumNewlinesBetween(buffer) - if numNewLines == 0 { - diagnose(.error, self.loc, prefix + "-NEXT: is on the same line as previous match") - rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "'next' match was here") - } - buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "previous match ended here") - } - return true - } - - if numNewLines != 1 { - diagnose(.error, self.loc, prefix + "-NEXT: is not on the line after the previous match") - rest.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "'next' match was here") - } - buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!, buf) - diagnose(.note, loc, "previous match ended here") - if let fnl = firstNewLine { - let noteLoc = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: buffer.distance(from: buffer.startIndex, to: fnl)), buf) - diagnose(.note, noteLoc, "non-matching line after previous match is here") - } - } - return true - } - - return false - } - - /// Verify there's no "not strings" in the given buffer. - private func checkNot(_ buffer : String, _ notStrings : [Pattern], _ variableTable : BoxedTable) -> Bool { - for pat in notStrings { - assert(pat.type == .not, "Expect CHECK-NOT!") - - guard let (Pos, _)/*(Pos, MatchLen)*/ = pat.match(buffer, variableTable) else { - continue - } - buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: Pos), buf) - diagnose(.error, loc, self.prefix + "-NOT: string occurred!") - } - diagnose(.note, pat.patternLoc, self.prefix + "-NOT: pattern specified here") - return true - } - - return false - } - - /// Match "dag strings" and their mixed "not strings". - func checkDAG(_ buffer : String, _ variableTable : BoxedTable) -> Int? { - var notStrings = [Pattern]() - if dagNotStrings.isEmpty { - return 0 - } - - var lastPos = 0 - var startPos = lastPos - - for pattern in self.dagNotStrings { - assert((pattern.type == .dag || pattern.type == .not), "Invalid CHECK-DAG or CHECK-NOT!") - - if pattern.type == .not { - notStrings.append(pattern) - continue - } - - assert((pattern.type == .dag), "Expect CHECK-DAG!") - - // CHECK-DAG always matches from the start. - let matchBuffer = buffer.substring(from: buffer.index(buffer.startIndex, offsetBy: startPos)) - // With a group of CHECK-DAGs, a single mismatching means the match on - // that group of CHECK-DAGs fails immediately. - guard let t = pattern.match(matchBuffer, variableTable) else { - // PrintCheckFailed(SM, Pat.getLoc(), Pat, MatchBuffer, VariableTable) - return nil - } - var matchPos = t.0 - let matchLen = t.1 - - // Re-calc it as the offset relative to the start of the original string. - matchPos += startPos - - if !notStrings.isEmpty { - if matchPos < lastPos { - // Reordered? - buffer.cString(using: .utf8)?.withUnsafeBufferPointer { buf in - let loc1 = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: matchPos), buf) - diagnose(.error, loc1, prefix + "-DAG: found a match of CHECK-DAG reordering across a CHECK-NOT") - let loc2 = CheckLoc.inBuffer(buf.baseAddress!.advanced(by: lastPos), buf) - diagnose(.note, loc2, prefix + "-DAG: the farthest match of CHECK-DAG is found here") - } - diagnose(.note, notStrings[0].patternLoc, prefix + "-NOT: the crossed pattern specified here") - diagnose(.note, pattern.patternLoc, prefix + "-DAG: the reordered pattern specified here") - return nil - } - // All subsequent CHECK-DAGs should be matched from the farthest - // position of all precedent CHECK-DAGs (including this one.) - startPos = lastPos - // If there's CHECK-NOTs between two CHECK-DAGs or from CHECK to - // CHECK-DAG, verify that there's no 'not' strings occurred in that - // region. - let skippedRegion = buffer.substring( - with: Range( - uncheckedBounds: ( - buffer.index(buffer.startIndex, offsetBy: lastPos), - buffer.index(buffer.startIndex, offsetBy: matchPos) - ) - ) - ) - if self.checkNot(skippedRegion, notStrings, variableTable) { - return nil - } - // Clear "not strings". - notStrings.removeAll() - } - - // Update the last position with CHECK-DAG matches. - lastPos = max(matchPos + matchLen, lastPos) - } - - return lastPos - } -} - -private enum DiagnosticKind { - case error - case warning - case note -} - -private func diagnose(_ kind : DiagnosticKind, _ loc : CheckLoc, _ message : String) { - print(message) - let msg = loc.message - if !msg.isEmpty { - print(msg) - } -} diff --git a/Tests/SwiftCheckTests/FormatterSpec.swift b/Tests/SwiftCheckTests/FormatterSpec.swift index 97004c9..8729f98 100644 --- a/Tests/SwiftCheckTests/FormatterSpec.swift +++ b/Tests/SwiftCheckTests/FormatterSpec.swift @@ -10,6 +10,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif struct Formatter { let lengthLimit : UInt diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index 1243f21..2363ade 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif import Foundation class GenSpec : XCTestCase { diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index accfb78..7e6b129 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { let unName : String diff --git a/Tests/SwiftCheckTests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift index c99b909..4ccd82d 100644 --- a/Tests/SwiftCheckTests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif class ModifierSpec : XCTestCase { func testModifiers() { diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index 95f45ad..e81cb5a 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif struct Path : Arbitrary { let unPath : [A] diff --git a/Tests/SwiftCheckTests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift index 96d1736..16a0cb1 100644 --- a/Tests/SwiftCheckTests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -8,6 +8,9 @@ @testable import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif func ==(l : Property, r : Property) -> Bool { let res1 = quickCheckWithResult(CheckerArguments(name: "", silence: true), l) diff --git a/Tests/SwiftCheckTests/ReplaySpec.swift b/Tests/SwiftCheckTests/ReplaySpec.swift index 841f14b..6b03e75 100644 --- a/Tests/SwiftCheckTests/ReplaySpec.swift +++ b/Tests/SwiftCheckTests/ReplaySpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif class ReplaySpec : XCTestCase { func testAll() { diff --git a/Tests/SwiftCheckTests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift index 0356576..e6e74dd 100644 --- a/Tests/SwiftCheckTests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif class RoseSpec : XCTestCase { private static func intRoseTree(_ v : Int) -> Rose { diff --git a/Tests/SwiftCheckTests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift index 4cbaf0a..a43fc3a 100644 --- a/Tests/SwiftCheckTests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif #if os(Linux) import Glibc diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index 2a1e1a9..a0ebbc1 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif private func pack(_ f : @escaping (A, B) -> C) -> ((A, B)) -> C { return f diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index a7d6b51..2d072a7 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -8,6 +8,9 @@ import SwiftCheck import XCTest +#if !XCODE_BUILD +import FileCheck +#endif class TestSpec : XCTestCase { func testAll() { From 29ddf4877e6135ed2de62eb4c0b1b84b183d3740 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 22 Sep 2017 01:34:08 -0400 Subject: [PATCH 408/460] Resolve FIXME (#245) --- Sources/SwiftCheck/WitnessedArbitrary.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index 8c5e6f6..5dea544 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -43,8 +43,6 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } } -//FIXME: This works as of Xcode 9 beta 3 but is disabled until Travis has Xcode 9 > beta 3 -#if os(Linux) extension AnyBidirectionalCollection : WitnessedArbitrary { public typealias Param = Element @@ -60,7 +58,6 @@ extension AnyBidirectionalCollection : WitnessedArbitrary { ) } } -#endif extension AnySequence where Element : Arbitrary { /// Returns a generator of `AnySequence`s of arbitrary `Element`s. From 970da24ffc506f7500ad403faeb1159900a4f106 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 28 Sep 2017 18:25:11 -0400 Subject: [PATCH 409/460] Switch to built-in SWIFT_PACKAGE flag --- SwiftCheck.xcodeproj/project.pbxproj | 12 ++++++------ Templates/CartesianSpec.swift.gyb | 2 +- Tests/SwiftCheckTests/BooleanIdentitySpec.swift | 2 +- Tests/SwiftCheckTests/CartesianSpec.swift | 2 +- Tests/SwiftCheckTests/ComplexSpec.swift | 2 +- Tests/SwiftCheckTests/DiscardSpec.swift | 2 +- Tests/SwiftCheckTests/FailureSpec.swift | 2 +- Tests/SwiftCheckTests/FormatterSpec.swift | 2 +- Tests/SwiftCheckTests/GenSpec.swift | 2 +- Tests/SwiftCheckTests/LambdaSpec.swift | 2 +- Tests/SwiftCheckTests/ModifierSpec.swift | 2 +- Tests/SwiftCheckTests/PathSpec.swift | 2 +- Tests/SwiftCheckTests/PropertySpec.swift | 2 +- Tests/SwiftCheckTests/ReplaySpec.swift | 2 +- Tests/SwiftCheckTests/RoseSpec.swift | 2 +- Tests/SwiftCheckTests/ShrinkSpec.swift | 2 +- Tests/SwiftCheckTests/SimpleSpec.swift | 2 +- Tests/SwiftCheckTests/TestSpec.swift | 2 +- 18 files changed, 23 insertions(+), 23 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index ca6890b..d575527 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -905,7 +905,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; @@ -925,7 +925,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; @@ -1119,7 +1119,7 @@ ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1141,7 +1141,7 @@ GCC_OPTIMIZATION_LEVEL = s; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -1240,7 +1240,7 @@ INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; @@ -1263,7 +1263,7 @@ INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - OTHER_SWIFT_FLAGS = "-D XCODE_BUILD"; + OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; diff --git a/Templates/CartesianSpec.swift.gyb b/Templates/CartesianSpec.swift.gyb index d42637f..3ac614b 100644 --- a/Templates/CartesianSpec.swift.gyb +++ b/Templates/CartesianSpec.swift.gyb @@ -16,7 +16,7 @@ MAX_ARITY = 22 import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif import Foundation diff --git a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift index 4a19c87..8ece98d 100644 --- a/Tests/SwiftCheckTests/BooleanIdentitySpec.swift +++ b/Tests/SwiftCheckTests/BooleanIdentitySpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/CartesianSpec.swift b/Tests/SwiftCheckTests/CartesianSpec.swift index fbd9fe5..3fea720 100644 --- a/Tests/SwiftCheckTests/CartesianSpec.swift +++ b/Tests/SwiftCheckTests/CartesianSpec.swift @@ -13,7 +13,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif import Foundation diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 52943ea..225f66b 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/DiscardSpec.swift b/Tests/SwiftCheckTests/DiscardSpec.swift index 3f2fe71..441e616 100644 --- a/Tests/SwiftCheckTests/DiscardSpec.swift +++ b/Tests/SwiftCheckTests/DiscardSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/FailureSpec.swift b/Tests/SwiftCheckTests/FailureSpec.swift index 9e2d1d3..ea15409 100644 --- a/Tests/SwiftCheckTests/FailureSpec.swift +++ b/Tests/SwiftCheckTests/FailureSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/FormatterSpec.swift b/Tests/SwiftCheckTests/FormatterSpec.swift index 8729f98..10a85a5 100644 --- a/Tests/SwiftCheckTests/FormatterSpec.swift +++ b/Tests/SwiftCheckTests/FormatterSpec.swift @@ -10,7 +10,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index 2363ade..dcdcd04 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif import Foundation diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index 7e6b129..366cd39 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift index 4ccd82d..3363791 100644 --- a/Tests/SwiftCheckTests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/PathSpec.swift b/Tests/SwiftCheckTests/PathSpec.swift index e81cb5a..786f780 100644 --- a/Tests/SwiftCheckTests/PathSpec.swift +++ b/Tests/SwiftCheckTests/PathSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift index 16a0cb1..909941f 100644 --- a/Tests/SwiftCheckTests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -8,7 +8,7 @@ @testable import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/ReplaySpec.swift b/Tests/SwiftCheckTests/ReplaySpec.swift index 6b03e75..198b642 100644 --- a/Tests/SwiftCheckTests/ReplaySpec.swift +++ b/Tests/SwiftCheckTests/ReplaySpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/RoseSpec.swift b/Tests/SwiftCheckTests/RoseSpec.swift index e6e74dd..03d16ea 100644 --- a/Tests/SwiftCheckTests/RoseSpec.swift +++ b/Tests/SwiftCheckTests/RoseSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift index a43fc3a..eb26b7d 100644 --- a/Tests/SwiftCheckTests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index a0ebbc1..c755d76 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index 2d072a7..4345db7 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -8,7 +8,7 @@ import SwiftCheck import XCTest -#if !XCODE_BUILD +#if SWIFT_PACKAGE import FileCheck #endif From 31fbb27127a9bb4a8d370bf1a6a7ca8c48976f91 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 9 Oct 2017 18:54:31 -0400 Subject: [PATCH 410/460] Cleanup documentation and indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some code blocks were not being rendered as much because they were not aligned properly. Additionally, clean up some places and use Swiftdoc markup to properly annotate notes, requirements, invariants, and comments. Unfortunately, it looks like some attributes (e.g. seealso https://developer.apple.com/library/content/documentation/Xcode/Referenc e/xcode_markup_formatting_ref/SeeAlso.html#//apple_ref/doc/uid/TP4001649 7-CH45-SW1) don’t work. --- Sources/SwiftCheck/Check.swift | 57 ++++++++++++++++++++---------- Sources/SwiftCheck/Compose.swift | 14 ++++---- Sources/SwiftCheck/Gen.swift | 19 +++++----- Sources/SwiftCheck/Random.swift | 17 +++++---- Sources/SwiftCheck/Rose.swift | 4 +-- Sources/SwiftCheck/Testable.swift | 1 - Sources/SwiftCheck/Witness.swift | 48 ++++++++++++------------- Tutorial.playground/Contents.swift | 2 +- 8 files changed, 92 insertions(+), 70 deletions(-) diff --git a/Sources/SwiftCheck/Check.swift b/Sources/SwiftCheck/Check.swift index ffdb948..3cc80e4 100644 --- a/Sources/SwiftCheck/Check.swift +++ b/Sources/SwiftCheck/Check.swift @@ -32,9 +32,18 @@ /// return i == i /// } /// -/// If no arguments are provided, or nil is given, SwiftCheck will select an internal default. -public func property(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { - return AssertiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) +/// If no arguments are provided, or nil is given, SwiftCheck will select an +/// internal default. +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +public func property(_ message : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> AssertiveQuickCheck { + return AssertiveQuickCheck(msg: message, file: file, line: line, args: arguments ?? CheckerArguments(name: message)) } /// Describes a checker that uses XCTest to assert all testing failures and @@ -55,8 +64,16 @@ public struct AssertiveQuickCheck { /// The interface for properties to be run through SwiftCheck without an XCTest /// assert. The property will still generate console output during testing. -public func reportProperty(_ msg : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { - return ReportiveQuickCheck(msg: msg, file: file, line: line, args: arguments ?? CheckerArguments(name: msg)) +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +public func reportProperty(_ message : String, arguments : CheckerArguments? = nil, file : StaticString = #file, line : UInt = #line) -> ReportiveQuickCheck { + return ReportiveQuickCheck(msg: message, file: file, line: line, args: arguments ?? CheckerArguments(name: message)) } /// Describes a checker that only reports failures to the testing log but does @@ -78,27 +95,29 @@ public struct ReportiveQuickCheck { /// Represents the arguments the test driver will use while performing testing, /// shrinking, and printing results. public struct CheckerArguments { - /// Provides a way of re-doing a test at the given size with a new generator. + /// Provides a way of re-doing a test at the given size with a new + /// generator. let replay : Optional<(StdGen, Int)> - /// The maximum number of test cases that must pass before the property itself - /// passes. + /// The maximum number of test cases that must pass before the property + /// itself passes. /// - /// The default value of this property is 100. In general, some tests may require more than - /// this amount, but less is rare. If you need a value of 1 use `.once` - /// on the property instead. + /// The default value of this property is 100. In general, some tests may + /// require more than this amount, but less is rare. If you need a value of + /// 1 use `.once` on the property instead. let maxAllowableSuccessfulTests : Int - /// The maximum number of tests cases that can be discarded before testing gives up on the - /// property. + /// The maximum number of tests cases that can be discarded before testing + /// gives up on the property. /// - /// The default value of this property is 500. In general, most tests will require less than - /// this amount. `Discard`ed test cases do not affect the passing or failing status of the - /// property as a whole. + /// The default value of this property is 500. In general, most tests will + /// require less than this amount. `Discard`ed test cases do not affect + /// the passing or failing status of the property as a whole. let maxAllowableDiscardedTests : Int /// The limit to the size of all generators in the test. /// - /// The default value of this property is 100. If "large" values, in magnitude or - /// size, are necessary then increase this value, else keep it relatively near the default. If - /// it becomes too small the samples present in the test case will lose diversity. + /// The default value of this property is 100. If "large" values, in + /// magnitude or size, are necessary then increase this value, else keep it + /// relatively near the default. If it becomes too small the samples + /// present in the test case will lose diversity. let maxTestCaseSize : Int internal let silence : Bool diff --git a/Sources/SwiftCheck/Compose.swift b/Sources/SwiftCheck/Compose.swift index 1b348e1..430a334 100644 --- a/Sources/SwiftCheck/Compose.swift +++ b/Sources/SwiftCheck/Compose.swift @@ -22,9 +22,9 @@ extension Gen { /// a: c.generate(), /// /// // or pass a custom generator - /// b: c.generate(Bool.suchThat { $0 == false }), + /// b: c.generate(Bool.arbitrary.suchThat { $0 == false }), /// - /// // .. and so on, for as many values & types as you need + /// // ... and so on, for as many values & types as you need /// c: c.generate(), ... /// ) /// } @@ -45,8 +45,8 @@ extension Gen { /// `GenComposer` presents an imperative interface over top of `Gen`. /// -/// Instances of this class may not be constructed manually. -/// Use `Gen.compose` instead. +/// - Important: Instances of this class may not be constructed manually. +/// Use `Gen.compose` instead. /// /// - seealso: Gen.compose public final class GenComposer { @@ -59,7 +59,7 @@ public final class GenComposer { } - /// Generate a new `T` with a specific generator. + /// Generate a new value of type `T` with a specific generator. /// /// - parameter gen: The generator used to create a random value. /// @@ -72,9 +72,9 @@ public final class GenComposer { /// Generate a new value of type `T` with the default `Gen`erator /// for that type. /// - /// - returns: An arbitrary value of type `T`. + /// - returns: An arbitrary value of type `T`. /// - /// - seealso: generate\(gen:) + /// - seealso: generate(using:) public func generate() -> T where T: Arbitrary { diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 044a707..37818dc 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -43,7 +43,7 @@ public struct Gen { /// Constructs a Generator that selects a random value from the given /// collection and produces only that value. /// - /// The input collection is required to be non-empty. + /// - Requires: The input collection is required to be non-empty. public static func fromElements(of xs : S) -> Gen where S.Index : RandomType { @@ -55,7 +55,7 @@ public struct Gen { /// Constructs a Generator that selects a random value from the given /// collection and produces only that value. /// - /// The input collection is required to be non-empty. + /// - Requires: The input collection is required to be non-empty. public static func fromElements(of xs : Set) -> Gen { precondition(!xs.isEmpty) return Gen.fromElements(in: 0...xs.distance(from: xs.startIndex, to: xs.endIndex)-1).map { i in @@ -66,7 +66,7 @@ public struct Gen { /// Constructs a Generator that selects a random value from the given /// interval and produces only that value. /// - /// The input interval is required to be non-empty. + /// - Requires: The input interval is required to be non-empty. public static func fromElements(in xs : ClosedRange) -> Gen { assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") @@ -294,9 +294,9 @@ extension Gen /*: Functor*/ { /// /// This function is most useful for converting between generators of inter- /// related types. For example, you might have a Generator of `Character` - /// values that you then `.proliferate` into an `Array` of `Character`s. You - /// can then use `map` to convert that generator of `Array`s to a generator - /// of `String`s. + /// values that you then `.proliferate` into an `Array` of `Character`s. + /// You can then use `map` to convert that generator of `Array`s to a + /// generator of `String`s. public func map(_ f : @escaping (A) -> B) -> Gen { return Gen(unGen: { r, n in return f(self.unGen(r, n)) @@ -342,9 +342,10 @@ extension Gen /*: Monad*/ { /// Creates and returns a Generator of arrays of values drawn from each /// generator in the given array. /// -/// The array that is created is guaranteed to use each of the given Generators -/// in the order they were given to the function exactly once. Thus all arrays -/// generated are of the same rank as the array that was given. +/// - Invariant: The array that is created is guaranteed to use each of the +/// given Generators in the order they were given to the function exactly +/// once. Thus all arrays generated are of the same rank as the array that +/// was given. public func sequence(_ ms : [Gen]) -> Gen<[A]> { return Gen<[A]>(unGen: { r, n in var r1 = r diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index 9bf9e9a..564c515 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -52,7 +52,8 @@ public struct StdGen : RandomGeneneratorType { /// Returns an `Int` generated uniformly within the bounds of the generator /// and a new distinct random number generator. public var next : (Int, StdGen) { - // P. L'Ecuyer, ``Efficient and Portable Combined Random Number Generators'', Communications of the ACM, 31 (1988), 742--749 and 774. + // P. L'Ecuyer, "Efficient and Portable Combined Random Number + ///Generators". Communications of the ACM, 31 (1988), 742-749 and 774. // https://www.iro.umontreal.ca/~lecuyer/myftp/papers/cacm88.pdf let s1 = self.seed1 @@ -109,13 +110,15 @@ public func newStdGen() -> StdGen { /// Types that can generate random versions of themselves. public protocol RandomType { - /// Takes a range `(lo, hi)` and a random number generator `G`, and returns - /// a random value uniformly distributed in the closed interval `[lo,hi]`, - /// together with a new generator. It is unspecified what happens if lo>hi. + /// Takes a range as a tuple of values `(lo, hi)` and a random number + /// generator `G`, and returns a random value uniformly distributed in the + /// closed interval `[lo,hi]`, together with a new generator. /// - /// For continuous types there is no requirement that the values `lo` and - /// `hi` are ever produced, but they may be, depending on the implementation - /// and the interval. + /// - Note: It is unspecified what happens if `lo > hi`. + /// + /// - Remark: For continuous types there is no requirement that the values + /// `lo` and `hi` are ever produced, but they may be, depending on the + /// implementation and the interval. static func randomInRange(_ range : (Self, Self), gen : G) -> (Self, G) } diff --git a/Sources/SwiftCheck/Rose.swift b/Sources/SwiftCheck/Rose.swift index 511b751..b88802f 100644 --- a/Sources/SwiftCheck/Rose.swift +++ b/Sources/SwiftCheck/Rose.swift @@ -12,8 +12,8 @@ /// IO action SwiftCheck must execute in order to produce another rose tree. /// All values in a `Rose` are lazy. /// -/// In practice SwiftCheck will minimize the side-effects performed in a given -/// `IORose` to printing values to the console and executing callbacks. +/// - Note: In practice SwiftCheck will minimize the side-effects performed in +/// a given `IORose` to printing values to the console and executing callbacks. public enum Rose { /// A normal branch in the rose tree. case mkRose(() -> A, () -> [Rose]) diff --git a/Sources/SwiftCheck/Testable.swift b/Sources/SwiftCheck/Testable.swift index fc199f2..c3bd744 100644 --- a/Sources/SwiftCheck/Testable.swift +++ b/Sources/SwiftCheck/Testable.swift @@ -6,7 +6,6 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - /// The type of things that can be tested. Consequently, the type of things /// that can be returned from a `forAll` block. /// diff --git a/Sources/SwiftCheck/Witness.swift b/Sources/SwiftCheck/Witness.swift index 29c750d..edb1af3 100644 --- a/Sources/SwiftCheck/Witness.swift +++ b/Sources/SwiftCheck/Witness.swift @@ -23,24 +23,24 @@ /// example, to implement the protocol for `Array`, we declare the usual /// `arbitrary` and `shrink`: /// -/// extension Array where Element : Arbitrary { -/// public static var arbitrary : Gen> { -/// return Gen.sized { n in -/// return Gen.choose((0, n)).flatMap { k in -/// if k == 0 { -/// return Gen.pure([]) -/// } -/// -/// return sequence((0...k).map { _ in Element.arbitrary }) -/// } -/// } -/// } -/// -/// public static func shrink(bl : Array) -> [[Element]] { -/// let rec : [[Element]] = shrinkOne(bl) -/// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec -/// } -/// } +/// extension Array where Element : Arbitrary { +/// public static var arbitrary : Gen> { +/// return Gen.sized { n in +/// return Gen.choose((0, n)).flatMap { k in +/// if k == 0 { +/// return Gen.pure([]) +/// } +/// +/// return sequence((0...k).map { _ in Element.arbitrary }) +/// } +/// } +/// } +/// +/// public static func shrink(bl : Array) -> [[Element]] { +/// let rec : [[Element]] = shrinkOne(bl) +/// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec +/// } +/// } /// /// In addition, we declare a witnessed version of `forAll` that simply invokes /// `forAllShrink` and `map`s the witness function to make sure all generated @@ -49,12 +49,12 @@ /// extension Array : WitnessedArbitrary { /// public typealias Param = Element /// -/// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { -/// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in -/// return pf(bl.map(wit)) -/// }) -/// } -/// } +/// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { +/// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in +/// return pf(bl.map(wit)) +/// }) +/// } +/// } public protocol WitnessedArbitrary { /// The witnessing type parameter. associatedtype Param diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index e84c172..d62b475 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -285,7 +285,7 @@ emailGen.generate //: There's our old friend, `Gen`! So, an `Arbitrary` type is a type that can give us a generator //: to create `Arbitrary` values. SwiftCheck defines `Arbitrary` instances for the majority of //: types in the Swift Standard Library in the ways you might expect e.g. The `Arbitrary` instance -//: for `Int` calls `arc4random_uniform`. +//: for `Int` essentially calls `arc4random_uniform`. //: //: SwiftCheck uses a strategy called a `Modifier Type`–a wrapper around one type that we can't //: generate with another that we can–for a few of the more "difficult" types in the Swift Standard From 360413c25b30b178965ac57f8a4039fe3fd48f47 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 9 Oct 2017 18:55:01 -0400 Subject: [PATCH 411/460] [NFC] Move generate and sample to an extension These things are already too easy to reach for. Make them a little harder to find. --- Sources/SwiftCheck/Gen.swift | 45 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 37818dc..25cb270 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -21,25 +21,6 @@ public struct Gen { /// v v let unGen : (StdGen, Int) -> A - /// Generates a value. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var generate : A { - let r = newStdGen() - return unGen(r, 30) - } - - /// Generates some example values. - /// - /// This property exists as a convenience mostly to test generators. In - /// practice, you should never use this property because it hinders the - /// replay functionality and the robustness of tests in general. - public var sample : [A] { - return sequence((2...20).map(self.resize)).generate - } - /// Constructs a Generator that selects a random value from the given /// collection and produces only that value. /// @@ -286,6 +267,32 @@ extension Gen { } } +// MARK: Generating Example Values + +extension Gen { + /// Generates a value. + /// + /// - Attention: This property exists as a convenience mostly to test + /// generators. In practice, you should never use this property because + /// it hinders the replay functionality and the robustness of tests in + /// general. + public var generate : A { + let r = newStdGen() + return unGen(r, 30) + } + + /// Generates some example values. + /// + /// - Attention: This property exists as a convenience mostly to test + /// generators. In practice, you should never use this property because + /// it hinders the replay functionality and the robustness of tests in + /// general. + public var sample : [A] { + return sequence((2...20).map(self.resize)).generate + } + +} + // MARK: Instances extension Gen /*: Functor*/ { From 65733fbd5da400f93a3a75bbfd9a397dab95f5bf Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 9 Oct 2017 18:55:23 -0400 Subject: [PATCH 412/460] Use inline Equatable conformance --- Sources/SwiftCheck/Random.swift | 14 ++++++------- Tests/SwiftCheckTests/LambdaSpec.swift | 28 +++++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index 564c515..3a52025 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -87,18 +87,18 @@ public struct StdGen : RandomGeneneratorType { } extension StdGen : Equatable, CustomStringConvertible { + /// Equality over random number generators. + /// + /// Two `StdGen`s are equal iff their seeds match. + public static func == (l : StdGen, r : StdGen) -> Bool { + return l.seed1 == r.seed1 && l.seed2 == r.seed2 + } + public var description : String { return "\(self.seed1) \(self.seed2)" } } -/// Equality over random number generators. -/// -/// Two `StdGen`s are equal iff their seeds match. -public func == (l : StdGen, r : StdGen) -> Bool { - return l.seed1 == r.seed1 && l.seed2 == r.seed2 -} - private var theStdGen : StdGen = mkStdRNG(0) /// A library-provided standard random number generator. diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index 366cd39..618ca55 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -27,10 +27,10 @@ struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { var hashValue : Int { return self.unName.hashValue } -} -func == (l : Name, r : Name) -> Bool { - return l.unName == r.unName + static func == (l : Name, r : Name) -> Bool { + return l.unName == r.unName + } } private func liftM2(_ f : @escaping (A, B) -> C, _ m1 : Gen, _ m2 : Gen) -> Gen { @@ -45,18 +45,18 @@ indirect enum Exp : Equatable { case lam(Name, Exp) case app(Exp, Exp) case `var`(Name) -} -func == (l : Exp, r : Exp) -> Bool { - switch (l, r) { - case let (.lam(ln, le), .lam(rn, re)): - return ln == rn && le == re - case let (.app(ln, le), .app(rn, re)): - return ln == rn && le == re - case let (.var(n1), .var(n2)): - return n1 == n2 - default: - return false + static func == (l : Exp, r : Exp) -> Bool { + switch (l, r) { + case let (.lam(ln, le), .lam(rn, re)): + return ln == rn && le == re + case let (.app(ln, le), .app(rn, re)): + return ln == rn && le == re + case let (.var(n1), .var(n2)): + return n1 == n2 + default: + return false + } } } From 2522f5a7a0531c9cf9c39b9488818590e6fb0fdf Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 9 Oct 2017 18:55:34 -0400 Subject: [PATCH 413/460] Inline 'id' --- Sources/SwiftCheck/Gen.swift | 2 +- Sources/SwiftCheck/Property.swift | 27 +++++++++++++-------------- Sources/SwiftCheck/Witness.swift | 6 +++--- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 25cb270..e4337cc 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -58,7 +58,7 @@ public struct Gen { /// composed of its initial segments. The size of each initial segment /// increases with the generator's size parameter. /// - /// The input array is required to be non-empty. + /// - Requires: The input array is required to be non-empty. public static func fromInitialSegments(of xs : [S]) -> Gen<[S]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") diff --git a/Sources/SwiftCheck/Property.swift b/Sources/SwiftCheck/Property.swift index 7dc6237..ed69078 100644 --- a/Sources/SwiftCheck/Property.swift +++ b/Sources/SwiftCheck/Property.swift @@ -15,7 +15,7 @@ /// masked. If fine-grained error reporting is needed, use a combination of /// `disjoin(_:)` and `verbose(_:)`. /// -/// When conjoining properties all calls to `expectFailure` will fail. +/// - note: When conjoining properties all calls to `expectFailure` will fail. /// /// - parameter ps: A variadic list of properties to be conjoined. /// @@ -25,7 +25,7 @@ public func conjoin(_ ps : Testable...) -> Property { return Property(sequence(ps.map({ (p : Testable) in return p.property.unProperty.map { $0.unProp } })).flatMap({ roses in - return Gen.pure(Prop(unProp: conj(id, xs: roses))) + return Gen.pure(Prop(unProp: conj({ $0 }, xs: roses))) })).again } @@ -38,8 +38,8 @@ public func conjoin(_ ps : Testable...) -> Property { /// SwiftCheck to print a distribution map of the success rate of each sub- /// property. /// -/// When disjoining properties all calls to `expectFailure` will fail. You can, -/// however, `invert` the property. +/// - note: When disjoining properties all calls to `expectFailure` will fail. +/// You may `invert` the property instead. /// /// - parameter ps: A variadic list of properties to be disjoined. /// @@ -171,7 +171,8 @@ extension Testable { /// - parameter callback: A callback block to be executed after all failures /// have been processed. /// - /// - returns: A `Property` that executes the given callback block on failure. + /// - returns: A `Property` that executes the given callback block on + /// failure. public func whenFail(_ callback : @escaping () -> ()) -> Property { return self.withCallback(Callback.afterFinalFailure(kind: .notCounterexample) { (_,_) in return callback() @@ -197,7 +198,7 @@ extension Testable { /// result of the property every time it is tested. /// /// This function maps AfterFinalFailure callbacks that have the - /// `.Counterexample` kind to `.AfterTest` callbacks. + /// `.counterexample` kind to `.afterTest` callbacks. public var verbose : Property { func chattyCallbacks(_ cbs : [Callback]) -> [Callback] { let c = Callback.afterTest(kind: .counterexample) { (st, res) in @@ -334,10 +335,11 @@ extension Testable { /// generated test cases by replacing the test's rose tree with a custom /// one. /// - /// - parameter transform: The transformation function to apply to the + /// - parameter transform: The transformation function to apply to the /// `Prop`s of this `Property`. /// - /// - returns: A `Property` that applies the given transformation upon evaluation. + /// - returns: A `Property` that applies the given transformation upon + /// evaluation. public func mapProp(_ transform : @escaping (Prop) -> Prop) -> Property { return Property(self.property.unProperty.map(transform)) } @@ -347,7 +349,8 @@ extension Testable { /// - parameter transform: The transformation function to apply to the size /// of the generators underlying this `Property`. /// - /// - returns: A `Property` that applies the given transformation upon evaluation. + /// - returns: A `Property` that applies the given transformation upon + /// evaluation. public func mapSize(_ transform : @escaping (Int) -> Int) -> Property { return Property(Gen.sized { n in return self.property.unProperty.resize(transform(n)) @@ -577,7 +580,7 @@ private func protectResults(_ rs : Rose) -> Rose { // return { protect(Rose.pure • exception("Exception"), x: f) } //} -internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { +private func protect(_ f : (Error) -> A, x : () throws -> A) -> A { do { return try x() } catch let e { @@ -585,10 +588,6 @@ internal func protect(_ f : (Error) -> A, x : () throws -> A) -> A { } } -internal func id(_ x : A) -> A { - return x -} - internal func comp(_ f : @escaping (B) -> C, _ g : @escaping (A) -> B) -> (A) -> C { return { f(g($0)) } } diff --git a/Sources/SwiftCheck/Witness.swift b/Sources/SwiftCheck/Witness.swift index edb1af3..a654e0e 100644 --- a/Sources/SwiftCheck/Witness.swift +++ b/Sources/SwiftCheck/Witness.swift @@ -46,8 +46,8 @@ /// `forAllShrink` and `map`s the witness function to make sure all generated /// `Array`s are made of `Arbitrary ` elements: /// -/// extension Array : WitnessedArbitrary { -/// public typealias Param = Element +/// extension Array : WitnessedArbitrary { +/// public typealias Param = Element /// /// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { /// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in @@ -73,7 +73,7 @@ public protocol WitnessedArbitrary { public func forAll(_ pf : @escaping (A) -> Testable) -> Property where A.Param : Arbitrary { - return A.forAllWitnessed(id, pf: pf) + return A.forAllWitnessed({ $0 }, pf: pf) } /// Converts a function into a universally quantified property using the default From c6e929b62bfb548d966bd6fc0b0a5911b170624f Mon Sep 17 00:00:00 2001 From: Sebastian Grail Date: Tue, 17 Oct 2017 11:43:24 +1100 Subject: [PATCH 414/460] Fix random number generation for Float and Double --- Sources/SwiftCheck/Random.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index 3a52025..549d4de 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -298,7 +298,7 @@ extension Float : RandomType { /// Produces a random `Float` value in the range `[Float.min, Float.max]`. public static func random(_ rng : G) -> (Float, G) { let (x, rng_) : (Int32, G) = randomBound(rng) - let twoto24 = Int32(2) ^ Int32(24) + let twoto24: Int32 = 1 << 24 let mask24 = twoto24 - 1 return (Float(mask24 & (x)) / Float(twoto24), rng_) @@ -320,7 +320,7 @@ extension Double : RandomType { /// Produces a random `Float` value in the range `[Double.min, Double.max]`. public static func random(_ rng : G) -> (Double, G) { let (x, rng_) : (Int64, G) = randomBound(rng) - let twoto53 = Int64(2) ^ Int64(53) + let twoto53: Int64 = 1 << 53 let mask53 = twoto53 - 1 return (Double(mask53 & (x)) / Double(twoto53), rng_) From a12b3b9d4509159997497e8f4645f1110e0026e7 Mon Sep 17 00:00:00 2001 From: Sebastian Grail Date: Tue, 17 Oct 2017 12:27:35 +1100 Subject: [PATCH 415/460] Refactor generic static functions on Gen --- README.md | 7 +- Sources/SwiftCheck/Arbitrary.swift | 2 +- Sources/SwiftCheck/Gen.swift | 122 +++++++++++++++------------- Tests/SwiftCheckTests/GenSpec.swift | 14 ++-- 4 files changed, 76 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 6afe412..f2415f2 100644 --- a/README.md +++ b/README.md @@ -281,9 +281,9 @@ let vowels = Gen.fromElements(of: [ "A", "E", "I", "O", "U" ]) let randomHexValue = Gen.choose((0, 15)) -let uppers : Gen = Gen.fromElements(in: "A"..."Z") -let lowers : Gen = Gen.fromElements(in: "a"..."z") -let numbers : Gen = Gen.fromElements(in: "0"..."9") +let uppers = Gen.fromElements(in: "A"..."Z") +let lowers = Gen.fromElements(in: "a"..."z") +let numbers = Gen.fromElements(in: "0"..."9") /// This generator will generate `.none` 1/4 of the time and an arbitrary /// `.some` 3/4 of the time @@ -346,4 +346,3 @@ License ======= SwiftCheck is released under the MIT license. - diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index 5b176e1..755d2fe 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -321,7 +321,7 @@ extension String : Arbitrary { extension Character : Arbitrary { /// Returns a generator of `Character` values. public static var arbitrary : Gen { - return Gen.choose((32, 255)).flatMap(comp(Gen.pure, comp(Character.init, UnicodeScalar.init))) + return Gen.choose((32, 255)).flatMap(comp(Gen.pure, comp(Character.init, UnicodeScalar.init))) } /// The default shrinking function for `Character` values. diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index e4337cc..143d0f0 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -26,52 +26,31 @@ public struct Gen { /// /// - Requires: The input collection is required to be non-empty. public static func fromElements(of xs : S) -> Gen - where S.Index : RandomType + where S.Index : RandomType, A == S.Element { - return Gen.fromElements(in: xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in + return Gen.fromElements(in: xs.startIndex...xs.index(xs.endIndex, offsetBy: -1)).map { i in return xs[i] } } - /// Constructs a Generator that selects a random value from the given - /// collection and produces only that value. - /// - /// - Requires: The input collection is required to be non-empty. - public static func fromElements(of xs : Set) -> Gen { - precondition(!xs.isEmpty) - return Gen.fromElements(in: 0...xs.distance(from: xs.startIndex, to: xs.endIndex)-1).map { i in - return xs[xs.index(xs.startIndex, offsetBy: i)] - } - } - - /// Constructs a Generator that selects a random value from the given - /// interval and produces only that value. - /// - /// - Requires: The input interval is required to be non-empty. - public static func fromElements(in xs : ClosedRange) -> Gen { - assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") - - return choose((xs.lowerBound, xs.upperBound)) - } - /// Constructs a Generator that uses a given array to produce smaller arrays /// composed of its initial segments. The size of each initial segment /// increases with the generator's size parameter. /// /// - Requires: The input array is required to be non-empty. - public static func fromInitialSegments(of xs : [S]) -> Gen<[S]> { + public static func fromInitialSegments(of xs : [A]) -> Gen<[A]> { assert(!xs.isEmpty, "Gen.fromInitialSegmentsOf used with empty list") - return Gen<[S]>.sized { n in + return Gen<[A]>.sized { n in let ss = xs[xs.startIndex...pure([S](ss)) + return Gen<[A]>.pure([A](ss)) } } /// Constructs a Generator that produces permutations of a given array. - public static func fromShufflingElements(of xs : [S]) -> Gen<[S]> { - return choose((Int.min + 1, Int.max)).proliferate(withSize: xs.count).flatMap { ns in - return Gen<[S]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) + public static func fromShufflingElements(of xs : [A]) -> Gen<[A]> { + return Gen.choose((Int.min + 1, Int.max)).proliferate(withSize: xs.count).flatMap { ns in + return Gen<[A]>.pure(Swift.zip(ns, xs).sorted(by: { l, r in l.0 < r.0 }).map { $0.1 }) } } @@ -82,30 +61,6 @@ public struct Gen { }) } - /// Constructs a random element in the inclusive range of two `RandomType`s. - /// - /// When using this function, it is necessary to explicitly specialize the - /// generic parameter `A`. For example: - /// - /// Gen.choose((32, 255)).flatMap(Gen.pure • Character.init • UnicodeScalar.init) - public static func choose(_ rng : (A, A)) -> Gen { - return Gen(unGen: { s, _ in - return A.randomInRange(rng, gen: s).0 - }) - } - - /// Constructs a random element in the range of a bounded `RandomType`. - /// - /// When using this function, it is necessary to explicitly specialize the - /// generic parameter `A`. For example: - /// - /// Gen.chooseAny().flatMap(Gen.pure • Character.init • UnicodeScalar.init) - public static func chooseAny() -> Gen { - return Gen(unGen: { (s, _) in - return randomBound(s).0 - }) - } - /// Constructs a Generator that randomly selects and uses a particular /// generator from the given sequence of Generators. /// @@ -116,7 +71,7 @@ public struct Gen { { assert(gs.count != 0, "oneOf used with empty list") - return choose((gs.startIndex, gs.index(before: gs.endIndex))).flatMap { x in + return Gen.choose((gs.startIndex, gs.index(before: gs.endIndex))).flatMap { x in return gs[x] } } @@ -133,7 +88,7 @@ public struct Gen { let xs: [(Int, Gen)] = Array(xs) assert(xs.count != 0, "frequency used with empty list") - return choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in + return Gen.choose((1, xs.map({ $0.0 }).reduce(0, +))).flatMap { l in return pick(l, xs) } } @@ -153,6 +108,59 @@ public struct Gen { } } +extension Gen where A : RandomType, A : Comparable { + /// Constructs a Generator that selects a random value from the given + /// interval and produces only that value. + /// + /// - Requires: The input interval is required to be non-empty. + public static func fromElements(in xs : ClosedRange) -> Gen { + assert(!xs.isEmpty, "Gen.fromElementsOf used with empty interval") + + return choose((xs.lowerBound, xs.upperBound)) + } +} + +extension Gen where A : RandomType { + /// Constructs a random element in the inclusive range of two `RandomType`s. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.choose((32, 255)).flatMap(Gen.pure • Character.init • UnicodeScalar.init) + public static func choose(_ rng : (A, A)) -> Gen { + return Gen(unGen: { s, _ in + return A.randomInRange(rng, gen: s).0 + }) + } +} + +extension Gen where A : RandomType, A : LatticeType { + /// Constructs a random element in the range of a bounded `RandomType`. + /// + /// When using this function, it is necessary to explicitly specialize the + /// generic parameter `A`. For example: + /// + /// Gen.chooseAny().flatMap(Gen.pure • Character.init • UnicodeScalar.init) + public static func chooseAny() -> Gen { + return Gen(unGen: { (s, _) in + return randomBound(s).0 + }) + } +} + +extension Gen where A : Hashable { + /// Constructs a Generator that selects a random value from the given + /// collection and produces only that value. + /// + /// - Requires: The input collection is required to be non-empty. + public static func fromElements(of xs : Set) -> Gen { + precondition(!xs.isEmpty) + return Gen.fromElements(in: 0...xs.distance(from: xs.startIndex, to: xs.endIndex)-1).map { i in + return xs[xs.index(xs.startIndex, offsetBy: i)] + } + } +} + // MARK: Monoidal Functor methods. extension Gen { @@ -249,7 +257,7 @@ extension Gen { /// determined by the generator's size parameter. public var proliferate : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((0, n)).flatMap(self.proliferate(withSize:)) + return Gen.choose((0, n)).flatMap(self.proliferate(withSize:)) } } @@ -257,7 +265,7 @@ extension Gen { /// length determined by the generator's size parameter. public var proliferateNonEmpty : Gen<[A]> { return Gen<[A]>.sized { n in - return Gen.choose((1, max(1, n))).flatMap(self.proliferate(withSize:)) + return Gen.choose((1, max(1, n))).flatMap(self.proliferate(withSize:)) } } diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index dcdcd04..b556ddc 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -109,13 +109,13 @@ class GenSpec : XCTestCase { return Discard() } let l = Set(xss) - return forAll(Gen<[Int]>.fromElements(of: xss)) { l.contains($0) } + return forAll(Gen.fromElements(of: xss)) { l.contains($0) } } // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . property("Gen.fromElementsOf only generates the elements of the given array") <- forAll { (n1 : Int, n2 : Int) in - return forAll(Gen<[Int]>.fromElements(of: [n1, n2])) { $0 == n1 || $0 == n2 } + return forAll(Gen.fromElements(of: [n1, n2])) { $0 == n1 || $0 == n2 } } // CHECK-NEXT: *** Passed 100 tests @@ -123,7 +123,7 @@ class GenSpec : XCTestCase { property("Gen.fromElementsIn only generates the elements of the given interval") <- forAll { (n1 : Int, n2 : Int) in return (n1 < n2) ==> { let interval = n1...n2 - return forAll(Gen<[Int]>.fromElements(in: n1...n2)) { interval.contains($0) } + return forAll(Gen.fromElements(in: n1...n2)) { interval.contains($0) } } } @@ -131,7 +131,7 @@ class GenSpec : XCTestCase { // CHECK-NEXT: . property("Gen.fromInitialSegmentsOf produces only prefixes of the generated array") <- forAll { (xs : Array) in return !xs.isEmpty ==> { - return forAllNoShrink(Gen<[Int]>.fromInitialSegments(of: xs)) { (ys : Array) in + return forAllNoShrink(Gen.fromInitialSegments(of: xs)) { (ys : Array) in return xs.starts(with: ys) } } @@ -140,7 +140,7 @@ class GenSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . property("Gen.fromShufflingElementsOf produces only permutations of the generated array") <- forAll { (xs : Array) in - return forAllNoShrink(Gen<[Int]>.fromShufflingElements(of: xs)) { (ys : Array) in + return forAllNoShrink(Gen.fromShufflingElements(of: xs)) { (ys : Array) in return (xs.count == ys.count) ^&&^ (xs.sorted() == ys.sorted()) } } @@ -355,8 +355,8 @@ class GenSpec : XCTestCase { func testLaws() { XCTAssert(fileCheckOutput(withPrefixes: ["LAW"]) { /// Turns out Gen is a really sketchy monad because of the underlying randomness. - let lawfulGen = Gen>.fromElements(of: (0...500).map(Gen.pure)) - let lawfulArrowGen = Gen>>.fromElements(of: ArrowOf.arbitrary.proliferate(withSize: 10).generate.map(Gen.pure)) + let lawfulGen = Gen.fromElements(of: (0...500).map(Gen.pure)) + let lawfulArrowGen = Gen.fromElements(of: ArrowOf.arbitrary.proliferate(withSize: 10).generate.map(Gen.pure)) // LAW: *** Passed 100 tests // LAW-NEXT: . From 328fff3bc4aa7ae8f7f17c3ed3be91c3c600ba43 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 17 Oct 2017 12:29:47 -0400 Subject: [PATCH 416/460] Update to Swift 4 package def --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f2415f2..a958420 100644 --- a/README.md +++ b/README.md @@ -311,7 +311,7 @@ SwiftCheck can be included one of two ways: - Add SwiftCheck to your `Package.swift` file's dependencies section: ```swift -.Package(url: "https://github.com/typelift/SwiftCheck.git", versions: Version(0,6,0).. Date: Sat, 21 Oct 2017 05:51:37 +1100 Subject: [PATCH 417/460] Refactor zip to ensure type consistency (#252) * Refactor zip to ensure type consistency * Deprecate static 'map' in favor of 'zipWith' * Use zipWith in implementation of deprecated map --- Sources/SwiftCheck/Cartesian.swift | 610 ++++++++++++++++++---- Sources/SwiftCheck/Gen.swift | 6 +- Templates/Cartesian.swift.gyb | 27 +- Templates/CartesianSpec.swift.gyb | 6 +- Tests/SwiftCheckTests/CartesianSpec.swift | 42 +- Tests/SwiftCheckTests/GenSpec.swift | 2 +- Tests/SwiftCheckTests/SimpleSpec.swift | 6 +- 7 files changed, 562 insertions(+), 137 deletions(-) diff --git a/Sources/SwiftCheck/Cartesian.swift b/Sources/SwiftCheck/Cartesian.swift index 628d0e9..67699df 100644 --- a/Sources/SwiftCheck/Cartesian.swift +++ b/Sources/SwiftCheck/Cartesian.swift @@ -18,10 +18,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga1: A generator of values of type `A1`. /// - parameter ga2: A generator of values of type `A2`. /// - parameter ga3: A generator of values of type `A3`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen) -> Gen<(A1, A2, A3)> where A == (A1, A2, A3) { + return Gen<((A1, A2), A3)> .zip( - .zip(ga1, ga2), + Gen<(A1, A2)>.zip(ga1, ga2), ga3 ).map { t in (t.0.0, t.0.1, t.1) @@ -34,8 +34,19 @@ extension Gen /*: Cartesian*/ { /// - parameter ga1: A generator of values of type `A1`. /// - parameter ga2: A generator of values of type `A2`. /// - parameter ga3: A generator of values of type `A3`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> R) -> Gen { - return zip(ga1, ga2, ga3).map({ t in transform(t.0, t.1, t.2) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> A) -> Gen { + return Gen<(A1, A2, A3)>.zip(ga1, ga2, ga3).map({ t in transform(t.0, t.1, t.2) }) } /// Zips together 4 generators into a generator of 4-tuples. @@ -44,10 +55,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga2: A generator of values of type `A2`. /// - parameter ga3: A generator of values of type `A3`. /// - parameter ga4: A generator of values of type `A4`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen) -> Gen<(A1, A2, A3, A4)> where A == (A1, A2, A3, A4) { + return Gen<((A1, A2, A3), A4)> .zip( - .zip(ga1, ga2, ga3), + Gen<(A1, A2, A3)>.zip(ga1, ga2, ga3), ga4 ).map { t in (t.0.0, t.0.1, t.0.2, t.1) @@ -61,8 +72,20 @@ extension Gen /*: Cartesian*/ { /// - parameter ga2: A generator of values of type `A2`. /// - parameter ga3: A generator of values of type `A3`. /// - parameter ga4: A generator of values of type `A4`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4).map({ t in transform(t.0, t.1, t.2, t.3) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> A) -> Gen { + return Gen<(A1, A2, A3, A4)>.zip(ga1, ga2, ga3, ga4).map({ t in transform(t.0, t.1, t.2, t.3) }) } /// Zips together 5 generators into a generator of 5-tuples. @@ -72,10 +95,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga3: A generator of values of type `A3`. /// - parameter ga4: A generator of values of type `A4`. /// - parameter ga5: A generator of values of type `A5`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen) -> Gen<(A1, A2, A3, A4, A5)> where A == (A1, A2, A3, A4, A5) { + return Gen<((A1, A2, A3, A4), A5)> .zip( - .zip(ga1, ga2, ga3, ga4), + Gen<(A1, A2, A3, A4)>.zip(ga1, ga2, ga3, ga4), ga5 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.1) @@ -90,8 +113,21 @@ extension Gen /*: Cartesian*/ { /// - parameter ga3: A generator of values of type `A3`. /// - parameter ga4: A generator of values of type `A4`. /// - parameter ga5: A generator of values of type `A5`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5).map({ t in transform(t.0, t.1, t.2, t.3, t.4) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5)>.zip(ga1, ga2, ga3, ga4, ga5).map({ t in transform(t.0, t.1, t.2, t.3, t.4) }) } /// Zips together 6 generators into a generator of 6-tuples. @@ -102,10 +138,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga4: A generator of values of type `A4`. /// - parameter ga5: A generator of values of type `A5`. /// - parameter ga6: A generator of values of type `A6`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6)> where A == (A1, A2, A3, A4, A5, A6) { + return Gen<((A1, A2, A3, A4, A5), A6)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5), + Gen<(A1, A2, A3, A4, A5)>.zip(ga1, ga2, ga3, ga4, ga5), ga6 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.1) @@ -121,8 +157,22 @@ extension Gen /*: Cartesian*/ { /// - parameter ga4: A generator of values of type `A4`. /// - parameter ga5: A generator of values of type `A5`. /// - parameter ga6: A generator of values of type `A6`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6)>.zip(ga1, ga2, ga3, ga4, ga5, ga6).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5) }) } /// Zips together 7 generators into a generator of 7-tuples. @@ -134,10 +184,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga5: A generator of values of type `A5`. /// - parameter ga6: A generator of values of type `A6`. /// - parameter ga7: A generator of values of type `A7`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7)> where A == (A1, A2, A3, A4, A5, A6, A7) { + return Gen<((A1, A2, A3, A4, A5, A6), A7)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6), + Gen<(A1, A2, A3, A4, A5, A6)>.zip(ga1, ga2, ga3, ga4, ga5, ga6), ga7 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.1) @@ -154,8 +204,23 @@ extension Gen /*: Cartesian*/ { /// - parameter ga5: A generator of values of type `A5`. /// - parameter ga6: A generator of values of type `A6`. /// - parameter ga7: A generator of values of type `A7`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6) }) } /// Zips together 8 generators into a generator of 8-tuples. @@ -168,10 +233,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga6: A generator of values of type `A6`. /// - parameter ga7: A generator of values of type `A7`. /// - parameter ga8: A generator of values of type `A8`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8)> where A == (A1, A2, A3, A4, A5, A6, A7, A8) { + return Gen<((A1, A2, A3, A4, A5, A6, A7), A8)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7), + Gen<(A1, A2, A3, A4, A5, A6, A7)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7), ga8 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.1) @@ -189,8 +254,24 @@ extension Gen /*: Cartesian*/ { /// - parameter ga6: A generator of values of type `A6`. /// - parameter ga7: A generator of values of type `A7`. /// - parameter ga8: A generator of values of type `A8`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7) }) } /// Zips together 9 generators into a generator of 9-tuples. @@ -204,10 +285,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga7: A generator of values of type `A7`. /// - parameter ga8: A generator of values of type `A8`. /// - parameter ga9: A generator of values of type `A9`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8), A9)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8), ga9 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.1) @@ -226,8 +307,25 @@ extension Gen /*: Cartesian*/ { /// - parameter ga7: A generator of values of type `A7`. /// - parameter ga8: A generator of values of type `A8`. /// - parameter ga9: A generator of values of type `A9`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8) }) } /// Zips together 10 generators into a generator of 10-tuples. @@ -242,10 +340,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga8: A generator of values of type `A8`. /// - parameter ga9: A generator of values of type `A9`. /// - parameter ga10: A generator of values of type `A10`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9), A10)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9), ga10 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.1) @@ -265,8 +363,26 @@ extension Gen /*: Cartesian*/ { /// - parameter ga8: A generator of values of type `A8`. /// - parameter ga9: A generator of values of type `A9`. /// - parameter ga10: A generator of values of type `A10`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9) }) } /// Zips together 11 generators into a generator of 11-tuples. @@ -282,10 +398,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga9: A generator of values of type `A9`. /// - parameter ga10: A generator of values of type `A10`. /// - parameter ga11: A generator of values of type `A11`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10), A11)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10), ga11 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.1) @@ -306,8 +422,27 @@ extension Gen /*: Cartesian*/ { /// - parameter ga9: A generator of values of type `A9`. /// - parameter ga10: A generator of values of type `A10`. /// - parameter ga11: A generator of values of type `A11`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10) }) } /// Zips together 12 generators into a generator of 12-tuples. @@ -324,10 +459,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga10: A generator of values of type `A10`. /// - parameter ga11: A generator of values of type `A11`. /// - parameter ga12: A generator of values of type `A12`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11), A12)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11), ga12 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.1) @@ -349,8 +484,28 @@ extension Gen /*: Cartesian*/ { /// - parameter ga10: A generator of values of type `A10`. /// - parameter ga11: A generator of values of type `A11`. /// - parameter ga12: A generator of values of type `A12`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11) }) } /// Zips together 13 generators into a generator of 13-tuples. @@ -368,10 +523,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga11: A generator of values of type `A11`. /// - parameter ga12: A generator of values of type `A12`. /// - parameter ga13: A generator of values of type `A13`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12), A13)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12), ga13 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.1) @@ -394,8 +549,29 @@ extension Gen /*: Cartesian*/ { /// - parameter ga11: A generator of values of type `A11`. /// - parameter ga12: A generator of values of type `A12`. /// - parameter ga13: A generator of values of type `A13`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12) }) } /// Zips together 14 generators into a generator of 14-tuples. @@ -414,10 +590,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga12: A generator of values of type `A12`. /// - parameter ga13: A generator of values of type `A13`. /// - parameter ga14: A generator of values of type `A14`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13), A14)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13), ga14 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.1) @@ -441,8 +617,30 @@ extension Gen /*: Cartesian*/ { /// - parameter ga12: A generator of values of type `A12`. /// - parameter ga13: A generator of values of type `A13`. /// - parameter ga14: A generator of values of type `A14`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13) }) } /// Zips together 15 generators into a generator of 15-tuples. @@ -462,10 +660,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga13: A generator of values of type `A13`. /// - parameter ga14: A generator of values of type `A14`. /// - parameter ga15: A generator of values of type `A15`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14), A15)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14), ga15 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.1) @@ -490,8 +688,31 @@ extension Gen /*: Cartesian*/ { /// - parameter ga13: A generator of values of type `A13`. /// - parameter ga14: A generator of values of type `A14`. /// - parameter ga15: A generator of values of type `A15`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14) }) } /// Zips together 16 generators into a generator of 16-tuples. @@ -512,10 +733,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga14: A generator of values of type `A14`. /// - parameter ga15: A generator of values of type `A15`. /// - parameter ga16: A generator of values of type `A16`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15), A16)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15), ga16 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.1) @@ -541,8 +762,32 @@ extension Gen /*: Cartesian*/ { /// - parameter ga14: A generator of values of type `A14`. /// - parameter ga15: A generator of values of type `A15`. /// - parameter ga16: A generator of values of type `A16`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15) }) } /// Zips together 17 generators into a generator of 17-tuples. @@ -564,10 +809,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga15: A generator of values of type `A15`. /// - parameter ga16: A generator of values of type `A16`. /// - parameter ga17: A generator of values of type `A17`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16), A17)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16), ga17 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.1) @@ -594,8 +839,33 @@ extension Gen /*: Cartesian*/ { /// - parameter ga15: A generator of values of type `A15`. /// - parameter ga16: A generator of values of type `A16`. /// - parameter ga17: A generator of values of type `A17`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16) }) } /// Zips together 18 generators into a generator of 18-tuples. @@ -618,10 +888,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga16: A generator of values of type `A16`. /// - parameter ga17: A generator of values of type `A17`. /// - parameter ga18: A generator of values of type `A18`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17), A18)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17), ga18 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.1) @@ -649,8 +919,34 @@ extension Gen /*: Cartesian*/ { /// - parameter ga16: A generator of values of type `A16`. /// - parameter ga17: A generator of values of type `A17`. /// - parameter ga18: A generator of values of type `A18`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17) }) } /// Zips together 19 generators into a generator of 19-tuples. @@ -674,10 +970,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga17: A generator of values of type `A17`. /// - parameter ga18: A generator of values of type `A18`. /// - parameter ga19: A generator of values of type `A19`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18), A19)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18), ga19 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.1) @@ -706,8 +1002,35 @@ extension Gen /*: Cartesian*/ { /// - parameter ga17: A generator of values of type `A17`. /// - parameter ga18: A generator of values of type `A18`. /// - parameter ga19: A generator of values of type `A19`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18) }) } /// Zips together 20 generators into a generator of 20-tuples. @@ -732,10 +1055,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga18: A generator of values of type `A18`. /// - parameter ga19: A generator of values of type `A19`. /// - parameter ga20: A generator of values of type `A20`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19), A20)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19), ga20 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.1) @@ -765,8 +1088,36 @@ extension Gen /*: Cartesian*/ { /// - parameter ga18: A generator of values of type `A18`. /// - parameter ga19: A generator of values of type `A19`. /// - parameter ga20: A generator of values of type `A20`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19) }) } /// Zips together 21 generators into a generator of 21-tuples. @@ -792,10 +1143,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga19: A generator of values of type `A19`. /// - parameter ga20: A generator of values of type `A20`. /// - parameter ga21: A generator of values of type `A21`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20), A21)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20), ga21 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.0.19, t.1) @@ -826,8 +1177,37 @@ extension Gen /*: Cartesian*/ { /// - parameter ga19: A generator of values of type `A19`. /// - parameter ga20: A generator of values of type `A20`. /// - parameter ga21: A generator of values of type `A21`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20) }) } /// Zips together 22 generators into a generator of 22-tuples. @@ -854,10 +1234,10 @@ extension Gen /*: Cartesian*/ { /// - parameter ga20: A generator of values of type `A20`. /// - parameter ga21: A generator of values of type `A21`. /// - parameter ga22: A generator of values of type `A22`. - public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> { - return Gen + public static func zip(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen) -> Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)> where A == (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) { + return Gen<((A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21), A22)> .zip( - .zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21), + Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21), ga22 ).map { t in (t.0.0, t.0.1, t.0.2, t.0.3, t.0.4, t.0.5, t.0.6, t.0.7, t.0.8, t.0.9, t.0.10, t.0.11, t.0.12, t.0.13, t.0.14, t.0.15, t.0.16, t.0.17, t.0.18, t.0.19, t.0.20, t.1) @@ -889,8 +1269,38 @@ extension Gen /*: Cartesian*/ { /// - parameter ga20: A generator of values of type `A20`. /// - parameter ga21: A generator of values of type `A21`. /// - parameter ga22: A generator of values of type `A22`. - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> R) -> Gen { - return zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20, t.21) }) + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// + /// - parameter ga1: A generator of values of type `A1`. + /// - parameter ga2: A generator of values of type `A2`. + /// - parameter ga3: A generator of values of type `A3`. + /// - parameter ga4: A generator of values of type `A4`. + /// - parameter ga5: A generator of values of type `A5`. + /// - parameter ga6: A generator of values of type `A6`. + /// - parameter ga7: A generator of values of type `A7`. + /// - parameter ga8: A generator of values of type `A8`. + /// - parameter ga9: A generator of values of type `A9`. + /// - parameter ga10: A generator of values of type `A10`. + /// - parameter ga11: A generator of values of type `A11`. + /// - parameter ga12: A generator of values of type `A12`. + /// - parameter ga13: A generator of values of type `A13`. + /// - parameter ga14: A generator of values of type `A14`. + /// - parameter ga15: A generator of values of type `A15`. + /// - parameter ga16: A generator of values of type `A16`. + /// - parameter ga17: A generator of values of type `A17`. + /// - parameter ga18: A generator of values of type `A18`. + /// - parameter ga19: A generator of values of type `A19`. + /// - parameter ga20: A generator of values of type `A20`. + /// - parameter ga21: A generator of values of type `A21`. + /// - parameter ga22: A generator of values of type `A22`. + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> A) -> Gen { + return Gen<(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22)>.zip(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22).map({ t in transform(t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, t.9, t.10, t.11, t.12, t.13, t.14, t.15, t.16, t.17, t.18, t.19, t.20, t.21) }) } } diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 143d0f0..24b775c 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -165,7 +165,7 @@ extension Gen where A : Hashable { extension Gen { /// Zips together two generators and returns a generator of tuples. - public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> { + public static func zip(_ ga1 : Gen, _ ga2 : Gen) -> Gen<(A1, A2)> where A == (A1, A2) { return Gen<(A1, A2)> { r, n in let (r1, r2) = r.split return (ga1.unGen(r1, n), ga2.unGen(r2, n)) @@ -174,8 +174,8 @@ extension Gen { /// Returns a new generator that applies a given function to any outputs the /// given generators produce. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> R) -> Gen { - return zip(ga1, ga2).map({ t in transform(t.0, t.1) }) + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { + return Gen<(A1, A2)>.zip(ga1, ga2).map({ t in transform(t.0, t.1) }) } } diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 41ca5f5..9c46c50 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -21,6 +21,8 @@ extension Gen /*: Cartesian*/ { # Function definition template types_list = ['A{0}'.format(n) for n in range(1, arity + 1)] type_parameter_list = ', '.join(types_list) +previouse_type_parameter_list = ', '.join(['A{0}'.format(n) for n in range(1, arity)]) +latest_type_parameter = 'A{0}'.format(arity) parameter_list = ', '.join(['_ ga{0} : Gen'.format(n) for n in range(1, arity + 1)]) # Zip body template @@ -31,18 +33,18 @@ expanded_previous_tuple = ', '.join(['t.0.{0}'.format(n - 1) for n in previous_p expanded_previous_tuple2 = ', '.join(['t.{0}'.format(n) for n in range(0, arity)]) -# Map body template -map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) +# ZipWith body template +zip_with_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1)]) }% /// Zips together ${arity} generators into a generator of ${arity}-tuples. /// % for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): /// - parameter ${p}: A generator of values of type `${t}`. % end - public static func zip<${type_parameter_list}>(${parameter_list}) -> Gen<(${type_parameter_list})> { - return Gen + public static func zip<${type_parameter_list}>(${parameter_list}) -> Gen<(${type_parameter_list})> where A == (${type_parameter_list}) { + return Gen<((${previouse_type_parameter_list}), ${latest_type_parameter})> .zip( - .zip(${previous_zip_arguments}), + Gen<(${previouse_type_parameter_list})>.zip(${previous_zip_arguments}), ga${arity} ).map { t in (${expanded_previous_tuple}, t.1) @@ -55,8 +57,19 @@ map_zip_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + 1 % for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): /// - parameter ${p}: A generator of values of type `${t}`. % end - public static func map<${type_parameter_list}, R>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> R) -> Gen { - return zip(${map_zip_argument_list}).map({ t in transform(${expanded_previous_tuple2}) }) + @available(*, deprecated, renamed: "zipWith") + public static func map<${type_parameter_list}>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> A) -> Gen { + return Gen.zipWith(${zip_with_argument_list}, transform: transform) + } + + /// Returns a new generator that applies a given function to any outputs the + /// given generators produce. + /// +% for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): + /// - parameter ${p}: A generator of values of type `${t}`. +% end + public static func zipWith<${type_parameter_list}>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> A) -> Gen { + return Gen<(${type_parameter_list})>.zip(${zip_with_argument_list}).map({ t in transform(${expanded_previous_tuple2}) }) } % end diff --git a/Templates/CartesianSpec.swift.gyb b/Templates/CartesianSpec.swift.gyb index 3ac614b..e4f6951 100644 --- a/Templates/CartesianSpec.swift.gyb +++ b/Templates/CartesianSpec.swift.gyb @@ -38,16 +38,16 @@ tupled_parameters = ', '.join(['x{0}'.format(n) for n in range(1, arity + 1 % end } - func testGeneratedMaps() { + func testGeneratedZipWiths() { % for arity in range(3, MAX_ARITY + 1): %{ gen_type_argument_list = ', '.join(['Int' for _ in range(1, arity + 1)]) -map_argument_list = ', '.join(['Gen.pure({0})'.format(n) for n in range(1, arity + 1)]) +zip_with_argument_list = ', '.join(['Gen.pure({0})'.format(n) for n in range(1, arity + 1)]) tupled_parameters = ', '.join(['x{0}'.format(n) for n in range(1, arity + 1)]) max_argument_list = ', '.join(['${0}'.format(n) for n in range(0, arity)]) }% - let g${arity} = Gen<(${gen_type_argument_list})>.map(${map_argument_list}) { max(${max_argument_list}) } + let g${arity} = Gen.zipWith(${zip_with_argument_list}) { max(${max_argument_list}) } property("Gen.zip${arity} behaves") <- forAllNoShrink(g${arity}) { maxInt in maxInt == ${arity} diff --git a/Tests/SwiftCheckTests/CartesianSpec.swift b/Tests/SwiftCheckTests/CartesianSpec.swift index 3fea720..a313282 100644 --- a/Tests/SwiftCheckTests/CartesianSpec.swift +++ b/Tests/SwiftCheckTests/CartesianSpec.swift @@ -142,123 +142,123 @@ final class CartesianSpec : XCTestCase { } } - func testGeneratedMaps() { + func testGeneratedZipWiths() { - let g3 = Gen<(Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3)) { max($0, $1, $2) } + let g3 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3)) { max($0, $1, $2) } property("Gen.zip3 behaves") <- forAllNoShrink(g3) { maxInt in maxInt == 3 } - let g4 = Gen<(Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) { max($0, $1, $2, $3) } + let g4 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4)) { max($0, $1, $2, $3) } property("Gen.zip4 behaves") <- forAllNoShrink(g4) { maxInt in maxInt == 4 } - let g5 = Gen<(Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) { max($0, $1, $2, $3, $4) } + let g5 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5)) { max($0, $1, $2, $3, $4) } property("Gen.zip5 behaves") <- forAllNoShrink(g5) { maxInt in maxInt == 5 } - let g6 = Gen<(Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) { max($0, $1, $2, $3, $4, $5) } + let g6 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6)) { max($0, $1, $2, $3, $4, $5) } property("Gen.zip6 behaves") <- forAllNoShrink(g6) { maxInt in maxInt == 6 } - let g7 = Gen<(Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) { max($0, $1, $2, $3, $4, $5, $6) } + let g7 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7)) { max($0, $1, $2, $3, $4, $5, $6) } property("Gen.zip7 behaves") <- forAllNoShrink(g7) { maxInt in maxInt == 7 } - let g8 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) { max($0, $1, $2, $3, $4, $5, $6, $7) } + let g8 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8)) { max($0, $1, $2, $3, $4, $5, $6, $7) } property("Gen.zip8 behaves") <- forAllNoShrink(g8) { maxInt in maxInt == 8 } - let g9 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8) } + let g9 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8) } property("Gen.zip9 behaves") <- forAllNoShrink(g9) { maxInt in maxInt == 9 } - let g10 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) } + let g10 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9) } property("Gen.zip10 behaves") <- forAllNoShrink(g10) { maxInt in maxInt == 10 } - let g11 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } + let g11 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) } property("Gen.zip11 behaves") <- forAllNoShrink(g11) { maxInt in maxInt == 11 } - let g12 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } + let g12 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) } property("Gen.zip12 behaves") <- forAllNoShrink(g12) { maxInt in maxInt == 12 } - let g13 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) } + let g13 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) } property("Gen.zip13 behaves") <- forAllNoShrink(g13) { maxInt in maxInt == 13 } - let g14 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) } + let g14 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) } property("Gen.zip14 behaves") <- forAllNoShrink(g14) { maxInt in maxInt == 14 } - let g15 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) } + let g15 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) } property("Gen.zip15 behaves") <- forAllNoShrink(g15) { maxInt in maxInt == 15 } - let g16 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) } + let g16 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) } property("Gen.zip16 behaves") <- forAllNoShrink(g16) { maxInt in maxInt == 16 } - let g17 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) } + let g17 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) } property("Gen.zip17 behaves") <- forAllNoShrink(g17) { maxInt in maxInt == 17 } - let g18 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) } + let g18 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17) } property("Gen.zip18 behaves") <- forAllNoShrink(g18) { maxInt in maxInt == 18 } - let g19 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) } + let g19 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) } property("Gen.zip19 behaves") <- forAllNoShrink(g19) { maxInt in maxInt == 19 } - let g20 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) } + let g20 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) } property("Gen.zip20 behaves") <- forAllNoShrink(g20) { maxInt in maxInt == 20 } - let g21 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) } + let g21 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) } property("Gen.zip21 behaves") <- forAllNoShrink(g21) { maxInt in maxInt == 21 } - let g22 = Gen<(Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int)>.map(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) } + let g22 = Gen.zipWith(Gen.pure(1), Gen.pure(2), Gen.pure(3), Gen.pure(4), Gen.pure(5), Gen.pure(6), Gen.pure(7), Gen.pure(8), Gen.pure(9), Gen.pure(10), Gen.pure(11), Gen.pure(12), Gen.pure(13), Gen.pure(14), Gen.pure(15), Gen.pure(16), Gen.pure(17), Gen.pure(18), Gen.pure(19), Gen.pure(20), Gen.pure(21), Gen.pure(22)) { max($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) } property("Gen.zip22 behaves") <- forAllNoShrink(g22) { maxInt in maxInt == 22 diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index b556ddc..567af82 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -319,7 +319,7 @@ class GenSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . property("Gen.zip8 behaves") <- forAll { (x : Int, y : Int, z : Int, w : Int, a : Int, b : Int, c : Int, d : Int) in - let g = Gen<(Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) + let g = Gen<(Int, Int, Int, Int, Int, Int, Int, Int)>.zip(Gen.pure(x), Gen.pure(y), Gen.pure(z), Gen.pure(w), Gen.pure(a), Gen.pure(b), Gen.pure(c), Gen.pure(d)) return forAllNoShrink(g) { (t) in return (t.0, t.1, t.2, t.3, t.4, t.5) == (x, y, z, w, a, b) && (t.6, t.7) == (c, d) diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index c755d76..5472cda 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -105,8 +105,10 @@ extension ArbitraryLargeFoo : Arbitrary { , UInt8.arbitrary, UInt16.arbitrary, UInt32.arbitrary, UInt64.arbitrary , Int.arbitrary, UInt.arbitrary) .flatMap { t in - return Gen<(Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> - .map( + return Gen<(Int8, Int16, Int32, Int64 + , UInt8, UInt16, UInt32, UInt64 + , Int , UInt, Bool, (Bool, Bool), (Bool, Bool, Bool), (Bool, Bool, Bool, Bool))> + .zipWith( Bool.arbitrary, Gen<(Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary), Gen<(Bool, Bool, Bool)>.zip(Bool.arbitrary, Bool.arbitrary, Bool.arbitrary), From b6459af3abebcf44ee1d46bd9c3e52004700d0fb Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Oct 2017 14:53:38 -0400 Subject: [PATCH 418/460] XXX --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 4d2dbe1..cdda6d1 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( targets: ["SwiftCheck"]), ], dependencies: [ - .package(url: "https://github.com/trill-lang/FileCheck.git", .branch("master")) + .package(url: "https://github.com/trill-lang/FileCheck.git", from: "0.0.3") ], targets: [ .target( From 816076eac8d54f2e350a50d9ea2640c55a0e8fa1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 1 Nov 2017 22:20:44 -0400 Subject: [PATCH 419/460] Update for Xcode 9.1 --- Cartfile.resolved | 2 +- Carthage/Checkouts/FileCheck | 2 +- Sources/SwiftCheck/Arbitrary.swift | 2 +- Sources/SwiftCheck/CoArbitrary.swift | 2 +- Sources/SwiftCheck/Property.swift | 2 +- Tests/SwiftCheckTests/ComplexSpec.swift | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 32291f6..11ebc19 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "trill-lang/FileCheck" "0.0.3" +github "trill-lang/FileCheck" "0.0.4" diff --git a/Carthage/Checkouts/FileCheck b/Carthage/Checkouts/FileCheck index 482e229..0830734 160000 --- a/Carthage/Checkouts/FileCheck +++ b/Carthage/Checkouts/FileCheck @@ -1 +1 @@ -Subproject commit 482e22960391b02e3630ae3af4dce64d16dd63e7 +Subproject commit 083073480112406580f0242036a079f9f8b170ad diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index 755d2fe..ba885e1 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -314,7 +314,7 @@ extension String : Arbitrary { /// The default shrinking function for `String` values. public static func shrink(_ s : String) -> [String] { - return [Character].shrink([Character](s.characters)).map { String($0) } + return [Character].shrink(s.map{$0}).map { String($0) } } } diff --git a/Sources/SwiftCheck/CoArbitrary.swift b/Sources/SwiftCheck/CoArbitrary.swift index 53f1388..582719a 100644 --- a/Sources/SwiftCheck/CoArbitrary.swift +++ b/Sources/SwiftCheck/CoArbitrary.swift @@ -71,7 +71,7 @@ extension String : CoArbitrary { } return comp( Character.coarbitrary(x[x.startIndex]), - String.coarbitrary(String(x[x.characters.index(after: x.startIndex)..]) -> Gen { extension String { fileprivate var initial : String { - return String(self[self.startIndex.. Date: Sat, 4 Nov 2017 15:24:46 -0400 Subject: [PATCH 420/460] Fix printing passing counter-countexamples in verbose mode --- Sources/SwiftCheck/Check.swift | 4 +++- Tests/SwiftCheckTests/SimpleSpec.swift | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftCheck/Check.swift b/Sources/SwiftCheck/Check.swift index 3cc80e4..39f2efc 100644 --- a/Sources/SwiftCheck/Check.swift +++ b/Sources/SwiftCheck/Check.swift @@ -227,7 +227,9 @@ infix operator ==== : ComparisonPrecedence public func ==== (x : A, y : A) -> Property where A : Equatable { - return (x == y).counterexample(String(describing: x) + " /= " + String(describing: y)) + let isEq = (x == y) + let text = isEq ? "==" : "!=" + return isEq.counterexample("\(x) \(text) \(y)") } precedencegroup SwiftCheckLabelPrecedence { diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index 5472cda..918169f 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -232,6 +232,22 @@ class SimpleSpec : XCTestCase { ) { a, b in return a != b } + + // CHECK: Passed: (.) + // CHECK-NEXT: 0 + // CHECK-NEXT: 0 == 0 + // CHECK: Passed: (.) + // CHECK-NEXT: {{[0-9]+}} + // CHECK-NEXT: {{[0-9]+}} == {{[0-9]+}} + // CHECK: Passed: (.) + // CHECK-NEXT: {{[0-9]+}} + // CHECK-NEXT: {{[0-9]+}} == {{[0-9]+}} + // CHECK: *** Passed 3 tests + // CHECK-NEXT: . + let verboseLimit = CheckerArguments(maxAllowableSuccessfulTests: 3) + property("Passing counter-counterexamples print correctly", arguments: verboseLimit) <- forAll { (x : Int) in + return x*x ==== x*x + }.verbose }) } From 129b08a5255bae70933b9f185b9a1fcc28f87ca6 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Nov 2017 15:31:36 -0400 Subject: [PATCH 421/460] Bump podspec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 99e8d93..81118fc 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.8.1" + s.version = "0.9.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 32fe7603477a5986ffccb28753c497c3a0ab5ffa Mon Sep 17 00:00:00 2001 From: Adrian Kashivskyy Date: Tue, 14 Nov 2017 20:28:51 +0100 Subject: [PATCH 422/460] Rename Cartfile to Cartfile.private --- Cartfile => Cartfile.private | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Cartfile => Cartfile.private (100%) diff --git a/Cartfile b/Cartfile.private similarity index 100% rename from Cartfile rename to Cartfile.private From 113370ae586fc7f76fb0085847ed41b2a5960953 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 14 Nov 2017 18:46:25 -0500 Subject: [PATCH 423/460] Bump podspec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 81118fc..8a4494d 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.9.0" + s.version = "0.9.1" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From efc6c97c21ea09016cdf23d7745d29262caf25dc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 28 Dec 2017 14:52:51 -0500 Subject: [PATCH 424/460] Provide non-DSL spellings of primitives --- Sources/SwiftCheck/Check.swift | 85 ++++++++++++++++++++++++++++++++++ Sources/SwiftCheck/Test.swift | 8 ---- 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/Sources/SwiftCheck/Check.swift b/Sources/SwiftCheck/Check.swift index 39f2efc..ec78ee5 100644 --- a/Sources/SwiftCheck/Check.swift +++ b/Sources/SwiftCheck/Check.swift @@ -194,6 +194,91 @@ public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () _ = quickCheckWithResult(checker.args, test()) } +/// Tests a property and prints the results to stdout. +/// +/// - parameter prop: The property to be tested. +/// - parameter name: The name of the property being tested. +@available(*, deprecated, message: "Use quickCheck(asserting:) or quickCheck(reporting:) instead.") +public func quickCheck(_ prop : Testable, name : String = "") { + _ = quickCheckWithResult(CheckerArguments(name: name), prop) +} + +/// The interface for properties to be run through SwiftCheck with an XCTest +/// assert. The property will still generate console output during testing. +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +/// - prop: A block that carries the property or invariant to be tested. +public func quickCheck( + asserting message: String, arguments: CheckerArguments? = nil, + file : StaticString = #file, line : UInt = #line, + property prop : @autoclosure @escaping () -> Testable +) { + property(message, arguments: arguments, file: file, line: line) <- prop +} + +/// The interface for properties to be run through SwiftCheck with an XCTest +/// assert. The property will still generate console output during testing. +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +/// - prop: A block that carries the property or invariant to be tested. +public func quickCheck( + asserting message: String, arguments: CheckerArguments? = nil, + file : StaticString = #file, line : UInt = #line, + property prop : () -> Testable +) { + property(message, arguments: arguments, file: file, line: line) <- prop +} + +/// The interface for properties to be run through SwiftCheck without an XCTest +/// assert. The property will still generate console output during testing. +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +/// - prop: A block that carries the property or invariant to be tested. +public func quickCheck( + reporting message: String, arguments: CheckerArguments? = nil, + file : StaticString = #file, line : UInt = #line, + property prop : @autoclosure @escaping () -> Testable +) { + reportProperty(message, arguments: arguments, file: file, line: line) <- prop +} + +/// The interface for properties to be run through SwiftCheck without an XCTest +/// assert. The property will still generate console output during testing. +/// +/// - Parameters: +/// - message: A description of the property. +/// - arguments: An optional set of arguments to tune the test runner. +/// - file: The file in which test occurred. Defaults to the file name of the +/// test case in which this function was called. +/// - line: The line number on which test occurred. Defaults to the line +/// number on which this function was called. +/// - prop: A block that carries the property or invariant to be tested. +public func quickCheck( + reporting message: String, arguments: CheckerArguments? = nil, + file : StaticString = #file, line : UInt = #line, + property prop : () -> Testable +) { + reportProperty(message, arguments: arguments, file: file, line: line) <- prop +} + precedencegroup SwiftCheckImplicationPrecedence { associativity: right lowerThan: ComparisonPrecedence diff --git a/Sources/SwiftCheck/Test.swift b/Sources/SwiftCheck/Test.swift index 0b01ebb..d5913e2 100644 --- a/Sources/SwiftCheck/Test.swift +++ b/Sources/SwiftCheck/Test.swift @@ -533,14 +533,6 @@ public func exists(_ gen : Gen, pf : @escaping (A) throws -> T } } -/// Tests a property and prints the results to stdout. -/// -/// - parameter prop: The property to be tested. -/// - parameter name: The name of the property being tested. -public func quickCheck(_ prop : Testable, name : String = "") { - _ = quickCheckWithResult(CheckerArguments(name: name), prop) -} - // MARK: - Implementation Details internal enum Result { From 5002b1ecf4607975d47618b3c0bb86daec9a6c12 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 5 Jan 2018 16:51:19 -0700 Subject: [PATCH 425/460] Formalize re-org --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index cdda6d1..f114597 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( targets: ["SwiftCheck"]), ], dependencies: [ - .package(url: "https://github.com/trill-lang/FileCheck.git", from: "0.0.3") + .package(url: "https://github.com/llvm-swift/FileCheck.git", from: "0.0.3") ], targets: [ .target( From c489d88f40aeb87e64bf010a85ac5371db552d5c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 18 Nov 2017 15:02:09 -0500 Subject: [PATCH 426/460] Use conditional conformances --- .travis.yml | 6 +- README.md | 15 +- Sources/SwiftCheck/Arbitrary.swift | 4 +- Sources/SwiftCheck/Modifiers.swift | 167 -------------------- Sources/SwiftCheck/Testable.swift | 2 +- Sources/SwiftCheck/Witness.swift | 161 ------------------- Sources/SwiftCheck/WitnessedArbitrary.swift | 139 ++-------------- SwiftCheck.xcodeproj/project.pbxproj | 8 - Tests/SwiftCheckTests/FailureSpec.swift | 12 -- Tests/SwiftCheckTests/GenSpec.swift | 16 +- Tests/SwiftCheckTests/ModifierSpec.swift | 16 +- Tests/SwiftCheckTests/ShrinkSpec.swift | 6 +- Tests/SwiftCheckTests/SimpleSpec.swift | 4 +- 13 files changed, 46 insertions(+), 510 deletions(-) delete mode 100644 Sources/SwiftCheck/Witness.swift diff --git a/.travis.yml b/.travis.yml index a3c04dc..5a42c8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,9 +45,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-4.0-release/ubuntu1404/swift-4.0-RELEASE/swift-4.0-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-4.0-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-4.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04.tar.gz + - tar xzf swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/README.md b/README.md index a958420..d84c128 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,7 @@ For a less contrived example, here is a program property that tests whether Array identity holds under double reversal: ```swift -// Because Swift doesn't allow us to implement `Arbitrary` for certain types, -// SwiftCheck instead implements 'modifier' types that wrap them. Here, -// `ArrayOf` generates random arrays of values of type `T`. -property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in +property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in // This property is using a number of SwiftCheck's more interesting // features. `^&&^` is the conjunction operator for properties that turns // both properties into a larger property that only holds when both sub-properties @@ -56,9 +53,9 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // *** Passed 100 tests // (100% , Right identity, Left identity) return - (xs.getArray.reverse().reverse() == xs.getArray) "Left identity" + (xs.reverse().reverse() == xs) "Left identity" ^&&^ - (xs.getArray == xs.getArray.reverse().reverse()) "Right identity" + (xs == xs.reverse().reverse()) "Right identity" } ``` @@ -66,12 +63,12 @@ Because SwiftCheck doesn't require tests to return `Bool`, just `Testable`, we can produce tests for complex properties with ease: ```swift -property("Shrunken lists of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in +property("Shrunken lists of integers always contain [] or [0]") <- forAll { (l : [Int]) in // Here we use the Implication Operator `==>` to define a precondition for // this test. If the precondition fails the test is discarded. If it holds // the test proceeds. - return (!l.getArray.isEmpty && l.getArray != [0]) ==> { - let ls = self.shrinkArbitrary(l).map { $0.getArray } + return (!l.isEmpty && l != [0]) ==> { + let ls = self.shrinkArbitrary(l) return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) } } diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index ba885e1..17106e7 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -23,9 +23,9 @@ /// implementation of `shrink` is provided, SwiftCheck will default to an empty /// one - that is, no shrinking will occur. /// -/// As an example, take the `ArrayOf` implementation of shrink: +/// As an example, take `Array`'s implementation of shrink: /// -/// Arbitrary.shrink(ArrayOf([1, 2, 3])) +/// Arbitrary.shrink([1, 2, 3]) /// > [[], [2,3], [1,3], [1,2], [0,2,3], [1,0,3], [1,1,3], [1,2,0], [1,2,2]] /// /// SwiftCheck will search each case forward, one-by-one, and continue shrinking diff --git a/Sources/SwiftCheck/Modifiers.swift b/Sources/SwiftCheck/Modifiers.swift index 806829d..e69de79 100644 --- a/Sources/SwiftCheck/Modifiers.swift +++ b/Sources/SwiftCheck/Modifiers.swift @@ -37,16 +37,6 @@ /// return xs.map(f.getArrow) == xs.map(f.getArrow) /// } /// } -/// -/// Finally, modifiers nest to allow the generation of intricate structures that -/// would not otherwise be possible due to the limitations above. For example, -/// to generate an Array of Arrays of Dictionaries of Integers and Strings (a -/// type that normally looks like `Array>>`), -/// would look like this: -/// -/// property("Generating monstrous data types is possible") <- forAll { (xs : ArrayOf>>) in -/// /// We're gonna need a bigger boat. -/// } /// For types that either do not have a `CustomStringConvertible` instance or /// that wish to have no description to print, Blind will create a default @@ -115,48 +105,6 @@ extension Static : CoArbitrary { } } -/// Generates an array of arbitrary values of type A. -public struct ArrayOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying array of values. - public let getArray : [A] - - /// Retrieves the underlying array of values as a contiguous array. - public var getContiguousArray : ContiguousArray { - return ContiguousArray(self.getArray) - } - - /// Creates a new `ArrayOf` modifier from an underlying array of values. - public init(_ array : [A]) { - self.getArray = array - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getArray)" - } - - /// Returns a generator of `ArrayOf` values. - public static var arbitrary : Gen> { - return Array.arbitrary.map(ArrayOf.init) - } - - /// The default shrinking function for an `ArrayOf` values. - public static func shrink(_ bl : ArrayOf) -> [ArrayOf] { - return Array.shrink(bl.getArray).map(ArrayOf.init) - } -} - -extension ArrayOf : CoArbitrary { - /// Uses the underlying array of values to perturb a generator. - public static func coarbitrary(_ x : ArrayOf) -> ((Gen) -> Gen) { - let a = x.getArray - if a.isEmpty { - return { $0.variant(0) } - } - return comp({ $0.variant(1) }, ArrayOf.coarbitrary(ArrayOf([A](a[1.. : Arbitrary, CustomStringConvertible { /// Retrieves the underlying sorted array of values. @@ -193,121 +141,6 @@ public struct OrderedArrayOf : Arbitrary, CustomStri } } - -/// Generates an dictionary of arbitrary keys and values. -public struct DictionaryOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying dictionary of values. - public let getDictionary : Dictionary - - /// Creates a new `DictionaryOf` modifier from an underlying dictionary of - /// key-value pairs. - public init(_ dict : Dictionary) { - self.getDictionary = dict - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getDictionary)" - } - - /// Returns a generator for a `DictionaryOf` values. - public static var arbitrary : Gen> { - return Dictionary.arbitrary.map(DictionaryOf.init) - } - - /// The default shrinking function for a `DictionaryOf` values. - public static func shrink(_ d : DictionaryOf) -> [DictionaryOf] { - return Dictionary.shrink(d.getDictionary).map(DictionaryOf.init) - } -} - -extension DictionaryOf : CoArbitrary { - /// Uses the underlying array of values to perturb a generator. - public static func coarbitrary(_ x : DictionaryOf) -> ((Gen) -> Gen) { - return Dictionary.coarbitrary(x.getDictionary) - } -} - -/// Generates an Optional of arbitrary values of type A. -public struct OptionalOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying optional value. - public let getOptional : A? - - /// Creates a new `OptionalOf` modifier from an underlying `Optional` value. - public init(_ opt : A?) { - self.getOptional = opt - } - - /// A textual representation of `self`. - public var description : String { - return "\(String(describing: self.getOptional))" - } - - /// Returns a generator for `OptionalOf` values. - public static var arbitrary : Gen> { - return Optional.arbitrary.map(OptionalOf.init) - } - - /// The default shrinking function for `OptionalOf` values. - public static func shrink(_ bl : OptionalOf) -> [OptionalOf] { - return Optional.shrink(bl.getOptional).map(OptionalOf.init) - } -} - -extension OptionalOf : CoArbitrary { - /// Uses the underlying presence or lack of a value to perturb a generator. - public static func coarbitrary(_ x : OptionalOf) -> ((Gen) -> Gen) { - if let _ = x.getOptional { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - -/// Generates a set of arbitrary values of type A. -public struct SetOf : Arbitrary, CustomStringConvertible { - /// Retrieves the underlying set of values. - public let getSet : Set - - /// Creates a new `SetOf` modifier from an underlying set of values. - public init(_ set : Set) { - self.getSet = set - } - - /// A textual representation of `self`. - public var description : String { - return "\(self.getSet)" - } - - /// Returns a generator for a `SetOf` values. - public static var arbitrary : Gen> { - return Gen.sized { n in - return Gen.choose((0, n)).flatMap { k in - if k == 0 { - return Gen.pure(SetOf(Set([]))) - } - - return sequence(Array((0...k)).map { _ in A.arbitrary }).map(comp(SetOf.init, Set.init)) - } - } - } - - /// The default shrinking function for a `SetOf` values. - public static func shrink(_ s : SetOf) -> [SetOf] { - return ArrayOf.shrink(ArrayOf([A](s.getSet))).map({ SetOf(Set($0.getArray)) }) - } -} - -extension SetOf : CoArbitrary { - /// Uses the underlying set of values to perturb a generator. - public static func coarbitrary(_ x : SetOf) -> ((Gen) -> Gen) { - if x.getSet.isEmpty { - return { $0.variant(0) } - } - return { $0.variant(1) } - } -} - /// Generates pointers of varying size of random values of type T. public struct PointerOf : Arbitrary, CustomStringConvertible { fileprivate let _impl : PointerOfImpl diff --git a/Sources/SwiftCheck/Testable.swift b/Sources/SwiftCheck/Testable.swift index c3bd744..c1f4fd9 100644 --- a/Sources/SwiftCheck/Testable.swift +++ b/Sources/SwiftCheck/Testable.swift @@ -79,7 +79,7 @@ extension Bool : Testable { } } -extension Gen /*: Testable*/ where A : Testable { +extension Gen : Testable where A : Testable { public var property : Property { return Property(self.flatMap { $0.property.unProperty }) } diff --git a/Sources/SwiftCheck/Witness.swift b/Sources/SwiftCheck/Witness.swift deleted file mode 100644 index a654e0e..0000000 --- a/Sources/SwiftCheck/Witness.swift +++ /dev/null @@ -1,161 +0,0 @@ -// -// Witness.swift -// SwiftCheck -// -// Created by Robert Widmann on 7/26/15. -// Copyright © 2015 TypeLift. All rights reserved. -// - -/// Provides a way for higher-order types to implement the `Arbitrary` protocol. -/// -/// The `WitnessedArbitrary` protocol is a *HACK*, but a very necessary one. -/// Because Swift does not have Higher Kinded Types, but we need to know that, -/// say, the `Element`s underlying an `Array` are all `Arbitrary`, we -/// instead ask the conformee to hand over information about the type parameter -/// it wishes to guarantee is `Arbitrary` then SwiftCheck will synthesize a -/// function to act as a Witness that the parameter is in fact `Arbitrary`. -/// SwiftCheck presents a stronger but less general version of `forAll` that -/// must be implemented by the conformee to guarantee a type-safe interface with -/// the rest of the framework. -/// -/// Implementating the `WitnessedArbitrary` protocol functions much like -/// implementing the `Arbitrary` protocol, but with a little extra baggage. For -/// example, to implement the protocol for `Array`, we declare the usual -/// `arbitrary` and `shrink`: -/// -/// extension Array where Element : Arbitrary { -/// public static var arbitrary : Gen> { -/// return Gen.sized { n in -/// return Gen.choose((0, n)).flatMap { k in -/// if k == 0 { -/// return Gen.pure([]) -/// } -/// -/// return sequence((0...k).map { _ in Element.arbitrary }) -/// } -/// } -/// } -/// -/// public static func shrink(bl : Array) -> [[Element]] { -/// let rec : [[Element]] = shrinkOne(bl) -/// return Int.shrink(bl.count).reverse().flatMap({ k in removes(k.successor(), n: bl.count, xs: bl) }) + rec -/// } -/// } -/// -/// In addition, we declare a witnessed version of `forAll` that simply invokes -/// `forAllShrink` and `map`s the witness function to make sure all generated -/// `Array`s are made of `Arbitrary ` elements: -/// -/// extension Array : WitnessedArbitrary { -/// public typealias Param = Element -/// -/// public static func forAllWitnessed(wit : A -> Element, pf : ([Element] -> Testable)) -> Property { -/// return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in -/// return pf(bl.map(wit)) -/// }) -/// } -/// } -public protocol WitnessedArbitrary { - /// The witnessing type parameter. - associatedtype Param - - /// A property test that relies on a witness that the given type parameter - /// is actually `Arbitrary`. - static func forAllWitnessed(_ wit : @escaping (A) -> Param, pf : @escaping (Self) -> Testable) -> Property -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for that type. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A) -> Testable) -> Property - where A.Param : Arbitrary -{ - return A.forAllWitnessed({ $0 }, pf: pf) -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 2 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary -{ - return forAll { t in forAll { b in pf(t, b) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 3 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary -{ - return forAll { t in forAll { b, c in pf(t, b, c) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 4 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary -{ - return forAll { t in forAll { b, c, d in pf(t, b, c, d) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 5 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D, E) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary -{ - return forAll { t in forAll { b, c, d, e in pf(t, b, c, d, e) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 6 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D, E, F) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary -{ - return forAll { t in forAll { b, c, d, e, f in pf(t, b, c, d, e, f) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 7 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D, E, F, G) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary -{ - return forAll { t in forAll { b, c, d, e, f, g in pf(t, b, c, d, e, f, g) } } -} - -/// Converts a function into a universally quantified property using the default -/// shrinker and generator for 8 types. -/// -/// - parameter pf: A block that carries the property or invariant to be tested. -/// -/// - returns: A `Property` that executes the given testing block. -public func forAll(_ pf : @escaping (A, B, C, D, E, F, G, H) -> Testable) -> Property - where A.Param : Arbitrary, B.Param : Arbitrary, C.Param : Arbitrary, D.Param : Arbitrary, E.Param : Arbitrary, F.Param : Arbitrary, G.Param : Arbitrary, H.Param : Arbitrary -{ - return forAll { t in forAll { b, c, d, e, f, g, h in pf(t, b, c, d, e, f, g, h) } } -} diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index 5dea544..bc7f9a9 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -6,7 +6,7 @@ // Copyright © 2016 Typelift. All rights reserved. // -extension Array where Element : Arbitrary { +extension Array : Arbitrary where Element : Arbitrary { /// Returns a generator of `Array`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Element.arbitrary.proliferate @@ -19,19 +19,7 @@ extension Array where Element : Arbitrary { } } -extension Array : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Array`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping ([Element]) -> Testable) -> Property { - return forAllShrink([A].arbitrary, shrinker: [A].shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - -extension AnyBidirectionalCollection where Element : Arbitrary { +extension AnyBidirectionalCollection : Arbitrary where Element : Arbitrary { /// Returns a generator of `AnyBidirectionalCollection`s of arbitrary `Element`s. public static var arbitrary : Gen> { return [Element].arbitrary.map(AnyBidirectionalCollection.init) @@ -43,23 +31,7 @@ extension AnyBidirectionalCollection where Element : Arbitrary { } } -extension AnyBidirectionalCollection : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnyBidirectionalCollection`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnyBidirectionalCollection) -> Testable) -> Property { - return forAllShrink( - AnyBidirectionalCollection.arbitrary, - shrinker: AnyBidirectionalCollection.shrink, - f: { bl in - return pf(AnyBidirectionalCollection(bl.map(wit))) - } - ) - } -} - -extension AnySequence where Element : Arbitrary { +extension AnySequence : Arbitrary where Element : Arbitrary { /// Returns a generator of `AnySequence`s of arbitrary `Element`s. public static var arbitrary : Gen> { return [Element].arbitrary.map(AnySequence.init) @@ -71,19 +43,7 @@ extension AnySequence where Element : Arbitrary { } } -extension AnySequence : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `AnySequence`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (AnySequence) -> Testable) -> Property { - return forAllShrink(AnySequence.arbitrary, shrinker: AnySequence.shrink, f: { bl in - return pf(AnySequence(bl.map(wit))) - }) - } -} - -extension ArraySlice where Element : Arbitrary { +extension ArraySlice : Arbitrary where Element : Arbitrary { /// Returns a generator of `ArraySlice`s of arbitrary `Element`s. public static var arbitrary : Gen> { return [Element].arbitrary.map(ArraySlice.init) @@ -95,39 +55,15 @@ extension ArraySlice where Element : Arbitrary { } } -extension ArraySlice : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ArraySlice`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ArraySlice) -> Testable) -> Property { - return forAllShrink(ArraySlice.arbitrary, shrinker: ArraySlice.shrink, f: { bl in - return pf(ArraySlice(bl.map(wit))) - }) - } -} - -extension CollectionOfOne where Element : Arbitrary { +extension CollectionOfOne : Arbitrary where Element : Arbitrary { /// Returns a generator of `CollectionOfOne`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Element.arbitrary.map(CollectionOfOne.init) } } -extension CollectionOfOne : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `CollectionOfOne`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (CollectionOfOne) -> Testable) -> Property { - return forAllShrink(CollectionOfOne.arbitrary, shrinker: { _ in [] }, f: { (bl : CollectionOfOne) -> Testable in - return pf(CollectionOfOne(wit(bl[bl.startIndex]))) - }) - } -} - /// Generates an Optional of arbitrary values of type A. -extension Optional where Wrapped : Arbitrary { +extension Optional : Arbitrary where Wrapped : Arbitrary { /// Returns a generator of `Optional`s of arbitrary `Wrapped` values. public static var arbitrary : Gen> { return Gen>.frequency([ @@ -146,19 +82,7 @@ extension Optional where Wrapped : Arbitrary { } } -extension Optional : WitnessedArbitrary { - public typealias Param = Wrapped - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Optional`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Wrapped, pf : @escaping (Optional) -> Testable) -> Property { - return forAllShrink(Optional.arbitrary, shrinker: Optional.shrink, f: { bl in - return pf(bl.map(wit)) - }) - } -} - -extension ContiguousArray where Element : Arbitrary { +extension ContiguousArray : Arbitrary where Element : Arbitrary { /// Returns a generator of `ContiguousArray`s of arbitrary `Element`s. public static var arbitrary : Gen> { return [Element].arbitrary.map(ContiguousArray.init) @@ -170,20 +94,8 @@ extension ContiguousArray where Element : Arbitrary { } } -extension ContiguousArray : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `ContiguousArray`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (ContiguousArray) -> Testable) -> Property { - return forAllShrink(ContiguousArray.arbitrary, shrinker: ContiguousArray.shrink, f: { bl in - return pf(ContiguousArray(bl.map(wit))) - }) - } -} - /// Generates an dictionary of arbitrary keys and values. -extension Dictionary where Key : Arbitrary, Value : Arbitrary { +extension Dictionary : Arbitrary where Key : Arbitrary, Value : Arbitrary { /// Returns a generator of `Dictionary`s of arbitrary `Key`s and `Value`s. public static var arbitrary : Gen> { return [Key].arbitrary.flatMap { (k : [Key]) in @@ -207,7 +119,7 @@ extension EmptyCollection : Arbitrary { } } -extension Range where Bound : Arbitrary { +extension Range : Arbitrary where Bound : Arbitrary { /// Returns a generator of `HalfOpenInterval`s of arbitrary `Bound`s. public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in @@ -223,21 +135,21 @@ extension Range where Bound : Arbitrary { } } -extension LazyCollection where Base : Arbitrary { +extension LazyCollection : Arbitrary where Base : Arbitrary { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazyCollection.arbitrary } } -extension LazySequence where Base : Arbitrary { +extension LazySequence : Arbitrary where Base : Arbitrary { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { return LazySequence.arbitrary } } -extension Repeated where Element : Arbitrary { +extension Repeated : Arbitrary where Element : Arbitrary { /// Returns a generator of `Repeat`s of arbitrary `Element`s. public static var arbitrary : Gen> { let constructor: (Element, Int) -> Repeated = { (element, count) in @@ -248,20 +160,7 @@ extension Repeated where Element : Arbitrary { } } -extension Repeated : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Repeat`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Repeated) -> Testable) -> Property { - return forAllShrink(Repeated.arbitrary, shrinker: { _ in [] }, f: { bl in - let xs = bl.map(wit) - return pf(repeatElement(xs.first!, count: xs.count)) - }) - } -} - -extension Set where Element : Arbitrary { +extension Set : Arbitrary where Element : Arbitrary { /// Returns a generator of `Set`s of arbitrary `Element`s. public static var arbitrary : Gen> { return Gen.sized { n in @@ -281,18 +180,6 @@ extension Set where Element : Arbitrary { } } -extension Set : WitnessedArbitrary { - public typealias Param = Element - - /// Given a witness and a function to test, converts them into a universally - /// quantified property over `Set`s. - public static func forAllWitnessed(_ wit : @escaping (A) -> Element, pf : @escaping (Set) -> Testable) -> Property { - return forAll { (xs : [A]) in - return pf(Set(xs.map(wit))) - } - } -} - // MARK: - Implementation Details Follow private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index d575527..7b7f2a2 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ 6A761BAA1F14E92100A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6A761BAB1F14E92100A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; 6A761BAC1F14E92100A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; - 6A761BAD1F14E92100A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; 6A761BAE1F14E92100A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; 6A761BAF1F14E92100A7D74F /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B771F14E91400A7D74F /* Arbitrary.swift */; }; 6A761BB01F14E92200A7D74F /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B781F14E91400A7D74F /* Cartesian.swift */; }; @@ -39,7 +38,6 @@ 6A761BBB1F14E92200A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6A761BBC1F14E92200A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; 6A761BBD1F14E92200A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; - 6A761BBE1F14E92200A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; 6A761BBF1F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; 6A761BC01F14E92200A7D74F /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B771F14E91400A7D74F /* Arbitrary.swift */; }; 6A761BC11F14E92200A7D74F /* Cartesian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B781F14E91400A7D74F /* Cartesian.swift */; }; @@ -56,7 +54,6 @@ 6A761BCC1F14E92200A7D74F /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A761B831F14E91500A7D74F /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6A761BCD1F14E92200A7D74F /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B841F14E91500A7D74F /* Test.swift */; }; 6A761BCE1F14E92200A7D74F /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B851F14E91500A7D74F /* Testable.swift */; }; - 6A761BCF1F14E92200A7D74F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B861F14E91500A7D74F /* Witness.swift */; }; 6A761BD01F14E92200A7D74F /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */; }; 6A761BD11F14E93900A7D74F /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8D1F14E91500A7D74F /* BooleanIdentitySpec.swift */; }; 6A761BD21F14E93900A7D74F /* CartesianSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A761B8E1F14E91500A7D74F /* CartesianSpec.swift */; }; @@ -195,7 +192,6 @@ 6A761B831F14E91500A7D74F /* SwiftCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftCheck.h; sourceTree = ""; }; 6A761B841F14E91500A7D74F /* Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; }; 6A761B851F14E91500A7D74F /* Testable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; }; - 6A761B861F14E91500A7D74F /* Witness.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; }; 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WitnessedArbitrary.swift; sourceTree = ""; }; 6A761B881F14E91500A7D74F /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 6A761B8A1F14E91500A7D74F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -308,7 +304,6 @@ 6A761B821F14E91500A7D74F /* State.swift */, 6A761B841F14E91500A7D74F /* Test.swift */, 6A761B851F14E91500A7D74F /* Testable.swift */, - 6A761B861F14E91500A7D74F /* Witness.swift */, 6A761B871F14E91500A7D74F /* WitnessedArbitrary.swift */, ); path = SwiftCheck; @@ -669,7 +664,6 @@ 6A761BC31F14E92200A7D74F /* CoArbitrary.swift in Sources */, 6A761BC21F14E92200A7D74F /* Check.swift in Sources */, 6A761BC41F14E92200A7D74F /* Compose.swift in Sources */, - 6A761BCF1F14E92200A7D74F /* Witness.swift in Sources */, 6A761BCB1F14E92200A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -721,7 +715,6 @@ 6A761BA11F14E92100A7D74F /* CoArbitrary.swift in Sources */, 6A761BA01F14E92100A7D74F /* Check.swift in Sources */, 6A761BA21F14E92100A7D74F /* Compose.swift in Sources */, - 6A761BAD1F14E92100A7D74F /* Witness.swift in Sources */, 6A761BA91F14E92100A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -773,7 +766,6 @@ 6A761BB21F14E92200A7D74F /* CoArbitrary.swift in Sources */, 6A761BB11F14E92200A7D74F /* Check.swift in Sources */, 6A761BB31F14E92200A7D74F /* Compose.swift in Sources */, - 6A761BBE1F14E92200A7D74F /* Witness.swift in Sources */, 6A761BBA1F14E92200A7D74F /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Tests/SwiftCheckTests/FailureSpec.swift b/Tests/SwiftCheckTests/FailureSpec.swift index ea15409..f6e7e9c 100644 --- a/Tests/SwiftCheckTests/FailureSpec.swift +++ b/Tests/SwiftCheckTests/FailureSpec.swift @@ -57,17 +57,6 @@ class FailureSpec : XCTestCase { /// h/t @robrix for the suggestion ~( https://github.com/antitypical/Assertions/blob/master/AssertionsTests/AssertionsTests.swift ) /// and @ishikawa for the idea ~( https://github.com/antitypical/Assertions/pull/3#issuecomment-76337761 ) - #if os(Linux) - override func recordFailure( - withDescription description: String, inFile filePath: String?, atLine lineNumber: UInt, expected: Bool) { - if !expected { - assert(false, "Assertion should never throw.") - } else { - // super.recordFailureWithDescription(message, inFile: file, atLine: line, expected: expected) - failCount = (failCount + 1) - } - } - #else override func recordFailure( withDescription message : String, inFile file : String, atLine line : Int, expected : Bool) { if !expected { @@ -77,7 +66,6 @@ class FailureSpec : XCTestCase { failCount = (failCount + 1) } } - #endif override func tearDown() { XCTAssert(failCount == tests.count) diff --git a/Tests/SwiftCheckTests/GenSpec.swift b/Tests/SwiftCheckTests/GenSpec.swift index 567af82..93d0fca 100644 --- a/Tests/SwiftCheckTests/GenSpec.swift +++ b/Tests/SwiftCheckTests/GenSpec.swift @@ -147,12 +147,12 @@ class GenSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("oneOf n") <- forAll { (xss : ArrayOf) in - if xss.getArray.isEmpty { + property("oneOf n") <- forAll { (xss : [Int]) in + if xss.isEmpty { return Discard() } - let l = Set(xss.getArray) - return forAll(Gen.one(of: xss.getArray.map(Gen.pure))) { l.contains($0) } + let l = Set(xss) + return forAll(Gen.one(of: xss.map(Gen.pure))) { l.contains($0) } } // CHECK-NEXT: *** Passed 100 tests @@ -166,14 +166,14 @@ class GenSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . property("Gen.proliferateSized n generates arrays of length n") <- forAll(Gen.choose((0, 100))) { n in - let g = Int.arbitrary.proliferate(withSize: n).map(ArrayOf.init) - return forAll(g) { $0.getArray.count == n } + let g = Int.arbitrary.proliferate(withSize: n) + return forAll(g) { $0.count == n } } // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferate(withSize: 0).map(ArrayOf.init)) { - return $0.getArray.isEmpty + property("Gen.proliferateSized 0 generates only empty arrays") <- forAll(Int.arbitrary.proliferate(withSize: 0)) { + return $0.isEmpty } // CHECK-NEXT: *** Passed 100 tests diff --git a/Tests/SwiftCheckTests/ModifierSpec.swift b/Tests/SwiftCheckTests/ModifierSpec.swift index 3363791..a5827b6 100644 --- a/Tests/SwiftCheckTests/ModifierSpec.swift +++ b/Tests/SwiftCheckTests/ModifierSpec.swift @@ -53,22 +53,22 @@ class ModifierSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("ArrayOf modifiers nest") <- forAll { (xxxs : ArrayOf>) in + property("ArrayOf modifiers nest") <- forAll { (xxs : [[Int8]]) in return true } // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: (100%, {{Left|Right}} identity, {{Left|Right}} identity) - property("The reverse of the reverse of an array is that array") <- forAll { (xs : ArrayOf) in - return (xs.getArray.reversed().reversed() == xs.getArray) "Left identity" + property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in + return (xs.reversed().reversed() == xs) "Left identity" ^&&^ - (xs.getArray == xs.getArray.reversed().reversed()) "Right identity" + (xs == xs.reversed().reversed()) "Right identity" } // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("map behaves") <- forAll { (xs : ArrayOf, f : ArrowOf) in - return xs.getArray.map(f.getArrow) == xs.getArray.map(f.getArrow) + property("map behaves") <- forAll { (xs : [Int], f : ArrowOf) in + return xs.map(f.getArrow) == xs.map(f.getArrow) } // CHECK-NEXT: *** Passed 100 tests @@ -81,9 +81,9 @@ class ModifierSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in + property("filter behaves") <- forAll { (xs : [Int], pred : ArrowOf) in let f = pred.getArrow - return (xs.getArray.filter(f).reduce(true, { (acc, val) in acc && f(val) }) as Bool) + return (xs.filter(f).reduce(true, { (acc, val) in acc && f(val) }) as Bool) } }) } diff --git a/Tests/SwiftCheckTests/ShrinkSpec.swift b/Tests/SwiftCheckTests/ShrinkSpec.swift index eb26b7d..182f9d3 100644 --- a/Tests/SwiftCheckTests/ShrinkSpec.swift +++ b/Tests/SwiftCheckTests/ShrinkSpec.swift @@ -49,9 +49,9 @@ class ShrinkSpec : XCTestCase { // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . - property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : ArrayOf) in - return (!l.getArray.isEmpty && l.getArray != [0]) ==> { - let ls = self.shrinkArbitrary(l).map { $0.getArray } + property("Shrunken arrays of integers always contain [] or [0]") <- forAll { (l : [Int]) in + return (!l.isEmpty && l != [0]) ==> { + let ls = self.shrinkArbitrary(l) return (ls.filter({ $0 == [] || $0 == [0] }).count >= 1) } } diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index 918169f..f9b0f29 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -13,11 +13,11 @@ import FileCheck #endif private func pack(_ f : @escaping (A, B) -> C) -> ((A, B)) -> C { - return f + return { xs in f(xs.0, xs.1) } } private func pack(_ f : @escaping (A, B, C, D, E, F, G, H, I, J, K, L, M, N) -> O) -> ((A, B, C, D, E, F, G, H, I, J, K, L, M, N)) -> O { - return f + return { xs in f(xs.0, xs.1, xs.2, xs.3, xs.4, xs.5, xs.6, xs.7, xs.8, xs.9, xs.10, xs.11, xs.12, xs.13) } } public struct ArbitraryFoo { From b6b4bc61dc0a41889040a38ebe8f5926ae713d2c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 15 Feb 2018 00:58:16 -0500 Subject: [PATCH 427/460] Try an update to Xcode 9.3 --- .swift-version | 2 +- .travis.yml | 27 +++++++------------ Package.swift | 2 +- Sources/SwiftCheck/Modifiers.swift | 6 ++--- SwiftCheck.xcodeproj/project.pbxproj | 6 ++++- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ .../xcschemes/SwiftCheck-iOS.xcscheme | 4 +-- .../xcschemes/SwiftCheck-tvOS.xcscheme | 4 +-- .../xcschemes/SwiftCheck.xcscheme | 4 +-- Tests/SwiftCheckTests/FormatterSpec.swift | 4 +-- Tests/SwiftCheckTests/LambdaSpec.swift | 2 +- Tests/SwiftCheckTests/PropertySpec.swift | 2 +- Tutorial.playground/Contents.swift | 10 +++---- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++ 14 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Tutorial.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/.swift-version b/.swift-version index 5186d07..7d5c902 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.0 +4.1 diff --git a/.travis.yml b/.travis.yml index 5a42c8d..845282e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode9 + osx_image: xcode9.3 before_install: - git submodule update --init --recursive - pushd Utilities @@ -16,7 +16,7 @@ matrix: - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode9 + osx_image: xcode9.3 before_install: - git submodule update --init --recursive - pushd Utilities @@ -25,19 +25,10 @@ matrix: script: - set -o pipefail - xcodebuild test -scheme SwiftCheck | xcpretty -c - # -- Start iOS -- - # !!!: Make sure desired device name & OS version are suitable for the Xcode version installed on osx_image - - iOS_DEVICE_NAME="iPad Pro (12.9-inch) (2nd generation)" - - iOS_RUNTIME_VERSION="11.0" - # Get simulator identifier for desired device/runtime pair - - SIMULATOR_ID=$(xcrun instruments -s | grep -o "${iOS_DEVICE_NAME} (${iOS_RUNTIME_VERSION}) \[.*\]" | grep -o "\[.*\]" | sed "s/^\[\(.*\)\]$/\1/") - - echo $SIMULATOR_ID - - echo $iOS_DEVICE_NAME - - echo $iOS_RUNTIME_VERSION - - xcodebuild build-for-testing -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c - - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=${iOS_DEVICE_NAME},OS=${iOS_RUNTIME_VERSION}" | xcpretty -c - - xcodebuild build-for-testing -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c - - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c + - xcodebuild build-for-testing -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=iPad Pro (12.9-inch) (2nd generation)" | xcpretty -c + - xcodebuild test -scheme SwiftCheck-iOS -destination "platform=iOS Simulator,name=iPad Pro (12.9-inch) (2nd generation)" | xcpretty -c + - xcodebuild build-for-testing -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 4K (at 1080p)' | xcpretty -c + - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 4K (at 1080p)' | xcpretty -c - os: linux language: generic sudo: required @@ -45,9 +36,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04.tar.gz - - tar xzf swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2017-11-16-a-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-4.1-release/ubuntu1404/swift-4.1-RELEASE/swift-4.1-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-4.1-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-4.1-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/Package.swift b/Package.swift index f114597..2afb8c5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.0 +// swift-tools-version:4.1 import PackageDescription diff --git a/Sources/SwiftCheck/Modifiers.swift b/Sources/SwiftCheck/Modifiers.swift index e69de79..b37c829 100644 --- a/Sources/SwiftCheck/Modifiers.swift +++ b/Sources/SwiftCheck/Modifiers.swift @@ -496,10 +496,8 @@ private final class PointerOfImpl : Arbitrary { } deinit { - if self.size > 0 && self.ptr != nil { - self.ptr?.deallocate(capacity: self.size) - self.ptr = nil - } + self.ptr?.deallocate() + self.ptr = nil } static var arbitrary : Gen> { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 7b7f2a2..a0fe41b 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -532,7 +532,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -941,12 +941,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -995,12 +997,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/SwiftCheck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index e1d02b1..4a0ec67 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ { func format(_ value : Value) -> String { let formatted = makeString(value) - let maxIndex = formatted.index(formatted.startIndex, offsetBy: String.IndexDistance(lengthLimit)) + let maxIndex = formatted.index(formatted.startIndex, offsetBy: Int(lengthLimit)) if maxIndex >= formatted.endIndex { return formatted } else { @@ -76,7 +76,7 @@ class FormatterSpec : XCTestCase { let formatter = af.get let string = formatter.format(x) _ = formatter.unFormat(string) - return string.distance(from: string.startIndex, to: string.endIndex) <= String.IndexDistance(formatter.lengthLimit) + return string.distance(from: string.startIndex, to: string.endIndex) <= Int(formatter.lengthLimit) } }) diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index 618ca55..cac0381 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -82,7 +82,7 @@ extension Exp : Arbitrary { return [a] + Exp.shrink(a).map { .lam(x, $0) } case let .app(a, b): let part1 : [Exp] = [a, b] - + [a].flatMap({ (expr : Exp) -> Exp? in + + [a].compactMap({ (expr : Exp) -> Exp? in if case let .lam(x, a) = expr { return a.subst(x, b) } diff --git a/Tests/SwiftCheckTests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift index 909941f..344fe89 100644 --- a/Tests/SwiftCheckTests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -62,7 +62,7 @@ class PropertySpec : XCTestCase { // CHECK-NEXT: . property("Again undoes once") <- forAll { (n : Int) in var counter : Int = 0 - quickCheck(forAll { (_ : Int) in + quickCheck(asserting: "", property: forAll { (_ : Int) in counter += 1 return true }.once.again) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index d62b475..7c07839 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -336,11 +336,11 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs //: Because `forAll` is variadic it works for a large number and variety of types too: -// +--- This Modifier Type produces Arrays of Integers. -// | +--- This Modifier Type generates functions. That's right, SwiftCheck -// | | can generate *functions*!! -// v v -property("filter behaves") <- forAll { (xs : ArrayOf, pred : ArrowOf) in +// +--- Produce arrays of integers. +// | +--- This Modifier Type generates functions. That's right, SwiftCheck +// | | can generate *functions*!! +// v v +property("filter behaves") <- forAll { (xs : [Int], pred : ArrowOf) in let f = pred.getArrow return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) // ^ This property says that if we filter an array then apply the predicate diff --git a/Tutorial.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Tutorial.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Tutorial.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 9e2122d3b359d357ffdbcb7754e45fded39d2992 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 28 Apr 2018 14:40:43 -0400 Subject: [PATCH 428/460] Bump podspec version --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 8a4494d..2663e79 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.9.1" + s.version = "0.10.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 57b86a0e0923893b7ff878c418c6caaad5911498 Mon Sep 17 00:00:00 2001 From: Dan Jackson Date: Thu, 10 May 2018 15:49:06 -0700 Subject: [PATCH 429/460] Fix Tutorial playground for removal of `ArrayOf<>` This case was changed from `ArrayOf` to `[Int]`, but the corresponding `getArray` stuck around. From #264, on this line https://github.com/CodaFi/SwiftCheck/commit/b6b4bc61dc0a41889040a38ebe8f5926ae713d2c#diff-47970fd31917fb63ccf81bd68065f0abR343 --- Tutorial.playground/Contents.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tutorial.playground/Contents.swift b/Tutorial.playground/Contents.swift index 7c07839..b4488d8 100644 --- a/Tutorial.playground/Contents.swift +++ b/Tutorial.playground/Contents.swift @@ -342,7 +342,7 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // v v property("filter behaves") <- forAll { (xs : [Int], pred : ArrowOf) in let f = pred.getArrow - return xs.getArray.filter(f).reduce(true, { $0 && f($1) }) + return xs.filter(f).reduce(true, { $0 && f($1) }) // ^ This property says that if we filter an array then apply the predicate // to all its elements, then they should all respond with `true`. } From 2c505de5a808ef26b0d34730db6db19950984b9c Mon Sep 17 00:00:00 2001 From: Sebastian Grail Date: Wed, 8 Aug 2018 22:05:22 +1000 Subject: [PATCH 430/460] Rename static map to zipWith --- Sources/SwiftCheck/Gen.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 24b775c..da15f96 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -172,9 +172,13 @@ extension Gen { } } + @available(*, deprecated, renamed: "zipWith") + public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { + return Gen.zipWith(ga1, ga2, transform: transform) + } /// Returns a new generator that applies a given function to any outputs the /// given generators produce. - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { + public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { return Gen<(A1, A2)>.zip(ga1, ga2).map({ t in transform(t.0, t.1) }) } } From a662ceca8ea336d586cdf8bcf51bf98e06cc8320 Mon Sep 17 00:00:00 2001 From: Sebastian Grail Date: Thu, 16 Aug 2018 13:44:39 +1000 Subject: [PATCH 431/460] Fix vary function (#268) * Switch to a prefix-free code for variant This commit fixes a bug where `vary(k, rng)` always returns `rng.split.0` which in turn led to `Gen.variant(seed)` ignoring the `seed` argument See https://github.com/nick8325/quickcheck/commit/71477ceb62c68cdceaf2c3454a0c10d0e55b0326 for the corresponding change in QuickCheck --- Sources/SwiftCheck/Gen.swift | 48 ++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index da15f96..4f5f0db 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -189,7 +189,7 @@ extension Gen { /// Shakes up the generator's internal Random Number Generator with a seed. public func variant(_ seed : S) -> Gen { return Gen(unGen: { rng, n in - return self.unGen(vary(seed, rng), n) + return self.unGen(rng.vary(seed), n) }) } @@ -416,10 +416,48 @@ private func delay() -> Gen<(Gen) -> A> { }) } -private func vary(_ k : S, _ rng : StdGen) -> StdGen { - let s = rng.split - let gen = ((k % 2) == 0) ? s.0 : s.1 - return (k == (k / 2)) ? gen : vary(k / 2, rng) +extension StdGen { + fileprivate func vary(_ seed : S) -> StdGen { + if seed >= 0 { + return variant(bool: false).variant(nat: seed) + } else if seed == -1 { + return variant(bool: true).variant(nat: 0) + } else { + return variant(bool: true).variant(int: (-Int(seed)) - 1) + } + } + + private func variant(bool : Bool) -> StdGen { + return bool ? split.0 : split.1 + } + + private func variant(nat n : N) -> StdGen { + if stop(n) { + return chip(true, seed: Int(n)) + } else { + return variant(int: Int(n)) + } + } + + private func variant(int n : Int) -> StdGen { + if stop(n) { + return chip(true, seed: n) + } else { + return chip(false, seed: n).variant(int: chop(n)) + } + } + + private func chip(_ finished : Bool, seed n : Int) -> StdGen { + return variant(bool: n%2 == 0).variant(bool: finished) + } +} + +private func chop(_ n : Int) -> Int { + return n / 2 +} + +private func stop(_ n: N) -> Bool { + return n <= 1 } private func size(_ k : Int, _ m : Int) -> Int { From 73f5cf8d249f3d9a61b016f1ef786063990f77b1 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 25 Aug 2018 17:22:30 -0600 Subject: [PATCH 432/460] Provide actual Arbitrary conformances for Lazy* --- Sources/SwiftCheck/WitnessedArbitrary.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index bc7f9a9..eedb7a3 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -124,7 +124,7 @@ extension Range : Arbitrary where Bound : Arbitrary { public static var arbitrary : Gen> { return Bound.arbitrary.flatMap { l in return Bound.arbitrary.flatMap { r in - return Gen.pure((min(l, r) ..< max(l, r))) + return Gen.pure((Swift.min(l, r) ..< Swift.max(l, r))) } } } @@ -138,14 +138,14 @@ extension Range : Arbitrary where Bound : Arbitrary { extension LazyCollection : Arbitrary where Base : Arbitrary { /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. public static var arbitrary : Gen> { - return LazyCollection.arbitrary + return Base.arbitrary.map({ $0.lazy }) } } extension LazySequence : Arbitrary where Base : Arbitrary { /// Returns a generator of `LazySequence`s of arbitrary `Base`s. public static var arbitrary : Gen> { - return LazySequence.arbitrary + return Base.arbitrary.map({ $0.lazy }) } } From 79b306c9f34236f089c2529224f62f510a2b48b7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 19 Sep 2018 13:39:05 -0400 Subject: [PATCH 433/460] Update to Swift 4.2 --- .swift-version | 2 +- .travis.yml | 13 +- Cartfile.resolved | 2 +- Carthage/Checkouts/FileCheck | 2 +- Package.swift | 2 +- Sources/SwiftCheck/Cartesian.swift | 410 --------------------------- Sources/SwiftCheck/Check.swift | 9 - Sources/SwiftCheck/Gen.swift | 4 - SwiftCheck.xcodeproj/project.pbxproj | 24 +- Templates/Cartesian.swift.gyb | 11 - 10 files changed, 23 insertions(+), 456 deletions(-) diff --git a/.swift-version b/.swift-version index 7d5c902..bf77d54 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.1 +4.2 diff --git a/.travis.yml b/.travis.yml index 845282e..0e320cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,18 +5,19 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode9.3 + osx_image: xcode10 before_install: - git submodule update --init --recursive - pushd Utilities - ./compile.sh - popd script: - - pod lib lint +# FIXME: Re-enable when pods 1.6.0 is out of beta +# - pod lib lint - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode9.3 + osx_image: xcode10 before_install: - git submodule update --init --recursive - pushd Utilities @@ -36,9 +37,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-4.1-release/ubuntu1404/swift-4.1-RELEASE/swift-4.1-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-4.1-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-4.1-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-4.2-release/ubuntu1404/swift-4.2-RELEASE/swift-4.2-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-4.2-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-4.2-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/Cartfile.resolved b/Cartfile.resolved index 11ebc19..0cb4861 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "trill-lang/FileCheck" "0.0.4" +github "trill-lang/FileCheck" "0.0.8" diff --git a/Carthage/Checkouts/FileCheck b/Carthage/Checkouts/FileCheck index 0830734..89b8480 160000 --- a/Carthage/Checkouts/FileCheck +++ b/Carthage/Checkouts/FileCheck @@ -1 +1 @@ -Subproject commit 083073480112406580f0242036a079f9f8b170ad +Subproject commit 89b8480055f9adf8ce2f9ad5e2fac7ac1076242e diff --git a/Package.swift b/Package.swift index 2afb8c5..003c2d8 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.1 +// swift-tools-version:4.2 import PackageDescription diff --git a/Sources/SwiftCheck/Cartesian.swift b/Sources/SwiftCheck/Cartesian.swift index 67699df..47db722 100644 --- a/Sources/SwiftCheck/Cartesian.swift +++ b/Sources/SwiftCheck/Cartesian.swift @@ -28,17 +28,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, transform : @escaping (A1, A2, A3) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -65,18 +54,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, transform : @escaping (A1, A2, A3, A4) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -105,19 +82,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, transform : @escaping (A1, A2, A3, A4, A5) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -148,20 +112,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -194,21 +144,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -243,22 +178,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -295,23 +214,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -350,24 +252,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -408,25 +292,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -469,26 +334,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -533,27 +378,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -600,28 +424,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -670,29 +472,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -743,30 +522,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -819,31 +574,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -898,32 +628,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - /// - parameter ga18: A generator of values of type `A18`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -980,33 +684,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - /// - parameter ga18: A generator of values of type `A18`. - /// - parameter ga19: A generator of values of type `A19`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -1065,34 +742,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - /// - parameter ga18: A generator of values of type `A18`. - /// - parameter ga19: A generator of values of type `A19`. - /// - parameter ga20: A generator of values of type `A20`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -1153,35 +802,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - /// - parameter ga18: A generator of values of type `A18`. - /// - parameter ga19: A generator of values of type `A19`. - /// - parameter ga20: A generator of values of type `A20`. - /// - parameter ga21: A generator of values of type `A21`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// @@ -1244,36 +864,6 @@ extension Gen /*: Cartesian*/ { } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// - /// - parameter ga1: A generator of values of type `A1`. - /// - parameter ga2: A generator of values of type `A2`. - /// - parameter ga3: A generator of values of type `A3`. - /// - parameter ga4: A generator of values of type `A4`. - /// - parameter ga5: A generator of values of type `A5`. - /// - parameter ga6: A generator of values of type `A6`. - /// - parameter ga7: A generator of values of type `A7`. - /// - parameter ga8: A generator of values of type `A8`. - /// - parameter ga9: A generator of values of type `A9`. - /// - parameter ga10: A generator of values of type `A10`. - /// - parameter ga11: A generator of values of type `A11`. - /// - parameter ga12: A generator of values of type `A12`. - /// - parameter ga13: A generator of values of type `A13`. - /// - parameter ga14: A generator of values of type `A14`. - /// - parameter ga15: A generator of values of type `A15`. - /// - parameter ga16: A generator of values of type `A16`. - /// - parameter ga17: A generator of values of type `A17`. - /// - parameter ga18: A generator of values of type `A18`. - /// - parameter ga19: A generator of values of type `A19`. - /// - parameter ga20: A generator of values of type `A20`. - /// - parameter ga21: A generator of values of type `A21`. - /// - parameter ga22: A generator of values of type `A22`. - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, _ ga3 : Gen, _ ga4 : Gen, _ ga5 : Gen, _ ga6 : Gen, _ ga7 : Gen, _ ga8 : Gen, _ ga9 : Gen, _ ga10 : Gen, _ ga11 : Gen, _ ga12 : Gen, _ ga13 : Gen, _ ga14 : Gen, _ ga15 : Gen, _ ga16 : Gen, _ ga17 : Gen, _ ga18 : Gen, _ ga19 : Gen, _ ga20 : Gen, _ ga21 : Gen, _ ga22 : Gen, transform : @escaping (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, ga3, ga4, ga5, ga6, ga7, ga8, ga9, ga10, ga11, ga12, ga13, ga14, ga15, ga16, ga17, ga18, ga19, ga20, ga21, ga22, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// diff --git a/Sources/SwiftCheck/Check.swift b/Sources/SwiftCheck/Check.swift index ec78ee5..60635f3 100644 --- a/Sources/SwiftCheck/Check.swift +++ b/Sources/SwiftCheck/Check.swift @@ -194,15 +194,6 @@ public func <- (checker : ReportiveQuickCheck, test : @autoclosure @escaping () _ = quickCheckWithResult(checker.args, test()) } -/// Tests a property and prints the results to stdout. -/// -/// - parameter prop: The property to be tested. -/// - parameter name: The name of the property being tested. -@available(*, deprecated, message: "Use quickCheck(asserting:) or quickCheck(reporting:) instead.") -public func quickCheck(_ prop : Testable, name : String = "") { - _ = quickCheckWithResult(CheckerArguments(name: name), prop) -} - /// The interface for properties to be run through SwiftCheck with an XCTest /// assert. The property will still generate console output during testing. /// diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index 4f5f0db..a13dfa9 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -172,10 +172,6 @@ extension Gen { } } - @available(*, deprecated, renamed: "zipWith") - public static func map(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { - return Gen.zipWith(ga1, ga2, transform: transform) - } /// Returns a new generator that applies a given function to any outputs the /// given generators produce. public static func zipWith(_ ga1 : Gen, _ ga2 : Gen, transform: @escaping (A1, A2) -> A) -> Gen { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index a0fe41b..f4dfd6d 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -847,7 +847,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -880,7 +880,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -903,7 +903,7 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -923,7 +923,7 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -1062,7 +1062,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1095,7 +1095,7 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1120,7 +1120,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1142,7 +1142,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1178,7 +1178,7 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1212,7 +1212,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1243,7 +1243,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1266,7 +1266,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 4.2; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Templates/Cartesian.swift.gyb b/Templates/Cartesian.swift.gyb index 9c46c50..bf887f6 100644 --- a/Templates/Cartesian.swift.gyb +++ b/Templates/Cartesian.swift.gyb @@ -51,17 +51,6 @@ zip_with_argument_list = ', '.join(['ga{0}'.format(n) for n in range(1, arity + } } - /// Returns a new generator that applies a given function to any outputs the - /// given generators produce. - /// -% for (t, p) in zip(types_list, ['ga{0}'.format(n) for n in range(1, arity + 1)]): - /// - parameter ${p}: A generator of values of type `${t}`. -% end - @available(*, deprecated, renamed: "zipWith") - public static func map<${type_parameter_list}>(${parameter_list}, transform : @escaping (${type_parameter_list}) -> A) -> Gen { - return Gen.zipWith(${zip_with_argument_list}, transform: transform) - } - /// Returns a new generator that applies a given function to any outputs the /// given generators produce. /// From 35f01510bb7eeda5fbf7b443440576afd3420244 Mon Sep 17 00:00:00 2001 From: Brian Gerstle Date: Mon, 26 Nov 2018 15:19:00 -0600 Subject: [PATCH 434/460] Always add labels to test cases, but only stamp if condition is true Otherwise, `cover` will yield a false positive if the condition was never true and the percentage > 0 (because the label was never added). --- Sources/SwiftCheck/Property.swift | 27 +++++++++++------------- Tests/SwiftCheckTests/PropertySpec.swift | 8 +++++++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Sources/SwiftCheck/Property.swift b/Sources/SwiftCheck/Property.swift index 9faf894..e710d77 100644 --- a/Sources/SwiftCheck/Property.swift +++ b/Sources/SwiftCheck/Property.swift @@ -311,22 +311,19 @@ extension Testable { /// /// - returns: A property that carries a label dependent upon the condition. public func cover(_ condition : Bool, percentage : Int, label : String) -> Property { - if condition { - return self.mapResult { res in - return TestResult( - ok: res.ok, - expect: res.expect, - reason: res.reason, - theException: res.theException, - labels: insertWith(max, k: label, v: percentage, m: res.labels), - stamp: res.stamp.union([label]), - callbacks: res.callbacks, - abort: res.abort, - quantifier: res.quantifier - ) - } + return self.mapResult { res in + return TestResult( + ok: res.ok, + expect: res.expect, + reason: res.reason, + theException: res.theException, + labels: insertWith(max, k: label, v: percentage, m: res.labels), + stamp: condition ? res.stamp.union([label]) : res.stamp, + callbacks: res.callbacks, + abort: res.abort, + quantifier: res.quantifier + ) } - return self.property } /// Applies a function that modifies the property generator's inner `Prop`. diff --git a/Tests/SwiftCheckTests/PropertySpec.swift b/Tests/SwiftCheckTests/PropertySpec.swift index 344fe89..be6eb61 100644 --- a/Tests/SwiftCheckTests/PropertySpec.swift +++ b/Tests/SwiftCheckTests/PropertySpec.swift @@ -132,6 +132,14 @@ class PropertySpec : XCTestCase { return (s.count == [Int](s).count).cover(s.count >= 15, percentage: 70, label: "large") }.expectFailure + // CHECK-NEXT: +++ OK, failed as expected. + // CHECK-NEXT: *** Insufficient coverage after 100 tests + // CHECK-NEXT: (only {{[0-9]+}}% something happened, not {{[0-9]+}}%) + property("Cover reports failures for conditions that never happen") <- forAll { (s : Set) in + let somethingHappened = false + return (s.count == [Int](s).count).cover(somethingHappened, percentage: 1, label: "something happened") + }.expectFailure + // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: . property("Prop ==> true") <- forAllNoShrink(Bool.arbitrary, Gen.pure(true)) { (p1, p2) in From 9493ce0f9870de18fd5d71ea772d30ca4706bcab Mon Sep 17 00:00:00 2001 From: Oleg Dreyman Date: Thu, 13 Dec 2018 14:30:29 -0800 Subject: [PATCH 435/460] Bump version in .posdpec --- SwiftCheck.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 2663e79..4887352 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.10.0" + s.version = "0.11.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From 4ea2eebbe669e98f308c0749cc44009c04edcf5d Mon Sep 17 00:00:00 2001 From: Grigory Entin Date: Mon, 21 Jan 2019 04:47:42 +0100 Subject: [PATCH 436/460] Updated references to `one(of:)`. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d84c128..de0292f 100644 --- a/README.md +++ b/README.md @@ -77,13 +77,13 @@ property("Shrunken lists of integers always contain [] or [0]") <- forAll { (l : Properties can even depend on other properties: ```swift -property("Gen.oneOf multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in +property("Gen.one(of:) multiple generators picks only given generators") <- forAll { (n1 : Int, n2 : Int) in let g1 = Gen.pure(n1) let g2 = Gen.pure(n2) // Here we give `forAll` an explicit generator. Before SwiftCheck was using // the types of variables involved in the property to create an implicit // Generator behind the scenes. - return forAll(Gen.oneOf([g1, g2])) { $0 == n1 || $0 == n2 } + return forAll(Gen.one(of: [g1, g2])) { $0 == n1 || $0 == n2 } } ``` From c34b4adc026234d107ea387c42ae35ea4ae635c7 Mon Sep 17 00:00:00 2001 From: Grigory Entin Date: Mon, 21 Jan 2019 04:58:16 +0100 Subject: [PATCH 437/460] Updated references to `one(of:)` in the docs. --- Sources/SwiftCheck/Gen.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftCheck/Gen.swift b/Sources/SwiftCheck/Gen.swift index a13dfa9..b632c5a 100644 --- a/Sources/SwiftCheck/Gen.swift +++ b/Sources/SwiftCheck/Gen.swift @@ -69,7 +69,7 @@ public struct Gen { public static func one(of gs : S) -> Gen where S.Iterator.Element == Gen, S.Index : RandomType { - assert(gs.count != 0, "oneOf used with empty list") + assert(gs.count != 0, "one(of:) used with empty list") return Gen.choose((gs.startIndex, gs.index(before: gs.endIndex))).flatMap { x in return gs[x] @@ -81,7 +81,7 @@ public struct Gen { /// /// Only use this function when you need to assign uneven "weights" to each /// generator. If all generators need to have an equal chance of being - /// selected, use `Gen.oneOf`. + /// selected, use `Gen.one(of:)`. public static func frequency(_ xs : S) -> Gen where S.Iterator.Element == (Int, Gen) { From 8a3867017e8622df4b8b01a3b20708e8513e7ca1 Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 12:25:41 +1100 Subject: [PATCH 438/460] migrate to swift 5 --- Sources/SwiftCheck/Modifiers.swift | 2 +- Sources/SwiftCheck/WitnessedArbitrary.swift | 7 ------ SwiftCheck.xcodeproj/project.pbxproj | 22 +++++++++---------- .../xcschemes/SwiftCheck-iOS.xcscheme | 2 +- .../xcschemes/SwiftCheck-tvOS.xcscheme | 2 +- .../xcschemes/SwiftCheck.xcscheme | 2 +- Tests/SwiftCheckTests/ComplexSpec.swift | 6 ++--- Tests/SwiftCheckTests/LambdaSpec.swift | 4 ++-- 8 files changed, 19 insertions(+), 28 deletions(-) diff --git a/Sources/SwiftCheck/Modifiers.swift b/Sources/SwiftCheck/Modifiers.swift index b37c829..762d688 100644 --- a/Sources/SwiftCheck/Modifiers.swift +++ b/Sources/SwiftCheck/Modifiers.swift @@ -462,7 +462,7 @@ fileprivate final class IsoOfImpl) -> [IsoOfImpl] { return f.table.flatMap { (t) -> [IsoOfImpl] in let (x, y) = t - return Zip2Sequence(_sequence1: T.shrink(x), _sequence2: U.shrink(y)).map({ t in + return zip(T.shrink(x), U.shrink(y)).map({ t in let (y1 , y2) = t return IsoOfImpl( { (z : T) -> U in diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index eedb7a3..03524c4 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -142,13 +142,6 @@ extension LazyCollection : Arbitrary where Base : Arbitrary { } } -extension LazySequence : Arbitrary where Base : Arbitrary { - /// Returns a generator of `LazySequence`s of arbitrary `Base`s. - public static var arbitrary : Gen> { - return Base.arbitrary.map({ $0.lazy }) - } -} - extension Repeated : Arbitrary where Element : Arbitrary { /// Returns a generator of `Repeat`s of arbitrary `Element`s. public static var arbitrary : Gen> { diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index f4dfd6d..aef97bf 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -532,7 +532,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -554,17 +554,17 @@ }; 84DF75F71B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0900; + LastSwiftMigration = 1020; }; 84DF76011B0BD54600C912B0 = { CreatedOnToolsVersion = 6.4; - LastSwiftMigration = 0900; + LastSwiftMigration = 1020; }; }; }; buildConfigurationList = 844FCC87198B320500EB242A /* Build configuration list for PBXProject "SwiftCheck" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -933,6 +933,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -989,6 +990,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -1177,8 +1179,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1211,8 +1212,7 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1242,8 +1242,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -1265,8 +1264,7 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index 4a0ec67..bf406fc 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ .one(of: [ lower, numeric, Gen.pure("-"), - ]).proliferateNonEmpty.map(String.init(stringInterpolationSegment:)) + ]).proliferateNonEmpty.map { String($0) } - let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map(String.init(stringInterpolationSegment:)) + let tld = lower.proliferateNonEmpty.suchThat({ $0.count > 1 }).map { String($0) } let emailGen = glue([localEmail, Gen.pure("@"), hostname, Gen.pure("."), tld]) diff --git a/Tests/SwiftCheckTests/LambdaSpec.swift b/Tests/SwiftCheckTests/LambdaSpec.swift index cac0381..f7675c7 100644 --- a/Tests/SwiftCheckTests/LambdaSpec.swift +++ b/Tests/SwiftCheckTests/LambdaSpec.swift @@ -24,8 +24,8 @@ struct Name : Arbitrary, Equatable, Hashable, CustomStringConvertible { return self.unName } - var hashValue : Int { - return self.unName.hashValue + func hash(into hasher: inout Hasher) { + hasher.combine(unName) } static func == (l : Name, r : Name) -> Bool { From 4b9dfe474c52583e304251dd900b890be93977fa Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 13:05:00 +1100 Subject: [PATCH 439/460] fix LazySequence conformance --- Sources/SwiftCheck/WitnessedArbitrary.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index 03524c4..baf3926 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -135,9 +135,9 @@ extension Range : Arbitrary where Bound : Arbitrary { } } -extension LazyCollection : Arbitrary where Base : Arbitrary { - /// Returns a generator of `LazyCollection`s of arbitrary `Base`s. - public static var arbitrary : Gen> { +extension LazySequence : Arbitrary where Base : Arbitrary { + /// Returns a generator of `LazySequence`s of arbitrary `Base`s. + public static var arbitrary : Gen> { return Base.arbitrary.map({ $0.lazy }) } } From e903282afce061bfaa4926fa8c59f642fce05602 Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 13:23:42 +1100 Subject: [PATCH 440/460] Update FileCheck, should fix travis --- .travis.yml | 8 ++++---- Cartfile.resolved | 2 +- Carthage/Checkouts/FileCheck | 2 +- Package.swift | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e320cc..19e69bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: include: - os: osx language: objective-c - osx_image: xcode10 + osx_image: xcode10.2 before_install: - git submodule update --init --recursive - pushd Utilities @@ -37,9 +37,9 @@ matrix: before_install: - git submodule update --init --recursive - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - - - wget https://swift.org/builds/swift-4.2-release/ubuntu1404/swift-4.2-RELEASE/swift-4.2-RELEASE-ubuntu14.04.tar.gz - - tar xzf swift-4.2-RELEASE-ubuntu14.04.tar.gz - - export PATH=${PWD}/swift-4.2-RELEASE-ubuntu14.04/usr/bin:"${PATH}" + - wget https://swift.org/builds/swift-5.0-release/ubuntu1404/swift-5.0-RELEASE/swift-5.0-RELEASE-ubuntu14.04.tar.gz + - tar xzf swift-5.0-RELEASE-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-5.0-RELEASE-ubuntu14.04/usr/bin:"${PATH}" - pushd Utilities - ./compile.sh - popd diff --git a/Cartfile.resolved b/Cartfile.resolved index 0cb4861..97d0c6e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "trill-lang/FileCheck" "0.0.8" +github "trill-lang/FileCheck" "0.1.0" diff --git a/Carthage/Checkouts/FileCheck b/Carthage/Checkouts/FileCheck index 89b8480..bd9cb30 160000 --- a/Carthage/Checkouts/FileCheck +++ b/Carthage/Checkouts/FileCheck @@ -1 +1 @@ -Subproject commit 89b8480055f9adf8ce2f9ad5e2fac7ac1076242e +Subproject commit bd9cb30ceee1f21c02f51a7168f58471449807d8 diff --git a/Package.swift b/Package.swift index 003c2d8..43d82bc 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( targets: ["SwiftCheck"]), ], dependencies: [ - .package(url: "https://github.com/llvm-swift/FileCheck.git", from: "0.0.3") + .package(url: "https://github.com/llvm-swift/FileCheck.git", from: "0.1.0") ], targets: [ .target( From 9ec88c84675cc581af1ea90140b2d8d2da22d242 Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 13:32:40 +1100 Subject: [PATCH 441/460] change xcode10 to xcode10.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 19e69bb..7d57737 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - carthage build --no-skip-current - os: osx language: objective-c - osx_image: xcode10 + osx_image: xcode10.2 before_install: - git submodule update --init --recursive - pushd Utilities From 92d1faf48d9db2ff77579021437610e1d1cb5d82 Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 14:55:51 +1100 Subject: [PATCH 442/460] fix configs --- SwiftCheck.xcodeproj/project.pbxproj | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index aef97bf..a9e4edf 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -847,7 +847,6 @@ SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -880,7 +879,6 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -903,7 +901,6 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -923,7 +920,6 @@ SDKROOT = appletvos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; @@ -981,6 +977,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1030,6 +1027,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -1064,7 +1062,6 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1097,7 +1094,6 @@ SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1122,7 +1118,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -1144,7 +1139,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; - SWIFT_VERSION = 4.2; }; name = Release; }; @@ -1179,7 +1173,6 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OBJC_INTERFACE_HEADER_NAME = ""; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; @@ -1212,7 +1205,6 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; @@ -1242,7 +1234,6 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -1264,7 +1255,6 @@ SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; From 18dd0acfbadccbf8940e59a4142dd4dcb0fdb264 Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 15:19:27 +1100 Subject: [PATCH 443/460] fix ^&&^ operator randomly concatenates labels --- Sources/SwiftCheck/Test.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SwiftCheck/Test.swift b/Sources/SwiftCheck/Test.swift index d5913e2..1dfb5d4 100644 --- a/Sources/SwiftCheck/Test.swift +++ b/Sources/SwiftCheck/Test.swift @@ -1006,7 +1006,7 @@ private func printDistributionGraph(_ st : CheckerState) { } let gAllLabels : [String] = st.collected.map({ (s : Set) in - return s.filter({ t in st.labels[t] == .some(0) }).reduce("", { (l : String, r : String) in l + ", " + r }) + return s.filter({ t in st.labels[t] == .some(0) }).sorted().reduce("", { (l : String, r : String) in l + ", " + r }) }) let gAll : [[String]] = gAllLabels.filter({ !$0.isEmpty }).sorted().groupBy(==) let gPrint : [String] = gAll.map({ ss in showP((ss.count * 100) / st.successfulTestCount) + ss.first! }) From e6983b1870b59b74e26680fbecb7219d2de9487a Mon Sep 17 00:00:00 2001 From: Igor Nikitin Date: Tue, 26 Mar 2019 16:03:46 +1100 Subject: [PATCH 444/460] update .swift-version and Package.swift --- .swift-version | 2 +- Package.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.swift-version b/.swift-version index bf77d54..819e07a 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.2 +5.0 diff --git a/Package.swift b/Package.swift index 43d82bc..da0f1d5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:4.2 +// swift-tools-version:5.0 import PackageDescription From ee00f18a42bed0f4624d075f6c091c6f030ccd5b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 29 Mar 2019 08:24:50 -0400 Subject: [PATCH 445/460] Bump podspec to 0.12.0 --- .travis.yml | 3 +-- SwiftCheck.podspec | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d57737..3477e13 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,7 @@ matrix: - ./compile.sh - popd script: -# FIXME: Re-enable when pods 1.6.0 is out of beta -# - pod lib lint + - pod lib lint - carthage build --no-skip-current - os: osx language: objective-c diff --git a/SwiftCheck.podspec b/SwiftCheck.podspec index 4887352..7839e4c 100644 --- a/SwiftCheck.podspec +++ b/SwiftCheck.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SwiftCheck" - s.version = "0.11.0" + s.version = "0.12.0" s.summary = "QuickCheck for Swift." s.homepage = "https://github.com/typelift/SwiftCheck" s.license = { :type => "MIT", :text => <<-LICENSE From c0f577dbecbdd4efcec3d39debf9e089342855ed Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:26:16 -0700 Subject: [PATCH 446/460] Fix unfoldr Match the actual semantics of unfoldr with respect to sequence ordering. Also use UnfoldSequence to drop our primitive. --- Sources/SwiftCheck/Arbitrary.swift | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index 17106e7..ccfef50 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -64,13 +64,14 @@ extension Arbitrary { extension FixedWidthInteger { /// Shrinks any `IntegerType`. public var shrinkIntegral : [Self] { - return unfoldr({ i in + let start = self < 0 ? self.multipliedReportingOverflow(by: -1).partialValue : self + return [Self](sequence(state: start) { i in if i <= 0 { return .none } - let n = i / 2 - return .some((n, n)) - }, initial: self < 0 ? self.multipliedReportingOverflow(by: -1).partialValue : self) + i = i / 2 + return .some(i) + }) } } @@ -92,13 +93,14 @@ extension Bool : Arbitrary { extension BinaryInteger { /// Shrinks any `Numeric` type. public var shrinkIntegral : [Self] { - return unfoldr({ i in + let start = self < 0 ? (self * -1) : self + return [Self](sequence(state: start) { i in if i <= 0 { return .none } - let n = i / 2 - return .some((n, n)) - }, initial: self < 0 ? (self * -1) : self) + i = i / 2 + return .some(i) + }) } } @@ -371,17 +373,6 @@ extension Array where Element : Hashable { return [Element](Set(self)) } } - -private func unfoldr(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] { - var acc = [A]() - var ini = initial - while let next = f(ini) { - acc.append(next.0) - ini = next.1 - } - return acc.reversed() -} - #if os(Linux) import Glibc #else From c083db51bdd4f9be52590afc8560ed612a9b5aff Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:27:01 -0700 Subject: [PATCH 447/460] Restore deterministic shrinking for UnicodeScalar nub changes the order of the shrink from run to run and is probably less efficient than tail-allocating these arrays --- Sources/SwiftCheck/Arbitrary.swift | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Sources/SwiftCheck/Arbitrary.swift b/Sources/SwiftCheck/Arbitrary.swift index ccfef50..b4e8ca8 100644 --- a/Sources/SwiftCheck/Arbitrary.swift +++ b/Sources/SwiftCheck/Arbitrary.swift @@ -303,7 +303,12 @@ extension UnicodeScalar : Arbitrary { /// The default shrinking function for `UnicodeScalar` values. public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] { let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))! - return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } + let scalarSet = Set([ "a", "b", "c", "A", "B", "C", "1", "2", "3", "\n", " " ]) + if scalarSet.contains(s) { + return [ "a", "b", "c", "A", "B", "C", "1", "2", "3", "\n", " " ].filter { $0 < x } + } else { + return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].filter { $0 < x } + } } } @@ -365,14 +370,6 @@ extension Mirror : Arbitrary { } } - -// MARK: - Implementation Details Follow - -extension Array where Element : Hashable { - fileprivate var nub : [Element] { - return [Element](Set(self)) - } -} #if os(Linux) import Glibc #else From 3b17149720f68dd7504bdbf8e9e93a095d9ca890 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:27:21 -0700 Subject: [PATCH 448/460] Provide more information in fatalErrors instead of using `undefined` --- Sources/SwiftCheck/Modifiers.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Sources/SwiftCheck/Modifiers.swift b/Sources/SwiftCheck/Modifiers.swift index 762d688..91cb75e 100644 --- a/Sources/SwiftCheck/Modifiers.swift +++ b/Sources/SwiftCheck/Modifiers.swift @@ -359,11 +359,6 @@ extension NonNegative : CoArbitrary { // MARK: - Implementation Details Follow - -private func undefined() -> A { - fatalError("") -} - fileprivate final class ArrowOfImpl : Arbitrary, CustomStringConvertible { fileprivate var table : Dictionary fileprivate var arr : (T) -> U @@ -375,7 +370,9 @@ fileprivate final class ArrowOfImpl : convenience init(_ arr : @escaping (T) -> U) { var table = [T:U]() - self.init(table, { (_ : T) -> U in return undefined() }) + self.init(table, { (_ : T) -> U in + fatalError("Table forced before initialization completed; is something re-entrant?") + }) self.arr = { x in if let v = table[x] { @@ -425,7 +422,11 @@ fileprivate final class IsoOfImpl U, _ project : @escaping (U) -> T) { var table = [T:U]() - self.init(table, { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() }) + self.init(table, { (_ : T) -> U in + fatalError("Table forced before initialization completed; is something re-entrant?") + }, { (_ : U) -> T in + fatalError("Table forced before initialization completed; is something re-entrant?") + }) self.embed = { t in if let v = table[t] { From 778f536f9e4bdd49885a43d3aff31ea5a02e52fd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:28:04 -0700 Subject: [PATCH 449/460] Use the sequence initializer on Dictionary --- Sources/SwiftCheck/WitnessedArbitrary.swift | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index baf3926..f2ba395 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -100,7 +100,7 @@ extension Dictionary : Arbitrary where Key : Arbitrary, Value : Arbitrary { public static var arbitrary : Gen> { return [Key].arbitrary.flatMap { (k : [Key]) in return [Value].arbitrary.flatMap { (v : [Value]) in - return Gen.pure(Dictionary(zip(k, v))) + return Gen.pure(Dictionary(zip(k, v)) { $1 }) } } } @@ -173,7 +173,7 @@ extension Set : Arbitrary where Element : Arbitrary { } } -// MARK: - Implementation Details Follow +// MARK: - Implementation Details private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { let xs2 : [A] = Array(xs.suffix(max(0, xs.count - k))) @@ -200,14 +200,9 @@ private func shrinkOne(_ xs : [A]) -> [[A]] { fatalError("Array could not produce a first element") } -extension Dictionary { - fileprivate init(_ pairs : S) - where S.Iterator.Element == (Key, Value) - { - self.init() - var g = pairs.makeIterator() - while let (k, v): (Key, Value) = g.next() { - self[k] = v - } - } + let xss = [A](xs[1.. Date: Sun, 4 Aug 2019 14:28:14 -0700 Subject: [PATCH 450/460] Un-pyramid-of-doom shrinkOne --- Sources/SwiftCheck/WitnessedArbitrary.swift | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index f2ba395..d138993 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -189,16 +189,9 @@ private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { } private func shrinkOne(_ xs : [A]) -> [[A]] { - if xs.isEmpty { + guard let x : A = xs.first else { return [[A]]() - } else if let x : A = xs.first { - let xss = [A](xs[1.. Date: Sun, 4 Aug 2019 14:29:16 -0700 Subject: [PATCH 451/460] Rename Result to QuickCheckResult You know, in case we want to use Result in the future --- Sources/SwiftCheck/Test.swift | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Sources/SwiftCheck/Test.swift b/Sources/SwiftCheck/Test.swift index 1dfb5d4..a0245ca 100644 --- a/Sources/SwiftCheck/Test.swift +++ b/Sources/SwiftCheck/Test.swift @@ -535,7 +535,7 @@ public func exists(_ gen : Gen, pf : @escaping (A) throws -> T // MARK: - Implementation Details -internal enum Result { +internal enum QuickCheckResult { case success( numTests : Int, labels : [(String, Int)], @@ -585,7 +585,7 @@ private indirect enum Either { case right(R) } -internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result { +internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> QuickCheckResult { let istate = CheckerState( name: args.name, maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests, @@ -621,7 +621,7 @@ internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> // - giveUp: When the number of discarded tests exceeds the number given in the // arguments we just give up turning the run loop to prevent excessive // generation. -private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result { +private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> QuickCheckResult { var state = st while true { switch runATest(state, caseGen: caseGen) { @@ -631,9 +631,9 @@ private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Resul return fail.0 case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)): return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output) - // Existential Failures need explicit propagation. Existentials increment the - // discard count so we check if it has been surpassed. If it has with any kind - // of success we're done. If no successes are found we've failed checking the + // Existential Failures need explicit propagation. Existentials increment the + // discard count so we check if it has been surpassed. If it has with any kind + // of success we're done. If no successes are found we've failed checking the // existential and report it as such. Otherwise turn the testing loop. case (.existentialFailure(_, _, _, _, _, _, _), _): if fail.1.successfulTestCount == 0 || fail.1.discardedTestCount >= fail.1.maxAllowableDiscardedTests { @@ -661,7 +661,7 @@ private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Resul // // On success the next state is returned. On failure the final result and state // are returned. -private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> { +private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(QuickCheckResult, CheckerState), CheckerState> { let size = st.computeSize(st.successfulTestCount, st.discardedTestCount) let (rnd1, rnd2) = st.randomSeedGenerator.split @@ -751,7 +751,7 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E /// However, some existentials outlive their usefulness if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests { - let resul = Result.existentialFailure( + let resul = QuickCheckResult.existentialFailure( numTests: (st.successfulTestCount + 1), usedSeed: st.randomSeedGenerator, usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount), @@ -769,11 +769,11 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) if !expect { - let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") + let s = QuickCheckResult.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") return .left((s, st)) } - let stat = Result.failure( + let stat = QuickCheckResult.failure( numTests: (st.successfulTestCount + 1), numShrinks: numShrinks, usedSeed: st.randomSeedGenerator, @@ -809,7 +809,7 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E } } -private func doneTesting(_ st : CheckerState) -> Result { +private func doneTesting(_ st : CheckerState) -> QuickCheckResult { if !st.hasFulfilledExpectedFailure { if insufficientCoverage(st) { printCond(st.silence, "+++ OK, failed as expected. ") @@ -843,7 +843,7 @@ private func doneTesting(_ st : CheckerState) -> Result { } } -private func giveUp(_ st : CheckerState) -> Result { +private func giveUp(_ st : CheckerState) -> QuickCheckResult { printDistributionGraph(st) return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "") } @@ -944,7 +944,7 @@ private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (I return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance) } -private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result { +private func reportExistentialFailure(_ st : CheckerState, res : QuickCheckResult) -> QuickCheckResult { switch res { case let .existentialFailure(_, _, _, reason, _, _, lastTest): let testMsg = " (after \(st.discardedTestCount) test" From 61dbede0c2a1b2fe2d60efcf5e85b17d54ddb428 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:29:31 -0700 Subject: [PATCH 452/460] Minor comment shuffling --- Sources/SwiftCheck/Lattice.swift | 2 +- Sources/SwiftCheck/Random.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftCheck/Lattice.swift b/Sources/SwiftCheck/Lattice.swift index f71a64c..f5eabaf 100644 --- a/Sources/SwiftCheck/Lattice.swift +++ b/Sources/SwiftCheck/Lattice.swift @@ -90,7 +90,7 @@ extension AnyIndex : LatticeType { } } -/// float.h does not export Float80's limits, nor does the Swift Standard Library. +// float.h does not export Float80's limits, nor does the Swift Standard Library. // rdar://18404510 //extension Swift.Float80 : LatticeType { // public static var min : Swift.Float80 { diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index 549d4de..e442beb 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -338,7 +338,8 @@ extension Double : RandomType { } } -/// Implementation Details Follow +// MARK: - Implementation Details + private enum ClockTimeResult { case success case failure(Int) From 3d97f5a04006f1d6b69a0d9bac424810d47fed73 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 14:29:40 -0700 Subject: [PATCH 453/460] Xcode 11 stuff --- SwiftCheck.xcodeproj/project.pbxproj | 7 +++--- .../xcschemes/SwiftCheck-iOS.xcscheme | 24 ++++++++----------- .../xcschemes/SwiftCheck-tvOS.xcscheme | 24 ++++++++----------- .../xcschemes/SwiftCheck.xcscheme | 24 ++++++++----------- 4 files changed, 34 insertions(+), 45 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index a9e4edf..60aad52 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -532,7 +532,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1100; ORGANIZATIONNAME = Typelift; TargetAttributes = { 8240CCB01C3A123600EF4D29 = { @@ -568,6 +568,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 844FCC83198B320500EB242A; productRefGroup = 844FCC8E198B320500EB242A /* Products */; @@ -823,7 +824,7 @@ 8240CCC21C3A123700EF4D29 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DEBUG_INFORMATION_FORMAT = dwarf; @@ -856,7 +857,7 @@ 8240CCC31C3A123700EF4D29 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; COPY_PHASE_STRIP = NO; diff --git a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme index bf406fc..7679d42 100644 --- a/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme +++ b/SwiftCheck.xcodeproj/xcshareddata/xcschemes/SwiftCheck-iOS.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -53,17 +62,6 @@ - - - - - - - - + + + + @@ -39,17 +48,6 @@ - - - - - - - - + + + + @@ -39,17 +48,6 @@ - - - - - - - - Date: Sun, 4 Aug 2019 15:05:52 -0700 Subject: [PATCH 454/460] Document conj and disj --- Sources/SwiftCheck/Property.swift | 34 +++++++++++++++++++++++++------ Sources/SwiftCheck/Test.swift | 2 +- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Sources/SwiftCheck/Property.swift b/Sources/SwiftCheck/Property.swift index e710d77..fb59927 100644 --- a/Sources/SwiftCheck/Property.swift +++ b/Sources/SwiftCheck/Property.swift @@ -671,6 +671,18 @@ private func printLabels(_ st : TestResult) { } } +/// Takes a sequence of trees of test results from several properties into +/// a single labelled rose tree for the conjunction. +/// +/// This function is written in continuation passsing style to facilitate the +/// construction of a lazy rose tree that preserves the labels and callbacks +/// associated with the sub-properties. +/// +/// The general idea is that the properties are tested from first to last. If +/// any of them fails, the conjunct need not evaluate further and returns that +/// first failing result. Else, each passing sub-property continues on to the +/// next sub-property and decorates the overall result with its callbacks and +/// labels. Discards act to skip that sub-property, as expected. private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose]) -> Rose { guard let p = xs.first else { return Rose.mkRose({ k(TestResult.succeeded) }, { [] }) @@ -679,16 +691,20 @@ private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose](xs[1..](xs[1.. TestResult, xs : [Rose, q : Rose) -> Rose { return p.flatMap { result1 in - if !result1.expect { + guard result1.expect else { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result1.ok { case .some(true): + // Passed - Don't evaluate the other tree. return Rose.pure(result1) case .some(false): - return q.flatMap { (result2 : TestResult) in - if !result2.expect { + // Failed - Try the other tree. + return q.flatMap { result2 in + guard result2.expect else { return Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { case .some(true): return Rose.pure(result2) case .some(false): + // Failed - Combine the exceptions and callbacks from each + // sub-property. let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { (_, _) in return print("") })] return Rose.pure(TestResult( ok: .some(false), @@ -745,8 +766,9 @@ private func disj(_ p : Rose, q : Rose) -> Rose.pure(TestResult.failed("expectFailure may not occur inside a disjunction")) } switch result2.ok { diff --git a/Sources/SwiftCheck/Test.swift b/Sources/SwiftCheck/Test.swift index a0245ca..d314303 100644 --- a/Sources/SwiftCheck/Test.swift +++ b/Sources/SwiftCheck/Test.swift @@ -768,7 +768,7 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E // Attempt a shrink. let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts()) - if !expect { + guard expect else { let s = QuickCheckResult.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ") return .left((s, st)) } From b62bbb6eda3933d6c9f0f208e336a773dbfcc110 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 8 Aug 2019 11:08:50 -0400 Subject: [PATCH 455/460] Deprecate genRange requirement --- Sources/SwiftCheck/Random.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index e442beb..c804261 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -16,6 +16,7 @@ public protocol RandomGeneneratorType { /// Yields the range of values returned by the generator. /// /// This property must return integers in ascending order. + @available(*, deprecated, message: "genRange serves no purpose and will be removed in a future release") var genRange : (Int, Int) { get } /// Splits the current random value generator into two distinct random value /// generators. From b1674f6046f6f27e562367b0fa538e9258b8d136 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 15:38:44 -0700 Subject: [PATCH 456/460] Add an Arbitrary conformance for Result --- Sources/SwiftCheck/WitnessedArbitrary.swift | 22 +++++++++++++++++++++ Tests/SwiftCheckTests/TestSpec.swift | 18 +++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftCheck/WitnessedArbitrary.swift b/Sources/SwiftCheck/WitnessedArbitrary.swift index d138993..91c0e0c 100644 --- a/Sources/SwiftCheck/WitnessedArbitrary.swift +++ b/Sources/SwiftCheck/WitnessedArbitrary.swift @@ -173,6 +173,28 @@ extension Set : Arbitrary where Element : Arbitrary { } } +extension Result : Arbitrary where Success : Arbitrary, Failure : Arbitrary { + /// Returns a generator of `Result`s of arbitrary `Success` and + /// `Failure` values. + public static var arbitrary : Gen> { + return Gen>.one(of: [ + Success.arbitrary.map(Result.success), + Failure.arbitrary.map(Result.failure), + ]) + } + + /// The default shrinking function for `Result`s of arbitrary `Success` and + /// `Failure` values. + public static func shrink(_ bl : Result) -> [Result] { + switch bl { + case let .success(value): + return Success.shrink(value).map(Result.success) + case let .failure(value): + return Failure.shrink(value).map(Result.failure) + } + } +} + // MARK: - Implementation Details private func removes(_ k : Int, n : Int, xs : [A]) -> [[A]] { diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index 4345db7..6f70304 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -12,13 +12,21 @@ import XCTest import FileCheck #endif +enum MyException: String, Error, Arbitrary { + case phony + case baloney + + static var arbitrary: Gen { + return Gen.fromElements(of: [ .phony, .baloney ]) + } +} + class TestSpec : XCTestCase { func testAll() { - let dictionaryGen: Gen> = Gen<(String, Int)>.zip(String.arbitrary, Int.arbitrary).proliferate.map { _ -> Dictionary in [:] } XCTAssert(fileCheckOutput { // CHECK: *** Passed 100 tests // CHECK-NEXT: . - property("Dictionaries behave") <- forAllNoShrink(dictionaryGen) { (xs : Dictionary) in + property("Dictionaries behave") <- forAll { (xs : Dictionary) in return true } @@ -34,6 +42,12 @@ class TestSpec : XCTestCase { return true } + // CHECK-NEXT: *** Passed 100 tests + // CHECK-NEXT: . + property("Results behave") <- forAll { (xs : Result) in + return true + } + // CHECK-NEXT: *** Passed 100 tests // CHECK-NEXT: (100%, {{Right|Left}} identity, {{Right|Left}} identity) // CHECK: Failed: (Bad Sort Right) From 555b6f6c977dd5d141ced69ee4fd5bb2c624b1b5 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 4 Aug 2019 15:42:25 -0700 Subject: [PATCH 457/460] Cheapen the dictionary API regression test --- Tests/SwiftCheckTests/TestSpec.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SwiftCheckTests/TestSpec.swift b/Tests/SwiftCheckTests/TestSpec.swift index 6f70304..1cac24a 100644 --- a/Tests/SwiftCheckTests/TestSpec.swift +++ b/Tests/SwiftCheckTests/TestSpec.swift @@ -26,7 +26,7 @@ class TestSpec : XCTestCase { XCTAssert(fileCheckOutput { // CHECK: *** Passed 100 tests // CHECK-NEXT: . - property("Dictionaries behave") <- forAll { (xs : Dictionary) in + property("Dictionaries behave") <- forAll { (xs : Dictionary) in return true } From c3bb2da15f0d9689eefd85394694d4f5057d5ea6 Mon Sep 17 00:00:00 2001 From: stnamco Date: Thu, 5 Sep 2019 09:59:34 +0900 Subject: [PATCH 458/460] Update references to `reverse` in the docs (#294) --- README.md | 4 ++-- Sources/SwiftCheck/Test.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index de0292f..0efac41 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,9 @@ property("The reverse of the reverse of an array is that array") <- forAll { (xs // *** Passed 100 tests // (100% , Right identity, Left identity) return - (xs.reverse().reverse() == xs) "Left identity" + (xs.reversed().reversed() == xs) "Left identity" ^&&^ - (xs == xs.reverse().reverse()) "Right identity" + (xs == xs.reversed().reversed()) "Right identity" } ``` diff --git a/Sources/SwiftCheck/Test.swift b/Sources/SwiftCheck/Test.swift index d314303..1f101d8 100644 --- a/Sources/SwiftCheck/Test.swift +++ b/Sources/SwiftCheck/Test.swift @@ -83,9 +83,9 @@ /// v v /// property("The reverse of the reverse of an array is that array") <- forAll { (xs : [Int]) in /// return -/// (xs.reverse().reverse() == xs) "Reverse on the left" +/// (xs.reversed().reversed() == xs) "Reverse on the left" /// ^&&^ -/// (xs == xs.reverse().reverse()) "Reverse on the right" +/// (xs == xs.reversed().reversed()) "Reverse on the right" /// } /// /// Why require types? For one, Swift cannot infer the types of local variables From abeeb225cb0268561d67485a8c767d71813d9fe2 Mon Sep 17 00:00:00 2001 From: Jay Lee Date: Mon, 15 Jun 2020 11:26:52 +0900 Subject: [PATCH 459/460] Update swift tools version to 5.2 (#297) --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index da0f1d5..f81b361 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.2 import PackageDescription From 7494bedfa42972431004a5d478dbf1fc2655e1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20H=C3=B6ller?= Date: Thu, 6 May 2021 02:44:17 +0200 Subject: [PATCH 460/460] Fix Xcode 12.5 build issues (#305) --- SwiftCheck.xcodeproj/project.pbxproj | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 60aad52..59e3455 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -126,6 +126,8 @@ 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; + DEFDC7592638423100D7E550 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEFDC7582638423100D7E550 /* XCTest.framework */; }; + DEFDC75C2638430200D7E550 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEFDC7582638423100D7E550 /* XCTest.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -224,6 +226,7 @@ 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + DEFDC7582638423100D7E550 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/AppleTVOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; FA3C18581D9300EF003DEB10 /* CartesianSpec.swift.gyb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CartesianSpec.swift.gyb; sourceTree = ""; }; FAAB9E791D91B96C0097AC78 /* Cartesian.swift.gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartesian.swift.gyb; sourceTree = ""; }; /* End PBXFileReference section */ @@ -233,6 +236,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DEFDC75C2638430200D7E550 /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -263,6 +267,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DEFDC7592638423100D7E550 /* XCTest.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -356,6 +361,7 @@ 6A761B891F14E91500A7D74F /* Tests */, FAAB9E781D91B96C0097AC78 /* Templates */, 844FCC8E198B320500EB242A /* Products */, + DEFDC7572638423100D7E550 /* Frameworks */, ); indentWidth = 4; sourceTree = ""; @@ -375,6 +381,14 @@ name = Products; sourceTree = ""; }; + DEFDC7572638423100D7E550 /* Frameworks */ = { + isa = PBXGroup; + children = ( + DEFDC7582638423100D7E550 /* XCTest.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; FAAB9E781D91B96C0097AC78 /* Templates */ = { isa = PBXGroup; children = ( @@ -839,7 +853,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; PRODUCT_NAME = SwiftCheck; @@ -872,7 +886,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.typelift.SwiftCheck; PRODUCT_NAME = SwiftCheck; @@ -1164,7 +1178,7 @@ ); INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; @@ -1197,7 +1211,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_SWIFT_FLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)";

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 : A -> Param, pf : (Self -> Testable)) -> Property } From 2638054802a54453b6f17d06ed28fd582e077d43 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 28 Feb 2016 13:53:10 -0500 Subject: [PATCH 276/460] restore build script --- .swift-version | 1 - .travis.yml | 35 +- Package.swift | 9 +- {SwiftCheck => Sources}/Arbitrary.swift | 6 +- {SwiftCheck => Sources}/Check.swift | 2 +- {SwiftCheck => Sources}/CoArbitrary.swift | 20 + {SwiftCheck => Sources}/Gen.swift | 2 +- {SwiftCheck => Sources}/Info.plist | 0 {SwiftCheck => Sources}/Lattice.swift | 0 {SwiftCheck => Sources}/Modifiers.swift | 4 +- Sources/Operators.swift | 246 ++++++++ {SwiftCheck => Sources}/Property.swift | 0 {SwiftCheck => Sources}/Random.swift | 0 {SwiftCheck => Sources}/Rose.swift | 0 {SwiftCheck => Sources}/State.swift | 0 {SwiftCheck => Sources}/SwiftCheck.h | 0 {SwiftCheck => Sources}/Test.swift | 0 {SwiftCheck => Sources}/TestOperators.swift | 0 {SwiftCheck => Sources}/Testable.swift | 0 {SwiftCheck => Sources}/Witness.swift | 0 .../WitnessedArbitrary.swift | 0 SwiftCheck.podspec | 2 +- SwiftCheck.xcodeproj/project.pbxproj | 539 +++++++++--------- SwiftCheck/Operators.swift | Bin 306900 -> 0 bytes .../BooleanIdentitySpec.swift | 0 {SwiftCheckTests => Tests}/ComplexSpec.swift | 0 {SwiftCheckTests => Tests}/DiscardSpec.swift | 0 {SwiftCheckTests => Tests}/FailureSpec.swift | 0 {SwiftCheckTests => Tests}/GenSpec.swift | 0 {SwiftCheckTests => Tests}/Info.plist | 0 {SwiftCheckTests => Tests}/LambdaSpec.swift | 0 {SwiftCheckTests => Tests}/ModifierSpec.swift | 0 {SwiftCheckTests => Tests}/PathSpec.swift | 0 {SwiftCheckTests => Tests}/PropertySpec.swift | 0 {SwiftCheckTests => Tests}/ReplaySpec.swift | 0 {SwiftCheckTests => Tests}/RoseSpec.swift | 0 {SwiftCheckTests => Tests}/ShrinkSpec.swift | 0 {SwiftCheckTests => Tests}/SimpleSpec.swift | 0 {SwiftCheckTests => Tests}/TestSpec.swift | 0 Tutorial.playground/Contents.swift | 25 +- script/cibuild | 8 +- 41 files changed, 595 insertions(+), 304 deletions(-) delete mode 100644 .swift-version rename {SwiftCheck => Sources}/Arbitrary.swift (98%) rename {SwiftCheck => Sources}/Check.swift (99%) rename {SwiftCheck => Sources}/CoArbitrary.swift (78%) rename {SwiftCheck => Sources}/Gen.swift (99%) rename {SwiftCheck => Sources}/Info.plist (100%) rename {SwiftCheck => Sources}/Lattice.swift (100%) rename {SwiftCheck => Sources}/Modifiers.swift (99%) create mode 100644 Sources/Operators.swift rename {SwiftCheck => Sources}/Property.swift (100%) rename {SwiftCheck => Sources}/Random.swift (100%) rename {SwiftCheck => Sources}/Rose.swift (100%) rename {SwiftCheck => Sources}/State.swift (100%) rename {SwiftCheck => Sources}/SwiftCheck.h (100%) rename {SwiftCheck => Sources}/Test.swift (100%) rename {SwiftCheck => Sources}/TestOperators.swift (100%) rename {SwiftCheck => Sources}/Testable.swift (100%) rename {SwiftCheck => Sources}/Witness.swift (100%) rename {SwiftCheck => Sources}/WitnessedArbitrary.swift (100%) delete mode 100644 SwiftCheck/Operators.swift rename {SwiftCheckTests => Tests}/BooleanIdentitySpec.swift (100%) rename {SwiftCheckTests => Tests}/ComplexSpec.swift (100%) rename {SwiftCheckTests => Tests}/DiscardSpec.swift (100%) rename {SwiftCheckTests => Tests}/FailureSpec.swift (100%) rename {SwiftCheckTests => Tests}/GenSpec.swift (100%) rename {SwiftCheckTests => Tests}/Info.plist (100%) rename {SwiftCheckTests => Tests}/LambdaSpec.swift (100%) rename {SwiftCheckTests => Tests}/ModifierSpec.swift (100%) rename {SwiftCheckTests => Tests}/PathSpec.swift (100%) rename {SwiftCheckTests => Tests}/PropertySpec.swift (100%) rename {SwiftCheckTests => Tests}/ReplaySpec.swift (100%) rename {SwiftCheckTests => Tests}/RoseSpec.swift (100%) rename {SwiftCheckTests => Tests}/ShrinkSpec.swift (100%) rename {SwiftCheckTests => Tests}/SimpleSpec.swift (100%) rename {SwiftCheckTests => Tests}/TestSpec.swift (100%) diff --git a/.swift-version b/.swift-version deleted file mode 100644 index 09d1e5e..0000000 --- a/.swift-version +++ /dev/null @@ -1 +0,0 @@ -swift-2.2-SNAPSHOT-2016-01-11-a diff --git a/.travis.yml b/.travis.yml index c45a75e..7a66856 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,26 +6,37 @@ matrix: - os: osx language: objective-c osx_image: xcode7.3 + before_install: + - git submodule update --init --recursive + script: + - pod lib lint + - carthage build --no-skip-current + - os: osx + language: objective-c + osx_image: xcode7.3 + before_install: + - git submodule update --init --recursive + script: + - set -o pipefail + - xcodebuild test -scheme SwiftCheck + - xcodebuild test -scheme SwiftCheck-iOS -destination 'platform=iOS Simulator,name=iPad Pro' + - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' - os: linux language: generic sudo: required dist: trusty before_install: - git submodule update --init --recursive - - curl -sL https://gist.github.com/kylef/5c0475ff02b7c7671d2a/raw/621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash + - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - + - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz + - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" + - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - + - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz + - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04.tar.gz + - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-02-08-a-ubuntu14.04/usr/bin:"${PATH}" script: - - . ~/.swiftenv/init - swift build -git: - submodules: false -before_install: - - git submodule update --init --recursive -script: - - pod lib lint - - set -o pipefail - - carthage build --no-skip-current - - xcodebuild test -scheme SwiftCheck-tvOS -destination 'platform=tvOS Simulator,name=Apple TV 1080p' - - script/cibuild SwiftCheck SwiftCheck-iOS notifications: webhooks: urls: diff --git a/Package.swift b/Package.swift index 3cc0951..682f4a3 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,11 @@ import PackageDescription -let package = Package(name: "SwiftCheck") +let package = Package( + name: "SwiftCheck", + targets: [ + Target(name: "SwiftCheck"), + Target(name: "SwiftCheck-iOS"), + Target(name: "SwiftCheck-tvOS"), + ] +) diff --git a/SwiftCheck/Arbitrary.swift b/Sources/Arbitrary.swift similarity index 98% rename from SwiftCheck/Arbitrary.swift rename to Sources/Arbitrary.swift index 0cb6ede..301698e 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/Sources/Arbitrary.swift @@ -291,7 +291,7 @@ extension UnicodeScalar : Arbitrary { /// The default shrinking function for `UnicodeScalar` values. public static func shrink(x : UnicodeScalar) -> [UnicodeScalar] { - let s : UnicodeScalar = UnicodeScalar(UInt32(towlower(Int32(x.value)))) + let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value)))) return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x } } } @@ -300,12 +300,12 @@ extension String : Arbitrary { /// Returns a generator of `String` values. public static var arbitrary : Gen { let chars = Gen.sized(Character.arbitrary.proliferateSized) - return chars >>- (Gen.pure • String.init) + return chars >>- { Gen.pure(String($0)) } } /// The default shrinking function for `String` values. public static func shrink(s : String) -> [String] { - return [Character].shrink([Character](s.characters)).map(String.init) + return [Character].shrink([Character](s.characters)).map { String($0) } } } diff --git a/SwiftCheck/Check.swift b/Sources/Check.swift similarity index 99% rename from SwiftCheck/Check.swift rename to Sources/Check.swift index 94b37c9..7759ff8 100644 --- a/SwiftCheck/Check.swift +++ b/Sources/Check.swift @@ -79,7 +79,7 @@ public struct CheckerArguments { /// Provides a way of re-doing a test at the given size with a new generator. let replay : Optional<(StdGen, Int)> /// The maximum number of test cases that must pass before the property itself - /// passes. + /// passes. /// /// The default value of this property is 100. In general, some tests may require more than /// this amount, but less is rare. If you need a value less than or equal to 1, use `.once` diff --git a/SwiftCheck/CoArbitrary.swift b/Sources/CoArbitrary.swift similarity index 78% rename from SwiftCheck/CoArbitrary.swift rename to Sources/CoArbitrary.swift index 32e9453..83aef26 100644 --- a/SwiftCheck/CoArbitrary.swift +++ b/Sources/CoArbitrary.swift @@ -37,6 +37,7 @@ public func coarbitraryPrintable(x : A) -> Gen -> Gen { } extension Bool : CoArbitrary { + /// The default coarbitrary implementation for `Bool` values. public static func coarbitrary(x : Bool) -> Gen -> Gen { return { g in if x { @@ -48,12 +49,14 @@ extension Bool : CoArbitrary { } extension UnicodeScalar : CoArbitrary { + /// The default coarbitrary implementation for `UnicodeScalar` values. public static func coarbitrary(x : UnicodeScalar) -> Gen -> Gen { return UInt32.coarbitrary(x.value) } } extension Character : CoArbitrary { + /// The default coarbitrary implementation for `Character` values. public static func coarbitrary(x : Character) -> (Gen -> Gen) { let ss = String(x).unicodeScalars return UnicodeScalar.coarbitrary(ss[ss.startIndex]) @@ -61,6 +64,7 @@ extension Character : CoArbitrary { } extension String : CoArbitrary { + /// The default coarbitrary implementation for `String` values. public static func coarbitrary(x : String) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -70,60 +74,70 @@ extension String : CoArbitrary { } extension Int : CoArbitrary { + /// The default coarbitrary implementation for `Int` values. public static func coarbitrary(x : Int) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int8 : CoArbitrary { + /// The default coarbitrary implementation for `Int8` values. public static func coarbitrary(x : Int8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int16 : CoArbitrary { + /// The default coarbitrary implementation for `Int16` values. public static func coarbitrary(x : Int16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int32 : CoArbitrary { + /// The default coarbitrary implementation for `Int32` values. public static func coarbitrary(x : Int32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension Int64 : CoArbitrary { + /// The default coarbitrary implementation for `Int64` values. public static func coarbitrary(x : Int64) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt : CoArbitrary { + /// The default coarbitrary implementation for `UInt` values. public static func coarbitrary(x : UInt) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt8 : CoArbitrary { + /// The default coarbitrary implementation for `UInt8` values. public static func coarbitrary(x : UInt8) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt16 : CoArbitrary { + /// The default coarbitrary implementation for `UInt16` values. public static func coarbitrary(x : UInt16) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt32 : CoArbitrary { + /// The default coarbitrary implementation for `UInt32` values. public static func coarbitrary(x : UInt32) -> Gen -> Gen { return x.coarbitraryIntegral() } } extension UInt64 : CoArbitrary { + /// The default coarbitrary implementation for `UInt64` values. public static func coarbitrary(x : UInt64) -> Gen -> Gen { return x.coarbitraryIntegral() } @@ -131,18 +145,21 @@ extension UInt64 : CoArbitrary { // In future, implement these with Ratios like QuickCheck. extension Float : CoArbitrary { + /// The default coarbitrary implementation for `Float` values. public static func coarbitrary(x : Float) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Double : CoArbitrary { + /// The default coarbitrary implementation for `Double` values. public static func coarbitrary(x : Double) -> (Gen -> Gen) { return Int64(x).coarbitraryIntegral() } } extension Array : CoArbitrary { + /// The default coarbitrary implementation for an `Array` of values. public static func coarbitrary(a : [Element]) -> (Gen -> Gen) { if a.isEmpty { return { $0.variant(0) } @@ -152,6 +169,7 @@ extension Array : CoArbitrary { } extension Dictionary : CoArbitrary { + /// The default coarbitrary implementation for a `Dictionary` of values. public static func coarbitrary(x : Dictionary) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } @@ -161,6 +179,7 @@ extension Dictionary : CoArbitrary { } extension Optional : CoArbitrary { + /// The default coarbitrary implementation for `Optional` values. public static func coarbitrary(x : Optional) -> (Gen -> Gen) { if let _ = x { return { $0.variant(0) } @@ -170,6 +189,7 @@ extension Optional : CoArbitrary { } extension Set : CoArbitrary { + /// The default coarbitrary implementation for `Set`s of values. public static func coarbitrary(x : Set) -> (Gen -> Gen) { if x.isEmpty { return { $0.variant(0) } diff --git a/SwiftCheck/Gen.swift b/Sources/Gen.swift similarity index 99% rename from SwiftCheck/Gen.swift rename to Sources/Gen.swift index 7ee6235..6a9acad 100644 --- a/SwiftCheck/Gen.swift +++ b/Sources/Gen.swift @@ -37,7 +37,7 @@ public struct Gen { /// practice, you should never use this property because it hinders the /// replay functionality and the robustness of tests in general. public var sample : [A] { - return sequence((2...20).map { self.resize($0) }).generate + return sequence((2...20).map(self.resize)).generate } /// Constructs a Generator that selects a random value from the given diff --git a/SwiftCheck/Info.plist b/Sources/Info.plist similarity index 100% rename from SwiftCheck/Info.plist rename to Sources/Info.plist diff --git a/SwiftCheck/Lattice.swift b/Sources/Lattice.swift similarity index 100% rename from SwiftCheck/Lattice.swift rename to Sources/Lattice.swift diff --git a/SwiftCheck/Modifiers.swift b/Sources/Modifiers.swift similarity index 99% rename from SwiftCheck/Modifiers.swift rename to Sources/Modifiers.swift index 7e5d756..cdf109e 100644 --- a/SwiftCheck/Modifiers.swift +++ b/Sources/Modifiers.swift @@ -151,7 +151,7 @@ public struct OrderedArrayOf> : Arbitrary, C /// Retrieves the underlying sorted array of values. public let getOrderedArray : [A] - /// Retrieves the underlying sorted array of value values as a contiguous + /// Retrieves the underlying sorted array of values as a contiguous /// array. public var getContiguousArray : ContiguousArray { return ContiguousArray(self.getOrderedArray) @@ -571,7 +571,7 @@ private final class IsoOfImpl, U return T.coarbitrary(a)(U.arbitrary) }), promote({ a in return U.coarbitrary(a)(T.arbitrary) - })).map { IsoOfImpl($0, $1) } + })).map(IsoOfImpl.init) } static func shrink(f : IsoOfImpl) -> [IsoOfImpl] { diff --git a/Sources/Operators.swift b/Sources/Operators.swift new file mode 100644 index 0000000..e4218fe --- /dev/null +++ b/Sources/Operators.swift @@ -0,0 +1,246 @@ +// +// Operators.swift +// Operadics +// +// Created by Robert Widmann on 07/07/2015. +// Copyright (c) 2015 TypeLift. All rights reserved. +// Released under the MIT License. +// +// Precedence marks for certain symbols aligned with Runes +// ~( https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift ) until Swift gets a proper +// resolver. + +// MARK: Combinators + +/// Compose | Applies one function to the result of another function to produce a third function. +infix operator • { + associativity right + precedence 190 +} + +/// Apply | Applies an argument to a function. +infix operator § { + associativity right + precedence 95 +} + +/// Pipe Backward | Applies the function to its left to an argument on its right. +infix operator <| { + associativity right + precedence 95 +} + +/// Pipe forward | Applies an argument on the left to a function on the right. +infix operator |> { + associativity left + precedence 95 +} + +/// On | Given a "combining" function and a function that converts arguments to the target of the +/// combiner, returns a function that applies the right hand side to two arguments, then runs both +/// results through the combiner. +infix operator |*| { + associativity left + precedence 100 +} + + +// MARK: Control.* + +/// Fmap | Maps a function over the value encapsulated by a functor. +infix operator <^> { + associativity left + // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift + precedence 130 +} + +/// Replace | Maps all the values encapsulated by a functor to a user-specified constant. +infix operator <^ { + associativity left + precedence 140 +} + +/// Replace Backwards | Maps all the values encapsulated by a functor to a user-specified constant. +infix operator ^> { + associativity left + precedence 140 +} + + +/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. +infix operator <*> { + associativity left + // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift + precedence 130 +} + +/// Sequence Right | Disregards the Functor on the Left. +/// +/// Default definition: +/// `const(id) <^> a <*> b` +infix operator *> { + associativity left + precedence 140 +} + +/// Sequence Left | Disregards the Functor on the Right. +/// +/// Default definition: +/// `const <^> a <*> b` +infix operator <* { + associativity left + precedence 140 +} + +/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the +/// left to a function on the right yielding a new monad. +infix operator >>- { + associativity left + // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift + precedence 100 +} + +/// Bind Backwards | Composes two monadic actions by passing the value inside the monad on the +/// right to the funciton on the left. +infix operator -<< { + associativity right + // https://github.com/thoughtbot/Runes/blob/master/Source/Runes.swift + precedence 100 +} + +/// Left-to-Right Kleisli | Composition for monads. +infix operator >>->> { + associativity right + precedence 110 +} + +/// Right-to-Left Kleisli | Composition for monads. +infix operator <<-<< { + associativity right + precedence 110 +} + +/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the +/// original context. +infix operator ->> { + associativity left + precedence 110 +} + +/// Imap | Maps covariantly over the index of a right-leaning bifunctor. +infix operator <^^> { + associativity left + precedence 140 +} + +/// Contramap | Contravariantly maps a function over the value encapsulated by a functor. +infix operator { + associativity left + precedence 140 +} + +// MARK: Data.Result + +/// From | Creates a Result given a function that can possibly fail with an error. +infix operator !! { + associativity none + precedence 120 +} + +// MARK: Data.Monoid + +/// Append | Alias for a Semigroup's operation. +infix operator <> { + associativity right + precedence 160 +} + +// MARK: Control.Category + +/// Right-to-Left Composition | Composes two categories to form a new category with the source of +/// the second category and the target of the first category. +/// +/// This function is literally `•`, but for Categories. +infix operator <<< { + associativity right + precedence 110 +} + +/// Left-to-Right Composition | Composes two categories to form a new category with the source of +/// the first category and the target of the second category. +/// +/// Function composition with the arguments flipped. +infix operator >>> { + associativity right + precedence 110 +} + +// MARK: Control.Arrow + +/// Split | Splits two computations and combines the result into one Arrow yielding a tuple of +/// the result of each side. +infix operator *** { + associativity right + precedence 130 +} + +/// Fanout | Given two functions with the same source but different targets, this function +/// splits the computation and combines the result of each Arrow into a tuple of the result of +/// each side. +infix operator &&& { + associativity right + precedence 130 +} + +// MARK: Control.Arrow.Choice + +/// Splat | Splits two computations and combines the results into Eithers on the left and right. +infix operator +++ { + associativity right + precedence 120 +} + +/// Fanin | Given two functions with the same target but different sources, this function splits +/// the input between the two and merges the output. +infix operator ||| { + associativity right + precedence 120 +} + +// MARK: Control.Arrow.Plus + +/// Op | Combines two ArrowZero monoids. +infix operator <+> { + associativity right + precedence 150 +} + +// MARK: Data.JSON + +/// Retrieve | Retrieves a value from a dictionary of JSON values using a given keypath. +/// +/// If the given keypath is not present or the retrieved value is not of the appropriate type, this +/// function returns `.None`. +infix operator "https://github.com/typelift/SwiftCheck.git", :tag => "v#{s.version}", :submodules => true } - s.source_files = "SwiftCheck/*.swift" + s.source_files = "Sources/*.swift" end diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 77f5f65..fe1fda9 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -7,104 +7,104 @@ objects = { /* Begin PBXBuildFile section */ - 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; - 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; - 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; - 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; 8240CCBB1C3A123700EF4D29 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; }; - 8240CCC81C3A124B00EF4D29 /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCA9198B323800EB242A /* Arbitrary.swift */; }; - 8240CCC91C3A124B00EF4D29 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; - 8240CCCA1C3A124B00EF4D29 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; - 8240CCCB1C3A124B00EF4D29 /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAB198B32DC00EB242A /* Gen.swift */; }; - 8240CCCC1C3A124B00EF4D29 /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; - 8240CCCD1C3A124B00EF4D29 /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; - 8240CCCE1C3A124B00EF4D29 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; - 8240CCCF1C3A124B00EF4D29 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAD198B367000EB242A /* Property.swift */; }; - 8240CCD01C3A124B00EF4D29 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; - 8240CCD11C3A124B00EF4D29 /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; - 8240CCD21C3A124B00EF4D29 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCB3198B39F300EB242A /* State.swift */; }; - 8240CCD31C3A124B00EF4D29 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAF198B36BE00EB242A /* Test.swift */; }; - 8240CCD41C3A124B00EF4D29 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; - 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; - 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; - 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; - 8240CCD91C3A125800EF4D29 /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 844FCC92198B320500EB242A /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8240CCDB1C3A126800EF4D29 /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 8240CCDC1C3A12AB00EF4D29 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */; }; - 8240CCDD1C3A12AB00EF4D29 /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8216BAB61B97775100A0D282 /* ComplexSpec.swift */; }; - 8240CCDE1C3A12AB00EF4D29 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; - 8240CCDF1C3A12AB00EF4D29 /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */; }; - 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4A91B16D37800280089 /* GenSpec.swift */; }; - 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; - 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */; }; - 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; - 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */; }; - 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; - 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; - 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; - 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; - 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */; }; - 82575B231C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; - 82575B241C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; - 82575B251C55524A00F0CD54 /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82575B221C55524A00F0CD54 /* RoseSpec.swift */; }; - 825794A71C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; - 825794A81C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; - 825794A91C6BDAD100BA20EA /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 825794A61C6BDAD100BA20EA /* PathSpec.swift */; }; - 827749F81B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; - 827749F91B65ABCC00A7965F /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 827749F71B65ABCC00A7965F /* Witness.swift */; }; - 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; - 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */; }; - 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; - 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82DD8EEB1B4CC88C00B66551 /* Operators.swift */; }; - 82ED49DF1C210D85008E9595 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; - 82ED49E01C210D85008E9595 /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */; }; - 82ED49E21C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; - 82ED49E31C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */; }; + 826D81581C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; + 826D81591C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; + 826D815A1C953D070022266C /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81461C953D070022266C /* Arbitrary.swift */; }; + 826D815B1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; + 826D815C1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; + 826D815D1C953D070022266C /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81471C953D070022266C /* Check.swift */; }; + 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; + 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; + 826D81601C953D070022266C /* CoArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81481C953D070022266C /* CoArbitrary.swift */; }; + 826D81611C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; + 826D81621C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; + 826D81631C953D070022266C /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81491C953D070022266C /* Gen.swift */; }; + 826D81671C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; + 826D81681C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; + 826D81691C953D070022266C /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814B1C953D070022266C /* Lattice.swift */; }; + 826D816A1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; + 826D816B1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; + 826D816C1C953D070022266C /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814C1C953D070022266C /* Modifiers.swift */; }; + 826D816D1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; + 826D816E1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; + 826D816F1C953D070022266C /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814D1C953D070022266C /* Operators.swift */; }; + 826D81701C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; + 826D81711C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; + 826D81721C953D070022266C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814E1C953D070022266C /* Property.swift */; }; + 826D81731C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; + 826D81741C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; + 826D81751C953D070022266C /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D814F1C953D070022266C /* Random.swift */; }; + 826D81761C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; + 826D81771C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; + 826D81781C953D070022266C /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81501C953D070022266C /* Rose.swift */; }; + 826D81791C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; + 826D817A1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; + 826D817B1C953D070022266C /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81511C953D070022266C /* State.swift */; }; + 826D817C1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 826D817D1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 826D817E1C953D070022266C /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 826D81521C953D070022266C /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 826D817F1C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; + 826D81801C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; + 826D81811C953D070022266C /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81531C953D070022266C /* Test.swift */; }; + 826D81821C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; + 826D81831C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; + 826D81841C953D070022266C /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81541C953D070022266C /* Testable.swift */; }; + 826D81851C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; + 826D81861C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; + 826D81871C953D070022266C /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81551C953D070022266C /* TestOperators.swift */; }; + 826D81881C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; + 826D81891C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; + 826D818A1C953D070022266C /* Witness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81561C953D070022266C /* Witness.swift */; }; + 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; + 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; + 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81571C953D070022266C /* WitnessedArbitrary.swift */; }; + 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; + 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; + 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */; }; + 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; + 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; + 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D818F1C953D2D0022266C /* ComplexSpec.swift */; }; + 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; + 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; + 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81901C953D2D0022266C /* DiscardSpec.swift */; }; + 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; + 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; + 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81911C953D2D0022266C /* FailureSpec.swift */; }; + 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; + 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; + 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81921C953D2D0022266C /* GenSpec.swift */; }; + 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; + 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; + 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81931C953D2D0022266C /* LambdaSpec.swift */; }; + 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; + 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; + 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81941C953D2D0022266C /* ModifierSpec.swift */; }; + 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; + 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; + 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81951C953D2D0022266C /* PathSpec.swift */; }; + 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; + 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; + 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81961C953D2D0022266C /* PropertySpec.swift */; }; + 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; + 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; + 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81971C953D2D0022266C /* ReplaySpec.swift */; }; + 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; + 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; + 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81981C953D2D0022266C /* RoseSpec.swift */; }; + 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; + 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; + 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D81991C953D2D0022266C /* ShrinkSpec.swift */; }; + 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; + 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; + 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819A1C953D2D0022266C /* SimpleSpec.swift */; }; + 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; + 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; + 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 826D819B1C953D2D0022266C /* TestSpec.swift */; }; 841408BB1B1A85A900BA2B6C /* SwiftCheck.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; - 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; - 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */; }; - 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */; }; - 8445C4AA1B16D37800280089 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4A91B16D37800280089 /* GenSpec.swift */; }; - 8445C4AB1B16D37800280089 /* GenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4A91B16D37800280089 /* GenSpec.swift */; }; - 8445C4AD1B17E48300280089 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */; }; - 8445C4AE1B17E48300280089 /* ShrinkSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */; }; - 844FCC93198B320500EB242A /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 844FCC92198B320500EB242A /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; 844FCC99198B320500EB242A /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 844FCC8D198B320500EB242A /* SwiftCheck.framework */; }; - 844FCCAA198B323800EB242A /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCA9198B323800EB242A /* Arbitrary.swift */; }; - 844FCCAC198B32DC00EB242A /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAB198B32DC00EB242A /* Gen.swift */; }; - 844FCCAE198B367000EB242A /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAD198B367000EB242A /* Property.swift */; }; - 844FCCB0198B36BE00EB242A /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAF198B36BE00EB242A /* Test.swift */; }; - 844FCCB4198B39F300EB242A /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCB3198B39F300EB242A /* State.swift */; }; - 844FCCC3198EC4F000EB242A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; - 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; - 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; - 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; - 84572C251A6DBAA800241F68 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; - 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; - 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; - 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */; }; 84DF76031B0BD54600C912B0 /* SwiftCheck.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */; }; - 84DF76111B0BD58100C912B0 /* Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCA9198B323800EB242A /* Arbitrary.swift */; }; - 84DF76121B0BD58100C912B0 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; - 84DF76141B0BD58100C912B0 /* Gen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAB198B32DC00EB242A /* Gen.swift */; }; - 84DF76151B0BD58100C912B0 /* Lattice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842015101AF5C91C00F1F3CD /* Lattice.swift */; }; - 84DF76161B0BD58100C912B0 /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; - 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8450D2491AF8003700095EF6 /* TestOperators.swift */; }; - 84DF76181B0BD58100C912B0 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAD198B367000EB242A /* Property.swift */; }; - 84DF76191B0BD58100C912B0 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC2198EC4F000EB242A /* Random.swift */; }; - 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC6198EFB4700EB242A /* Rose.swift */; }; - 84DF761B1B0BD58100C912B0 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCB3198B39F300EB242A /* State.swift */; }; - 84DF761C1B0BD58100C912B0 /* Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCAF198B36BE00EB242A /* Test.swift */; }; - 84DF761D1B0BD58100C912B0 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; - 84DF761E1B0BD58900C912B0 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */; }; - 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; - 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */; }; - 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */; }; - 84DF76241B0BD99900C912B0 /* SwiftCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 844FCC92198B320500EB242A /* SwiftCheck.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 84EA2C391B2287200001FB3F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; - 84EA2C3A1B2287200001FB3F /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EA2C381B2287200001FB3F /* PropertySpec.swift */; }; - 84F2C4F71A7AD43F00316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -155,45 +155,45 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 8216BAB61B97775100A0D282 /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexSpec.swift; sourceTree = ""; }; - 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureSpec.swift; sourceTree = ""; }; 8240CCB11C3A123600EF4D29 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 8240CCBA1C3A123700EF4D29 /* SwiftCheck-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LambdaSpec.swift; sourceTree = ""; }; - 82575B221C55524A00F0CD54 /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoseSpec.swift; sourceTree = ""; }; - 825794A61C6BDAD100BA20EA /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PathSpec.swift; sourceTree = ""; }; - 827749F71B65ABCC00A7965F /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Witness.swift; sourceTree = ""; usesTabs = 1; }; - 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaySpec.swift; sourceTree = ""; }; - 82DD8EEB1B4CC88C00B66551 /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Carthage/Checkouts/Operadics/Operators.swift; sourceTree = SOURCE_ROOT; usesTabs = 1; }; - 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoArbitrary.swift; sourceTree = ""; }; - 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WitnessedArbitrary.swift; sourceTree = ""; }; - 842015101AF5C91C00F1F3CD /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lattice.swift; sourceTree = ""; usesTabs = 1; }; - 8445C4A91B16D37800280089 /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenSpec.swift; sourceTree = ""; usesTabs = 1; }; - 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShrinkSpec.swift; sourceTree = ""; usesTabs = 1; }; + 826D81461C953D070022266C /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Arbitrary.swift; path = Sources/Arbitrary.swift; sourceTree = SOURCE_ROOT; }; + 826D81471C953D070022266C /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Check.swift; path = Sources/Check.swift; sourceTree = SOURCE_ROOT; }; + 826D81481C953D070022266C /* CoArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CoArbitrary.swift; path = Sources/CoArbitrary.swift; sourceTree = SOURCE_ROOT; }; + 826D81491C953D070022266C /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gen.swift; path = Sources/Gen.swift; sourceTree = SOURCE_ROOT; }; + 826D814A1C953D070022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = SOURCE_ROOT; }; + 826D814B1C953D070022266C /* Lattice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Lattice.swift; path = Sources/Lattice.swift; sourceTree = SOURCE_ROOT; }; + 826D814C1C953D070022266C /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = Sources/Modifiers.swift; sourceTree = SOURCE_ROOT; }; + 826D814D1C953D070022266C /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/Operators.swift; sourceTree = SOURCE_ROOT; }; + 826D814E1C953D070022266C /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Property.swift; path = Sources/Property.swift; sourceTree = SOURCE_ROOT; }; + 826D814F1C953D070022266C /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Random.swift; path = Sources/Random.swift; sourceTree = SOURCE_ROOT; }; + 826D81501C953D070022266C /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Rose.swift; path = Sources/Rose.swift; sourceTree = SOURCE_ROOT; }; + 826D81511C953D070022266C /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = State.swift; path = Sources/State.swift; sourceTree = SOURCE_ROOT; }; + 826D81521C953D070022266C /* SwiftCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = Sources/SwiftCheck.h; sourceTree = SOURCE_ROOT; }; + 826D81531C953D070022266C /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Test.swift; path = Sources/Test.swift; sourceTree = SOURCE_ROOT; }; + 826D81541C953D070022266C /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Testable.swift; path = Sources/Testable.swift; sourceTree = SOURCE_ROOT; }; + 826D81551C953D070022266C /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestOperators.swift; path = Sources/TestOperators.swift; sourceTree = SOURCE_ROOT; }; + 826D81561C953D070022266C /* Witness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Witness.swift; path = Sources/Witness.swift; sourceTree = SOURCE_ROOT; }; + 826D81571C953D070022266C /* WitnessedArbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WitnessedArbitrary.swift; path = Sources/WitnessedArbitrary.swift; sourceTree = SOURCE_ROOT; }; + 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BooleanIdentitySpec.swift; path = Tests/BooleanIdentitySpec.swift; sourceTree = SOURCE_ROOT; }; + 826D818F1C953D2D0022266C /* ComplexSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ComplexSpec.swift; path = Tests/ComplexSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81901C953D2D0022266C /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = Tests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81911C953D2D0022266C /* FailureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FailureSpec.swift; path = Tests/FailureSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81921C953D2D0022266C /* GenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GenSpec.swift; path = Tests/GenSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81931C953D2D0022266C /* LambdaSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LambdaSpec.swift; path = Tests/LambdaSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81941C953D2D0022266C /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = Tests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81951C953D2D0022266C /* PathSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PathSpec.swift; path = Tests/PathSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81961C953D2D0022266C /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PropertySpec.swift; path = Tests/PropertySpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81971C953D2D0022266C /* ReplaySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReplaySpec.swift; path = Tests/ReplaySpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81981C953D2D0022266C /* RoseSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoseSpec.swift; path = Tests/RoseSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81991C953D2D0022266C /* ShrinkSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShrinkSpec.swift; path = Tests/ShrinkSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D819A1C953D2D0022266C /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = Tests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D819B1C953D2D0022266C /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestSpec.swift; path = Tests/TestSpec.swift; sourceTree = SOURCE_ROOT; }; + 826D81C61C953D350022266C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Tests/Info.plist; sourceTree = SOURCE_ROOT; }; 844FCC8D198B320500EB242A /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 844FCC91198B320500EB242A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 844FCC92198B320500EB242A /* SwiftCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SwiftCheck.h; path = SwiftCheck/SwiftCheck.h; sourceTree = ""; usesTabs = 1; }; 844FCC98198B320500EB242A /* SwiftCheckTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftCheckTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 844FCC9E198B320500EB242A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 844FCCA9198B323800EB242A /* Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Arbitrary.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCAB198B32DC00EB242A /* Gen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Gen.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCAD198B367000EB242A /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCAF198B36BE00EB242A /* Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Test.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCB3198B39F300EB242A /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCC2198EC4F000EB242A /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCC6198EFB4700EB242A /* Rose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Rose.swift; sourceTree = ""; usesTabs = 1; }; - 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSpec.swift; sourceTree = ""; usesTabs = 1; }; - 8450D2491AF8003700095EF6 /* TestOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestOperators.swift; sourceTree = ""; usesTabs = 1; }; - 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscardSpec.swift; sourceTree = ""; usesTabs = 1; }; - 84572C241A6DBAA800241F68 /* Check.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Check.swift; sourceTree = ""; usesTabs = 1; }; - 84572C2A1A6DBABA00241F68 /* Testable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Testable.swift; sourceTree = ""; usesTabs = 1; }; - 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BooleanIdentitySpec.swift; sourceTree = ""; usesTabs = 1; }; - 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; usesTabs = 1; }; - 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestSpec.swift; sourceTree = ""; usesTabs = 1; }; 84DF75F81B0BD54600C912B0 /* SwiftCheck.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 84DF76021B0BD54600C912B0 /* SwiftCheck-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftCheck-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 84EA2C381B2287200001FB3F /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PropertySpec.swift; sourceTree = ""; usesTabs = 1; }; - 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; usesTabs = 1; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -248,7 +248,7 @@ 844FCC83198B320500EB242A = { isa = PBXGroup; children = ( - 844FCC92198B320500EB242A /* SwiftCheck.h */, + 826D81521C953D070022266C /* SwiftCheck.h */, 844FCC8F198B320500EB242A /* SwiftCheck */, 844FCC9C198B320500EB242A /* SwiftCheckTests */, 844FCC8E198B320500EB242A /* Products */, @@ -271,22 +271,22 @@ 844FCC8F198B320500EB242A /* SwiftCheck */ = { isa = PBXGroup; children = ( - 844FCCA9198B323800EB242A /* Arbitrary.swift */, - 82ED49DE1C210D85008E9595 /* CoArbitrary.swift */, - 84572C241A6DBAA800241F68 /* Check.swift */, - 844FCCAB198B32DC00EB242A /* Gen.swift */, - 842015101AF5C91C00F1F3CD /* Lattice.swift */, - 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */, - 82DD8EEB1B4CC88C00B66551 /* Operators.swift */, - 844FCCAD198B367000EB242A /* Property.swift */, - 844FCCC2198EC4F000EB242A /* Random.swift */, - 844FCCC6198EFB4700EB242A /* Rose.swift */, - 844FCCB3198B39F300EB242A /* State.swift */, - 844FCCAF198B36BE00EB242A /* Test.swift */, - 84572C2A1A6DBABA00241F68 /* Testable.swift */, - 8450D2491AF8003700095EF6 /* TestOperators.swift */, - 827749F71B65ABCC00A7965F /* Witness.swift */, - 82ED49E11C210DEE008E9595 /* WitnessedArbitrary.swift */, + 826D81461C953D070022266C /* Arbitrary.swift */, + 826D81471C953D070022266C /* Check.swift */, + 826D81481C953D070022266C /* CoArbitrary.swift */, + 826D81491C953D070022266C /* Gen.swift */, + 826D814B1C953D070022266C /* Lattice.swift */, + 826D814C1C953D070022266C /* Modifiers.swift */, + 826D814D1C953D070022266C /* Operators.swift */, + 826D814E1C953D070022266C /* Property.swift */, + 826D814F1C953D070022266C /* Random.swift */, + 826D81501C953D070022266C /* Rose.swift */, + 826D81511C953D070022266C /* State.swift */, + 826D81531C953D070022266C /* Test.swift */, + 826D81541C953D070022266C /* Testable.swift */, + 826D81551C953D070022266C /* TestOperators.swift */, + 826D81561C953D070022266C /* Witness.swift */, + 826D81571C953D070022266C /* WitnessedArbitrary.swift */, 844FCC90198B320500EB242A /* Supporting Files */, ); path = SwiftCheck; @@ -295,7 +295,7 @@ 844FCC90198B320500EB242A /* Supporting Files */ = { isa = PBXGroup; children = ( - 844FCC91198B320500EB242A /* Info.plist */, + 826D814A1C953D070022266C /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -303,20 +303,20 @@ 844FCC9C198B320500EB242A /* SwiftCheckTests */ = { isa = PBXGroup; children = ( - 848076671AF5D6A100CBE3EF /* BooleanIdentitySpec.swift */, - 8216BAB61B97775100A0D282 /* ComplexSpec.swift */, - 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, - 821B76CC1BC4449300AF97D6 /* FailureSpec.swift */, - 8445C4A91B16D37800280089 /* GenSpec.swift */, - 8248E0BB1C3E2FF200EADEA9 /* LambdaSpec.swift */, - 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, - 825794A61C6BDAD100BA20EA /* PathSpec.swift */, - 84EA2C381B2287200001FB3F /* PropertySpec.swift */, - 82A6679E1BFD299500EBCDFA /* ReplaySpec.swift */, - 82575B221C55524A00F0CD54 /* RoseSpec.swift */, - 8445C4AC1B17E48300280089 /* ShrinkSpec.swift */, - 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, - 84B9E4A61B3A0EB900C8739E /* TestSpec.swift */, + 826D818E1C953D2D0022266C /* BooleanIdentitySpec.swift */, + 826D818F1C953D2D0022266C /* ComplexSpec.swift */, + 826D81901C953D2D0022266C /* DiscardSpec.swift */, + 826D81911C953D2D0022266C /* FailureSpec.swift */, + 826D81921C953D2D0022266C /* GenSpec.swift */, + 826D81931C953D2D0022266C /* LambdaSpec.swift */, + 826D81941C953D2D0022266C /* ModifierSpec.swift */, + 826D81951C953D2D0022266C /* PathSpec.swift */, + 826D81961C953D2D0022266C /* PropertySpec.swift */, + 826D81971C953D2D0022266C /* ReplaySpec.swift */, + 826D81981C953D2D0022266C /* RoseSpec.swift */, + 826D81991C953D2D0022266C /* ShrinkSpec.swift */, + 826D819A1C953D2D0022266C /* SimpleSpec.swift */, + 826D819B1C953D2D0022266C /* TestSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); path = SwiftCheckTests; @@ -325,7 +325,7 @@ 844FCC9D198B320500EB242A /* Supporting Files */ = { isa = PBXGroup; children = ( - 844FCC9E198B320500EB242A /* Info.plist */, + 826D81C61C953D350022266C /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -337,7 +337,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 8240CCD91C3A125800EF4D29 /* SwiftCheck.h in Headers */, + 826D817E1C953D070022266C /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -345,7 +345,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 844FCC93198B320500EB242A /* SwiftCheck.h in Headers */, + 826D817C1C953D070022266C /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -353,7 +353,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 84DF76241B0BD99900C912B0 /* SwiftCheck.h in Headers */, + 826D817D1C953D070022266C /* SwiftCheck.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -476,7 +476,7 @@ 844FCC84198B320500EB242A /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0720; + LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Robert Widmann"; TargetAttributes = { @@ -573,22 +573,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8240CCC81C3A124B00EF4D29 /* Arbitrary.swift in Sources */, - 8240CCC91C3A124B00EF4D29 /* CoArbitrary.swift in Sources */, - 8240CCCA1C3A124B00EF4D29 /* Check.swift in Sources */, - 8240CCCB1C3A124B00EF4D29 /* Gen.swift in Sources */, - 8240CCCC1C3A124B00EF4D29 /* Lattice.swift in Sources */, - 8240CCCD1C3A124B00EF4D29 /* Modifiers.swift in Sources */, - 8240CCCE1C3A124B00EF4D29 /* Operators.swift in Sources */, - 8240CCCF1C3A124B00EF4D29 /* Property.swift in Sources */, - 8240CCD01C3A124B00EF4D29 /* Random.swift in Sources */, - 8240CCD11C3A124B00EF4D29 /* Rose.swift in Sources */, - 8240CCD21C3A124B00EF4D29 /* State.swift in Sources */, - 8240CCD31C3A124B00EF4D29 /* Test.swift in Sources */, - 8240CCD41C3A124B00EF4D29 /* Testable.swift in Sources */, - 8240CCD51C3A124B00EF4D29 /* TestOperators.swift in Sources */, - 8240CCD61C3A124B00EF4D29 /* Witness.swift in Sources */, - 8240CCD71C3A124B00EF4D29 /* WitnessedArbitrary.swift in Sources */, + 826D81721C953D070022266C /* Property.swift in Sources */, + 826D81691C953D070022266C /* Lattice.swift in Sources */, + 826D81751C953D070022266C /* Random.swift in Sources */, + 826D81841C953D070022266C /* Testable.swift in Sources */, + 826D816F1C953D070022266C /* Operators.swift in Sources */, + 826D818A1C953D070022266C /* Witness.swift in Sources */, + 826D815A1C953D070022266C /* Arbitrary.swift in Sources */, + 826D816C1C953D070022266C /* Modifiers.swift in Sources */, + 826D81811C953D070022266C /* Test.swift in Sources */, + 826D81871C953D070022266C /* TestOperators.swift in Sources */, + 826D81781C953D070022266C /* Rose.swift in Sources */, + 826D81601C953D070022266C /* CoArbitrary.swift in Sources */, + 826D815D1C953D070022266C /* Check.swift in Sources */, + 826D81631C953D070022266C /* Gen.swift in Sources */, + 826D818D1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 826D817B1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -596,20 +596,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8240CCDC1C3A12AB00EF4D29 /* BooleanIdentitySpec.swift in Sources */, - 8240CCDD1C3A12AB00EF4D29 /* ComplexSpec.swift in Sources */, - 8240CCDE1C3A12AB00EF4D29 /* DiscardSpec.swift in Sources */, - 8240CCDF1C3A12AB00EF4D29 /* FailureSpec.swift in Sources */, - 8240CCE01C3A12AB00EF4D29 /* GenSpec.swift in Sources */, - 8240CCE11C3A12AB00EF4D29 /* PropertySpec.swift in Sources */, - 8240CCE21C3A12AB00EF4D29 /* ModifierSpec.swift in Sources */, - 82575B251C55524A00F0CD54 /* RoseSpec.swift in Sources */, - 8248E0BE1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, - 8240CCE31C3A12AB00EF4D29 /* ReplaySpec.swift in Sources */, - 8240CCE41C3A12AB00EF4D29 /* ShrinkSpec.swift in Sources */, - 8240CCE51C3A12AB00EF4D29 /* SimpleSpec.swift in Sources */, - 8240CCE61C3A12AB00EF4D29 /* TestSpec.swift in Sources */, - 825794A91C6BDAD100BA20EA /* PathSpec.swift in Sources */, + 826D819E1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, + 826D81BF1C953D2D0022266C /* ShrinkSpec.swift in Sources */, + 826D81B91C953D2D0022266C /* ReplaySpec.swift in Sources */, + 826D81B31C953D2D0022266C /* PathSpec.swift in Sources */, + 826D81AD1C953D2D0022266C /* LambdaSpec.swift in Sources */, + 826D81BC1C953D2D0022266C /* RoseSpec.swift in Sources */, + 826D81AA1C953D2D0022266C /* GenSpec.swift in Sources */, + 826D81B01C953D2D0022266C /* ModifierSpec.swift in Sources */, + 826D81B61C953D2D0022266C /* PropertySpec.swift in Sources */, + 826D81A11C953D2D0022266C /* ComplexSpec.swift in Sources */, + 826D81A41C953D2D0022266C /* DiscardSpec.swift in Sources */, + 826D81A71C953D2D0022266C /* FailureSpec.swift in Sources */, + 826D81C51C953D2D0022266C /* TestSpec.swift in Sources */, + 826D81C21C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -617,22 +617,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 844FCCAE198B367000EB242A /* Property.swift in Sources */, - 84F2C4F71A7AD43F00316E5F /* Modifiers.swift in Sources */, - 844FCCB0198B36BE00EB242A /* Test.swift in Sources */, - 84572C251A6DBAA800241F68 /* Check.swift in Sources */, - 844FCCC3198EC4F000EB242A /* Random.swift in Sources */, - 844FCCAC198B32DC00EB242A /* Gen.swift in Sources */, - 842015111AF5C91C00F1F3CD /* Lattice.swift in Sources */, - 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */, - 82DD8EEC1B4CC88C00B66551 /* Operators.swift in Sources */, - 844FCCAA198B323800EB242A /* Arbitrary.swift in Sources */, - 8450D24A1AF8003800095EF6 /* TestOperators.swift in Sources */, - 844FCCB4198B39F300EB242A /* State.swift in Sources */, - 827749F81B65ABCC00A7965F /* Witness.swift in Sources */, - 82ED49DF1C210D85008E9595 /* CoArbitrary.swift in Sources */, - 82ED49E21C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */, - 844FCCC7198EFB4700EB242A /* Rose.swift in Sources */, + 826D81701C953D070022266C /* Property.swift in Sources */, + 826D81671C953D070022266C /* Lattice.swift in Sources */, + 826D81731C953D070022266C /* Random.swift in Sources */, + 826D81821C953D070022266C /* Testable.swift in Sources */, + 826D816D1C953D070022266C /* Operators.swift in Sources */, + 826D81881C953D070022266C /* Witness.swift in Sources */, + 826D81581C953D070022266C /* Arbitrary.swift in Sources */, + 826D816A1C953D070022266C /* Modifiers.swift in Sources */, + 826D817F1C953D070022266C /* Test.swift in Sources */, + 826D81851C953D070022266C /* TestOperators.swift in Sources */, + 826D81761C953D070022266C /* Rose.swift in Sources */, + 826D815E1C953D070022266C /* CoArbitrary.swift in Sources */, + 826D815B1C953D070022266C /* Check.swift in Sources */, + 826D81611C953D070022266C /* Gen.swift in Sources */, + 826D818B1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 826D81791C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -640,20 +640,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84EA2C391B2287200001FB3F /* PropertySpec.swift in Sources */, - 8445C4A31B16897200280089 /* DiscardSpec.swift in Sources */, - 8445C4AD1B17E48300280089 /* ShrinkSpec.swift in Sources */, - 8445C4AA1B16D37800280089 /* GenSpec.swift in Sources */, - 8216BAB71B97775100A0D282 /* ComplexSpec.swift in Sources */, - 84B9E4A71B3A0EB900C8739E /* TestSpec.swift in Sources */, - 8445C4A41B16897200280089 /* ModifierSpec.swift in Sources */, - 82575B231C55524A00F0CD54 /* RoseSpec.swift in Sources */, - 8248E0BC1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, - 821B76CD1BC4449300AF97D6 /* FailureSpec.swift in Sources */, - 8445C4A51B16897200280089 /* BooleanIdentitySpec.swift in Sources */, - 82A6679F1BFD299500EBCDFA /* ReplaySpec.swift in Sources */, - 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, - 825794A71C6BDAD100BA20EA /* PathSpec.swift in Sources */, + 826D819C1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, + 826D81BD1C953D2D0022266C /* ShrinkSpec.swift in Sources */, + 826D81B71C953D2D0022266C /* ReplaySpec.swift in Sources */, + 826D81B11C953D2D0022266C /* PathSpec.swift in Sources */, + 826D81AB1C953D2D0022266C /* LambdaSpec.swift in Sources */, + 826D81BA1C953D2D0022266C /* RoseSpec.swift in Sources */, + 826D81A81C953D2D0022266C /* GenSpec.swift in Sources */, + 826D81AE1C953D2D0022266C /* ModifierSpec.swift in Sources */, + 826D81B41C953D2D0022266C /* PropertySpec.swift in Sources */, + 826D819F1C953D2D0022266C /* ComplexSpec.swift in Sources */, + 826D81A21C953D2D0022266C /* DiscardSpec.swift in Sources */, + 826D81A51C953D2D0022266C /* FailureSpec.swift in Sources */, + 826D81C31C953D2D0022266C /* TestSpec.swift in Sources */, + 826D81C01C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -661,22 +661,22 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84DF76111B0BD58100C912B0 /* Arbitrary.swift in Sources */, - 84DF76121B0BD58100C912B0 /* Check.swift in Sources */, - 84DF76141B0BD58100C912B0 /* Gen.swift in Sources */, - 84DF76151B0BD58100C912B0 /* Lattice.swift in Sources */, - 84DF76161B0BD58100C912B0 /* Modifiers.swift in Sources */, - 84DF76171B0BD58100C912B0 /* TestOperators.swift in Sources */, - 84DF76181B0BD58100C912B0 /* Property.swift in Sources */, - 84DF76191B0BD58100C912B0 /* Random.swift in Sources */, - 82DD8EED1B4CC88C00B66551 /* Operators.swift in Sources */, - 84DF761A1B0BD58100C912B0 /* Rose.swift in Sources */, - 84DF761B1B0BD58100C912B0 /* State.swift in Sources */, - 84DF761C1B0BD58100C912B0 /* Test.swift in Sources */, - 827749F91B65ABCC00A7965F /* Witness.swift in Sources */, - 82ED49E01C210D85008E9595 /* CoArbitrary.swift in Sources */, - 82ED49E31C210DEE008E9595 /* WitnessedArbitrary.swift in Sources */, - 84DF761D1B0BD58100C912B0 /* Testable.swift in Sources */, + 826D81711C953D070022266C /* Property.swift in Sources */, + 826D81681C953D070022266C /* Lattice.swift in Sources */, + 826D81741C953D070022266C /* Random.swift in Sources */, + 826D81831C953D070022266C /* Testable.swift in Sources */, + 826D816E1C953D070022266C /* Operators.swift in Sources */, + 826D81891C953D070022266C /* Witness.swift in Sources */, + 826D81591C953D070022266C /* Arbitrary.swift in Sources */, + 826D816B1C953D070022266C /* Modifiers.swift in Sources */, + 826D81801C953D070022266C /* Test.swift in Sources */, + 826D81861C953D070022266C /* TestOperators.swift in Sources */, + 826D81771C953D070022266C /* Rose.swift in Sources */, + 826D815F1C953D070022266C /* CoArbitrary.swift in Sources */, + 826D815C1C953D070022266C /* Check.swift in Sources */, + 826D81621C953D070022266C /* Gen.swift in Sources */, + 826D818C1C953D070022266C /* WitnessedArbitrary.swift in Sources */, + 826D817A1C953D070022266C /* State.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -684,20 +684,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 84EA2C3A1B2287200001FB3F /* PropertySpec.swift in Sources */, - 84DF761E1B0BD58900C912B0 /* SimpleSpec.swift in Sources */, - 8445C4AE1B17E48300280089 /* ShrinkSpec.swift in Sources */, - 8445C4AB1B16D37800280089 /* GenSpec.swift in Sources */, - 8216BAB81B97775100A0D282 /* ComplexSpec.swift in Sources */, - 84B9E4A81B3A0EB900C8739E /* TestSpec.swift in Sources */, - 84DF761F1B0BD58900C912B0 /* DiscardSpec.swift in Sources */, - 82575B241C55524A00F0CD54 /* RoseSpec.swift in Sources */, - 8248E0BD1C3E2FF200EADEA9 /* LambdaSpec.swift in Sources */, - 821B76CE1BC4449300AF97D6 /* FailureSpec.swift in Sources */, - 84DF76201B0BD58900C912B0 /* ModifierSpec.swift in Sources */, - 82A667A01BFD299500EBCDFA /* ReplaySpec.swift in Sources */, - 84DF76211B0BD58900C912B0 /* BooleanIdentitySpec.swift in Sources */, - 825794A81C6BDAD100BA20EA /* PathSpec.swift in Sources */, + 826D819D1C953D2D0022266C /* BooleanIdentitySpec.swift in Sources */, + 826D81BE1C953D2D0022266C /* ShrinkSpec.swift in Sources */, + 826D81B81C953D2D0022266C /* ReplaySpec.swift in Sources */, + 826D81B21C953D2D0022266C /* PathSpec.swift in Sources */, + 826D81AC1C953D2D0022266C /* LambdaSpec.swift in Sources */, + 826D81BB1C953D2D0022266C /* RoseSpec.swift in Sources */, + 826D81A91C953D2D0022266C /* GenSpec.swift in Sources */, + 826D81AF1C953D2D0022266C /* ModifierSpec.swift in Sources */, + 826D81B51C953D2D0022266C /* PropertySpec.swift in Sources */, + 826D81A01C953D2D0022266C /* ComplexSpec.swift in Sources */, + 826D81A31C953D2D0022266C /* DiscardSpec.swift in Sources */, + 826D81A61C953D2D0022266C /* FailureSpec.swift in Sources */, + 826D81C41C953D2D0022266C /* TestSpec.swift in Sources */, + 826D81C11C953D2D0022266C /* SimpleSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -737,7 +737,7 @@ "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -768,7 +768,7 @@ "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -788,13 +788,15 @@ 8240CCC41C3A123700EF4D29 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; @@ -802,9 +804,10 @@ 8240CCC51C3A123700EF4D29 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; COPY_PHASE_STRIP = NO; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.typelift.SwiftCheck-tvOSTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -912,7 +915,7 @@ "$(inherited)", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( @@ -945,7 +948,7 @@ "$(inherited)", ); FRAMEWORK_VERSION = A; - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( @@ -964,6 +967,7 @@ 844FCCA7198B320500EB242A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", @@ -973,23 +977,25 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 844FCCA8198B320500EB242A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_OPTIMIZATION_LEVEL = s; - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1015,7 +1021,7 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1047,7 +1053,7 @@ "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheck/Info.plist; + INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -1069,6 +1075,7 @@ 84DF760F1B0BD54600C912B0 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -1077,24 +1084,26 @@ "DEBUG=1", "$(inherited)", ); - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 84DF76101B0BD54600C912B0 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = SwiftCheckTests/Info.plist; + INFOPLIST_FILE = Tests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.codafi.$(PRODUCT_NAME:rfc1034identifier)"; diff --git a/SwiftCheck/Operators.swift b/SwiftCheck/Operators.swift deleted file mode 100644 index efbd1b751dd9084885dada41c114cb505aa19bd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306900 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%0A+$}WOF=31-?^@Df^i>+W^5rPm=JU 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