Skip to content

Commit

Permalink
Clarify Default Override Behavior API
Browse files Browse the repository at this point in the history
A terminology update to clarify what the different behaviors are for default overrides.
  • Loading branch information
bradfol committed Jan 11, 2024
1 parent dbb8e72 commit 1604e24
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 33 deletions.
12 changes: 6 additions & 6 deletions Sources/Knit/Module/DependencyBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ final class DependencyBuilder {
private var inputModules: [any ModuleAssembly] = []
var assemblies: [any ModuleAssembly] = []
let isRegisteredInParent: (any ModuleAssembly.Type) -> Bool
private let defaultOverrides: DefaultOverrideState
private let overrideBehavior: OverrideBehavior
private var moduleSources: [String: any ModuleAssembly.Type] = [:]

init(
modules: [any ModuleAssembly],
assemblyValidation: ((any ModuleAssembly.Type) throws -> Void)? = nil,
defaultOverrides: DefaultOverrideState = .whenTesting,
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
isRegisteredInParent: ((any ModuleAssembly.Type) -> Bool)? = nil
) throws {
self.assemblyValidation = assemblyValidation
self.defaultOverrides = defaultOverrides
self.overrideBehavior = overrideBehavior

inputModules = modules
self.isRegisteredInParent = isRegisteredInParent ?? {_ in false }
Expand Down Expand Up @@ -134,7 +134,7 @@ final class DependencyBuilder {
_ moduleType: any ModuleAssembly.Type,
fromInput: Bool
) throws -> (any ModuleAssembly.Type)? {
guard defaultOverrides.allow,
guard overrideBehavior.allowDefaultOverrides,
!fromInput,
let defaultType = (moduleType as? any DefaultModuleAssemblyOverride.Type)
else {
Expand Down Expand Up @@ -199,7 +199,7 @@ extension DependencyBuilder {
switch self {
case let .moduleNotProvided(moduleType, sourcePath):
var testAdvice = ""
if DefaultOverrideState.isRunningTests {
if OverrideBehavior.isRunningTests {
testAdvice += "Adding a dependency on the testing module for \(moduleType) should fix this issue"
}
return """
Expand Down Expand Up @@ -240,7 +240,7 @@ extension ModuleAssembly {

/// All original dependencies are registered along with any additional dependencies that the override requires
static var combinedDependencies: [any ModuleAssembly.Type] {
if DefaultOverrideState.isRunningTests {
if OverrideBehavior.isRunningTests {
// For tests only take this modules dependencies
return Self.dependencies
} else {
Expand Down
11 changes: 5 additions & 6 deletions Sources/Knit/Module/ModuleAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ public final class ModuleAssembler {
- Parameters:
- parent: A ModuleAssembler that has already been setup with some dependencies.
- modules: Array of modules to register
- defaultOverrides: Array of override types to use when resolving modules
- overrideBehavior: Behavior of default override usage.
- postAssemble: Hook after all assemblies are registered to make changes to the container.

*/
public convenience init(
parent: ModuleAssembler? = nil,
_ modules: [any Assembly],
defaultOverrides: DefaultOverrideState = .whenTesting,
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
assemblyValidation: ((any ModuleAssembly.Type) throws -> Void)? = nil,
postAssemble: ((Container) -> Void)? = nil,
file: StaticString = #file,
Expand All @@ -44,7 +43,7 @@ public final class ModuleAssembler {
try self.init(
parent: parent,
_modules: modules,
defaultOverrides: defaultOverrides,
overrideBehavior: overrideBehavior,
assemblyValidation: assemblyValidation,
postAssemble: postAssemble
)
Expand All @@ -63,7 +62,7 @@ public final class ModuleAssembler {
required init(
parent: ModuleAssembler? = nil,
_modules modules: [any Assembly],
defaultOverrides: DefaultOverrideState = .whenTesting,
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
assemblyValidation: ((any ModuleAssembly.Type) throws -> Void)? = nil,
postAssemble: ((Container) -> Void)? = nil
) throws {
Expand All @@ -73,7 +72,7 @@ public final class ModuleAssembler {
self.builder = try DependencyBuilder(
modules: moduleAssemblies,
assemblyValidation: assemblyValidation,
defaultOverrides: defaultOverrides,
overrideBehavior: overrideBehavior,
isRegisteredInParent: { type in
return parent?.isRegistered(type) ?? false
}
Expand Down
24 changes: 18 additions & 6 deletions Sources/Knit/Module/ModuleAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,26 @@ extension ModuleAssembly where Self: GeneratedModuleAssembly {
public static var dependencies: [any ModuleAssembly.Type] { scoped(generatedDependencies) }
}

public enum DefaultOverrideState {
case on, off, whenTesting
/// Control the behavior of Assembly Overrides.
public enum OverrideBehavior {

var allow: Bool {
/// Use any default overrides that are available.
case useDefaultOverrides

/// Disable and ignore any default overrides.
/// Overrides that are _explicitly provided_ will still be used.
case disableDefaultOverrides

/// Use default overrides *based on the runtime context*.
/// If the ModuleAssembler is running in a unit test environment, the default overrides will be used.
/// Otherwise disable and ignore default overrides.
case defaultOverridesWhenTesting

var allowDefaultOverrides: Bool {
switch self {
case .on: return true
case .off: return false
case .whenTesting: return Self.isRunningTests
case .useDefaultOverrides: return true
case .disableDefaultOverrides: return false
case .defaultOverridesWhenTesting: return Self.isRunningTests
}
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/Knit/Module/ScopedModuleAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
public convenience init(
parent: ModuleAssembler? = nil,
_ modules: [any Assembly],
defaultOverrides: DefaultOverrideState = .whenTesting,
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
postAssemble: ((Container) -> Void)? = nil,
file: StaticString = #file,
line: UInt = #line
Expand All @@ -26,7 +26,7 @@ public final class ScopedModuleAssembler<ScopedResolver> {
try self.init(
parent: parent,
_modules: modules,
defaultOverrides: defaultOverrides,
overrideBehavior: overrideBehavior,
postAssemble: postAssemble
)
} catch {
Expand All @@ -42,13 +42,13 @@ public final class ScopedModuleAssembler<ScopedResolver> {
required init(
parent: ModuleAssembler? = nil,
_modules modules: [any Assembly],
defaultOverrides: DefaultOverrideState = .whenTesting,
overrideBehavior: OverrideBehavior = .defaultOverridesWhenTesting,
postAssemble: ((Container) -> Void)? = nil
) throws {
self.internalAssembler = try ModuleAssembler(
parent: parent,
_modules: modules,
defaultOverrides: defaultOverrides,
overrideBehavior: overrideBehavior,
assemblyValidation: { moduleAssemblyType in
guard moduleAssemblyType.resolverType == ScopedResolver.self else {
throw ScopedModuleAssemblerError.incorrectTargetResolver(
Expand Down
28 changes: 17 additions & 11 deletions Tests/KnitTests/ModuleAssemblyOverrideTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import XCTest
final class ModuleAssemblyOverrideTests: XCTestCase {

func test_registrationWithoutFakes() throws {
let builder = try DependencyBuilder(modules: [Assembly2()], defaultOverrides: .off)
let builder = try DependencyBuilder(modules: [Assembly2()], overrideBehavior: .disableDefaultOverrides)
XCTAssertEqual(builder.assemblies.count, 2)
XCTAssertTrue(builder.assemblies[0] is Assembly1)
XCTAssertTrue(builder.assemblies[1] is Assembly2)
}

func test_registrationWithFakes() throws {
let builder = try DependencyBuilder(modules: [Assembly2(), Assembly2Fake()], defaultOverrides: .off)
let builder = try DependencyBuilder(
modules: [Assembly2(), Assembly2Fake()],
overrideBehavior: .disableDefaultOverrides
)
XCTAssertEqual(builder.assemblies.count, 3)
XCTAssertTrue(builder.assemblies[0] is Assembly1)
XCTAssertTrue(builder.assemblies[1] is FakeAssembly3)
Expand All @@ -33,28 +36,28 @@ final class ModuleAssemblyOverrideTests: XCTestCase {
}

func test_assemblerWithDefaultOverrides() {
let assembler = ModuleAssembler([Assembly2()], defaultOverrides: .on)
let assembler = ModuleAssembler([Assembly2()], overrideBehavior: .useDefaultOverrides)
XCTAssertTrue(assembler.registeredModules.contains(where: {$0 == Assembly1Fake.self}))
XCTAssertTrue(assembler.isRegistered(Assembly1Fake.self))
// Treat Assembly1 as being registered because the mock is
XCTAssertTrue(assembler.isRegistered(Assembly1.self))
}

func test_noDefaultOverrideForInputModules() {
let assembler = ModuleAssembler([Assembly1()], defaultOverrides: .on)
let assembler = ModuleAssembler([Assembly1()], overrideBehavior: .useDefaultOverrides)
XCTAssertTrue(assembler.isRegistered(Assembly1.self))
// The fake is not automatically registered
XCTAssertFalse(assembler.isRegistered(Assembly1Fake.self))
}

func test_explicitInputOverride() {
let assembler = ModuleAssembler([Assembly1(), Assembly1Fake()], defaultOverrides: .on)
let assembler = ModuleAssembler([Assembly1(), Assembly1Fake()], overrideBehavior: .useDefaultOverrides)
XCTAssertTrue(assembler.isRegistered(Assembly1.self))
XCTAssertTrue(assembler.isRegistered(Assembly1Fake.self))
}

func test_assemblerWithoutDefaultOverrides() {
let assembler = ModuleAssembler([Assembly2()], defaultOverrides: .off)
let assembler = ModuleAssembler([Assembly2()], overrideBehavior: .disableDefaultOverrides)
XCTAssertTrue(assembler.isRegistered(Assembly1.self))
XCTAssertFalse(assembler.isRegistered(Assembly1Fake.self))
}
Expand Down Expand Up @@ -83,29 +86,32 @@ final class ModuleAssemblyOverrideTests: XCTestCase {
func test_overrideDefaultOverride() {
let assembler = ModuleAssembler(
[Assembly4(), Assembly4Fake2()],
defaultOverrides: .on
overrideBehavior: .useDefaultOverrides
)
XCTAssertTrue(assembler.isRegistered(Assembly4.self))
XCTAssertTrue(assembler.isRegistered(Assembly4Fake2.self))
XCTAssertFalse(assembler.isRegistered(Assembly4Fake.self))
}

func test_nonAutoOverride() throws {
let builder = try DependencyBuilder(modules: [Assembly1(), NonAutoOverride()], defaultOverrides: .off)
let builder = try DependencyBuilder(
modules: [Assembly1(), NonAutoOverride()],
overrideBehavior: .disableDefaultOverrides
)
XCTAssertTrue(builder.assemblies.first is NonAutoOverride)
}

func test_parentNonAutoOverride() {
let parent = ModuleAssembler([NonAutoOverride()])
let child = ModuleAssembler(parent: parent, [Assembly1()], defaultOverrides: .off)
let child = ModuleAssembler(parent: parent, [Assembly1()], overrideBehavior: .disableDefaultOverrides)
XCTAssertTrue(child.isRegistered(Assembly1.self))
XCTAssertTrue(child.registeredModules.isEmpty)
}

func test_multipleOverrides() {
let assembler = ModuleAssembler(
[MultipleDependencyAssembly(), MultipleOverrideAssembly()],
defaultOverrides: .off
overrideBehavior: .disableDefaultOverrides
)

XCTAssertTrue(assembler.isRegistered(Assembly1.self))
Expand Down Expand Up @@ -135,7 +141,7 @@ private struct Assembly2: ModuleAssembly {
}
}

// Mock implementaiton of Assembly2. Adds an extra dependency on Assembly3
// Mock implementation of Assembly2. Adds an extra dependency on Assembly3
private struct Assembly2Fake: AutoInitModuleAssembly {

func assemble(container: Container) {
Expand Down

0 comments on commit 1604e24

Please sign in to comment.