Skip to content

Commit

Permalink
Provide basic integration with Swift Testing
Browse files Browse the repository at this point in the history
This is not reliable, in fact, failure reporting is flaky.
  • Loading branch information
younata committed Sep 9, 2024
1 parent 3e40449 commit b16e122
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 8 deletions.
8 changes: 8 additions & 0 deletions Nimble.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@
8923E60D2B47CE7E00F3961A /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8923E60C2B47CE7E00F3961A /* Map.swift */; };
8923E6102B47D08300F3961A /* MapTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8923E60E2B47D06E00F3961A /* MapTest.swift */; };
892FDF1329D3EA7700523A80 /* AsyncExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892FDF1229D3EA7700523A80 /* AsyncExpression.swift */; };
895644DD2C1B63910006EC12 /* NimbleSwiftTestingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895644DC2C1B63910006EC12 /* NimbleSwiftTestingHandler.swift */; };
895644DF2C1B71DE0006EC12 /* SwiftTestingSupportTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 895644DE2C1B71DE0006EC12 /* SwiftTestingSupportTest.swift */; };
896962412A5FABD000A7929D /* AsyncAllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896962402A5FABD000A7929D /* AsyncAllPass.swift */; };
8969624A2A5FAD5F00A7929D /* AsyncAllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896962452A5FAD4500A7929D /* AsyncAllPassTest.swift */; };
898F28B025D9F4C30052B8D0 /* AlwaysFailMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898F28AF25D9F4C30052B8D0 /* AlwaysFailMatcher.swift */; };
Expand Down Expand Up @@ -324,6 +326,8 @@
8923E60E2B47D06E00F3961A /* MapTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTest.swift; sourceTree = "<group>"; };
892FDF1229D3EA7700523A80 /* AsyncExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncExpression.swift; sourceTree = "<group>"; };
8952ADDC2B4F159400D9305F /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
895644DC2C1B63910006EC12 /* NimbleSwiftTestingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NimbleSwiftTestingHandler.swift; sourceTree = "<group>"; };
895644DE2C1B71DE0006EC12 /* SwiftTestingSupportTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTestingSupportTest.swift; sourceTree = "<group>"; };
896962402A5FABD000A7929D /* AsyncAllPass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAllPass.swift; sourceTree = "<group>"; };
896962452A5FAD4500A7929D /* AsyncAllPassTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAllPassTest.swift; sourceTree = "<group>"; };
898F28AF25D9F4C30052B8D0 /* AlwaysFailMatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlwaysFailMatcher.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -490,6 +494,7 @@
89C297CB2A911CDA002A143F /* AsyncTimerSequenceTest.swift */,
89C297CD2A92AB34002A143F /* AsyncPromiseTest.swift */,
965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */,
895644DE2C1B71DE0006EC12 /* SwiftTestingSupportTest.swift */,
6CAEDD091CAEA86F003F1584 /* LinuxSupport.swift */,
1F14FB61194180A7009F2A08 /* Helpers */,
1F925EE3195C11B000ED456B /* Matchers */,
Expand Down Expand Up @@ -561,6 +566,7 @@
89F5E090290B9D5C001F9377 /* AssertionRecorder+Async.swift */,
1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */,
1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */,
895644DC2C1B63910006EC12 /* NimbleSwiftTestingHandler.swift */,
1F1871BA1CA89E2500A34BF2 /* NonObjectiveC */,
1F1871C21CA89EDB00A34BF2 /* NMBExpectation.swift */,
);
Expand Down Expand Up @@ -872,6 +878,7 @@
CDF5C57B2647B89B0036532C /* Equal+Tuple.swift in Sources */,
857D1849253610A900D8693A /* BeWithin.swift in Sources */,
1FD8CD4D1968AB07008ED995 /* BeLessThan.swift in Sources */,
895644DD2C1B63910006EC12 /* NimbleSwiftTestingHandler.swift in Sources */,
1FD8CD471968AB07008ED995 /* BeGreaterThan.swift in Sources */,
F8A1BE301CB3710900031679 /* XCTestObservationCenter+Register.m in Sources */,
1FD8CD311968AB07008ED995 /* AdapterProtocols.swift in Sources */,
Expand Down Expand Up @@ -974,6 +981,7 @@
1F4A568C1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */,
DDEFAEB51A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */,
1F4A56801A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */,
895644DF2C1B71DE0006EC12 /* SwiftTestingSupportTest.swift in Sources */,
857D184F2536124400D8693A /* BeWithinTest.swift in Sources */,
8922828F2B283956002DA355 /* AsyncAwaitTest+Require.swift in Sources */,
1F0648CD19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */,
Expand Down
10 changes: 7 additions & 3 deletions Sources/Nimble/Adapters/AdapterProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ public protocol AssertionHandler {
}

/// Global backing interface for assertions that Nimble creates.
/// Defaults to a private test handler that passes through to XCTest.
/// Defaults to a private test handler that passes through to Swift Testing or XCTest.
///
/// If XCTest is not available, you must assign your own assertion handler
/// If neither Swift Testing or XCTest is available, you must assign your own assertion handler
/// before using any matchers, otherwise Nimble will abort the program.
///
/// @see AssertionHandler
public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in
// swiftlint:disable:previous identifier_name
return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler()
if isSwiftTestingAvailable() || isXCTestAvailable() {
return NimbleTestingHandler()
}

return NimbleTestingUnavailableHandler()
}()
34 changes: 34 additions & 0 deletions Sources/Nimble/Adapters/NimbleSwiftTestingHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Foundation
#if canImport(Testing)
import Testing
#endif

public class NimbleSwiftTestingHandler: AssertionHandler {
public func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) {
if !assertion {
recordTestingFailure("\(message.stringValue)\n", location: location)
}
}
}

func isSwiftTestingAvailable() -> Bool {
#if canImport(Testing)
true
#else
false
#endif
}

func isRunningSwiftTest() -> Bool {
#if canImport(Testing)
Test.current != nil
#else
false
#endif
}

public func recordTestingFailure(_ message: String, location: SourceLocation) {
#if canImport(Testing)
Issue.record("\(message)", filePath: "\(location.file)", line: Int(location.line), column: 0)
#endif
}
20 changes: 15 additions & 5 deletions Sources/Nimble/Adapters/NimbleXCTestHandler.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import Foundation
import XCTest

/// Default handler for Nimble. This assertion handler passes failures along to
/// XCTest.
/// Default handler for Nimble. This assertion handler passes on to Swift Testing or XCTest.
public class NimbleTestingHandler: AssertionHandler {
public func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) {
if isRunningSwiftTest() {
NimbleSwiftTestingHandler().assert(assertion, message: message, location: location)
} else {
NimbleXCTestHandler().assert(assertion, message: message, location: location)
}
}
}

/// This assertion handler passes failures along to XCTest.
public class NimbleXCTestHandler: AssertionHandler {
public func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) {
if !assertion {
Expand All @@ -27,11 +37,11 @@ public class NimbleShortXCTestHandler: AssertionHandler {
}
}

/// Fallback handler in case XCTest is unavailable. This assertion handler will abort
/// Fallback handler in case XCTest/Swift Testing is unavailable. This assertion handler will abort
/// the program if it is invoked.
class NimbleXCTestUnavailableHandler: AssertionHandler {
class NimbleTestingUnavailableHandler: AssertionHandler {
func assert(_ assertion: Bool, message: FailureMessage, location: SourceLocation) {
fatalError("XCTest is not available and no custom assertion handler was configured. Aborting.")
fatalError("XCTest and Swift Testing are not available and no custom assertion handler was configured. Aborting.")
}
}

Expand Down
33 changes: 33 additions & 0 deletions Tests/NimbleTests/SwiftTestingSupportTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#if canImport(Testing)
import Nimble
import Testing
import XCTest

@Suite struct SwiftTestingSupportSuite {
@Test func reportsAssertionFailuresToSwiftTesting() {
withKnownIssue {
fail()
}
}

@Test func reportsRequireErrorsToSwiftTesting() throws {
withKnownIssue {
try require(false).to(beTrue())
}
}
}

class MixedSwiftTestingXCTestSupport: XCTestCase {
func testAlsoRecordsErrorsToXCTest() {
XCTExpectFailure("This should fail")
fail()

}

func testAlsoRecordsRequireErrorsToXCTest() throws {
XCTExpectFailure("This should fail")
try require(false).to(beTrue())
}
}

#endif

0 comments on commit b16e122

Please sign in to comment.