diff --git a/Sources/EasyDi.swift b/Sources/EasyDi.swift index 98bf592..a558a71 100644 --- a/Sources/EasyDi.swift +++ b/Sources/EasyDi.swift @@ -24,9 +24,6 @@ struct WeakSingletonWrapper { weak var instance: AnyObject? } -// For handle fatalError calls in tests -var fatalError = Swift.fatalError - /// This class is used to join assembly instances into separated shared group. /// /// All assemblies with one context shares object graph stack. @@ -358,7 +355,7 @@ open class Assembly: AssemblyInternal { definitionClosure: DefinitionClosure? = nil) -> ResultType { guard let context = self.context else { - fatalError("Associated context doesn't exists anymore", #file, #line) + fatalError("Associated context doesn't exists anymore") } context.locker.lock(); defer { context.locker.unlock() } @@ -374,7 +371,7 @@ open class Assembly: AssemblyInternal { let substitutionObject = substitutionClosure() guard let object = substitutionObject as? ResultType else { - fatalError("Expected type: \(ResultType.self), received: \(type(of: substitutionObject))", #file, #line) + fatalError("Expected type: \(ResultType.self), received: \(type(of: substitutionObject))") } return object @@ -399,7 +396,7 @@ open class Assembly: AssemblyInternal { context.objectGraphStackDepth += 1 guard var object = definition.initObject() else { - fatalError("Failed to initialize object", #file, #line) + fatalError("Failed to initialize object") } context.objectGraphStackDepth -= 1 @@ -428,7 +425,8 @@ open class Assembly: AssemblyInternal { if type(of: current) is AnyClass { if unsafeBitCast(current, to: Int.self) != unsafeBitCast(result, to: Int.self) { - fatalError("Singleton already exist, inspect your dependencies graph", #file, #line) + let reason = "Singleton already exist, inspect your dependencies graph" + NSException(name: .internalInconsistencyException, reason: reason, userInfo: nil).raise() } } else { // Skip value types @@ -446,7 +444,7 @@ open class Assembly: AssemblyInternal { } guard let finalResult = result as? ResultType else { - fatalError("Failed to build result object. Expected \(ResultType.self) received: \(result)", #file, #line) + fatalError("Failed to build result object. Expected \(ResultType.self) received: \(result)") } return finalResult @@ -474,7 +472,7 @@ public final class Definition: DefinitionInternal func injectObject(object: InjectableObject) -> InjectableObject { guard let injectableObject = object as? ObjectType else { - fatalError("Failed to build result object. Expected \(ObjectType.self) received: \(object)", #file, #line) + fatalError("Failed to build result object. Expected \(ObjectType.self) received: \(object)") } guard let actualInjectClosure = self.injectClosure else { diff --git a/Tests/Test_SingletonDuplication.swift b/Tests/Test_SingletonDuplication.swift index f50074f..cc46950 100644 --- a/Tests/Test_SingletonDuplication.swift +++ b/Tests/Test_SingletonDuplication.swift @@ -36,32 +36,36 @@ fileprivate class TestAssembly: Assembly { final class Test_SingletonDuplication: XCTestCase { func testSingletonDuplication() { + NSException.test_swizzleRaise() + let context = DIContext() let assembly = TestAssembly.instance(from: context) - let error = FalatErrorHandler(test: self).catchFatalError { - let _ = assembly.objectA - let _ = assembly.objectB - } - XCTAssertEqual(error, "Singleton already exist, inspect your dependencies graph") + let _ = assembly.objectA + let _ = assembly.objectB + + XCTAssertEqual(NSException.last?.reason, "Singleton already exist, inspect your dependencies graph") + NSException.last = nil } } -private struct FalatErrorHandler { - let test: XCTestCase +extension NSException { + static var last: NSException? + static var alreadySwizzled = false - func catchFatalError(handler: @escaping () -> Void) -> String? { - let expectation = test.expectation(description: "fatal_error") - var result: String? - EasyDi.fatalError = { message, _, _ in - result = message() - expectation.fulfill() - while (true) { RunLoop.current.run() } - } + static func test_swizzleRaise() { + guard !alreadySwizzled else { return } - DispatchQueue.global(qos: .background).async(execute: handler) - test.waitForExpectations(timeout: 0.1, handler: nil) - EasyDi.fatalError = Swift.fatalError - return result + let origin = class_getInstanceMethod(NSException.self, NSSelectorFromString("raise")) + let new = class_getInstanceMethod(NSException.self, NSSelectorFromString("test_raise")) + + if let origin = origin, let new = new { + method_exchangeImplementations(origin, new) + alreadySwizzled = true + } + } + + @objc func test_raise() { + NSException.last = self } }