diff --git a/Sources/Knit/Module/Container+AbstractRegistration.swift b/Sources/Knit/Module/Container+AbstractRegistration.swift index 0545cee..c6d5420 100644 --- a/Sources/Knit/Module/Container+AbstractRegistration.swift +++ b/Sources/Knit/Module/Container+AbstractRegistration.swift @@ -59,7 +59,7 @@ internal struct RegistrationKey: Hashable, Equatable { internal protocol AbstractRegistration { associatedtype ServiceType - var serviceType: ServiceType.Type { get } + var serviceDescription: String { get } var file: String { get } var name: String? { get } var key: RegistrationKey { get } @@ -78,7 +78,7 @@ extension AbstractRegistration { // Convert the key into an error var error: Container.AbstractRegistrationError { return Container.AbstractRegistrationError( - serviceType: "\(serviceType)", + serviceType: serviceDescription, file: file, name: name ) @@ -91,7 +91,7 @@ fileprivate struct RealAbstractRegistration: AbstractRegistration { // Source file used for debugging. Not included in hash calculation or equality let file: String - var serviceType: ServiceType.Type { ServiceType.self } + var serviceDescription: String { String(describing: ServiceType.self) } let concurrency: ConcurrencyAttribute @@ -116,17 +116,25 @@ fileprivate struct RealAbstractRegistration: AbstractRegistration { } /// An abstract registration for an optional service -fileprivate struct OptionalAbstractRegistration: AbstractRegistration { +/// The `UnwrappedServiceType` represents the inner type of the Optional service type for the registration. +fileprivate struct OptionalAbstractRegistration: AbstractRegistration { let name: String? // Source file used for debugging. Not included in hash calculation or equality let file: String - var serviceType: ServiceType.Type { ServiceType.self } + /// The actual service type added for this registration (includes the Optional wrapper). + typealias ServiceType = Optional + + var serviceDescription: String { String(describing: ServiceType.self) } let concurrency: ConcurrencyAttribute var key: RegistrationKey { - return .init(typeIdentifier: ObjectIdentifier(ServiceType.self), name: name, concurrency: concurrency) + return .init( + typeIdentifier: ObjectIdentifier(ServiceType.self), + name: name, + concurrency: concurrency + ) } func registerPlaceholder( @@ -134,7 +142,7 @@ fileprivate struct OptionalAbstractRegistration: AbstractRegistrati errorFormatter: ModuleAssemblerErrorFormatter, dependencyTree: DependencyTree ) { - container.register(Optional.self, name: name) { _ in + container.register(ServiceType.self, name: name) { _ in return nil } } diff --git a/Tests/KnitTests/AbstractRegistrationTests.swift b/Tests/KnitTests/AbstractRegistrationTests.swift index 4b09a2f..dd2b873 100644 --- a/Tests/KnitTests/AbstractRegistrationTests.swift +++ b/Tests/KnitTests/AbstractRegistrationTests.swift @@ -12,6 +12,7 @@ final class AbstractRegistrationTests: XCTestCase { let abstractRegistrations = container.registerAbstractContainer() container.registerAbstract(String.self) container.registerAbstract(String.self, name: "test") + container.registerAbstract(Optional.self) XCTAssertThrowsError(try abstractRegistrations.validate()) { error in XCTAssertEqual( @@ -19,6 +20,7 @@ final class AbstractRegistrationTests: XCTestCase { """ Unsatisfied abstract registration. Service: String, File: KnitTests/AbstractRegistrationTests.swift Unsatisfied abstract registration. Service: String, File: KnitTests/AbstractRegistrationTests.swift, Name: test + Unsatisfied abstract registration. Service: Optional, File: KnitTests/AbstractRegistrationTests.swift """ ) } @@ -29,8 +31,14 @@ final class AbstractRegistrationTests: XCTestCase { let abstractRegistrations = container.registerAbstractContainer() container.registerAbstract(String.self) container.register(String.self) { _ in "Test" } + + // Abstract registrations of Optional types are handled differently so test that as well + container.registerAbstract(Optional.self) + container.register(Optional.self) { _ in 1 } + XCTAssertNoThrow(try abstractRegistrations.validate()) XCTAssertEqual(container.resolve(String.self), "Test") + XCTAssertEqual(container.resolve(Optional.self), 1) } func testNamedRegistrations() {