diff --git a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift index dab46287b96..2257ec2eaa9 100644 --- a/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift +++ b/Sources/Build/BuildManifest/LLBuildManifestBuilder.swift @@ -268,8 +268,9 @@ extension LLBuildManifestBuilder { let outputs = testEntryPointTarget.target.sources.paths - guard let mainOutput = (outputs.first { $0.basename == TestEntryPointTool.mainFileName }) else { - throw InternalError("main output (\(TestEntryPointTool.mainFileName)) not found") + let mainFileName = TestEntryPointTool.mainFileName(for: buildParameters.testingParameters.library) + guard let mainOutput = (outputs.first { $0.basename == mainFileName }) else { + throw InternalError("main output (\(mainFileName)) not found") } let cmdName = mainOutput.pathString self.manifest.addTestEntryPointCmd( diff --git a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift index 699309fdd0b..99feb123f1b 100644 --- a/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift +++ b/Sources/Build/BuildOperationBuildSystemDelegateHandler.swift @@ -200,15 +200,22 @@ final class TestDiscoveryCommand: CustomLLBuildCommand, TestBuildCommand { } } +extension TestEntryPointTool { + public static func mainFileName(for library: BuildParameters.Testing.Library) -> String { + "runner-\(library).swift" + } +} + final class TestEntryPointCommand: CustomLLBuildCommand, TestBuildCommand { private func execute(fileSystem: Basics.FileSystem, tool: TestEntryPointTool) throws { let outputs = tool.outputs.compactMap { try? AbsolutePath(validating: $0.name) } // Find the main output file + let mainFileName = TestEntryPointTool.mainFileName(for: self.context.buildParameters.testingParameters.library) guard let mainFile = outputs.first(where: { path in - path.basename == TestEntryPointTool.mainFileName + path.basename == mainFileName }) else { - throw InternalError("main file output (\(TestEntryPointTool.mainFileName)) not found") + throw InternalError("main file output (\(mainFileName)) not found") } // Write the main file. @@ -393,7 +400,8 @@ public struct BuildDescription: Codable { return try BuiltTestProduct( productName: desc.product.name, binaryPath: desc.binaryPath, - packagePath: desc.package.path + packagePath: desc.package.path, + library: desc.buildParameters.testingParameters.library ) } self.pluginDescriptions = pluginDescriptions diff --git a/Sources/Build/BuildPlan/BuildPlan+Test.swift b/Sources/Build/BuildPlan/BuildPlan+Test.swift index 831d95fae52..0b5427d134f 100644 --- a/Sources/Build/BuildPlan/BuildPlan+Test.swift +++ b/Sources/Build/BuildPlan/BuildPlan+Test.swift @@ -109,7 +109,8 @@ extension BuildPlan { resolvedTargetDependencies: [ResolvedTarget.Dependency] ) throws -> SwiftTargetBuildDescription { let entryPointDerivedDir = buildParameters.buildPath.appending(components: "\(testProduct.name).derived") - let entryPointMainFile = entryPointDerivedDir.appending(component: TestEntryPointTool.mainFileName) + let entryPointMainFileName = TestEntryPointTool.mainFileName(for: buildParameters.testingParameters.library) + let entryPointMainFile = entryPointDerivedDir.appending(component: entryPointMainFileName) let entryPointSources = Sources(paths: [entryPointMainFile], root: entryPointDerivedDir) let entryPointTarget = SwiftTarget( diff --git a/Sources/LLBuildManifest/Tools.swift b/Sources/LLBuildManifest/Tools.swift index 7c555903984..7a6172fe2fb 100644 --- a/Sources/LLBuildManifest/Tools.swift +++ b/Sources/LLBuildManifest/Tools.swift @@ -63,7 +63,6 @@ public struct TestDiscoveryTool: ToolProtocol { public struct TestEntryPointTool: ToolProtocol { public static let name: String = "test-entry-point-tool" - public static let mainFileName: String = "runner.swift" public var inputs: [Node] public var outputs: [Node] diff --git a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift index 156c9b4a7d1..9d6f9beec2f 100644 --- a/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift +++ b/Sources/SPMBuildCore/BuildParameters/BuildParameters.swift @@ -286,12 +286,16 @@ public struct BuildParameters: Encodable { guard !targetTriple.isWASI() else { return try RelativePath(validating: "\(product.name).wasm") } - - let base = "\(product.name).xctest" - if targetTriple.isDarwin() { - return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)") - } else { - return try RelativePath(validating: base) + switch testingParameters.library { + case .xctest: + let base = "\(product.name).xctest" + if targetTriple.isDarwin() { + return try RelativePath(validating: "\(base)/Contents/MacOS/\(product.name)") + } else { + return try RelativePath(validating: base) + } + case .swiftTesting: + return try RelativePath(validating: "\(product.name).swift-testing") } case .macro: #if BUILD_MACROS_AS_DYLIBS diff --git a/Sources/SPMBuildCore/BuiltTestProduct.swift b/Sources/SPMBuildCore/BuiltTestProduct.swift index 3b0bdb3ce0e..881ade7175f 100644 --- a/Sources/SPMBuildCore/BuiltTestProduct.swift +++ b/Sources/SPMBuildCore/BuiltTestProduct.swift @@ -24,24 +24,39 @@ public struct BuiltTestProduct: Codable { public let packagePath: AbsolutePath /// The path of the test bundle. + /// + /// When the test product is not bundled (for instance, when using XCTest on + /// non-Darwin targets), this path is equal to ``binaryPath``. public var bundlePath: AbsolutePath { - // Go up the folder hierarchy until we find the .xctest bundle. + // Go up the folder hierarchy until we find the .xctest or + // .swift-testing bundle. + let pathExtension: String + switch library { + case .xctest: + pathExtension = ".xctest" + case .swiftTesting: + pathExtension = ".swift-testing" + } let hierarchySequence = sequence(first: binaryPath, next: { $0.isRoot ? nil : $0.parentDirectory }) - guard let bundlePath = hierarchySequence.first(where: { $0.basename.hasSuffix(".xctest") }) else { + guard let bundlePath = hierarchySequence.first(where: { $0.basename.hasSuffix(pathExtension) }) else { fatalError("could not find test bundle path from '\(binaryPath)'") } return bundlePath } + /// The library used to build this test product. + public var library: BuildParameters.Testing.Library + /// Creates a new instance. /// - Parameters: /// - productName: The test product name. /// - binaryPath: The path of the test binary. /// - packagePath: The path to the package this product was declared in. - public init(productName: String, binaryPath: AbsolutePath, packagePath: AbsolutePath) { + public init(productName: String, binaryPath: AbsolutePath, packagePath: AbsolutePath, library: BuildParameters.Testing.Library) { self.productName = productName self.binaryPath = binaryPath self.packagePath = packagePath + self.library = library } } diff --git a/Sources/SPMTestSupport/SwiftPMProduct.swift b/Sources/SPMTestSupport/SwiftPMProduct.swift index a3bb5b845b0..9af859fb3b3 100644 --- a/Sources/SPMTestSupport/SwiftPMProduct.swift +++ b/Sources/SPMTestSupport/SwiftPMProduct.swift @@ -44,12 +44,11 @@ extension SwiftPM { } } - /// Path to currently built binary. - public var path: AbsolutePath { - return Self.testBinaryPath(for: self.executableName) + public var xctestBinaryPath: AbsolutePath { + Self.xctestBinaryPath(for: executableName) } - public static func testBinaryPath(for executableName: RelativePath) -> AbsolutePath { + public static func xctestBinaryPath(for executableName: RelativePath) -> AbsolutePath { #if canImport(Darwin) for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") { return try! AbsolutePath(AbsolutePath(validating: bundle.bundlePath).parentDirectory, executableName) @@ -114,7 +113,7 @@ extension SwiftPM { #endif // FIXME: We use this private environment variable hack to be able to // create special conditions in swift-build for swiftpm tests. - environment["SWIFTPM_TESTS_MODULECACHE"] = self.path.parentDirectory.pathString + environment["SWIFTPM_TESTS_MODULECACHE"] = xctestBinaryPath.parentDirectory.pathString #if !os(Windows) environment["SDKROOT"] = nil #endif @@ -122,7 +121,7 @@ extension SwiftPM { // Unset the internal env variable that allows skipping certain tests. environment["_SWIFTPM_SKIP_TESTS_LIST"] = nil - var completeArgs = [self.path.pathString] + var completeArgs = [xctestBinaryPath.pathString] if let packagePath = packagePath { completeArgs += ["--package-path", packagePath.pathString] } diff --git a/Sources/XCBuildSupport/XcodeBuildSystem.swift b/Sources/XCBuildSupport/XcodeBuildSystem.swift index ec1bb2ebe05..d51eb6f8de6 100644 --- a/Sources/XCBuildSupport/XcodeBuildSystem.swift +++ b/Sources/XCBuildSupport/XcodeBuildSystem.swift @@ -56,7 +56,8 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem { BuiltTestProduct( productName: product.name, binaryPath: binaryPath, - packagePath: package.path + packagePath: package.path, + library: buildParameters.testingParameters.library ) ) } diff --git a/Tests/CommandsTests/BuildToolTests.swift b/Tests/CommandsTests/BuildToolTests.swift index 78788f4e574..4a1db4db647 100644 --- a/Tests/CommandsTests/BuildToolTests.swift +++ b/Tests/CommandsTests/BuildToolTests.swift @@ -506,7 +506,7 @@ final class BuildToolTests: CommandsTestCase { return buildArenaPath.appending(component: filename) } - let dummySwiftcPath = SwiftPM.testBinaryPath(for: "dummy-swiftc") + let dummySwiftcPath = SwiftPM.xctestBinaryPath(for: "dummy-swiftc") let swiftCompilerPath = try UserToolchain.default.swiftCompilerPath var environment = [ diff --git a/Tests/CommandsTests/RunToolTests.swift b/Tests/CommandsTests/RunToolTests.swift index 44f91cffa73..081391fa8e9 100644 --- a/Tests/CommandsTests/RunToolTests.swift +++ b/Tests/CommandsTests/RunToolTests.swift @@ -123,7 +123,7 @@ final class RunToolTests: CommandsTestCase { let sync = DispatchGroup() let outputHandler = OutputHandler(sync: sync) let process = Process( - arguments: [SwiftPM.Run.path.pathString, "--package-path", fixturePath.pathString], + arguments: [SwiftPM.Run.xctestBinaryPath.pathString, "--package-path", fixturePath.pathString], outputRedirection: .stream(stdout: outputHandler.handle(bytes:), stderr: outputHandler.handle(bytes:)) )