Skip to content

Commit 9e53d13

Browse files
authored
Merge pull request #290 from CodaFi/janitorial-work-ethic
[NFCI] Cosmetic Improvements
2 parents 06f1432 + 7b19c5d commit 9e53d13

File tree

11 files changed

+111
-122
lines changed

11 files changed

+111
-122
lines changed

Sources/SwiftCheck/Arbitrary.swift

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ extension Arbitrary {
6464
extension FixedWidthInteger {
6565
/// Shrinks any `IntegerType`.
6666
public var shrinkIntegral : [Self] {
67-
return unfoldr({ i in
67+
let start = self < 0 ? self.multipliedReportingOverflow(by: -1).partialValue : self
68+
return [Self](sequence(state: start) { i in
6869
if i <= 0 {
6970
return .none
7071
}
71-
let n = i / 2
72-
return .some((n, n))
73-
}, initial: self < 0 ? self.multipliedReportingOverflow(by: -1).partialValue : self)
72+
i = i / 2
73+
return .some(i)
74+
})
7475
}
7576
}
7677

@@ -92,13 +93,14 @@ extension Bool : Arbitrary {
9293
extension BinaryInteger {
9394
/// Shrinks any `Numeric` type.
9495
public var shrinkIntegral : [Self] {
95-
return unfoldr({ i in
96+
let start = self < 0 ? (self * -1) : self
97+
return [Self](sequence(state: start) { i in
9698
if i <= 0 {
9799
return .none
98100
}
99-
let n = i / 2
100-
return .some((n, n))
101-
}, initial: self < 0 ? (self * -1) : self)
101+
i = i / 2
102+
return .some(i)
103+
})
102104
}
103105
}
104106

@@ -301,7 +303,12 @@ extension UnicodeScalar : Arbitrary {
301303
/// The default shrinking function for `UnicodeScalar` values.
302304
public static func shrink(_ x : UnicodeScalar) -> [UnicodeScalar] {
303305
let s : UnicodeScalar = UnicodeScalar(UInt32(tolower(Int32(x.value))))!
304-
return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].nub.filter { $0 < x }
306+
let scalarSet = Set<UnicodeScalar>([ "a", "b", "c", "A", "B", "C", "1", "2", "3", "\n", " " ])
307+
if scalarSet.contains(s) {
308+
return [ "a", "b", "c", "A", "B", "C", "1", "2", "3", "\n", " " ].filter { $0 < x }
309+
} else {
310+
return [ "a", "b", "c", s, "A", "B", "C", "1", "2", "3", "\n", " " ].filter { $0 < x }
311+
}
305312
}
306313
}
307314

@@ -363,25 +370,6 @@ extension Mirror : Arbitrary {
363370
}
364371
}
365372

366-
367-
// MARK: - Implementation Details Follow
368-
369-
extension Array where Element : Hashable {
370-
fileprivate var nub : [Element] {
371-
return [Element](Set(self))
372-
}
373-
}
374-
375-
private func unfoldr<A, B>(_ f : (B) -> Optional<(A, B)>, initial : B) -> [A] {
376-
var acc = [A]()
377-
var ini = initial
378-
while let next = f(ini) {
379-
acc.append(next.0)
380-
ini = next.1
381-
}
382-
return acc.reversed()
383-
}
384-
385373
#if os(Linux)
386374
import Glibc
387375
#else

Sources/SwiftCheck/Lattice.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ extension AnyIndex : LatticeType {
9090
}
9191
}
9292

93-
/// float.h does not export Float80's limits, nor does the Swift Standard Library.
93+
// float.h does not export Float80's limits, nor does the Swift Standard Library.
9494
// rdar://18404510
9595
//extension Swift.Float80 : LatticeType {
9696
// public static var min : Swift.Float80 {

Sources/SwiftCheck/Modifiers.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,6 @@ extension NonNegative : CoArbitrary {
359359

360360
// MARK: - Implementation Details Follow
361361

362-
363-
private func undefined<A>() -> A {
364-
fatalError("")
365-
}
366-
367362
fileprivate final class ArrowOfImpl<T : Hashable & CoArbitrary, U : Arbitrary> : Arbitrary, CustomStringConvertible {
368363
fileprivate var table : Dictionary<T, U>
369364
fileprivate var arr : (T) -> U
@@ -375,7 +370,9 @@ fileprivate final class ArrowOfImpl<T : Hashable & CoArbitrary, U : Arbitrary> :
375370

376371
convenience init(_ arr : @escaping (T) -> U) {
377372
var table = [T:U]()
378-
self.init(table, { (_ : T) -> U in return undefined() })
373+
self.init(table, { (_ : T) -> U in
374+
fatalError("Table forced before initialization completed; is something re-entrant?")
375+
})
379376

380377
self.arr = { x in
381378
if let v = table[x] {
@@ -425,7 +422,11 @@ fileprivate final class IsoOfImpl<T : Hashable & CoArbitrary & Arbitrary, U : Eq
425422

426423
convenience init(_ embed : @escaping (T) -> U, _ project : @escaping (U) -> T) {
427424
var table = [T:U]()
428-
self.init(table, { (_ : T) -> U in return undefined() }, { (_ : U) -> T in return undefined() })
425+
self.init(table, { (_ : T) -> U in
426+
fatalError("Table forced before initialization completed; is something re-entrant?")
427+
}, { (_ : U) -> T in
428+
fatalError("Table forced before initialization completed; is something re-entrant?")
429+
})
429430

430431
self.embed = { t in
431432
if let v = table[t] {

Sources/SwiftCheck/Property.swift

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,18 @@ private func printLabels(_ st : TestResult) {
671671
}
672672
}
673673

674+
/// Takes a sequence of trees of test results from several properties into
675+
/// a single labelled rose tree for the conjunction.
676+
///
677+
/// This function is written in continuation passsing style to facilitate the
678+
/// construction of a lazy rose tree that preserves the labels and callbacks
679+
/// associated with the sub-properties.
680+
///
681+
/// The general idea is that the properties are tested from first to last. If
682+
/// any of them fails, the conjunct need not evaluate further and returns that
683+
/// first failing result. Else, each passing sub-property continues on to the
684+
/// next sub-property and decorates the overall result with its callbacks and
685+
/// labels. Discards act to skip that sub-property, as expected.
674686
private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose<TestResult>]) -> Rose<TestResult> {
675687
guard let p = xs.first else {
676688
return Rose.mkRose({ k(TestResult.succeeded) }, { [] })
@@ -679,16 +691,20 @@ private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose<TestRes
679691
let rose = p.reduce
680692
switch rose {
681693
case .mkRose(let result, _):
682-
if !result().expect {
694+
guard result().expect else {
683695
return Rose.pure(TestResult.failed("expectFailure may not occur inside a conjunction"))
684696
}
685697

686698
switch result().ok {
687699
case .some(true):
700+
// Passed - Adjoin the labels and test the next property.
688701
return conj(comp(addLabels(result()), comp(addCallbacks(result()), k)), xs: [Rose<TestResult>](xs[1..<xs.endIndex]))
689702
case .some(false):
703+
// Failed - Return the first failure and don't continue
704+
// evaluating the other conjuncts.
690705
return rose
691706
case .none:
707+
// Discard - Try the next property.
692708
let rose2 = conj(comp(addCallbacks(result()), k), xs: [Rose<TestResult>](xs[1..<xs.endIndex])).reduce
693709
switch rose2 {
694710
case .mkRose(let result2, _):
@@ -711,23 +727,28 @@ private func conj(_ k : @escaping (TestResult) -> TestResult, xs : [Rose<TestRes
711727
}))
712728
}
713729

730+
/// Computes the disjunction of two test results.
714731
private func disj(_ p : Rose<TestResult>, q : Rose<TestResult>) -> Rose<TestResult> {
715732
return p.flatMap { result1 in
716-
if !result1.expect {
733+
guard result1.expect else {
717734
return Rose<TestResult>.pure(TestResult.failed("expectFailure may not occur inside a disjunction"))
718735
}
719736
switch result1.ok {
720737
case .some(true):
738+
// Passed - Don't evaluate the other tree.
721739
return Rose<TestResult>.pure(result1)
722740
case .some(false):
723-
return q.flatMap { (result2 : TestResult) in
724-
if !result2.expect {
741+
// Failed - Try the other tree.
742+
return q.flatMap { result2 in
743+
guard result2.expect else {
725744
return Rose<TestResult>.pure(TestResult.failed("expectFailure may not occur inside a disjunction"))
726745
}
727746
switch result2.ok {
728747
case .some(true):
729748
return Rose<TestResult>.pure(result2)
730749
case .some(false):
750+
// Failed - Combine the exceptions and callbacks from each
751+
// sub-property.
731752
let callbacks : [Callback] = [.afterFinalFailure(kind: .counterexample, { (_, _) in return print("") })]
732753
return Rose<TestResult>.pure(TestResult(
733754
ok: .some(false),
@@ -745,8 +766,9 @@ private func disj(_ p : Rose<TestResult>, q : Rose<TestResult>) -> Rose<TestResu
745766
}
746767
}
747768
case .none:
748-
return q.flatMap { (result2 : TestResult) in
749-
if !result2.expect {
769+
// Discarded - Try the other property.
770+
return q.flatMap { result2 in
771+
guard result2.expect else {
750772
return Rose<TestResult>.pure(TestResult.failed("expectFailure may not occur inside a disjunction"))
751773
}
752774
switch result2.ok {

Sources/SwiftCheck/Random.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ extension Double : RandomType {
338338
}
339339
}
340340

341-
/// Implementation Details Follow
341+
// MARK: - Implementation Details
342+
342343
private enum ClockTimeResult {
343344
case success
344345
case failure(Int)

Sources/SwiftCheck/Test.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ public func exists<A : Arbitrary>(_ gen : Gen<A>, pf : @escaping (A) throws -> T
535535

536536
// MARK: - Implementation Details
537537

538-
internal enum Result {
538+
internal enum QuickCheckResult {
539539
case success(
540540
numTests : Int,
541541
labels : [(String, Int)],
@@ -585,7 +585,7 @@ private indirect enum Either<L, R> {
585585
case right(R)
586586
}
587587

588-
internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> Result {
588+
internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) -> QuickCheckResult {
589589
let istate = CheckerState(
590590
name: args.name,
591591
maxAllowableSuccessfulTests: args.maxAllowableSuccessfulTests,
@@ -621,7 +621,7 @@ internal func quickCheckWithResult(_ args : CheckerArguments, _ p : Testable) ->
621621
// - giveUp: When the number of discarded tests exceeds the number given in the
622622
// arguments we just give up turning the run loop to prevent excessive
623623
// generation.
624-
private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Result {
624+
private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> QuickCheckResult {
625625
var state = st
626626
while true {
627627
switch runATest(state, caseGen: caseGen) {
@@ -631,9 +631,9 @@ private func test(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Resul
631631
return fail.0
632632
case let (_, .noExpectedFailure(numTests, seed, sz, labels, output)):
633633
return .noExpectedFailure(numTests: numTests, usedSeed: seed, usedSize: sz, labels: labels, output: output)
634-
// Existential Failures need explicit propagation. Existentials increment the
635-
// discard count so we check if it has been surpassed. If it has with any kind
636-
// of success we're done. If no successes are found we've failed checking the
634+
// Existential Failures need explicit propagation. Existentials increment the
635+
// discard count so we check if it has been surpassed. If it has with any kind
636+
// of success we're done. If no successes are found we've failed checking the
637637
// existential and report it as such. Otherwise turn the testing loop.
638638
case (.existentialFailure(_, _, _, _, _, _, _), _):
639639
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
661661
//
662662
// On success the next state is returned. On failure the final result and state
663663
// are returned.
664-
private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(Result, CheckerState), CheckerState> {
664+
private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> Either<(QuickCheckResult, CheckerState), CheckerState> {
665665
let size = st.computeSize(st.successfulTestCount, st.discardedTestCount)
666666
let (rnd1, rnd2) = st.randomSeedGenerator.split
667667

@@ -751,7 +751,7 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E
751751

752752
/// However, some existentials outlive their usefulness
753753
if nstate.discardedTestCount >= nstate.maxAllowableDiscardedTests {
754-
let resul = Result.existentialFailure(
754+
let resul = QuickCheckResult.existentialFailure(
755755
numTests: (st.successfulTestCount + 1),
756756
usedSeed: st.randomSeedGenerator,
757757
usedSize: st.computeSize(st.successfulTestCount, st.discardedTestCount),
@@ -768,12 +768,12 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E
768768
// Attempt a shrink.
769769
let (numShrinks, _, _) = findMinimalFailingTestCase(st, res: res, ts: ts())
770770

771-
if !expect {
772-
let s = Result.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ")
771+
guard expect else {
772+
let s = QuickCheckResult.success(numTests: (st.successfulTestCount + 1), labels: summary(st), output: "+++ OK, failed as expected. ")
773773
return .left((s, st))
774774
}
775775

776-
let stat = Result.failure(
776+
let stat = QuickCheckResult.failure(
777777
numTests: (st.successfulTestCount + 1),
778778
numShrinks: numShrinks,
779779
usedSeed: st.randomSeedGenerator,
@@ -809,7 +809,7 @@ private func runATest(_ st : CheckerState, caseGen : (StdGen, Int) -> Prop) -> E
809809
}
810810
}
811811

812-
private func doneTesting(_ st : CheckerState) -> Result {
812+
private func doneTesting(_ st : CheckerState) -> QuickCheckResult {
813813
if !st.hasFulfilledExpectedFailure {
814814
if insufficientCoverage(st) {
815815
printCond(st.silence, "+++ OK, failed as expected. ")
@@ -843,7 +843,7 @@ private func doneTesting(_ st : CheckerState) -> Result {
843843
}
844844
}
845845

846-
private func giveUp(_ st : CheckerState) -> Result {
846+
private func giveUp(_ st : CheckerState) -> QuickCheckResult {
847847
printDistributionGraph(st)
848848
return .gaveUp(numTests: st.successfulTestCount, labels: summary(st), output: "")
849849
}
@@ -944,7 +944,7 @@ private func reportMinimumCaseFound(_ st : CheckerState, res : TestResult) -> (I
944944
return (st.successfulShrinkCount, st.failedShrinkStepCount - st.failedShrinkStepDistance, st.failedShrinkStepDistance)
945945
}
946946

947-
private func reportExistentialFailure(_ st : CheckerState, res : Result) -> Result {
947+
private func reportExistentialFailure(_ st : CheckerState, res : QuickCheckResult) -> QuickCheckResult {
948948
switch res {
949949
case let .existentialFailure(_, _, _, reason, _, _, lastTest):
950950
let testMsg = " (after \(st.discardedTestCount) test"

Sources/SwiftCheck/WitnessedArbitrary.swift

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ extension Dictionary : Arbitrary where Key : Arbitrary, Value : Arbitrary {
100100
public static var arbitrary : Gen<Dictionary<Key, Value>> {
101101
return [Key].arbitrary.flatMap { (k : [Key]) in
102102
return [Value].arbitrary.flatMap { (v : [Value]) in
103-
return Gen.pure(Dictionary(zip(k, v)))
103+
return Gen.pure(Dictionary(zip(k, v)) { $1 })
104104
}
105105
}
106106
}
@@ -173,7 +173,7 @@ extension Set : Arbitrary where Element : Arbitrary {
173173
}
174174
}
175175

176-
// MARK: - Implementation Details Follow
176+
// MARK: - Implementation Details
177177

178178
private func removes<A : Arbitrary>(_ k : Int, n : Int, xs : [A]) -> [[A]] {
179179
let xs2 : [A] = Array(xs.suffix(max(0, xs.count - k)))
@@ -189,25 +189,13 @@ private func removes<A : Arbitrary>(_ k : Int, n : Int, xs : [A]) -> [[A]] {
189189
}
190190

191191
private func shrinkOne<A : Arbitrary>(_ xs : [A]) -> [[A]] {
192-
if xs.isEmpty {
192+
guard let x : A = xs.first else {
193193
return [[A]]()
194-
} else if let x : A = xs.first {
195-
let xss = [A](xs[1..<xs.endIndex])
196-
let a : [[A]] = A.shrink(x).map({ [$0] + xss })
197-
let b : [[A]] = shrinkOne(xss).map({ [x] + $0 })
198-
return a + b
199194
}
200-
fatalError("Array could not produce a first element")
201-
}
202195

203-
extension Dictionary {
204-
fileprivate init<S : Sequence>(_ pairs : S)
205-
where S.Iterator.Element == (Key, Value)
206-
{
207-
self.init()
208-
var g = pairs.makeIterator()
209-
while let (k, v): (Key, Value) = g.next() {
210-
self[k] = v
211-
}
212-
}
196+
let xss = [A](xs[1..<xs.endIndex])
197+
let a : [[A]] = A.shrink(x).map({ [$0] + xss })
198+
let b : [[A]] = shrinkOne(xss).map({ [x] + $0 })
199+
return a + b
213200
}
201+

0 commit comments

Comments
 (0)