Skip to content

Commit

Permalink
Allow ScopedModuleAssembler to be initialized with behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
bradfol committed Nov 9, 2024
1 parent 5ae0b17 commit 6a6db5c
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
6 changes: 5 additions & 1 deletion Sources/Knit/Module/ModuleAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public final class ModuleAssembler {
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
assemblyValidation: ((any ModuleAssembly.Type) throws -> Void)? = nil,
errorFormatter: ModuleAssemblerErrorFormatter = DefaultModuleAssemblerErrorFormatter(),
behaviors: [Behavior] = [],
postAssemble: ((Container) -> Void)? = nil
) throws {
self.builder = try DependencyBuilder(
Expand All @@ -84,7 +85,10 @@ public final class ModuleAssembler {
)

self.parent = parent
self._container = Container(parent: parent?._container)
self._container = Container(
parent: parent?._container,
behaviors: behaviors
)
self.serviceCollector = .init(parent: parent?.serviceCollector)
self._container.addBehavior(serviceCollector)
let abstractRegistrations = self._container.registerAbstractContainer()
Expand Down
4 changes: 4 additions & 0 deletions Sources/Knit/Module/ScopedModuleAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
_ modules: [any ModuleAssembly],
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
errorFormatter: ModuleAssemblerErrorFormatter = DefaultModuleAssemblerErrorFormatter(),
behaviors: [Behavior] = [],
postAssemble: ((Container) -> Void)? = nil,
file: StaticString = #fileID,
line: UInt = #line
Expand All @@ -34,6 +35,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
parent: parent,
_modules: modules,
overrideBehavior: overrideBehavior,
behaviors: behaviors,
postAssemble: postAssemble
)
} catch {
Expand All @@ -53,6 +55,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
_modules modules: [any ModuleAssembly],
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
errorFormatter: ModuleAssemblerErrorFormatter = DefaultModuleAssemblerErrorFormatter(),
behaviors: [Behavior] = [],
postAssemble: ((Container) -> Void)? = nil
) throws {
// For provided modules, fail early if they are scoped incorrectly
Expand Down Expand Up @@ -80,6 +83,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
}
},
errorFormatter: errorFormatter,
behaviors: behaviors,
postAssemble: postAssemble
)
}
Expand Down
38 changes: 38 additions & 0 deletions Tests/KnitTests/ScopedModuleAssemblerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import Foundation
@testable import Knit
@testable import Swinject
import XCTest

final class ScopedModuleAssemblerTests: XCTestCase {
Expand Down Expand Up @@ -76,6 +77,30 @@ final class ScopedModuleAssemblerTests: XCTestCase {
)
}

@MainActor
func test_integration_initializerBehaviorsPassedToInternalContainer() throws {
// This is a bit of an integration test to ensure that behaviors passed to the ScopedModuleAssembler initializer
// are passed through correctly to the backing Container instance.

let testBehavior = TestBehavior()
let scopedModuleAssembler = ScopedModuleAssembler<TestResolver>(
[],
behaviors: [testBehavior]
)
let container = scopedModuleAssembler._container
// ModuleAssembler automatically adds behaviors for ServiceCollector and AbstractRegistrationContainer
// so first filter those out
let foundBehaviors = container.behaviors.filter { behavior in
let behaviorType = type(of: behavior)
return behaviorType != ServiceCollector.self &&
behaviorType != Container.AbstractRegistrationContainer.self
}
// There should only be one behavior left
XCTAssertEqual(foundBehaviors.count, 1)
let containerBehavior = try XCTUnwrap(foundBehaviors.first as? AnyObject)
XCTAssert(containerBehavior === testBehavior)
}

}

private struct Assembly1: AutoInitModuleAssembly {
Expand All @@ -96,3 +121,16 @@ private struct Assembly3: AutoInitModuleAssembly {
static var dependencies: [any ModuleAssembly.Type] { [Assembly1.self] }
func assemble(container: Container) { }
}

private final class TestBehavior: Behavior {

func container<Type, Service>(
_ container: Container,
didRegisterType type: Type.Type,
toService entry: Swinject.ServiceEntry<Service>,
withName name: String?
) {
// No op
}

}

0 comments on commit 6a6db5c

Please sign in to comment.