diff --git a/Package.swift b/Package.swift index f81b361..980e833 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.2 +// swift-tools-version:6.0 import PackageDescription diff --git a/Package@swift-5.2.swift b/Package@swift-5.2.swift new file mode 100644 index 0000000..f81b361 --- /dev/null +++ b/Package@swift-5.2.swift @@ -0,0 +1,23 @@ +// swift-tools-version:5.2 + +import PackageDescription + +let package = Package( + name: "SwiftCheck", + products: [ + .library( + name: "SwiftCheck", + targets: ["SwiftCheck"]), + ], + dependencies: [ + .package(url: "https://github.com/llvm-swift/FileCheck.git", from: "0.1.0") + ], + targets: [ + .target( + name: "SwiftCheck"), + .testTarget( + name: "SwiftCheckTests", + dependencies: ["SwiftCheck", "FileCheck"]), + ] +) + diff --git a/Sources/SwiftCheck/Check.swift b/Sources/SwiftCheck/Check.swift index 60635f3..1b39fa1 100644 --- a/Sources/SwiftCheck/Check.swift +++ b/Sources/SwiftCheck/Check.swift @@ -161,12 +161,31 @@ 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 .failure(_, _, seed, sz, reason, _, _): + let message = "\(reason); Replay with \(seed) and size \(sz)" + + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) 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) + let message = "Expected property to fail but it didn't. Replay with \(seed) and size \(sz)" + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + let message = "Property coverage insufficient. Replay with \(seed) and size \(sz)" + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) default: () } } @@ -175,11 +194,29 @@ public func <- (checker : AssertiveQuickCheck, test : @autoclosure @escaping () 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) + let message = "\(reason); Replay with \(seed) and size \(sz)" + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) 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) + let message = "Expected property to fail but it didn't. Replay with \(seed) and size \(sz)" + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) case let .insufficientCoverage(_, seed, sz, _, _): - XCTFail("Property coverage insufficient. Replay with \(seed) and size \(sz)", file: checker.file, line: checker.line) + let message = "Property coverage insufficient. Replay with \(seed) and size \(sz)" + XCTFail(message, file: checker.file, line: checker.line) + Issue.record("\(message)", + sourceLocation: SourceLocation(fileID: String(describing: checker.file), + filePath: String(describing: checker.file), + line: Int(checker.line), column: 1) + ) default: () } } @@ -356,3 +393,4 @@ public func ^||^ (p1 : Testable, p2 : Testable) -> Property { } import XCTest +import Testing diff --git a/Sources/SwiftCheck/Random.swift b/Sources/SwiftCheck/Random.swift index c804261..5363077 100644 --- a/Sources/SwiftCheck/Random.swift +++ b/Sources/SwiftCheck/Random.swift @@ -100,12 +100,15 @@ extension StdGen : Equatable, CustomStringConvertible { } } -private var theStdGen : StdGen = mkStdRNG(0) +private actor TheStdGen { + static var shared : StdGen = mkStdRNG(0) + +} /// A library-provided standard random number generator. public func newStdGen() -> StdGen { - let (left, right) = theStdGen.split - theStdGen = left + let (left, right) = TheStdGen.shared.split + TheStdGen.shared = left return right } diff --git a/Tests/SwiftCheckTests/ComplexSpec.swift b/Tests/SwiftCheckTests/ComplexSpec.swift index 6646210..2a132eb 100644 --- a/Tests/SwiftCheckTests/ComplexSpec.swift +++ b/Tests/SwiftCheckTests/ComplexSpec.swift @@ -12,16 +12,16 @@ import XCTest import FileCheck #endif -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 { + 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: ["!", "#", "$", "%", "&", "'", "*", "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~", "."]) + lazy var hexDigits = Gen.one(of: [ + Gen.fromElements(in: "A"..."F"), + numeric, + ]) func testEmailAddressProperties() { XCTAssert(fileCheckOutput(withPrefixes: ["CHECKEMAIL"]) { let localEmail = Gen.one(of: [ diff --git a/Tests/SwiftCheckTests/SimpleSpec.swift b/Tests/SwiftCheckTests/SimpleSpec.swift index f9b0f29..5c475bb 100644 --- a/Tests/SwiftCheckTests/SimpleSpec.swift +++ b/Tests/SwiftCheckTests/SimpleSpec.swift @@ -120,28 +120,28 @@ 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() { + 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()) + ) + } + XCTAssert(fileCheckOutput { // CHECK: *** Passed 100 tests // CHECK-NEXT: .