Skip to content

Commit

Permalink
Use NSException
Browse files Browse the repository at this point in the history
  • Loading branch information
rock88 committed Jun 11, 2021
1 parent 68c1cb1 commit cdfb91e
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 28 deletions.
16 changes: 7 additions & 9 deletions Sources/EasyDi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -358,7 +355,7 @@ open class Assembly: AssemblyInternal {
definitionClosure: DefinitionClosure<ObjectType>? = 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() }
Expand All @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -474,7 +472,7 @@ public final class Definition<ObjectType: InjectableObject>: 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 {
Expand Down
42 changes: 23 additions & 19 deletions Tests/Test_SingletonDuplication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

0 comments on commit cdfb91e

Please sign in to comment.