Skip to content

Commit f517ecb

Browse files
committed
Update README and remove compound module concept
I deemed the compound module concept as useless for now. If we want to import protocol with an identical name from different targets, we should work on prefixing them with their target name in the generated mocks.
1 parent 5f33967 commit f517ecb

File tree

3 files changed

+24
-77
lines changed

3 files changed

+24
-77
lines changed

Generator/Plugin/Modular/CuckooPluginModular.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct CuckooPluginModular: BuildToolPlugin {
3737
}
3838

3939
return try commandsPerModule(
40-
targetName: target.name,
4140
sourceModules: allSourceModules,
4241
executableFactory: context.tool(named:),
4342
projectDir: context.package.directoryURL,
@@ -86,7 +85,6 @@ extension CuckooPluginModular: XcodeBuildToolPlugin {
8685
allSourceModules.append(selfModule)
8786

8887
return try commandsPerModule(
89-
targetName: target.displayName,
9088
sourceModules: allSourceModules,
9189
executableFactory: context.tool(named:),
9290
projectDir: context.xcodeProject.directoryURL,
@@ -102,7 +100,6 @@ struct SourceModule {
102100
}
103101

104102
private func commandsPerModule(
105-
targetName: String,
106103
sourceModules: [SourceModule],
107104
executableFactory: (String) throws -> PluginContext.Tool,
108105
projectDir: URL,
@@ -123,7 +120,6 @@ private func commandsPerModule(
123120
"DERIVED_SOURCES_DIR": derivedSourcesDir.path(),
124121
"CUCKOO_OVERRIDE_OUTPUT": outputURL.path(),
125122
"CUCKOO_MODULE_NAME": sourceModule.name,
126-
"CUCKOO_COMPOUND_MODULE_NAME": "\(targetName)/\(sourceModule.name)",
127123
],
128124
inputFiles: [configurationURL] + sourceModule.sources,
129125
outputFiles: [outputURL]

Generator/Sources/CLI/GenerateCommand.swift

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,9 @@ struct GenerateCommand: AsyncParsableCommand {
5656
)
5757

5858
if modules.isEmpty {
59-
let compoundModuleName = ProcessInfo.processInfo.environment["CUCKOO_COMPOUND_MODULE_NAME"]
6059
let requestedModuleName = ProcessInfo.processInfo.environment["CUCKOO_MODULE_NAME"]
61-
let effectiveName = compoundModuleName ?? requestedModuleName
62-
if let effectiveName {
63-
log(.info, message: "No module named '\(effectiveName)' found in Cuckoofile, skipping generation.")
60+
if let requestedModuleName {
61+
log(.info, message: "No module named '\(requestedModuleName)' found in Cuckoofile, skipping generation.")
6462
}
6563
if let outputPath = overriddenOutput {
6664
let path = Path(outputPath, expandingTilde: true)
@@ -124,7 +122,6 @@ struct GenerateCommand: AsyncParsableCommand {
124122

125123
func modules(configurationPath: Path, contents: String) throws -> [Module] {
126124
let requestedModuleName = ProcessInfo.processInfo.environment["CUCKOO_MODULE_NAME"]
127-
let compoundModuleName = ProcessInfo.processInfo.environment["CUCKOO_COMPOUND_MODULE_NAME"]
128125

129126
var errorMessages: [String] = []
130127
var globalOutput: String? = overriddenOutput
@@ -188,39 +185,9 @@ struct GenerateCommand: AsyncParsableCommand {
188185
throw GenerateError.configurationErrors(details: errorMessages)
189186
}
190187

191-
let filteredModules = filterModulesByEnvironment(
192-
allModules: allModules,
193-
compoundModuleName: compoundModuleName,
194-
requestedModuleName: requestedModuleName
195-
)
196-
197-
return filteredModules
198-
}
199-
200-
/// Filter modules based on environment variables set by the plugin.
201-
/// Priority: compound module name (TARGET/MODULE) > plain module name > all modules.
202-
/// This allows test targets to override shared dependency mock generation.
203-
private func filterModulesByEnvironment(
204-
allModules: [Module],
205-
compoundModuleName: String?,
206-
requestedModuleName: String?
207-
) -> [Module] {
208-
if let compoundModuleName {
209-
let compoundMatches = allModules.filter { $0.name == compoundModuleName }
210-
if !compoundMatches.isEmpty {
211-
// Compound key (TARGET/MODULE) found – use it exclusively.
212-
// An entry with empty sources acts as a suppressor, producing an empty output file.
213-
return compoundMatches
214-
} else if let requestedModuleName {
215-
// No compound override – fall back to the plain module name.
216-
return allModules.filter { $0.name == requestedModuleName }
217-
} else {
218-
return []
219-
}
220-
} else if let requestedModuleName {
188+
if let requestedModuleName {
221189
return allModules.filter { $0.name == requestedModuleName }
222190
}
223-
224191
return allModules
225192
}
226193

README.md

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -133,63 +133,47 @@ target = "Cuckoonator"
133133

134134
#### For CuckooPluginModular
135135

136-
When using `CuckooPluginModular`, the plugin automatically detects source modules from your test target's dependencies and generates a dedicated mock file for each one (`GeneratedMocks_<ModuleName>.swift`). It supports compound module names (`TARGET/MODULE`) in `Cuckoofile.toml` so that different test targets can customize mock generation for shared dependencies.
136+
When using `CuckooPluginModular`, the plugin collects every source module dependency of your test target (excluding Cuckoo) and runs the generator once per module, producing a separate `GeneratedMocks_<ModuleName>.swift` file for each one. It also runs the generator for the test target's own name, so you can add a `[modules.<TestTargetName>]` entry in `Cuckoofile.toml` to control exactly which files are mocked and which imports are added. If no matching entry exists in the configuration, that module is silently skipped.
137137

138138
**Example `Cuckoofile.toml` for modular projects:**
139139

140140
```toml
141-
# CoreModule mocks
142-
[modules.CoreModuleTests]
141+
# TargetA mocks
142+
[modules.TargetATests]
143143
imports = ["Foundation"]
144-
testableImports = ["CoreModule"]
144+
testableImports = ["TargetA"] #ProtocolA is internal to TargetA
145145
sources = [
146-
"Sources/CoreModule/ServiceProtocol.swift"
146+
"Sources/TargetA/InternalProtocolA.swift"
147147
]
148148

149-
# NetworkAPI module mocks
150-
[modules.FirstNetworkAPITests]
151-
imports = ["Foundation"]
152-
testableImports = ["FirstNetworkAPI"]
153-
sources = [
154-
"Sources/FirstNetworkAPI/Generated/Client.swift"
155-
]
156-
157-
# SecondNetworkAPI module mocks
158-
[modules.SecondNetworkAPITests]
159-
imports = ["Foundation"]
160-
testableImports = ["SecondNetworkAPI"]
149+
# AggregationTarget mocks - demonstrates multiple testableImports
150+
[modules.AggregationTargetTests]
151+
imports = ["Foundation", "TargetA", "TargetB"]
161152
sources = [
162-
"Sources/SecondNetworkAPI/Generated/Client.swift"
163-
]
164-
165-
# FeatureModule mocks - demonstrates multiple testableImports
166-
[modules.FeatureModuleTests]
167-
imports = ["Foundation"]
168-
testableImports = ["FirstNetworkAPI", "SecondNetworkAPI"]
169-
sources = [
170-
"Sources/FirstNetworkAPI/FirstNetworkAPI.swift",
171-
"Sources/SecondNetworkAPI/SecondNetworkAPI.swift"
153+
"Sources/TargetA/ProtocolA.swift",
154+
"Sources/TargetB/ProtocolB.swift",
172155
]
173156
```
174157

175-
**Note:** The modules specified in `testableImports` must be added as dependencies of your test target in `Package.swift`. For example:
158+
`Package.swift`:
176159

177160
```swift
178161
.testTarget(
179-
name: "CoreModuleTests",
180-
dependencies: ["CoreModule", "Cuckoo"]
162+
name: "TargetATests",
163+
dependencies: ["TargetA", "Cuckoo"],
164+
plugins: [
165+
.plugin(name: "CuckooPluginModular", package: "Cuckoo"),
166+
]
181167
),
182168
.testTarget(
183-
name: "FeatureModuleTests",
184-
dependencies: ["FirstNetworkAPI", "SecondNetworkAPI", "Cuckoo"]
169+
name: "AggregationTargetTests",
170+
dependencies: ["AggregationTarget", "Cuckoo"],
171+
plugins: [
172+
.plugin(name: "CuckooPluginModular", package: "Cuckoo"),
173+
]
185174
)
186175
```
187176

188-
This approach is essential when:
189-
- **Multiple modules define protocols/types with identical names** (e.g., both `ModuleA` and `ModuleB` have a `ServiceProtocol`)
190-
- Different test targets need different subsets of mocks from the same module
191-
- You want to organize and namespace mocks by test target for clarity
192-
193177
### 3. Usage
194178
Usage of Cuckoo is similar to [Mockito](http://mockito.org/) and [Hamcrest](http://hamcrest.org/). However, there are some differences and limitations caused by generating the mocks and Swift language itself. List of all the supported features can be found below. You can find complete examples in [tests](Tests).
195179

0 commit comments

Comments
 (0)