@@ -33,19 +33,21 @@ extension BuildPlan {
3333 _ observabilityScope: ObservabilityScope
3434 ) throws -> [ ( product: ResolvedProduct , discoveryTargetBuildDescription: SwiftTargetBuildDescription ? , entryPointTargetBuildDescription: SwiftTargetBuildDescription ) ] {
3535 guard buildParameters. testingParameters. testProductStyle. requiresAdditionalDerivedTestTargets,
36- case . entryPointExecutable( let explicitlySpecifiedPath) =
36+ case . entryPointExecutable( let explicitlyEnabledDiscovery , let explicitlySpecifiedPath) =
3737 buildParameters. testingParameters. testProductStyle
3838 else {
3939 throw InternalError ( " makeTestManifestTargets should not be used for build plan which does not require additional derived test targets " )
4040 }
4141
4242 let isEntryPointPathSpecifiedExplicitly = explicitlySpecifiedPath != nil
4343
44+ var isDiscoveryEnabledRedundantly = explicitlyEnabledDiscovery && !isEntryPointPathSpecifiedExplicitly
4445 var result : [ ( ResolvedProduct , SwiftTargetBuildDescription ? , SwiftTargetBuildDescription ) ] = [ ]
4546 for testProduct in graph. allProducts where testProduct. type == . test {
4647 guard let package = graph. package ( for: testProduct) else {
4748 throw InternalError ( " package not found for \( testProduct) " )
4849 }
50+ isDiscoveryEnabledRedundantly = isDiscoveryEnabledRedundantly && nil == testProduct. testEntryPointTarget
4951 // If a non-explicitly specified test entry point file exists, prefer that over test discovery.
5052 // This is designed as an escape hatch when test discovery is not appropriate and for backwards
5153 // compatibility for projects that have existing test entry point files (e.g. XCTMain.swift, LinuxMain.swift).
@@ -56,7 +58,10 @@ extension BuildPlan {
5658 // `--experimental-test-entry-point-path <file>`. The latter is useful because it still performs test discovery and places the discovered
5759 // tests into a separate target/module named "<PackageName>PackageDiscoveredTests". Then, that entry point file may import that module and
5860 // obtain that list to pass it to the `XCTMain(...)` function and avoid needing to maintain a list of tests itself.
59- if testProduct. testEntryPointTarget == nil , let testEntryPointPath = explicitlySpecifiedPath, !fileSystem. exists ( testEntryPointPath) {
61+ if testProduct. testEntryPointTarget != nil && explicitlyEnabledDiscovery && !isEntryPointPathSpecifiedExplicitly {
62+ let testEntryPointName = testProduct. underlying. testEntryPointPath? . basename ?? SwiftTarget . defaultTestEntryPointName
63+ observabilityScope. emit ( warning: " '--enable-test-discovery' was specified so the ' \( testEntryPointName) ' entry point file for ' \( testProduct. name) ' will be ignored and an entry point will be generated automatically. To use test discovery with a custom entry point file, pass '--experimental-test-entry-point-path <file>'. " )
64+ } else if testProduct. testEntryPointTarget == nil , let testEntryPointPath = explicitlySpecifiedPath, !fileSystem. exists ( testEntryPointPath) {
6065 observabilityScope. emit ( error: " '--experimental-test-entry-point-path' was specified but the file ' \( testEntryPointPath) ' could not be found. " )
6166 }
6267
@@ -155,34 +160,43 @@ extension BuildPlan {
155160 }
156161
157162 if let entryPointResolvedTarget = testProduct. testEntryPointTarget {
158- if isEntryPointPathSpecifiedExplicitly {
159- // Allow using the explicitly-specified test entry point target, but still perform test discovery and thus declare a dependency on the discovery targets.
160- let entryPointTarget = SwiftTarget (
161- name: entryPointResolvedTarget. underlying. name,
162- dependencies: entryPointResolvedTarget. underlying. dependencies + swiftTargetDependencies,
163- packageAccess: entryPointResolvedTarget. packageAccess,
164- testEntryPointSources: entryPointResolvedTarget. underlying. sources
165- )
166- let entryPointResolvedTarget = ResolvedTarget (
167- packageIdentity: testProduct. packageIdentity,
168- underlying: entryPointTarget,
169- dependencies: entryPointResolvedTarget. dependencies + resolvedTargetDependencies,
170- defaultLocalization: testProduct. defaultLocalization,
171- supportedPlatforms: testProduct. supportedPlatforms,
172- platformVersionProvider: testProduct. platformVersionProvider
173- )
174- let entryPointTargetBuildDescription = try SwiftTargetBuildDescription (
175- package : package ,
176- target: entryPointResolvedTarget,
177- toolsVersion: toolsVersion,
178- buildParameters: buildParameters,
179- testTargetRole: . entryPoint( isSynthesized: false ) ,
180- disableSandbox: disableSandbox,
181- fileSystem: fileSystem,
182- observabilityScope: observabilityScope
183- )
184-
185- result. append ( ( testProduct, discoveryTargets? . buildDescription, entryPointTargetBuildDescription) )
163+ if isEntryPointPathSpecifiedExplicitly || explicitlyEnabledDiscovery {
164+ if isEntryPointPathSpecifiedExplicitly {
165+ // Allow using the explicitly-specified test entry point target, but still perform test discovery and thus declare a dependency on the discovery targets.
166+ let entryPointTarget = SwiftTarget (
167+ name: entryPointResolvedTarget. underlying. name,
168+ dependencies: entryPointResolvedTarget. underlying. dependencies + swiftTargetDependencies,
169+ packageAccess: entryPointResolvedTarget. packageAccess,
170+ testEntryPointSources: entryPointResolvedTarget. underlying. sources
171+ )
172+ let entryPointResolvedTarget = ResolvedTarget (
173+ packageIdentity: testProduct. packageIdentity,
174+ underlying: entryPointTarget,
175+ dependencies: entryPointResolvedTarget. dependencies + resolvedTargetDependencies,
176+ defaultLocalization: testProduct. defaultLocalization,
177+ supportedPlatforms: testProduct. supportedPlatforms,
178+ platformVersionProvider: testProduct. platformVersionProvider
179+ )
180+ let entryPointTargetBuildDescription = try SwiftTargetBuildDescription (
181+ package : package ,
182+ target: entryPointResolvedTarget,
183+ toolsVersion: toolsVersion,
184+ buildParameters: buildParameters,
185+ testTargetRole: . entryPoint( isSynthesized: false ) ,
186+ disableSandbox: disableSandbox,
187+ fileSystem: fileSystem,
188+ observabilityScope: observabilityScope
189+ )
190+
191+ result. append ( ( testProduct, discoveryTargets? . buildDescription, entryPointTargetBuildDescription) )
192+ } else {
193+ // Ignore test entry point and synthesize one, declaring a dependency on the test discovery targets created above.
194+ let entryPointTargetBuildDescription = try generateSynthesizedEntryPointTarget (
195+ swiftTargetDependencies: swiftTargetDependencies,
196+ resolvedTargetDependencies: resolvedTargetDependencies
197+ )
198+ result. append ( ( testProduct, discoveryTargets? . buildDescription, entryPointTargetBuildDescription) )
199+ }
186200 } else {
187201 // Use the test entry point as-is, without performing test discovery.
188202 let entryPointTargetBuildDescription = try SwiftTargetBuildDescription (
@@ -207,6 +221,10 @@ extension BuildPlan {
207221 }
208222 }
209223
224+ if isDiscoveryEnabledRedundantly {
225+ observabilityScope. emit ( warning: " '--enable-test-discovery' option is deprecated; tests are automatically discovered on all platforms " )
226+ }
227+
210228 return result
211229 }
212230}
0 commit comments