From e6820f9059aa2b6683ca9318b1ca11adafafddc0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 13:48:48 -0700 Subject: [PATCH 01/19] Arbitrary no longer depends on Printable --- SwiftCheck/Arbitrary.swift | 2 +- SwiftCheck/Test.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index a0ad74a..9bf75b9 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -9,7 +9,7 @@ import Swiftz import Darwin -public protocol Arbitrary : Printable { +public protocol Arbitrary { // typealias A : Arbitrary class func arbitrary() -> Gen class func shrink(Self) -> [Self] diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index a6f4b9c..da450ac 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -131,7 +131,7 @@ public func forAll(gen : Gen, shrinker: A -> [A], f : A -> Testable) -> Property { return Property(gen >>- { (let x : A) in return shrinking(shrinker)(x0: x)({ (let xs : A) -> Testable in - return counterexample(xs.description)(p: f(xs)) + return counterexample("\(xs)")(p: f(xs)) }).unProperty }) } From 2dd284e63843fb492393c8675acb1b08b38fe457 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 14:19:36 -0700 Subject: [PATCH 02/19] Move combinators into extension on Gen --- Cartfile.resolved | 2 +- Carthage/Checkouts/Swiftz | 2 +- SwiftCheck-iOS.xcodeproj/project.pbxproj | 4 ++ SwiftCheck.xcodeproj/project.pbxproj | 4 ++ SwiftCheck/Arbitrary.swift | 12 ++-- SwiftCheck/Combinators.swift | 83 ++++++++++++------------ SwiftCheck/Property.swift | 2 +- 7 files changed, 61 insertions(+), 48 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 3f5f30d..87b0135 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Swiftz" "v0.1.0" +github "typelift/Swiftz" "v0.1.1" diff --git a/Carthage/Checkouts/Swiftz b/Carthage/Checkouts/Swiftz index 4bdcb8c..65c9c4d 160000 --- a/Carthage/Checkouts/Swiftz +++ b/Carthage/Checkouts/Swiftz @@ -1 +1 @@ -Subproject commit 4bdcb8ce0f142c0c88560bd9b405a259c87e3ad4 +Subproject commit 65c9c4d3e1460e574883a1f615903e127ff5e1c0 diff --git a/SwiftCheck-iOS.xcodeproj/project.pbxproj b/SwiftCheck-iOS.xcodeproj/project.pbxproj index 706fa73..ddc4eda 100644 --- a/SwiftCheck-iOS.xcodeproj/project.pbxproj +++ b/SwiftCheck-iOS.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 84572C391A6DC25200241F68 /* PrimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C331A6DC23100241F68 /* PrimeSpec.swift */; }; 84572C3A1A6DC25500241F68 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C341A6DC23100241F68 /* SimpleSpec.swift */; }; 84DD436D1A7703A200D492C6 /* Swiftz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD43681A77038A00D492C6 /* Swiftz.framework */; }; + 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F31A7AD43900316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -76,6 +77,7 @@ 84572C331A6DC23100241F68 /* PrimeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrimeSpec.swift; path = SwiftCheckTests/PrimeSpec.swift; sourceTree = SOURCE_ROOT; }; 84572C341A6DC23100241F68 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; 84DD43621A77038A00D492C6 /* Swiftz-iOS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "Swiftz-iOS.xcodeproj"; path = "Carthage/Checkouts/Swiftz/Swiftz-iOS.xcodeproj"; sourceTree = ""; }; + 84F2C4F31A7AD43900316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = SwiftCheck/Modifiers.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +127,7 @@ 84572C301A6DC21100241F68 /* Check.swift */, 841FAE4E19FB1BDA00AF4EA2 /* Combinators.swift */, 841FAE4F19FB1BDA00AF4EA2 /* Gen.swift */, + 84F2C4F31A7AD43900316E5F /* Modifiers.swift */, 841FAE5119FB1BDA00AF4EA2 /* Property.swift */, 841FAE5219FB1BDB00AF4EA2 /* Random.swift */, 841FAE5319FB1BDB00AF4EA2 /* Rose.swift */, @@ -304,6 +307,7 @@ buildActionMask = 2147483647; files = ( 841FAE8619FB1CEA00AF4EA2 /* Arbitrary.swift in Sources */, + 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */, 841FAE8719FB1CEA00AF4EA2 /* Combinators.swift in Sources */, 84572C311A6DC21100241F68 /* Check.swift in Sources */, 841FAE8819FB1CEA00AF4EA2 /* Gen.swift in Sources */, diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 1b2e35c..8c06d23 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 84572C251A6DBAA800241F68 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; 84DD439E1A78817100D492C6 /* Swiftz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD43991A78816800D492C6 /* Swiftz.framework */; }; + 84F2C4F71A7AD43F00316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -76,6 +77,7 @@ 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 = ""; }; 84DD43931A78816800D492C6 /* Swiftz.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Swiftz.xcodeproj; path = Carthage/Checkouts/Swiftz/Swiftz.xcodeproj; sourceTree = ""; }; + 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +127,7 @@ 84572C241A6DBAA800241F68 /* Check.swift */, 844FCCCE198F24CF00EB242A /* Combinators.swift */, 844FCCAB198B32DC00EB242A /* Gen.swift */, + 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */, 844FCCAD198B367000EB242A /* Property.swift */, 844FCCC2198EC4F000EB242A /* Random.swift */, 844FCCC6198EFB4700EB242A /* Rose.swift */, @@ -305,6 +308,7 @@ 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 */, diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 9bf75b9..fac8af8 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -231,7 +231,7 @@ private func bits(n : N) -> Int { private func inBounds(fi : (Int -> A)) -> Gen -> Gen { return { g in - return suchThat(g)({ x in + return g.suchThat({ x in return (fi(x) as Int) == x }).fmap(fi) } @@ -311,15 +311,17 @@ protocol CoArbitrary { } public func coarbitraryIntegral(x : A) -> Gen -> Gen { - return variant(x) + return { $0.variant(x) } } extension Bool : CoArbitrary { public static func coarbitrary(x: Bool) -> Gen -> Gen { - if x { - return variant(1) + return { g in + if x { + return g.variant(1) + } + return g.variant(0) } - return variant(0) } } diff --git a/SwiftCheck/Combinators.swift b/SwiftCheck/Combinators.swift index 2235bd5..f323c3f 100644 --- a/SwiftCheck/Combinators.swift +++ b/SwiftCheck/Combinators.swift @@ -9,13 +9,48 @@ import Foundation import Swiftz -/// Shakes up the internal Random Number generator for a given Generator with a seed. -public func variant(seed: S)(m: Gen) -> Gen { - return Gen(unGen: { r in - return { n in - return m.unGen(vary(seed)(r: r))(n) - } - }) +extension Gen { + /// Shakes up the internal Random Number generator for a given 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) + } + }) + } + + /// Constructs a generator that always uses a given size. + public func resize(n : Int) -> Gen { + return Gen(unGen: { r in + return { (_) in + return self.unGen(r)(n) + } + }) + } + + /// Constructs a Generator that only returns values that satisfy a predicate. + public func suchThat(p: (A -> Bool)) -> Gen { + return self.suchThatOptional(p) >>- ({ mx in + switch mx { + case .Some(let x): + return Gen.pure(x) + case .None: + return sized({ n in + return self.suchThat(p).resize(n + 1) + }) + } + }) + } + + /// Constructs a Generator that attempts to generate a values that satisfy a predicate. + /// + /// Passing values are wrapped in `.Some`. Failing values are `.None`. + public func suchThatOptional(p: A -> Bool) -> Gen> { + return sized({ n in + return try(self, 0, max(n, 1), p) + }) + } + } /// Constructs a generator that depends on a size parameter. @@ -27,15 +62,6 @@ public func sized(f: Int -> Gen) -> Gen { }) } -/// Constructs a generator that always uses a given size. -public func resize(n : Int)(m: Gen) -> Gen { - return Gen(unGen: { r in - return { (_) in - return m.unGen(r)(n) - } - }) -} - /// Constructs a random element in the range of two Integer Types public func choose(rng: (A, A)) -> Gen { return Gen(unGen: { s in @@ -49,29 +75,6 @@ public func choose(rng: (A, A)) -> Gen { }) } -/// Constructs a Generator that only returns values that satisfy a predicate. -public func suchThat(gen: Gen)(p: (A -> Bool)) -> Gen { - return suchThatOptional(gen)(p) >>- ({ mx in - switch mx { - case .Some(let x): - return Gen.pure(x) - case .None: - return sized({ n in - return resize(n + 1)(m: suchThat(gen)(p)) - }) - } - }) -} - -/// Constructs a Generator that attempts to generate a values that satisfy a predicate. -/// -/// Passing values are wrapped in `.Some`. Failing values are `.None`. -public func suchThatOptional(gen: Gen)(p: A -> Bool) -> Gen> { - return sized({ n in - return try(gen, 0, max(n, 1), p) - }) -} - /// Randomly selects and uses one of a number of given Generators. public func oneOf(gs : [Gen]) -> Gen { assert(gs.count != 0, "oneOf used with empty list") @@ -147,7 +150,7 @@ private func try(gen: Gen, k: Int, n : Int, p: A -> Bool) -> Gen>- ({ (let x : A) -> Gen> in + return gen.resize(2 * k + n) >>- ({ (let x : A) -> Gen> in if p(x) { return Gen.pure(.Some(x)) } diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 3c95e22..79aa05f 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -76,7 +76,7 @@ public func mapProp(f: Prop -> Prop)(p: Testable) -> Property { public func mapSize (f: Int -> Int)(p: Testable) -> Property { return Property(sized({ n in - return resize(f(n))(m: p.property().unProperty) + return p.property().unProperty.resize(f(n)) })) } From b158695a2afa00b8e3a4dbe022b6cc671412cc6f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 14:19:40 -0700 Subject: [PATCH 03/19] Add modifiers --- SwiftCheck/Modifiers.swift | 110 +++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 SwiftCheck/Modifiers.swift diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift new file mode 100644 index 0000000..4e46701 --- /dev/null +++ b/SwiftCheck/Modifiers.swift @@ -0,0 +1,110 @@ +// +// Modifiers.swift +// SwiftCheck-iOS +// +// Created by Robert Widmann on 1/29/15. +// Copyright (c) 2015 CodaFi. All rights reserved. +// + +import Swiftz + +public struct Blind : Arbitrary, Printable { + let getBlind : A + + public init(_ blind : A) { + self.getBlind = blind + } + + public var description : String { + return "(*)" + } + + private static func create(blind : A) -> Blind { + return Blind(blind) + } + + public static func arbitrary() -> Gen> { + return Blind.create <^> A.arbitrary() + } + + public static func shrink(bl : Blind) -> [Blind] { + return Blind.create <^> A.shrink(bl.getBlind) + } +} + +public func <^>(f: A -> B, ar : Blind) -> Blind { + return Blind(f(ar.getBlind)) +} + +public struct Fixed : Arbitrary { + let getFixed : A + + public init(_ fixed : A) { + self.getFixed = fixed + } + + private static func create(blind : A) -> Fixed { + return Fixed(blind) + } + + public static func arbitrary() -> Gen> { + return Fixed.create <^> A.arbitrary() + } + + public static func shrink(bl : Fixed) -> [Fixed] { + return [] + } +} + +public func <^>(f: A -> B, ar : Fixed) -> Fixed { + return Fixed(f(ar.getFixed)) +} + +public struct Positive> : Arbitrary { + let getPositive : A + + public init(_ pos : A) { + self.getPositive = pos + } + + private static func create(blind : A) -> Positive { + return Positive(blind) + } + + public static func arbitrary() -> Gen> { + return ((Positive.create • abs) <^> A.arbitrary().suchThat(!=0)).suchThat({ $0.getPositive > 0 }) + } + + public static func shrink(bl : Positive) -> [Positive] { + return A.shrink(bl.getPositive).filter(>0).map({ Positive($0) }) + } +} + +public func <^>, B : protocol>(f: A -> B, ar : Positive) -> Positive { + return Positive(f(ar.getPositive)) +} + +public struct NonZero> : Arbitrary { + let getNonZero : A + + public init(_ non : A) { + self.getNonZero = non + } + + private static func create(blind : A) -> NonZero { + return NonZero(blind) + } + + public static func arbitrary() -> Gen> { + return NonZero.create <^> A.arbitrary().suchThat(!=0) + } + + public static func shrink(bl : NonZero) -> [NonZero] { + return A.shrink(bl.getNonZero).filter(!=0).map({ NonZero($0) }) + } +} + +public func <^>, B : protocol>(f: A -> B, ar : NonZero) -> NonZero { + return NonZero(f(ar.getNonZero)) +} + From 6ffe630225021310473850a51f982ae9296f0bbc Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:20:03 -0700 Subject: [PATCH 04/19] ++Swiftz --- Cartfile.resolved | 2 +- Carthage/Checkouts/Swiftz | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 87b0135..95b5537 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Swiftz" "v0.1.1" +github "typelift/Swiftz" "v0.1.2" diff --git a/Carthage/Checkouts/Swiftz b/Carthage/Checkouts/Swiftz index 65c9c4d..0fb5047 160000 --- a/Carthage/Checkouts/Swiftz +++ b/Carthage/Checkouts/Swiftz @@ -1 +1 @@ -Subproject commit 65c9c4d3e1460e574883a1f615903e127ff5e1c0 +Subproject commit 0fb50471010f09e1d04babf75592fdf0b74f961f From 9eeb5360b48c5ca295251a0635e34b0e222dc8f0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:20:37 -0700 Subject: [PATCH 05/19] Cosmetics --- SwiftCheck/Property.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Property.swift b/SwiftCheck/Property.swift index 79aa05f..d6366d1 100644 --- a/SwiftCheck/Property.swift +++ b/SwiftCheck/Property.swift @@ -81,9 +81,9 @@ public func mapSize (f: Int -> Int)(p: Testable) -> Property { } 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) - })) + }) } public func shrinking (shrinker: A -> [A])(x0: A)(pf: A -> Testable) -> Property { From fcba2aa56589eaa207e1aa0f1f22f2471647266c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:20:58 -0700 Subject: [PATCH 06/19] Make tests print their proposition on failure --- SwiftCheck/Check.swift | 2 +- SwiftCheck/Combinators.swift | 2 +- SwiftCheck/State.swift | 2 +- SwiftCheck/Test.swift | 16 +++++++++------- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/SwiftCheck/Check.swift b/SwiftCheck/Check.swift index ffaa3ea..b1148c8 100644 --- a/SwiftCheck/Check.swift +++ b/SwiftCheck/Check.swift @@ -16,7 +16,7 @@ public struct QuickCheck { return undefined() } set(test) { - quickCheck(test) + quickCheck(test, name: s) } } } diff --git a/SwiftCheck/Combinators.swift b/SwiftCheck/Combinators.swift index f323c3f..321d644 100644 --- a/SwiftCheck/Combinators.swift +++ b/SwiftCheck/Combinators.swift @@ -54,7 +54,7 @@ extension Gen { } /// Constructs a generator that depends on a size parameter. -public func sized(f: Int -> Gen) -> Gen { +public func sized(f : Int -> Gen) -> Gen { return Gen(unGen:{ r in return { n in return f(n).unGen(r)(n) diff --git a/SwiftCheck/State.swift b/SwiftCheck/State.swift index 0843589..3f89c27 100644 --- a/SwiftCheck/State.swift +++ b/SwiftCheck/State.swift @@ -10,7 +10,7 @@ public struct Terminal {} public struct State { - var terminal : Terminal + var name : String var maxSuccessTests : Int var maxDiscardedTests : Int var computeSize : Int -> Int -> Int diff --git a/SwiftCheck/Test.swift b/SwiftCheck/Test.swift index da450ac..98a828b 100644 --- a/SwiftCheck/Test.swift +++ b/SwiftCheck/Test.swift @@ -9,6 +9,7 @@ import Swiftz public struct Arguments { + let name : String let replay : Optional<(StdGen, Int)> let maxSuccess : Int let maxDiscard : Int @@ -48,8 +49,8 @@ public func isSuccess(r: Result) -> Bool { } } -public func stdArgs() -> Arguments{ - return Arguments(replay: .None, maxSuccess: 100, maxDiscard: 500, maxSize: 100, chatty: true) +public func stdArgs(name : String = "") -> Arguments{ + return Arguments(name: name, replay: .None, maxSuccess: 100, maxDiscard: 500, maxSize: 100, chatty: true) } public func forAll(gen : Gen, pf : (A -> Testable)) -> Property { @@ -136,8 +137,8 @@ public func forAllShrink(gen : Gen, shrinker: A -> [A], f : A }) } -public func quickCheck(prop : Testable){ - quickCheckWithResult(stdArgs(), prop) +public func quickCheck(prop : Testable, name : String = "") { + quickCheckWithResult(stdArgs(name: name), prop) } public func quickCheckWithResult(args : Arguments, p : Testable) -> Result { @@ -181,7 +182,7 @@ public func quickCheckWithResult(args : Arguments, p : Testable) -> Result { } - let state = State(terminal: Terminal() + let state = State(name: args.name , maxSuccessTests: args.maxSuccess , maxDiscardedTests: args.maxDiscard , computeSize: computeSize @@ -193,10 +194,10 @@ public func quickCheckWithResult(args : Arguments, p : Testable) -> Result { , numSuccessShrinks: 0 , numTryShrinks: 0 , numTotTryShrinks: 0) - return test(state)(p.exhaustive ? once(p.property()).unProperty.unGen : p.property().unProperty.unGen) + return test(state, p.exhaustive ? once(p.property()).unProperty.unGen : p.property().unProperty.unGen) } -public func test(st: State)(f: (StdGen -> Int -> Prop)) -> Result { +public func test(st: State, f: (StdGen -> Int -> Prop)) -> Result { var state = st while true { switch runATest(state)(f) { @@ -355,6 +356,7 @@ public func localMinFound(st : State, res : TestResult) -> (Int, Int, Int) { return s } + println("Proposition: " + st.name) println(res.reason + pluralize(testMsg, st.numSuccessTests) + pluralize(shrinkMsg, st.numSuccessShrinks) + "):") callbackPostFinalFailure(st, res) return (st.numSuccessShrinks, st.numTotTryShrinks - st.numTryShrinks, st.numTryShrinks) From 5804a6d66d168fb1811fff4a4331a4f7ef6e12cd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:21:11 -0700 Subject: [PATCH 07/19] Arbitrary strings --- SwiftCheck/Arbitrary.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index fac8af8..9687ac5 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -176,17 +176,17 @@ extension UnicodeScalar : Arbitrary { } } -//extension String : Arbitrary { -// typealias A = String -// public static func arbitrary() -> Gen { -// let chars = sized({ n in vectorOf(n)(gen: UnicodeScalar.arbitrary()) }) -// return chars >>- { ls in Gen.pure(String(ls.map({ x in Character(x) }))) } -// } -// -// public static func shrink(x : String) -> [String] { -// return shrinkNone(x) -// } -//} +extension String : Arbitrary { + typealias A = String + public static func arbitrary() -> Gen { + let chars = sized({ n in vectorOf(n)(gen: UnicodeScalar.arbitrary()) }) + return chars >>- { ls in Gen.pure(String(ls.map({ x in Character(x) }))) } + } + + public static func shrink(x : String) -> [String] { + return shrinkNone(x) + } +} /// rdar://19437275 //extension Character : Arbitrary { From 95e6d173625669c0e822f1878335ed4950bcd28b Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:21:21 -0700 Subject: [PATCH 08/19] Make Modifiers Printable --- SwiftCheck/Modifiers.swift | 64 ++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 4e46701..95713a4 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -9,7 +9,7 @@ import Swiftz public struct Blind : Arbitrary, Printable { - let getBlind : A + public let getBlind : A public init(_ blind : A) { self.getBlind = blind @@ -32,47 +32,63 @@ public struct Blind : Arbitrary, Printable { } } +public func == >(lhs : Blind, rhs : Blind) -> Bool { + return lhs.getBlind == rhs.getBlind +} + public func <^>(f: A -> B, ar : Blind) -> Blind { return Blind(f(ar.getBlind)) } -public struct Fixed : Arbitrary { - let getFixed : A +public struct Static : Arbitrary, Printable { + public let getStatic : A public init(_ fixed : A) { - self.getFixed = fixed + self.getStatic = fixed + } + + public var description : String { + return "Static( \(self.getStatic) )" } - private static func create(blind : A) -> Fixed { - return Fixed(blind) + private static func create(blind : A) -> Static { + return Static(blind) } - public static func arbitrary() -> Gen> { - return Fixed.create <^> A.arbitrary() + public static func arbitrary() -> Gen> { + return Static.create <^> A.arbitrary() } - public static func shrink(bl : Fixed) -> [Fixed] { + public static func shrink(bl : Static) -> [Static] { return [] } } -public func <^>(f: A -> B, ar : Fixed) -> Fixed { - return Fixed(f(ar.getFixed)) +public func == >(lhs : Static, rhs : Static) -> Bool { + return lhs.getStatic == rhs.getStatic } -public struct Positive> : Arbitrary { - let getPositive : A +public func <^>(f: A -> B, ar : Static) -> Static { + return Static(f(ar.getStatic)) +} + +public struct Positive> : Arbitrary, Printable { + public let getPositive : A public init(_ pos : A) { self.getPositive = pos } + public var description : String { + return "Positive( \(self.getPositive) )" + } + private static func create(blind : A) -> Positive { return Positive(blind) } public static func arbitrary() -> Gen> { - return ((Positive.create • abs) <^> A.arbitrary().suchThat(!=0)).suchThat({ $0.getPositive > 0 }) + return (Positive.create • abs) <^> A.arbitrary().suchThat(>=0) } public static func shrink(bl : Positive) -> [Positive] { @@ -80,23 +96,33 @@ public struct Positive> : Arbitrary { } } +public func == >(lhs : Positive, rhs : Positive) -> Bool { + return lhs.getPositive == rhs.getPositive +} + public func <^>, B : protocol>(f: A -> B, ar : Positive) -> Positive { return Positive(f(ar.getPositive)) } -public struct NonZero> : Arbitrary { - let getNonZero : A +public struct NonZero> : Arbitrary, Printable { + public let getNonZero : A public init(_ non : A) { self.getNonZero = non } + public var description : String { + return "NonZero( \(self.getNonZero) )" + } + private static func create(blind : A) -> NonZero { return NonZero(blind) } public static func arbitrary() -> Gen> { - return NonZero.create <^> A.arbitrary().suchThat(!=0) + return NonZero.create <^> A.arbitrary().suchThat({ x in + x != 0 + }) } public static func shrink(bl : NonZero) -> [NonZero] { @@ -104,6 +130,10 @@ public struct NonZero> : Arbitrary { } } +public func == >(lhs : NonZero, rhs : NonZero) -> Bool { + return lhs.getNonZero == rhs.getNonZero +} + public func <^>, B : protocol>(f: A -> B, ar : NonZero) -> NonZero { return NonZero(f(ar.getNonZero)) } From c42e18c68f6deb458afe6e9c3b78773da82b072d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:21:27 -0700 Subject: [PATCH 09/19] Test modifiers --- SwiftCheck-iOS.xcodeproj/project.pbxproj | 4 ++++ SwiftCheck.xcodeproj/project.pbxproj | 4 ++++ SwiftCheckTests/ModifierSpec.swift | 30 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 SwiftCheckTests/ModifierSpec.swift diff --git a/SwiftCheck-iOS.xcodeproj/project.pbxproj b/SwiftCheck-iOS.xcodeproj/project.pbxproj index ddc4eda..8b1f0ba 100644 --- a/SwiftCheck-iOS.xcodeproj/project.pbxproj +++ b/SwiftCheck-iOS.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 84572C381A6DC25000241F68 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C321A6DC23100241F68 /* DiscardSpec.swift */; }; 84572C391A6DC25200241F68 /* PrimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C331A6DC23100241F68 /* PrimeSpec.swift */; }; 84572C3A1A6DC25500241F68 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C341A6DC23100241F68 /* SimpleSpec.swift */; }; + 8480AB301A7B0AA100C6162D /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */; }; 84DD436D1A7703A200D492C6 /* Swiftz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD43681A77038A00D492C6 /* Swiftz.framework */; }; 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F31A7AD43900316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ @@ -76,6 +77,7 @@ 84572C321A6DC23100241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; 84572C331A6DC23100241F68 /* PrimeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrimeSpec.swift; path = SwiftCheckTests/PrimeSpec.swift; sourceTree = SOURCE_ROOT; }; 84572C341A6DC23100241F68 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; + 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = SwiftCheckTests/ModifierSpec.swift; sourceTree = ""; }; 84DD43621A77038A00D492C6 /* Swiftz-iOS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "Swiftz-iOS.xcodeproj"; path = "Carthage/Checkouts/Swiftz/Swiftz-iOS.xcodeproj"; sourceTree = ""; }; 84F2C4F31A7AD43900316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = SwiftCheck/Modifiers.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -153,6 +155,7 @@ 84572C321A6DC23100241F68 /* DiscardSpec.swift */, 84572C331A6DC23100241F68 /* PrimeSpec.swift */, 84572C341A6DC23100241F68 /* SimpleSpec.swift */, + 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */, 841FAE4119FB1BA800AF4EA2 /* Supporting Files */, ); path = "SwiftCheck-iOSTests"; @@ -309,6 +312,7 @@ 841FAE8619FB1CEA00AF4EA2 /* Arbitrary.swift in Sources */, 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */, 841FAE8719FB1CEA00AF4EA2 /* Combinators.swift in Sources */, + 8480AB301A7B0AA100C6162D /* ModifierSpec.swift in Sources */, 84572C311A6DC21100241F68 /* Check.swift in Sources */, 841FAE8819FB1CEA00AF4EA2 /* Gen.swift in Sources */, 84572C291A6DBAB600241F68 /* Testable.swift in Sources */, diff --git a/SwiftCheck.xcodeproj/project.pbxproj b/SwiftCheck.xcodeproj/project.pbxproj index 8c06d23..00b3d23 100644 --- a/SwiftCheck.xcodeproj/project.pbxproj +++ b/SwiftCheck.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 84572C211A6DBA1C00241F68 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */; }; 84572C251A6DBAA800241F68 /* Check.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C241A6DBAA800241F68 /* Check.swift */; }; 84572C2B1A6DBABA00241F68 /* Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C2A1A6DBABA00241F68 /* Testable.swift */; }; + 8480AB2D1A7B0A9700C6162D /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */; }; 84DD439E1A78817100D492C6 /* Swiftz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD43991A78816800D492C6 /* Swiftz.framework */; }; 84F2C4F71A7AD43F00316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ @@ -76,6 +77,7 @@ 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 = ""; }; + 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModifierSpec.swift; sourceTree = ""; }; 84DD43931A78816800D492C6 /* Swiftz.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Swiftz.xcodeproj; path = Carthage/Checkouts/Swiftz/Swiftz.xcodeproj; sourceTree = ""; }; 84F2C4F61A7AD43F00316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Modifiers.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -153,6 +155,7 @@ 844FCCC8198EFF9B00EB242A /* SimpleSpec.swift */, 84572C1A1A6DB9D800241F68 /* PrimeSpec.swift */, 84572C201A6DBA1C00241F68 /* DiscardSpec.swift */, + 8480AB2C1A7B0A9700C6162D /* ModifierSpec.swift */, 844FCC9D198B320500EB242A /* Supporting Files */, ); path = SwiftCheckTests; @@ -328,6 +331,7 @@ 84572C1B1A6DB9D800241F68 /* PrimeSpec.swift in Sources */, 844FCCC9198EFF9B00EB242A /* SimpleSpec.swift in Sources */, 84572C211A6DBA1C00241F68 /* DiscardSpec.swift in Sources */, + 8480AB2D1A7B0A9700C6162D /* ModifierSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift new file mode 100644 index 0000000..99dff5a --- /dev/null +++ b/SwiftCheckTests/ModifierSpec.swift @@ -0,0 +1,30 @@ +// +// ModifierSpec.swift +// SwiftCheck +// +// Created by Robert Widmann on 1/29/15. +// Copyright (c) 2015 Robert Widmann. All rights reserved. +// + +import XCTest +import SwiftCheck + +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["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 + } + } +} From f3c6659c6165b3bbd3a792ca465efc4a75f5df42 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:23:01 -0700 Subject: [PATCH 10/19] Test string arbitrary --- SwiftCheckTests/SimpleSpec.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/SimpleSpec.swift b/SwiftCheckTests/SimpleSpec.swift index 1211141..9573bc3 100644 --- a/SwiftCheckTests/SimpleSpec.swift +++ b/SwiftCheckTests/SimpleSpec.swift @@ -52,9 +52,12 @@ class SimpleSpec : XCTestCase { 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 } - } } From ac49f30ca20a79fb5221b637a1528ea16bba1329 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 29 Jan 2015 19:58:02 -0700 Subject: [PATCH 11/19] What the actual hell, Xcode --- SwiftCheck-iOS.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SwiftCheck-iOS.xcodeproj/project.pbxproj b/SwiftCheck-iOS.xcodeproj/project.pbxproj index 8b1f0ba..fd9410a 100644 --- a/SwiftCheck-iOS.xcodeproj/project.pbxproj +++ b/SwiftCheck-iOS.xcodeproj/project.pbxproj @@ -22,7 +22,7 @@ 84572C381A6DC25000241F68 /* DiscardSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C321A6DC23100241F68 /* DiscardSpec.swift */; }; 84572C391A6DC25200241F68 /* PrimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C331A6DC23100241F68 /* PrimeSpec.swift */; }; 84572C3A1A6DC25500241F68 /* SimpleSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84572C341A6DC23100241F68 /* SimpleSpec.swift */; }; - 8480AB301A7B0AA100C6162D /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */; }; + 8480AB401A7B2AA100C6162D /* ModifierSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8480AB3E1A7B2A9A00C6162D /* ModifierSpec.swift */; }; 84DD436D1A7703A200D492C6 /* Swiftz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD43681A77038A00D492C6 /* Swiftz.framework */; }; 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2C4F31A7AD43900316E5F /* Modifiers.swift */; }; /* End PBXBuildFile section */ @@ -77,7 +77,7 @@ 84572C321A6DC23100241F68 /* DiscardSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DiscardSpec.swift; path = SwiftCheckTests/DiscardSpec.swift; sourceTree = SOURCE_ROOT; }; 84572C331A6DC23100241F68 /* PrimeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PrimeSpec.swift; path = SwiftCheckTests/PrimeSpec.swift; sourceTree = SOURCE_ROOT; }; 84572C341A6DC23100241F68 /* SimpleSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimpleSpec.swift; path = SwiftCheckTests/SimpleSpec.swift; sourceTree = SOURCE_ROOT; }; - 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = SwiftCheckTests/ModifierSpec.swift; sourceTree = ""; }; + 8480AB3E1A7B2A9A00C6162D /* ModifierSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModifierSpec.swift; path = SwiftCheckTests/ModifierSpec.swift; sourceTree = SOURCE_ROOT; }; 84DD43621A77038A00D492C6 /* Swiftz-iOS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "Swiftz-iOS.xcodeproj"; path = "Carthage/Checkouts/Swiftz/Swiftz-iOS.xcodeproj"; sourceTree = ""; }; 84F2C4F31A7AD43900316E5F /* Modifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Modifiers.swift; path = SwiftCheck/Modifiers.swift; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -154,8 +154,8 @@ children = ( 84572C321A6DC23100241F68 /* DiscardSpec.swift */, 84572C331A6DC23100241F68 /* PrimeSpec.swift */, + 8480AB3E1A7B2A9A00C6162D /* ModifierSpec.swift */, 84572C341A6DC23100241F68 /* SimpleSpec.swift */, - 8480AB2F1A7B0AA100C6162D /* ModifierSpec.swift */, 841FAE4119FB1BA800AF4EA2 /* Supporting Files */, ); path = "SwiftCheck-iOSTests"; @@ -312,7 +312,6 @@ 841FAE8619FB1CEA00AF4EA2 /* Arbitrary.swift in Sources */, 84F2C4F41A7AD43900316E5F /* Modifiers.swift in Sources */, 841FAE8719FB1CEA00AF4EA2 /* Combinators.swift in Sources */, - 8480AB301A7B0AA100C6162D /* ModifierSpec.swift in Sources */, 84572C311A6DC21100241F68 /* Check.swift in Sources */, 841FAE8819FB1CEA00AF4EA2 /* Gen.swift in Sources */, 84572C291A6DBAB600241F68 /* Testable.swift in Sources */, @@ -329,6 +328,7 @@ buildActionMask = 2147483647; files = ( 84572C391A6DC25200241F68 /* PrimeSpec.swift in Sources */, + 8480AB401A7B2AA100C6162D /* ModifierSpec.swift in Sources */, 84572C3A1A6DC25500241F68 /* SimpleSpec.swift in Sources */, 84572C381A6DC25000241F68 /* DiscardSpec.swift in Sources */, ); From 6ebac121bfffa1ad491024ed21478939d22ddc0d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:20:18 -0700 Subject: [PATCH 12/19] ++Swiftz --- Cartfile.resolved | 2 +- Carthage/Checkouts/Swiftz | 2 +- SwiftCheck/Modifiers.swift | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 95b5537..c6da7b1 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "typelift/Swiftz" "v0.1.2" +github "typelift/Swiftz" "v0.1.3" diff --git a/Carthage/Checkouts/Swiftz b/Carthage/Checkouts/Swiftz index 0fb5047..54328ae 160000 --- a/Carthage/Checkouts/Swiftz +++ b/Carthage/Checkouts/Swiftz @@ -1 +1 @@ -Subproject commit 0fb50471010f09e1d04babf75592fdf0b74f961f +Subproject commit 54328ae50b69015dea117dd56451fd4c51c34a8d diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 95713a4..50b7ce6 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -120,9 +120,7 @@ public struct NonZero> : Arbitrary, Printab } public static func arbitrary() -> Gen> { - return NonZero.create <^> A.arbitrary().suchThat({ x in - x != 0 - }) + return NonZero.create <^> A.arbitrary().suchThat(!=0) } public static func shrink(bl : NonZero) -> [NonZero] { From 8d6e1fc83194923bca2d2bbefa5a5348495e54a9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:48:18 -0700 Subject: [PATCH 13/19] Improve string Arbitrary with Character Arbitrary --- SwiftCheck/Arbitrary.swift | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/SwiftCheck/Arbitrary.swift b/SwiftCheck/Arbitrary.swift index 9687ac5..eb6b53d 100644 --- a/SwiftCheck/Arbitrary.swift +++ b/SwiftCheck/Arbitrary.swift @@ -179,8 +179,8 @@ extension UnicodeScalar : Arbitrary { extension String : Arbitrary { typealias A = String public static func arbitrary() -> Gen { - let chars = sized({ n in vectorOf(n)(gen: UnicodeScalar.arbitrary()) }) - return chars >>- { ls in Gen.pure(String(ls.map({ x in Character(x) }))) } + let chars = sized({ n in Character.arbitrary().vectorOf(n) }) + return chars >>- { ls in Gen.pure(String(ls)) } } public static func shrink(x : String) -> [String] { @@ -188,17 +188,16 @@ extension String : Arbitrary { } } -/// rdar://19437275 -//extension Character : Arbitrary { -// typealias A = Character -// public static func arbitrary() -> Gen { -// return choose((32, 255)) >>- { Gen.pure(Character(UnicodeScalar($0))) } -// } -// -// public static func shrink(x : Character) -> [Character] { -// return shrinkNone(x) -// } -//} +extension Character : Arbitrary { + typealias A = Character + public static func arbitrary() -> Gen { + return choose((32, 255)) >>- { Gen.pure(Character(UnicodeScalar($0))) } + } + + public static func shrink(x : Character) -> [Character] { + return shrinkNone(x) + } +} public func arbitraryArray() -> Gen<[A]> { return sized({ n in @@ -212,16 +211,6 @@ public func withBounds(f : A -> A -> Gen) -> Gen { return f(A.minBound())(A.maxBound()) } -public func arbitraryBoundedIntegral() -> Gen { - return withBounds({ (let mn : A) -> A -> Gen in - return { (let mx : A) -> Gen in - return choose((A(numericCast(mn)), A(numericCast(mx)))) >>- { n in - return Gen.pure(n) - } - } - }) -} - private func bits(n : N) -> Int { if n / 2 == 0 { return 0 From adb009e6e71e0f6df85fa18ca4ee692611757fe0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:48:36 -0700 Subject: [PATCH 14/19] Fix segfault in choose --- SwiftCheck/Combinators.swift | 55 ++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/SwiftCheck/Combinators.swift b/SwiftCheck/Combinators.swift index 321d644..8772d37 100644 --- a/SwiftCheck/Combinators.swift +++ b/SwiftCheck/Combinators.swift @@ -6,7 +6,6 @@ // Copyright (c) 2014 Robert Widmann. All rights reserved. // -import Foundation import Swiftz extension Gen { @@ -51,6 +50,28 @@ extension Gen { }) } + /// Generates a list of random length. + public func listOf() -> Gen<[A]> { + return sized({ n in + return choose((0, n)) >>- { k in + return self.vectorOf(k) + } + }) + } + + /// Generates a non-empty list of random length. + public func listOf1() -> Gen<[A]> { + return sized({ n in + return choose((1, max(1, n))) >>- { k in + return self.vectorOf(k) + } + }) + } + + /// Generates a list of a given length. + public func vectorOf(k : Int) -> Gen<[A]> { + return sequence(Array>(count: k, repeatedValue: self)) + } } /// Constructs a generator that depends on a size parameter. @@ -63,14 +84,11 @@ public func sized(f : Int -> Gen) -> Gen { } /// Constructs a random element in the range of two Integer Types -public func choose(rng: (A, A)) -> Gen { +public func choose(rng : (A, A)) -> Gen { return Gen(unGen: { s in return { (_) in - let l = rng.0 - let h = rng.1 - let x = numericCast(RAND_MAX * rand()) as A - let y = numericCast(h - l + 1) as A - return numericCast(l + x % y) + let (x, _) = A.randomInRange(rng, gen: s) + return x } }) } @@ -115,29 +133,6 @@ public func growingElements(xs: [A]) -> Gen { }) } -/// Generates a list of random length. -public func listOf(gen: Gen) -> Gen<[A]> { - return sized({ n in - return choose((0, n)) >>- { k in - return vectorOf(k)(gen: gen) - } - }) -} - -/// Generates a non-empty list of random length. -public func listOf1(gen: Gen) -> Gen<[A]> { - return sized({ n in - return choose((1, max(1, n))) >>- { k in - return vectorOf(k)(gen: gen) - } - }) -} - -/// Generates a list of a given length. -public func vectorOf(k: Int)(gen : Gen) -> Gen<[A]> { - return sequence(Array>(count: k, repeatedValue: gen)) -} - /// Implementation Details Follow private func vary(k : S)(r: StdGen) -> StdGen { From 468a162ad059ac6e932cf2bb7bb304efa1539ab0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:48:39 -0700 Subject: [PATCH 15/19] Add RandomType --- SwiftCheck/Random.swift | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index f28f381..76aeb1e 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -8,7 +8,7 @@ import Swiftz -public protocol RandonGen { +public protocol RandomGen { func next() -> (Int, Self) func genRange() -> (Int, Int) @@ -17,7 +17,7 @@ public protocol RandonGen { let theStdGen : StdGen = StdGen(time(nil)) -public struct StdGen : RandonGen { +public struct StdGen : RandomGen { let seed: Int init(_ seed : Int) { @@ -48,3 +48,17 @@ public func newStdGen() -> StdGen { private func mkStdRNG(seed : Int) -> StdGen { return StdGen(seed) } + +public protocol RandomType { + class func randomInRange(range : (Self, Self), gen : G) -> (Self, G) +} + +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; + + return (result, g); + } +} From 72883fc9c1927c6853566ab713ce1ac9745a3e5d Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:50:47 -0700 Subject: [PATCH 16/19] Integer instances of Random --- SwiftCheck/Random.swift | 91 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 76aeb1e..2a6f6e6 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -62,3 +62,94 @@ extension Int : RandomType { return (result, g); } } + +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; + + return (result, g); + } +} + +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; + + return (result, g); + } +} + +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; + + return (result, g); + } +} + +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; + + return (result, g); + } +} + +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 = (r % ((max + 1) - min)) + min; + + return (result, g); + } +} + +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 = (r % ((max + 1) - min)) + min; + + return (result, g); + } +} + +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 = (r % ((max + 1) - min)) + min; + + return (result, g); + } +} + +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 = (r % ((max + 1) - min)) + min; + + return (result, g); + } +} + +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 = (r % ((max + 1) - min)) + min; + + return (result, g); + } +} + From 93ef0e2636e96e6af69bcb7bc62a358c7458f849 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 11:57:51 -0700 Subject: [PATCH 17/19] Light documentation --- SwiftCheck/Random.swift | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Random.swift b/SwiftCheck/Random.swift index 2a6f6e6..7c514af 100644 --- a/SwiftCheck/Random.swift +++ b/SwiftCheck/Random.swift @@ -15,7 +15,8 @@ public protocol RandomGen { func split() -> (Self, Self) } -let theStdGen : StdGen = StdGen(time(nil)) +/// A library-provided standard random number generator. +let standardRNG : StdGen = StdGen(time(nil)) public struct StdGen : RandomGen { let seed: Int @@ -24,7 +25,6 @@ public struct StdGen : RandomGen { self.seed = seed } - public func next() -> (Int, StdGen) { let s = Int(time(nil)) return (Int(rand()), StdGen(s)) @@ -42,17 +42,23 @@ public struct StdGen : RandomGen { } public func newStdGen() -> StdGen { - return theStdGen.split().1 + return standardRNG.split().1 } private func mkStdRNG(seed : Int) -> StdGen { return StdGen(seed) } +/// Types that can generate random versions of themselves. public protocol RandomType { class func randomInRange(range : (Self, Self), gen : G) -> (Self, G) } +/// Generates a random value from a bounded random type. +public func random, G : RandomGen>(gen : G) -> (A, G) { + return A.randomInRange((A.minBound(), A.maxBound()), gen: gen) +} + extension Int : RandomType { public static func randomInRange(range : (Int, Int), gen : G) -> (Int, G) { let (min, max) = range @@ -153,3 +159,26 @@ extension UInt64 : RandomType { } } +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; + + return (result, 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; + + return (result, g); + } +} + + From 27cf32cfa3ea31d02876be9ed2a26ee72f5a3dcd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 12:08:08 -0700 Subject: [PATCH 18/19] Fix NonZero --- SwiftCheck/Modifiers.swift | 43 +++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/SwiftCheck/Modifiers.swift b/SwiftCheck/Modifiers.swift index 50b7ce6..0afa43c 100644 --- a/SwiftCheck/Modifiers.swift +++ b/SwiftCheck/Modifiers.swift @@ -8,6 +8,8 @@ import Swiftz +/// 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. public struct Blind : Arbitrary, Printable { public let getBlind : A @@ -40,6 +42,7 @@ public func <^>(f: A -> B, ar : Blind) -> Blind return Blind(f(ar.getBlind)) } +/// Guarantees test cases for its underlying type will not be shrunk. public struct Static : Arbitrary, Printable { public let getStatic : A @@ -72,6 +75,7 @@ public func <^>(f: A -> B, ar : Static) -> Stat return Static(f(ar.getStatic)) } +/// Guarantees that every generated integer is greater than 0. public struct Positive> : Arbitrary, Printable { public let getPositive : A @@ -88,7 +92,7 @@ public struct Positive> : Arbitrary, P } public static func arbitrary() -> Gen> { - return (Positive.create • abs) <^> A.arbitrary().suchThat(>=0) + return (Positive.create • abs) <^> A.arbitrary().suchThat(>0) } public static func shrink(bl : Positive) -> [Positive] { @@ -104,6 +108,7 @@ public func <^>, B : protocol(f(ar.getPositive)) } +/// Guarantees that every generated integer is never 0. public struct NonZero> : Arbitrary, Printable { public let getNonZero : A @@ -120,11 +125,11 @@ public struct NonZero> : Arbitrary, Printab } public static func arbitrary() -> Gen> { - return NonZero.create <^> A.arbitrary().suchThat(!=0) + return NonZero.create <^> A.arbitrary().suchThat { $0 != 0 } } public static func shrink(bl : NonZero) -> [NonZero] { - return A.shrink(bl.getNonZero).filter(!=0).map({ NonZero($0) }) + return A.shrink(bl.getNonZero).filter({ $0 != 0 }).map({ NonZero($0) }) } } @@ -136,3 +141,35 @@ public func <^>, B : protocol(f(ar.getNonZero)) } +/// Guarantees that every generated integer is greater than or equal to 0. +public struct NonNegative> : Arbitrary, Printable { + public let getNonNegative : A + + public init(_ non : A) { + self.getNonNegative = non + } + + public var description : String { + return "NonNegative( \(self.getNonNegative) )" + } + + private static func create(blind : A) -> NonNegative { + return NonNegative(blind) + } + + public static func arbitrary() -> Gen> { + return NonNegative.create <^> A.arbitrary().suchThat(>=0) + } + + public static func shrink(bl : NonNegative) -> [NonNegative] { + return A.shrink(bl.getNonNegative).filter(>=0).map({ NonNegative($0) }) + } +} + +public func == >(lhs : NonNegative, rhs : NonNegative) -> Bool { + return lhs.getNonNegative == rhs.getNonNegative +} + +public func <^>, B : protocol>(f: A -> B, ar : NonNegative) -> NonNegative { + return NonNegative(f(ar.getNonNegative)) +} From d0786f5925c9064527a679ab85330e52bc36ab74 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 8 Feb 2015 12:08:16 -0700 Subject: [PATCH 19/19] Add NonNegative --- SwiftCheckTests/ModifierSpec.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/SwiftCheckTests/ModifierSpec.swift b/SwiftCheckTests/ModifierSpec.swift index 99dff5a..e7b5684 100644 --- a/SwiftCheckTests/ModifierSpec.swift +++ b/SwiftCheckTests/ModifierSpec.swift @@ -20,11 +20,15 @@ class ModifierSpec : XCTestCase { } property["Positive propositions only generate positive numbers"] = forAll { (x : Positive) in - return x.getPositive >= 0 + 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 + } } }