diff --git a/.swiftlint.yml b/.swiftlint.yml index 5802f170b..cf347758e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,6 +1,5 @@ disabled_rules: - todo - - force_try included: - Sources diff --git a/Sources/Nimble/Adapters/AssertionRecorder.swift b/Sources/Nimble/Adapters/AssertionRecorder.swift index 740c3923d..b0b4caf8f 100644 --- a/Sources/Nimble/Adapters/AssertionRecorder.swift +++ b/Sources/Nimble/Adapters/AssertionRecorder.swift @@ -43,15 +43,26 @@ public class AssertionRecorder: AssertionHandler { /// Once the closure finishes, then the original Nimble assertion handler is restored. /// /// @see AssertionHandler -public func withAssertionHandler(_ tempAssertionHandler: AssertionHandler, closure: () throws -> Void) { +public func withAssertionHandler(_ tempAssertionHandler: AssertionHandler, + file: FileString = #file, + line: UInt = #line, + closure: () throws -> Void) { let environment = NimbleEnvironment.activeInstance let oldRecorder = environment.assertionHandler let capturer = NMBExceptionCapture(handler: nil, finally: ({ environment.assertionHandler = oldRecorder })) environment.assertionHandler = tempAssertionHandler - capturer.tryBlock { - try! closure() + + do { + try capturer.tryBlockThrows { + try closure() + } + } catch { + let failureMessage = FailureMessage() + failureMessage.stringValue = "unexpected error thrown: <\(error)>" + let location = SourceLocation(file: file, line: line) + tempAssertionHandler.assert(false, message: failureMessage, location: location) } } diff --git a/Sources/Nimble/Adapters/NMBExpectation.swift b/Sources/Nimble/Adapters/NMBExpectation.swift index 5e35c662b..e66e7e5d7 100644 --- a/Sources/Nimble/Adapters/NMBExpectation.swift +++ b/Sources/Nimble/Adapters/NMBExpectation.swift @@ -15,6 +15,7 @@ internal struct ObjCMatcherWrapper: Matcher { func matches(_ actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.matches( + // swiftlint:disable:next force_try ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) @@ -22,6 +23,7 @@ internal struct ObjCMatcherWrapper: Matcher { func doesNotMatch(_ actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.doesNotMatch( + // swiftlint:disable:next force_try ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) diff --git a/Sources/Nimble/Matchers/AllPass.swift b/Sources/Nimble/Matchers/AllPass.swift index cc6c24f05..d3920c5f5 100644 --- a/Sources/Nimble/Matchers/AllPass.swift +++ b/Sources/Nimble/Matchers/AllPass.swift @@ -103,6 +103,7 @@ extension NMBObjCMatcher { } else { let failureMessage = FailureMessage() let result = matcher.matches( + // swiftlint:disable:next force_try ({ try! expr.evaluate() }), failureMessage: failureMessage, location: expr.location diff --git a/Sources/Nimble/Matchers/RaisesException.swift b/Sources/Nimble/Matchers/RaisesException.swift index a03f20ac6..234285683 100644 --- a/Sources/Nimble/Matchers/RaisesException.swift +++ b/Sources/Nimble/Matchers/RaisesException.swift @@ -3,6 +3,22 @@ import Foundation // This matcher requires the Objective-C, and being built by Xcode rather than the Swift Package Manager #if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE +extension NMBExceptionCapture { + internal func tryBlockThrows(_ unsafeBlock: () throws -> Void) throws { + var catchedError: Error? + tryBlock { + do { + try unsafeBlock() + } catch { + catchedError = error + } + } + if let error = catchedError { + throw error + } + } +} + /// A Nimble matcher that succeeds when the actual expression raises an /// exception with the specified name, reason, and/or userInfo. /// @@ -24,9 +40,13 @@ public func raiseException( exception = e }), finally: nil) - capture.tryBlock { - _ = try! actualExpression.evaluate() - return + do { + try capture.tryBlockThrows { + _ = try actualExpression.evaluate() + } + } catch { + failureMessage.stringValue = "unexpected error thrown: <\(error)>" + return false } setFailureMessageForException( diff --git a/Sources/Nimble/Matchers/SatisfyAllOf.swift b/Sources/Nimble/Matchers/SatisfyAllOf.swift index 2b9eb2189..26d0d3599 100644 --- a/Sources/Nimble/Matchers/SatisfyAllOf.swift +++ b/Sources/Nimble/Matchers/SatisfyAllOf.swift @@ -60,8 +60,12 @@ extension NMBObjCMatcher { return predicate.satisfies({ try expression.evaluate() }, location: actualExpression.location).toSwift() } else { let failureMessage = FailureMessage() - // swiftlint:disable:next line_length - let success = matcher.matches({ try! expression.evaluate() }, failureMessage: failureMessage, location: actualExpression.location) + let success = matcher.matches( + // swiftlint:disable:next force_try + { try! expression.evaluate() }, + failureMessage: failureMessage, + location: actualExpression.location + ) return PredicateResult(bool: success, message: failureMessage.toExpectationMessage()) } } diff --git a/Sources/Nimble/Matchers/SatisfyAnyOf.swift b/Sources/Nimble/Matchers/SatisfyAnyOf.swift index 57b15fd38..20477371d 100644 --- a/Sources/Nimble/Matchers/SatisfyAnyOf.swift +++ b/Sources/Nimble/Matchers/SatisfyAnyOf.swift @@ -68,8 +68,12 @@ extension NMBObjCMatcher { return predicate.satisfies({ try expression.evaluate() }, location: actualExpression.location).toSwift() } else { let failureMessage = FailureMessage() - // swiftlint:disable:next line_length - let success = matcher.matches({ try! expression.evaluate() }, failureMessage: failureMessage, location: actualExpression.location) + let success = matcher.matches( + // swiftlint:disable:next force_try + { try! expression.evaluate() }, + failureMessage: failureMessage, + location: actualExpression.location + ) return PredicateResult(bool: success, message: failureMessage.toExpectationMessage()) } } diff --git a/Tests/NimbleTests/Helpers/utils.swift b/Tests/NimbleTests/Helpers/utils.swift index 373bd1be5..6b8289dad 100644 --- a/Tests/NimbleTests/Helpers/utils.swift +++ b/Tests/NimbleTests/Helpers/utils.swift @@ -8,7 +8,7 @@ func failsWithErrorMessage(_ messages: [String], file: FileString = #file, line: var lineNumber = line let recorder = AssertionRecorder() - withAssertionHandler(recorder, closure: closure) + withAssertionHandler(recorder, file: file, line: line, closure: closure) for msg in messages { var lastFailure: AssertionRecord?